Index: projects/ci20_mips/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l =================================================================== --- projects/ci20_mips/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l (revision 283030) +++ projects/ci20_mips/cddl/contrib/opensolaris/lib/libdtrace/common/dt_lex.l (revision 283031) @@ -1,883 +1,884 @@ %{ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright (c) 2013 by Delphix. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include /* * We need to undefine lex's input and unput macros so that references to these * call the functions provided at the end of this source file. */ #ifdef illumos #undef input #undef unput #else /* * Define YY_INPUT for flex since input() can't be re-defined. */ #define YY_INPUT(buf,result,max_size) \ if (yypcb->pcb_fileptr != NULL) { \ if (((result = fread(buf, 1, max_size, yypcb->pcb_fileptr)) == 0) \ && ferror(yypcb->pcb_fileptr)) \ longjmp(yypcb->pcb_jmpbuf, EDT_FIO); \ } else { \ int n; \ for (n = 0; n < max_size && \ yypcb->pcb_strptr < yypcb->pcb_string + yypcb->pcb_strlen; n++) \ buf[n] = *yypcb->pcb_strptr++; \ result = n; \ } /* * Do not EOF let tokens to be put back. This does not work with flex. * On the other hand, leaving current buffer in same state it was when * last EOF was received guarantees that input() will keep returning EOF * for all subsequent invocations, which is the effect desired. */ #undef unput #define unput(c) \ do { \ int _c = c; \ if (_c != EOF) \ yyunput(_c, yytext_ptr); \ } while(0) #endif static int id_or_type(const char *); #ifdef illumos static int input(void); static void unput(int); #endif /* * We first define a set of labeled states for use in the D lexer and then a * set of regular expressions to simplify things below. The lexer states are: * * S0 - D program clause and expression lexing * S1 - D comments (i.e. skip everything until end of comment) * S2 - D program outer scope (probe specifiers and declarations) * S3 - D control line parsing (i.e. after ^# is seen but before \n) * S4 - D control line scan (locate control directives only and invoke S3) */ %} %e 1500 /* maximum nodes */ %p 4900 /* maximum positions */ %n 600 /* maximum states */ %a 3000 /* maximum transitions */ %s S0 S1 S2 S3 S4 RGX_AGG "@"[a-zA-Z_][0-9a-zA-Z_]* RGX_PSPEC [-$:a-zA-Z_.?*\\\[\]!][-$:0-9a-zA-Z_.`?*\\\[\]!]* RGX_ALTIDENT [a-zA-Z_][0-9a-zA-Z_]* RGX_LMID LM[0-9a-fA-F]+` RGX_MOD_IDENT [a-zA-Z_`][0-9a-z.A-Z_`]*` RGX_IDENT [a-zA-Z_`][0-9a-zA-Z_`]* RGX_INT ([0-9]+|0[xX][0-9A-Fa-f]+)[uU]?[lL]?[lL]? RGX_FP ([0-9]+("."?)[0-9]*|"."[0-9]+)((e|E)("+"|-)?[0-9]+)?[fFlL]? RGX_WS [\f\n\r\t\v ] RGX_STR ([^"\\\n]|\\[^"\n]|\\\")* RGX_CHR ([^'\\\n]|\\[^'\n]|\\')* RGX_INTERP ^[\f\t\v ]*#!.* RGX_CTL ^[\f\t\v ]*# %% %{ /* * We insert a special prologue into yylex() itself: if the pcb contains a * context token, we return that prior to running the normal lexer. This * allows libdtrace to force yacc into one of our three parsing contexts: D * expression (DT_CTX_DEXPR), D program (DT_CTX_DPROG) or D type (DT_CTX_DTYPE). * Once the token is returned, we clear it so this only happens once. */ if (yypcb->pcb_token != 0) { int tok = yypcb->pcb_token; yypcb->pcb_token = 0; return (tok); } %} auto return (DT_KEY_AUTO); break return (DT_KEY_BREAK); case return (DT_KEY_CASE); char return (DT_KEY_CHAR); const return (DT_KEY_CONST); continue return (DT_KEY_CONTINUE); counter return (DT_KEY_COUNTER); default return (DT_KEY_DEFAULT); do return (DT_KEY_DO); double return (DT_KEY_DOUBLE); else return (DT_KEY_ELSE); enum return (DT_KEY_ENUM); extern return (DT_KEY_EXTERN); float return (DT_KEY_FLOAT); for return (DT_KEY_FOR); goto return (DT_KEY_GOTO); if return (DT_KEY_IF); import return (DT_KEY_IMPORT); inline return (DT_KEY_INLINE); int return (DT_KEY_INT); long return (DT_KEY_LONG); offsetof return (DT_TOK_OFFSETOF); probe return (DT_KEY_PROBE); provider return (DT_KEY_PROVIDER); register return (DT_KEY_REGISTER); restrict return (DT_KEY_RESTRICT); return return (DT_KEY_RETURN); self return (DT_KEY_SELF); short return (DT_KEY_SHORT); signed return (DT_KEY_SIGNED); sizeof return (DT_TOK_SIZEOF); static return (DT_KEY_STATIC); string return (DT_KEY_STRING); stringof return (DT_TOK_STRINGOF); struct return (DT_KEY_STRUCT); switch return (DT_KEY_SWITCH); this return (DT_KEY_THIS); translator return (DT_KEY_XLATOR); typedef return (DT_KEY_TYPEDEF); union return (DT_KEY_UNION); unsigned return (DT_KEY_UNSIGNED); userland return (DT_KEY_USERLAND); void return (DT_KEY_VOID); volatile return (DT_KEY_VOLATILE); while return (DT_KEY_WHILE); xlate return (DT_TOK_XLATE); auto { yybegin(YYS_EXPR); return (DT_KEY_AUTO); } char { yybegin(YYS_EXPR); return (DT_KEY_CHAR); } const { yybegin(YYS_EXPR); return (DT_KEY_CONST); } counter { yybegin(YYS_DEFINE); return (DT_KEY_COUNTER); } double { yybegin(YYS_EXPR); return (DT_KEY_DOUBLE); } enum { yybegin(YYS_EXPR); return (DT_KEY_ENUM); } extern { yybegin(YYS_EXPR); return (DT_KEY_EXTERN); } float { yybegin(YYS_EXPR); return (DT_KEY_FLOAT); } import { yybegin(YYS_EXPR); return (DT_KEY_IMPORT); } inline { yybegin(YYS_DEFINE); return (DT_KEY_INLINE); } int { yybegin(YYS_EXPR); return (DT_KEY_INT); } long { yybegin(YYS_EXPR); return (DT_KEY_LONG); } provider { yybegin(YYS_DEFINE); return (DT_KEY_PROVIDER); } register { yybegin(YYS_EXPR); return (DT_KEY_REGISTER); } restrict { yybegin(YYS_EXPR); return (DT_KEY_RESTRICT); } self { yybegin(YYS_EXPR); return (DT_KEY_SELF); } short { yybegin(YYS_EXPR); return (DT_KEY_SHORT); } signed { yybegin(YYS_EXPR); return (DT_KEY_SIGNED); } static { yybegin(YYS_EXPR); return (DT_KEY_STATIC); } string { yybegin(YYS_EXPR); return (DT_KEY_STRING); } struct { yybegin(YYS_EXPR); return (DT_KEY_STRUCT); } this { yybegin(YYS_EXPR); return (DT_KEY_THIS); } translator { yybegin(YYS_DEFINE); return (DT_KEY_XLATOR); } typedef { yybegin(YYS_EXPR); return (DT_KEY_TYPEDEF); } union { yybegin(YYS_EXPR); return (DT_KEY_UNION); } unsigned { yybegin(YYS_EXPR); return (DT_KEY_UNSIGNED); } void { yybegin(YYS_EXPR); return (DT_KEY_VOID); } volatile { yybegin(YYS_EXPR); return (DT_KEY_VOLATILE); } "$$"[0-9]+ { int i = atoi(yytext + 2); char *v = ""; /* * A macro argument reference substitutes the text of * an argument in place of the current token. When we * see $$ we fetch the saved string from pcb_sargv * (or use the default argument if the option has been * set and the argument hasn't been specified) and * return a token corresponding to this string. */ if (i < 0 || (i >= yypcb->pcb_sargc && !(yypcb->pcb_cflags & DTRACE_C_DEFARG))) { xyerror(D_MACRO_UNDEF, "macro argument %s is " "not defined\n", yytext); } if (i < yypcb->pcb_sargc) { v = yypcb->pcb_sargv[i]; /* get val from pcb */ yypcb->pcb_sflagv[i] |= DT_IDFLG_REF; } if ((yylval.l_str = strdup(v)) == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); (void) stresc2chr(yylval.l_str); return (DT_TOK_STRING); } "$"[0-9]+ { int i = atoi(yytext + 1); char *p, *v = "0"; /* * A macro argument reference substitutes the text of * one identifier or integer pattern for another. When * we see $ we fetch the saved string from pcb_sargv * (or use the default argument if the option has been * set and the argument hasn't been specified) and * return a token corresponding to this string. */ if (i < 0 || (i >= yypcb->pcb_sargc && !(yypcb->pcb_cflags & DTRACE_C_DEFARG))) { xyerror(D_MACRO_UNDEF, "macro argument %s is " "not defined\n", yytext); } if (i < yypcb->pcb_sargc) { v = yypcb->pcb_sargv[i]; /* get val from pcb */ yypcb->pcb_sflagv[i] |= DT_IDFLG_REF; } /* * If the macro text is not a valid integer or ident, * then we treat it as a string. The string may be * optionally enclosed in quotes, which we strip. */ if (strbadidnum(v)) { size_t len = strlen(v); if (len != 1 && *v == '"' && v[len - 1] == '"') yylval.l_str = strndup(v + 1, len - 2); else yylval.l_str = strndup(v, len); if (yylval.l_str == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); (void) stresc2chr(yylval.l_str); return (DT_TOK_STRING); } /* * If the macro text is not a string an begins with a * digit or a +/- sign, process it as an integer token. */ if (isdigit(v[0]) || v[0] == '-' || v[0] == '+') { if (isdigit(v[0])) yyintprefix = 0; else yyintprefix = *v++; errno = 0; yylval.l_int = strtoull(v, &p, 0); (void) strncpy(yyintsuffix, p, sizeof (yyintsuffix)); yyintdecimal = *v != '0'; if (errno == ERANGE) { xyerror(D_MACRO_OFLOW, "macro argument" " %s constant %s results in integer" " overflow\n", yytext, v); } return (DT_TOK_INT); } return (id_or_type(v)); } "$$"{RGX_IDENT} { dt_ident_t *idp = dt_idhash_lookup( yypcb->pcb_hdl->dt_macros, yytext + 2); char s[16]; /* enough for UINT_MAX + \0 */ if (idp == NULL) { xyerror(D_MACRO_UNDEF, "macro variable %s " "is not defined\n", yytext); } /* * For the moment, all current macro variables are of * type id_t (refer to dtrace_update() for details). */ (void) snprintf(s, sizeof (s), "%u", idp->di_id); if ((yylval.l_str = strdup(s)) == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); return (DT_TOK_STRING); } "$"{RGX_IDENT} { dt_ident_t *idp = dt_idhash_lookup( yypcb->pcb_hdl->dt_macros, yytext + 1); if (idp == NULL) { xyerror(D_MACRO_UNDEF, "macro variable %s " "is not defined\n", yytext); } /* * For the moment, all current macro variables are of * type id_t (refer to dtrace_update() for details). */ yylval.l_int = (intmax_t)(int)idp->di_id; yyintprefix = 0; yyintsuffix[0] = '\0'; yyintdecimal = 1; return (DT_TOK_INT); } {RGX_IDENT} | {RGX_MOD_IDENT}{RGX_IDENT} | {RGX_MOD_IDENT} { return (id_or_type(yytext)); } {RGX_AGG} { if ((yylval.l_str = strdup(yytext)) == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); return (DT_TOK_AGG); } "@" { if ((yylval.l_str = strdup("@_")) == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); return (DT_TOK_AGG); } {RGX_INT} | {RGX_INT} | {RGX_INT} { char *p; errno = 0; yylval.l_int = strtoull(yytext, &p, 0); yyintprefix = 0; (void) strncpy(yyintsuffix, p, sizeof (yyintsuffix)); yyintdecimal = yytext[0] != '0'; if (errno == ERANGE) { xyerror(D_INT_OFLOW, "constant %s results in " "integer overflow\n", yytext); } if (*p != '\0' && strchr("uUlL", *p) == NULL) { xyerror(D_INT_DIGIT, "constant %s contains " "invalid digit %c\n", yytext, *p); } if ((YYSTATE) != S3) return (DT_TOK_INT); yypragma = dt_node_link(yypragma, dt_node_int(yylval.l_int)); } {RGX_FP} yyerror("floating-point constants are not permitted\n"); \"{RGX_STR}$ | \"{RGX_STR}$ xyerror(D_STR_NL, "newline encountered in string literal"); \"{RGX_STR}\" | \"{RGX_STR}\" { /* * Quoted string -- convert C escape sequences and * return the string as a token. */ yylval.l_str = strndup(yytext + 1, yyleng - 2); if (yylval.l_str == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); (void) stresc2chr(yylval.l_str); if ((YYSTATE) != S3) return (DT_TOK_STRING); yypragma = dt_node_link(yypragma, dt_node_string(yylval.l_str)); } '{RGX_CHR}$ xyerror(D_CHR_NL, "newline encountered in character constant"); '{RGX_CHR}' { char *s, *p, *q; size_t nbytes; /* * Character constant -- convert C escape sequences and * return the character as an integer immediate value. */ if (yyleng == 2) xyerror(D_CHR_NULL, "empty character constant"); s = yytext + 1; yytext[yyleng - 1] = '\0'; nbytes = stresc2chr(s); yylval.l_int = 0; yyintprefix = 0; yyintsuffix[0] = '\0'; yyintdecimal = 1; if (nbytes > sizeof (yylval.l_int)) { xyerror(D_CHR_OFLOW, "character constant is " "too long"); } #if BYTE_ORDER == _LITTLE_ENDIAN p = ((char *)&yylval.l_int) + nbytes - 1; for (q = s; nbytes != 0; nbytes--) *p-- = *q++; #else bcopy(s, ((char *)&yylval.l_int) + sizeof (yylval.l_int) - nbytes, nbytes); #endif return (DT_TOK_INT); } "/*" | "/*" { yypcb->pcb_cstate = (YYSTATE); BEGIN(S1); } {RGX_INTERP} | {RGX_INTERP} ; /* discard any #! lines */ {RGX_CTL} | {RGX_CTL} | {RGX_CTL} { assert(yypragma == NULL); yypcb->pcb_cstate = (YYSTATE); BEGIN(S3); } . ; /* discard */ "\n" ; /* discard */ "/" { int c, tok; /* * The use of "/" as the predicate delimiter and as the * integer division symbol requires special lookahead * to avoid a shift/reduce conflict in the D grammar. * We look ahead to the next non-whitespace character. * If we encounter EOF, ";", "{", or "/", then this "/" * closes the predicate and we return DT_TOK_EPRED. * If we encounter anything else, it's DT_TOK_DIV. */ while ((c = input()) != 0) { if (strchr("\f\n\r\t\v ", c) == NULL) break; } if (c == 0 || c == ';' || c == '{' || c == '/') { if (yypcb->pcb_parens != 0) { yyerror("closing ) expected in " "predicate before /\n"); } if (yypcb->pcb_brackets != 0) { yyerror("closing ] expected in " "predicate before /\n"); } tok = DT_TOK_EPRED; } else tok = DT_TOK_DIV; unput(c); return (tok); } "(" { yypcb->pcb_parens++; return (DT_TOK_LPAR); } ")" { if (--yypcb->pcb_parens < 0) yyerror("extra ) in input stream\n"); return (DT_TOK_RPAR); } "[" { yypcb->pcb_brackets++; return (DT_TOK_LBRAC); } "]" { if (--yypcb->pcb_brackets < 0) yyerror("extra ] in input stream\n"); return (DT_TOK_RBRAC); } "{" | "{" { yypcb->pcb_braces++; return ('{'); } "}" { if (--yypcb->pcb_braces < 0) yyerror("extra } in input stream\n"); return ('}'); } "|" return (DT_TOK_BOR); "^" return (DT_TOK_XOR); "&" return (DT_TOK_BAND); "&&" return (DT_TOK_LAND); "^^" return (DT_TOK_LXOR); "||" return (DT_TOK_LOR); "==" return (DT_TOK_EQU); "!=" return (DT_TOK_NEQ); "<" return (DT_TOK_LT); "<=" return (DT_TOK_LE); ">" return (DT_TOK_GT); ">=" return (DT_TOK_GE); "<<" return (DT_TOK_LSH); ">>" return (DT_TOK_RSH); "+" return (DT_TOK_ADD); "-" return (DT_TOK_SUB); "*" return (DT_TOK_MUL); "%" return (DT_TOK_MOD); "~" return (DT_TOK_BNEG); "!" return (DT_TOK_LNEG); "?" return (DT_TOK_QUESTION); ":" return (DT_TOK_COLON); "." return (DT_TOK_DOT); "->" return (DT_TOK_PTR); "=" return (DT_TOK_ASGN); "+=" return (DT_TOK_ADD_EQ); "-=" return (DT_TOK_SUB_EQ); "*=" return (DT_TOK_MUL_EQ); "/=" return (DT_TOK_DIV_EQ); "%=" return (DT_TOK_MOD_EQ); "&=" return (DT_TOK_AND_EQ); "^=" return (DT_TOK_XOR_EQ); "|=" return (DT_TOK_OR_EQ); "<<=" return (DT_TOK_LSH_EQ); ">>=" return (DT_TOK_RSH_EQ); "++" return (DT_TOK_ADDADD); "--" return (DT_TOK_SUBSUB); "..." return (DT_TOK_ELLIPSIS); "," return (DT_TOK_COMMA); ";" return (';'); {RGX_WS} ; /* discard */ "\\"\n ; /* discard */ . yyerror("syntax error near \"%c\"\n", yytext[0]); "/*" yyerror("/* encountered inside a comment\n"); "*/" BEGIN(yypcb->pcb_cstate); .|\n ; /* discard */ {RGX_PSPEC} { /* * S2 has an ambiguity because RGX_PSPEC includes '*' * as a glob character and '*' also can be DT_TOK_STAR. * Since lex always matches the longest token, this * rule can be matched by an input string like "int*", * which could begin a global variable declaration such * as "int*x;" or could begin a RGX_PSPEC with globbing * such as "int* { trace(timestamp); }". If C_PSPEC is * not set, we must resolve the ambiguity in favor of * the type and perform lexer pushback if the fragment * before '*' or entire fragment matches a type name. * If C_PSPEC is set, we always return a PSPEC token. * If C_PSPEC is off, the user can avoid ambiguity by * including a ':' delimiter in the specifier, which * they should be doing anyway to specify the provider. */ if (!(yypcb->pcb_cflags & DTRACE_C_PSPEC) && strchr(yytext, ':') == NULL) { char *p = strchr(yytext, '*'); char *q = yytext + yyleng - 1; if (p != NULL && p > yytext) *p = '\0'; /* prune yytext */ if (dt_type_lookup(yytext, NULL) == 0) { yylval.l_str = strdup(yytext); if (yylval.l_str == NULL) { longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); } if (p != NULL && p > yytext) { for (*p = '*'; q >= p; q--) unput(*q); } yybegin(YYS_EXPR); return (DT_TOK_TNAME); } if (p != NULL && p > yytext) *p = '*'; /* restore yytext */ } if ((yylval.l_str = strdup(yytext)) == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); return (DT_TOK_PSPEC); } "/" return (DT_TOK_DIV); "," return (DT_TOK_COMMA); {RGX_WS} ; /* discard */ . yyerror("syntax error near \"%c\"\n", yytext[0]); \n { dt_pragma(yypragma); yypragma = NULL; BEGIN(yypcb->pcb_cstate); } [\f\t\v ]+ ; /* discard */ [^\f\n\t\v "]+ { dt_node_t *dnp; if ((yylval.l_str = strdup(yytext)) == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); /* * We want to call dt_node_ident() here, but we can't * because it will expand inlined identifiers, which we * don't want to do from #pragma context in order to * support pragmas that apply to the ident itself. We * call dt_node_string() and then reset dn_op instead. */ dnp = dt_node_string(yylval.l_str); dnp->dn_kind = DT_NODE_IDENT; dnp->dn_op = DT_TOK_IDENT; yypragma = dt_node_link(yypragma, dnp); } . yyerror("syntax error near \"%c\"\n", yytext[0]); %% /* * yybegin provides a wrapper for use from C code around the lex BEGIN() macro. * We use two main states for lexing because probe descriptions use a syntax * that is incompatible with the normal D tokens (e.g. names can contain "-"). * yybegin also handles the job of switching between two lists of dt_nodes * as we allocate persistent definitions, like inlines, and transient nodes * that will be freed once we are done parsing the current program file. */ void yybegin(yystate_t state) { #ifdef YYDEBUG yydebug = _dtrace_debug; #endif if (yypcb->pcb_yystate == state) return; /* nothing to do if we're in the state already */ if (yypcb->pcb_yystate == YYS_DEFINE) { yypcb->pcb_list = yypcb->pcb_hold; yypcb->pcb_hold = NULL; } switch (state) { case YYS_CLAUSE: BEGIN(S2); break; case YYS_DEFINE: assert(yypcb->pcb_hold == NULL); yypcb->pcb_hold = yypcb->pcb_list; yypcb->pcb_list = NULL; /*FALLTHRU*/ case YYS_EXPR: BEGIN(S0); break; case YYS_DONE: break; case YYS_CONTROL: BEGIN(S4); break; default: xyerror(D_UNKNOWN, "internal error -- bad yystate %d\n", state); } yypcb->pcb_yystate = state; } void yyinit(dt_pcb_t *pcb) { yypcb = pcb; yylineno = 1; yypragma = NULL; #ifdef illumos yysptr = yysbuf; #endif + YY_FLUSH_BUFFER; } /* * Given a lexeme 's' (typically yytext), set yylval and return an appropriate * token to the parser indicating either an identifier or a typedef name. * User-defined global variables always take precedence over types, but we do * use some heuristics because D programs can look at an ever-changing set of * kernel types and also can implicitly instantiate variables by assignment, * unlike in C. The code here is ordered carefully as lookups are not cheap. */ static int id_or_type(const char *s) { dtrace_hdl_t *dtp = yypcb->pcb_hdl; dt_decl_t *ddp = yypcb->pcb_dstack.ds_decl; int c0, c1, ttok = DT_TOK_TNAME; dt_ident_t *idp; if ((s = yylval.l_str = strdup(s)) == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); /* * If the lexeme is a global variable or likely identifier or *not* a * type_name, then it is an identifier token. */ if (dt_idstack_lookup(&yypcb->pcb_globals, s) != NULL || dt_idhash_lookup(yypcb->pcb_idents, s) != NULL || dt_type_lookup(s, NULL) != 0) return (DT_TOK_IDENT); /* * If we're in the midst of parsing a declaration and a type_specifier * has already been shifted, then return DT_TOK_IDENT instead of TNAME. * This semantic is necessary to permit valid ISO C code such as: * * typedef int foo; * struct s { foo foo; }; * * without causing shift/reduce conflicts in the direct_declarator part * of the grammar. The result is that we must check for conflicting * redeclarations of the same identifier as part of dt_node_decl(). */ if (ddp != NULL && ddp->dd_name != NULL) return (DT_TOK_IDENT); /* * If the lexeme is a type name and we are not in a program clause, * then always interpret it as a type and return DT_TOK_TNAME. */ if ((YYSTATE) != S0) return (DT_TOK_TNAME); /* * If the lexeme matches a type name but is in a program clause, then * it could be a type or it could be an undefined variable. Peek at * the next token to decide. If we see ++, --, [, or =, we know there * might be an assignment that is trying to create a global variable, * so we optimistically return DT_TOK_IDENT. There is no harm in being * wrong: a type_name followed by ++, --, [, or = is a syntax error. */ while ((c0 = input()) != 0) { if (strchr("\f\n\r\t\v ", c0) == NULL) break; } switch (c0) { case '+': case '-': if ((c1 = input()) == c0) ttok = DT_TOK_IDENT; unput(c1); break; case '=': if ((c1 = input()) != c0) ttok = DT_TOK_IDENT; unput(c1); break; case '[': ttok = DT_TOK_IDENT; break; } if (ttok == DT_TOK_IDENT) { idp = dt_idhash_insert(yypcb->pcb_idents, s, DT_IDENT_SCALAR, 0, 0, _dtrace_defattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen); if (idp == NULL) longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); } unput(c0); return (ttok); } #ifdef illumos static int input(void) { int c; if (yysptr > yysbuf) c = *--yysptr; else if (yypcb->pcb_fileptr != NULL) c = fgetc(yypcb->pcb_fileptr); else if (yypcb->pcb_strptr < yypcb->pcb_string + yypcb->pcb_strlen) c = *(unsigned char *)(yypcb->pcb_strptr++); else c = EOF; if (c == '\n') yylineno++; if (c != EOF) return (c); if ((YYSTATE) == S1) yyerror("end-of-file encountered before matching */\n"); if ((YYSTATE) == S3) yyerror("end-of-file encountered before end of control line\n"); if (yypcb->pcb_fileptr != NULL && ferror(yypcb->pcb_fileptr)) longjmp(yypcb->pcb_jmpbuf, EDT_FIO); return (0); /* EOF */ } static void unput(int c) { if (c == '\n') yylineno--; *yysptr++ = c; yytchar = c; } #endif /* illumos */ Index: projects/ci20_mips/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c =================================================================== --- projects/ci20_mips/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c (revision 283030) +++ projects/ci20_mips/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c (revision 283031) @@ -1,1964 +1,1967 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #define ELF_TARGET_ALL #include #include #ifdef illumos #include #else #define P2ROUNDUP(x, align) (-(-(x) & -(align))) #endif #include #include #ifdef illumos #include #endif #include #include #include #include #include #include #ifdef illumos #include #else #include #include #include #include #endif #include #include #include #include #include #include #define ESHDR_NULL 0 #define ESHDR_SHSTRTAB 1 #define ESHDR_DOF 2 #define ESHDR_STRTAB 3 #define ESHDR_SYMTAB 4 #define ESHDR_REL 5 #define ESHDR_NUM 6 #define PWRITE_SCN(index, data) \ (lseek64(fd, (off64_t)elf_file.shdr[(index)].sh_offset, SEEK_SET) != \ (off64_t)elf_file.shdr[(index)].sh_offset || \ dt_write(dtp, fd, (data), elf_file.shdr[(index)].sh_size) != \ elf_file.shdr[(index)].sh_size) static const char DTRACE_SHSTRTAB32[] = "\0" ".shstrtab\0" /* 1 */ ".SUNW_dof\0" /* 11 */ ".strtab\0" /* 21 */ ".symtab\0" /* 29 */ #ifdef __sparc ".rela.SUNW_dof"; /* 37 */ #else ".rel.SUNW_dof"; /* 37 */ #endif static const char DTRACE_SHSTRTAB64[] = "\0" ".shstrtab\0" /* 1 */ ".SUNW_dof\0" /* 11 */ ".strtab\0" /* 21 */ ".symtab\0" /* 29 */ ".rela.SUNW_dof"; /* 37 */ static const char DOFSTR[] = "__SUNW_dof"; static const char DOFLAZYSTR[] = "___SUNW_dof"; typedef struct dt_link_pair { struct dt_link_pair *dlp_next; /* next pair in linked list */ void *dlp_str; /* buffer for string table */ void *dlp_sym; /* buffer for symbol table */ } dt_link_pair_t; typedef struct dof_elf32 { uint32_t de_nrel; /* relocation count */ #ifdef __sparc Elf32_Rela *de_rel; /* array of relocations for sparc */ #else Elf32_Rel *de_rel; /* array of relocations for x86 */ #endif uint32_t de_nsym; /* symbol count */ Elf32_Sym *de_sym; /* array of symbols */ uint32_t de_strlen; /* size of of string table */ char *de_strtab; /* string table */ uint32_t de_global; /* index of the first global symbol */ } dof_elf32_t; static int prepare_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf32_t *dep) { dof_sec_t *dofs, *s; dof_relohdr_t *dofrh; dof_relodesc_t *dofr; char *strtab; int i, j, nrel; size_t strtabsz = 1; uint32_t count = 0; size_t base; Elf32_Sym *sym; #ifdef __sparc Elf32_Rela *rel; #else Elf32_Rel *rel; #endif /*LINTED*/ dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); /* * First compute the size of the string table and the number of * relocations present in the DOF. */ for (i = 0; i < dof->dofh_secnum; i++) { if (dofs[i].dofs_type != DOF_SECT_URELHDR) continue; /*LINTED*/ dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); s = &dofs[dofrh->dofr_strtab]; strtab = (char *)dof + s->dofs_offset; assert(strtab[0] == '\0'); strtabsz += s->dofs_size - 1; s = &dofs[dofrh->dofr_relsec]; /*LINTED*/ dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); count += s->dofs_size / s->dofs_entsize; } dep->de_strlen = strtabsz; dep->de_nrel = count; dep->de_nsym = count + 1; /* the first symbol is always null */ if (dtp->dt_lazyload) { dep->de_strlen += sizeof (DOFLAZYSTR); dep->de_nsym++; } else { dep->de_strlen += sizeof (DOFSTR); dep->de_nsym++; } if ((dep->de_rel = calloc(dep->de_nrel, sizeof (dep->de_rel[0]))) == NULL) { return (dt_set_errno(dtp, EDT_NOMEM)); } if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf32_Sym))) == NULL) { free(dep->de_rel); return (dt_set_errno(dtp, EDT_NOMEM)); } if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { free(dep->de_rel); free(dep->de_sym); return (dt_set_errno(dtp, EDT_NOMEM)); } count = 0; strtabsz = 1; dep->de_strtab[0] = '\0'; rel = dep->de_rel; sym = dep->de_sym; dep->de_global = 1; /* * The first symbol table entry must be zeroed and is always ignored. */ bzero(sym, sizeof (Elf32_Sym)); sym++; /* * Take a second pass through the DOF sections filling in the * memory we allocated. */ for (i = 0; i < dof->dofh_secnum; i++) { if (dofs[i].dofs_type != DOF_SECT_URELHDR) continue; /*LINTED*/ dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); s = &dofs[dofrh->dofr_strtab]; strtab = (char *)dof + s->dofs_offset; bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size); base = strtabsz; strtabsz += s->dofs_size - 1; s = &dofs[dofrh->dofr_relsec]; /*LINTED*/ dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); nrel = s->dofs_size / s->dofs_entsize; s = &dofs[dofrh->dofr_tgtsec]; for (j = 0; j < nrel; j++) { #if defined(__arm__) /* XXX */ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); #elif defined(__i386) || defined(__amd64) rel->r_offset = s->dofs_offset + dofr[j].dofr_offset; rel->r_info = ELF32_R_INFO(count + dep->de_global, R_386_32); #elif defined(__mips__) /* XXX */ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); #elif defined(__powerpc__) /* * Add 4 bytes to hit the low half of this 64-bit * big-endian address. */ rel->r_offset = s->dofs_offset + dofr[j].dofr_offset + 4; rel->r_info = ELF32_R_INFO(count + dep->de_global, R_PPC_REL32); #elif defined(__sparc) /* * Add 4 bytes to hit the low half of this 64-bit * big-endian address. */ rel->r_offset = s->dofs_offset + dofr[j].dofr_offset + 4; rel->r_info = ELF32_R_INFO(count + dep->de_global, R_SPARC_32); #else #error unknown ISA #endif sym->st_name = base + dofr[j].dofr_name - 1; sym->st_value = 0; sym->st_size = 0; sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC); sym->st_other = 0; sym->st_shndx = SHN_UNDEF; rel++; sym++; count++; } } /* * Add a symbol for the DOF itself. We use a different symbol for * lazily and actively loaded DOF to make them easy to distinguish. */ sym->st_name = strtabsz; sym->st_value = 0; sym->st_size = dof->dofh_filesz; sym->st_info = ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT); #ifdef illumos sym->st_other = 0; #else sym->st_other = ELF32_ST_VISIBILITY(STV_HIDDEN); #endif sym->st_shndx = ESHDR_DOF; sym++; if (dtp->dt_lazyload) { bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, sizeof (DOFLAZYSTR)); strtabsz += sizeof (DOFLAZYSTR); } else { bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); strtabsz += sizeof (DOFSTR); } assert(count == dep->de_nrel); assert(strtabsz == dep->de_strlen); return (0); } typedef struct dof_elf64 { uint32_t de_nrel; Elf64_Rela *de_rel; uint32_t de_nsym; Elf64_Sym *de_sym; uint32_t de_strlen; char *de_strtab; uint32_t de_global; } dof_elf64_t; static int prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep) { dof_sec_t *dofs, *s; dof_relohdr_t *dofrh; dof_relodesc_t *dofr; char *strtab; int i, j, nrel; size_t strtabsz = 1; #ifdef illumos uint32_t count = 0; #else uint64_t count = 0; #endif size_t base; Elf64_Sym *sym; Elf64_Rela *rel; /*LINTED*/ dofs = (dof_sec_t *)((char *)dof + dof->dofh_secoff); /* * First compute the size of the string table and the number of * relocations present in the DOF. */ for (i = 0; i < dof->dofh_secnum; i++) { if (dofs[i].dofs_type != DOF_SECT_URELHDR) continue; /*LINTED*/ dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); s = &dofs[dofrh->dofr_strtab]; strtab = (char *)dof + s->dofs_offset; assert(strtab[0] == '\0'); strtabsz += s->dofs_size - 1; s = &dofs[dofrh->dofr_relsec]; /*LINTED*/ dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); count += s->dofs_size / s->dofs_entsize; } dep->de_strlen = strtabsz; dep->de_nrel = count; dep->de_nsym = count + 1; /* the first symbol is always null */ if (dtp->dt_lazyload) { dep->de_strlen += sizeof (DOFLAZYSTR); dep->de_nsym++; } else { dep->de_strlen += sizeof (DOFSTR); dep->de_nsym++; } if ((dep->de_rel = calloc(dep->de_nrel, sizeof (dep->de_rel[0]))) == NULL) { return (dt_set_errno(dtp, EDT_NOMEM)); } if ((dep->de_sym = calloc(dep->de_nsym, sizeof (Elf64_Sym))) == NULL) { free(dep->de_rel); return (dt_set_errno(dtp, EDT_NOMEM)); } if ((dep->de_strtab = calloc(dep->de_strlen, 1)) == NULL) { free(dep->de_rel); free(dep->de_sym); return (dt_set_errno(dtp, EDT_NOMEM)); } count = 0; strtabsz = 1; dep->de_strtab[0] = '\0'; rel = dep->de_rel; sym = dep->de_sym; dep->de_global = 1; /* * The first symbol table entry must be zeroed and is always ignored. */ bzero(sym, sizeof (Elf64_Sym)); sym++; /* * Take a second pass through the DOF sections filling in the * memory we allocated. */ for (i = 0; i < dof->dofh_secnum; i++) { if (dofs[i].dofs_type != DOF_SECT_URELHDR) continue; /*LINTED*/ dofrh = (dof_relohdr_t *)((char *)dof + dofs[i].dofs_offset); s = &dofs[dofrh->dofr_strtab]; strtab = (char *)dof + s->dofs_offset; bcopy(strtab + 1, dep->de_strtab + strtabsz, s->dofs_size); base = strtabsz; strtabsz += s->dofs_size - 1; s = &dofs[dofrh->dofr_relsec]; /*LINTED*/ dofr = (dof_relodesc_t *)((char *)dof + s->dofs_offset); nrel = s->dofs_size / s->dofs_entsize; s = &dofs[dofrh->dofr_tgtsec]; for (j = 0; j < nrel; j++) { #if defined(__arm__) /* XXX */ #elif defined(__mips__) /* XXX */ #elif defined(__powerpc__) rel->r_offset = s->dofs_offset + dofr[j].dofr_offset; rel->r_info = ELF64_R_INFO(count + dep->de_global, R_PPC64_REL64); #elif defined(__i386) || defined(__amd64) rel->r_offset = s->dofs_offset + dofr[j].dofr_offset; #ifdef illumos rel->r_info = ELF64_R_INFO(count + dep->de_global, R_AMD64_64); #else rel->r_info = ELF64_R_INFO(count + dep->de_global, R_X86_64_RELATIVE); #endif #elif defined(__sparc) rel->r_offset = s->dofs_offset + dofr[j].dofr_offset; rel->r_info = ELF64_R_INFO(count + dep->de_global, R_SPARC_64); #else #error unknown ISA #endif sym->st_name = base + dofr[j].dofr_name - 1; sym->st_value = 0; sym->st_size = 0; sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC); sym->st_other = 0; sym->st_shndx = SHN_UNDEF; rel++; sym++; count++; } } /* * Add a symbol for the DOF itself. We use a different symbol for * lazily and actively loaded DOF to make them easy to distinguish. */ sym->st_name = strtabsz; sym->st_value = 0; sym->st_size = dof->dofh_filesz; sym->st_info = GELF_ST_INFO(STB_GLOBAL, STT_OBJECT); #ifdef illumos sym->st_other = 0; #else sym->st_other = ELF64_ST_VISIBILITY(STV_HIDDEN); #endif sym->st_shndx = ESHDR_DOF; sym++; if (dtp->dt_lazyload) { bcopy(DOFLAZYSTR, dep->de_strtab + strtabsz, sizeof (DOFLAZYSTR)); strtabsz += sizeof (DOFLAZYSTR); } else { bcopy(DOFSTR, dep->de_strtab + strtabsz, sizeof (DOFSTR)); strtabsz += sizeof (DOFSTR); } assert(count == dep->de_nrel); assert(strtabsz == dep->de_strlen); return (0); } /* * Write out an ELF32 file prologue consisting of a header, section headers, * and a section header string table. The DOF data will follow this prologue * and complete the contents of the given ELF file. */ static int dump_elf32(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) { struct { Elf32_Ehdr ehdr; Elf32_Shdr shdr[ESHDR_NUM]; } elf_file; Elf32_Shdr *shp; Elf32_Off off; dof_elf32_t de; int ret = 0; uint_t nshdr; if (prepare_elf32(dtp, dof, &de) != 0) return (-1); /* errno is set for us */ /* * If there are no relocations, we only need enough sections for * the shstrtab and the DOF. */ nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; bzero(&elf_file, sizeof (elf_file)); elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS32; #if BYTE_ORDER == _BIG_ENDIAN elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; #else elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; #endif #if defined(__FreeBSD__) elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; #endif elf_file.ehdr.e_type = ET_REL; #if defined(__arm__) elf_file.ehdr.e_machine = EM_ARM; #elif defined(__mips__) elf_file.ehdr.e_machine = EM_MIPS; #elif defined(__powerpc__) elf_file.ehdr.e_machine = EM_PPC; #elif defined(__sparc) elf_file.ehdr.e_machine = EM_SPARC; #elif defined(__i386) || defined(__amd64) elf_file.ehdr.e_machine = EM_386; #endif elf_file.ehdr.e_version = EV_CURRENT; elf_file.ehdr.e_shoff = sizeof (Elf32_Ehdr); elf_file.ehdr.e_ehsize = sizeof (Elf32_Ehdr); elf_file.ehdr.e_phentsize = sizeof (Elf32_Phdr); elf_file.ehdr.e_shentsize = sizeof (Elf32_Shdr); elf_file.ehdr.e_shnum = nshdr; elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; off = sizeof (elf_file) + nshdr * sizeof (Elf32_Shdr); shp = &elf_file.shdr[ESHDR_SHSTRTAB]; shp->sh_name = 1; /* DTRACE_SHSTRTAB32[1] = ".shstrtab" */ shp->sh_type = SHT_STRTAB; shp->sh_offset = off; shp->sh_size = sizeof (DTRACE_SHSTRTAB32); shp->sh_addralign = sizeof (char); off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); shp = &elf_file.shdr[ESHDR_DOF]; shp->sh_name = 11; /* DTRACE_SHSTRTAB32[11] = ".SUNW_dof" */ shp->sh_flags = SHF_ALLOC; shp->sh_type = SHT_SUNW_dof; shp->sh_offset = off; shp->sh_size = dof->dofh_filesz; shp->sh_addralign = 8; off = shp->sh_offset + shp->sh_size; shp = &elf_file.shdr[ESHDR_STRTAB]; shp->sh_name = 21; /* DTRACE_SHSTRTAB32[21] = ".strtab" */ shp->sh_flags = SHF_ALLOC; shp->sh_type = SHT_STRTAB; shp->sh_offset = off; shp->sh_size = de.de_strlen; shp->sh_addralign = sizeof (char); off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); shp = &elf_file.shdr[ESHDR_SYMTAB]; shp->sh_name = 29; /* DTRACE_SHSTRTAB32[29] = ".symtab" */ shp->sh_flags = SHF_ALLOC; shp->sh_type = SHT_SYMTAB; shp->sh_entsize = sizeof (Elf32_Sym); shp->sh_link = ESHDR_STRTAB; shp->sh_offset = off; shp->sh_info = de.de_global; shp->sh_size = de.de_nsym * sizeof (Elf32_Sym); shp->sh_addralign = 4; off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 4); if (de.de_nrel == 0) { if (dt_write(dtp, fd, &elf_file, sizeof (elf_file)) != sizeof (elf_file) || PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || PWRITE_SCN(ESHDR_DOF, dof)) { ret = dt_set_errno(dtp, errno); } } else { shp = &elf_file.shdr[ESHDR_REL]; shp->sh_name = 37; /* DTRACE_SHSTRTAB32[37] = ".rel.SUNW_dof" */ shp->sh_flags = SHF_ALLOC; #ifdef __sparc shp->sh_type = SHT_RELA; #else shp->sh_type = SHT_REL; #endif shp->sh_entsize = sizeof (de.de_rel[0]); shp->sh_link = ESHDR_SYMTAB; shp->sh_info = ESHDR_DOF; shp->sh_offset = off; shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); shp->sh_addralign = 4; if (dt_write(dtp, fd, &elf_file, sizeof (elf_file)) != sizeof (elf_file) || PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB32) || PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || PWRITE_SCN(ESHDR_REL, de.de_rel) || PWRITE_SCN(ESHDR_DOF, dof)) { ret = dt_set_errno(dtp, errno); } } free(de.de_strtab); free(de.de_sym); free(de.de_rel); return (ret); } /* * Write out an ELF64 file prologue consisting of a header, section headers, * and a section header string table. The DOF data will follow this prologue * and complete the contents of the given ELF file. */ static int dump_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, int fd) { struct { Elf64_Ehdr ehdr; Elf64_Shdr shdr[ESHDR_NUM]; } elf_file; Elf64_Shdr *shp; Elf64_Off off; dof_elf64_t de; int ret = 0; uint_t nshdr; if (prepare_elf64(dtp, dof, &de) != 0) return (-1); /* errno is set for us */ /* * If there are no relocations, we only need enough sections for * the shstrtab and the DOF. */ nshdr = de.de_nrel == 0 ? ESHDR_SYMTAB + 1 : ESHDR_NUM; bzero(&elf_file, sizeof (elf_file)); elf_file.ehdr.e_ident[EI_MAG0] = ELFMAG0; elf_file.ehdr.e_ident[EI_MAG1] = ELFMAG1; elf_file.ehdr.e_ident[EI_MAG2] = ELFMAG2; elf_file.ehdr.e_ident[EI_MAG3] = ELFMAG3; elf_file.ehdr.e_ident[EI_VERSION] = EV_CURRENT; elf_file.ehdr.e_ident[EI_CLASS] = ELFCLASS64; #if BYTE_ORDER == _BIG_ENDIAN elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2MSB; #else elf_file.ehdr.e_ident[EI_DATA] = ELFDATA2LSB; #endif #if defined(__FreeBSD__) elf_file.ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; #endif elf_file.ehdr.e_type = ET_REL; #if defined(__arm__) elf_file.ehdr.e_machine = EM_ARM; #elif defined(__mips__) elf_file.ehdr.e_machine = EM_MIPS; #elif defined(__powerpc64__) elf_file.ehdr.e_machine = EM_PPC64; #elif defined(__sparc) elf_file.ehdr.e_machine = EM_SPARCV9; #elif defined(__i386) || defined(__amd64) elf_file.ehdr.e_machine = EM_AMD64; #endif elf_file.ehdr.e_version = EV_CURRENT; elf_file.ehdr.e_shoff = sizeof (Elf64_Ehdr); elf_file.ehdr.e_ehsize = sizeof (Elf64_Ehdr); elf_file.ehdr.e_phentsize = sizeof (Elf64_Phdr); elf_file.ehdr.e_shentsize = sizeof (Elf64_Shdr); elf_file.ehdr.e_shnum = nshdr; elf_file.ehdr.e_shstrndx = ESHDR_SHSTRTAB; off = sizeof (elf_file) + nshdr * sizeof (Elf64_Shdr); shp = &elf_file.shdr[ESHDR_SHSTRTAB]; shp->sh_name = 1; /* DTRACE_SHSTRTAB64[1] = ".shstrtab" */ shp->sh_type = SHT_STRTAB; shp->sh_offset = off; shp->sh_size = sizeof (DTRACE_SHSTRTAB64); shp->sh_addralign = sizeof (char); off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); shp = &elf_file.shdr[ESHDR_DOF]; shp->sh_name = 11; /* DTRACE_SHSTRTAB64[11] = ".SUNW_dof" */ shp->sh_flags = SHF_ALLOC; shp->sh_type = SHT_SUNW_dof; shp->sh_offset = off; shp->sh_size = dof->dofh_filesz; shp->sh_addralign = 8; off = shp->sh_offset + shp->sh_size; shp = &elf_file.shdr[ESHDR_STRTAB]; shp->sh_name = 21; /* DTRACE_SHSTRTAB64[21] = ".strtab" */ shp->sh_flags = SHF_ALLOC; shp->sh_type = SHT_STRTAB; shp->sh_offset = off; shp->sh_size = de.de_strlen; shp->sh_addralign = sizeof (char); off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); shp = &elf_file.shdr[ESHDR_SYMTAB]; shp->sh_name = 29; /* DTRACE_SHSTRTAB64[29] = ".symtab" */ shp->sh_flags = SHF_ALLOC; shp->sh_type = SHT_SYMTAB; shp->sh_entsize = sizeof (Elf64_Sym); shp->sh_link = ESHDR_STRTAB; shp->sh_offset = off; shp->sh_info = de.de_global; shp->sh_size = de.de_nsym * sizeof (Elf64_Sym); shp->sh_addralign = 8; off = P2ROUNDUP(shp->sh_offset + shp->sh_size, 8); if (de.de_nrel == 0) { if (dt_write(dtp, fd, &elf_file, sizeof (elf_file)) != sizeof (elf_file) || PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || PWRITE_SCN(ESHDR_DOF, dof)) { ret = dt_set_errno(dtp, errno); } } else { shp = &elf_file.shdr[ESHDR_REL]; shp->sh_name = 37; /* DTRACE_SHSTRTAB64[37] = ".rel.SUNW_dof" */ shp->sh_flags = SHF_ALLOC; shp->sh_type = SHT_RELA; shp->sh_entsize = sizeof (de.de_rel[0]); shp->sh_link = ESHDR_SYMTAB; shp->sh_info = ESHDR_DOF; shp->sh_offset = off; shp->sh_size = de.de_nrel * sizeof (de.de_rel[0]); shp->sh_addralign = 8; if (dt_write(dtp, fd, &elf_file, sizeof (elf_file)) != sizeof (elf_file) || PWRITE_SCN(ESHDR_SHSTRTAB, DTRACE_SHSTRTAB64) || PWRITE_SCN(ESHDR_STRTAB, de.de_strtab) || PWRITE_SCN(ESHDR_SYMTAB, de.de_sym) || PWRITE_SCN(ESHDR_REL, de.de_rel) || PWRITE_SCN(ESHDR_DOF, dof)) { ret = dt_set_errno(dtp, errno); } } free(de.de_strtab); free(de.de_sym); free(de.de_rel); return (ret); } static int dt_symtab_lookup(Elf_Data *data_sym, int nsym, uintptr_t addr, uint_t shn, GElf_Sym *sym, int uses_funcdesc, Elf *elf) { int i, ret = -1; Elf64_Addr symval; Elf_Scn *opd_scn; Elf_Data *opd_desc; GElf_Sym s; for (i = 0; i < nsym && gelf_getsym(data_sym, i, sym) != NULL; i++) { if (GELF_ST_TYPE(sym->st_info) == STT_FUNC) { symval = sym->st_value; if (uses_funcdesc) { opd_scn = elf_getscn(elf, sym->st_shndx); opd_desc = elf_rawdata(opd_scn, NULL); symval = *(uint64_t*)((char *)opd_desc->d_buf + symval); } if ((uses_funcdesc || shn == sym->st_shndx) && symval <= addr && addr < symval + sym->st_size) { if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL) return (0); ret = 0; s = *sym; } } } if (ret == 0) *sym = s; return (ret); } #if defined(__arm__) /* XXX */ static int dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, uint32_t *off) { printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); return (0); } #elif defined(__mips__) /* XXX */ static int dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, uint32_t *off) { printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__); return (0); } #elif defined(__powerpc__) /* The sentinel is 'xor r3,r3,r3'. */ #define DT_OP_XOR_R3 0x7c631a78 #define DT_OP_NOP 0x60000000 #define DT_OP_BLR 0x4e800020 /* This captures all forms of branching to address. */ #define DT_IS_BRANCH(inst) ((inst & 0xfc000000) == 0x48000000) #define DT_IS_BL(inst) (DT_IS_BRANCH(inst) && (inst & 0x01)) /* XXX */ static int dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, uint32_t *off) { uint32_t *ip; if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0) return (-1); /*LINTED*/ ip = (uint32_t *)(p + rela->r_offset); /* * We only know about some specific relocation types. */ if (GELF_R_TYPE(rela->r_info) != R_PPC_REL24 && GELF_R_TYPE(rela->r_info) != R_PPC_PLTREL24) return (-1); /* * We may have already processed this object file in an earlier linker * invocation. Check to see if the present instruction sequence matches * the one we would install below. */ if (isenabled) { if (ip[0] == DT_OP_XOR_R3) { (*off) += sizeof (ip[0]); return (0); } } else { if (ip[0] == DT_OP_NOP) { (*off) += sizeof (ip[0]); return (0); } } /* * We only expect branch to address instructions. */ if (!DT_IS_BRANCH(ip[0])) { dt_dprintf("found %x instead of a branch instruction at %llx\n", ip[0], (u_longlong_t)rela->r_offset); return (-1); } if (isenabled) { /* * It would necessarily indicate incorrect usage if an is- * enabled probe were tail-called so flag that as an error. * It's also potentially (very) tricky to handle gracefully, * but could be done if this were a desired use scenario. */ if (!DT_IS_BL(ip[0])) { dt_dprintf("tail call to is-enabled probe at %llx\n", (u_longlong_t)rela->r_offset); return (-1); } ip[0] = DT_OP_XOR_R3; (*off) += sizeof (ip[0]); } else { if (DT_IS_BL(ip[0])) ip[0] = DT_OP_NOP; else ip[0] = DT_OP_BLR; } return (0); } #elif defined(__sparc) #define DT_OP_RET 0x81c7e008 #define DT_OP_NOP 0x01000000 #define DT_OP_CALL 0x40000000 #define DT_OP_CLR_O0 0x90102000 #define DT_IS_MOV_O7(inst) (((inst) & 0xffffe000) == 0x9e100000) #define DT_IS_RESTORE(inst) (((inst) & 0xc1f80000) == 0x81e80000) #define DT_IS_RETL(inst) (((inst) & 0xfff83fff) == 0x81c02008) #define DT_RS2(inst) ((inst) & 0x1f) #define DT_MAKE_RETL(reg) (0x81c02008 | ((reg) << 14)) /*ARGSUSED*/ static int dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, uint32_t *off) { uint32_t *ip; if ((rela->r_offset & (sizeof (uint32_t) - 1)) != 0) return (-1); /*LINTED*/ ip = (uint32_t *)(p + rela->r_offset); /* * We only know about some specific relocation types. */ if (GELF_R_TYPE(rela->r_info) != R_SPARC_WDISP30 && GELF_R_TYPE(rela->r_info) != R_SPARC_WPLT30) return (-1); /* * We may have already processed this object file in an earlier linker * invocation. Check to see if the present instruction sequence matches * the one we would install below. */ if (isenabled) { if (ip[0] == DT_OP_NOP) { (*off) += sizeof (ip[0]); return (0); } } else { if (DT_IS_RESTORE(ip[1])) { if (ip[0] == DT_OP_RET) { (*off) += sizeof (ip[0]); return (0); } } else if (DT_IS_MOV_O7(ip[1])) { if (DT_IS_RETL(ip[0])) return (0); } else { if (ip[0] == DT_OP_NOP) { (*off) += sizeof (ip[0]); return (0); } } } /* * We only expect call instructions with a displacement of 0. */ if (ip[0] != DT_OP_CALL) { dt_dprintf("found %x instead of a call instruction at %llx\n", ip[0], (u_longlong_t)rela->r_offset); return (-1); } if (isenabled) { /* * It would necessarily indicate incorrect usage if an is- * enabled probe were tail-called so flag that as an error. * It's also potentially (very) tricky to handle gracefully, * but could be done if this were a desired use scenario. */ if (DT_IS_RESTORE(ip[1]) || DT_IS_MOV_O7(ip[1])) { dt_dprintf("tail call to is-enabled probe at %llx\n", (u_longlong_t)rela->r_offset); return (-1); } /* * On SPARC, we take advantage of the fact that the first * argument shares the same register as for the return value. * The macro handles the work of zeroing that register so we * don't need to do anything special here. We instrument the * instruction in the delay slot as we'll need to modify the * return register after that instruction has been emulated. */ ip[0] = DT_OP_NOP; (*off) += sizeof (ip[0]); } else { /* * If the call is followed by a restore, it's a tail call so * change the call to a ret. If the call if followed by a mov * of a register into %o7, it's a tail call in leaf context * so change the call to a retl-like instruction that returns * to that register value + 8 (rather than the typical %o7 + * 8); the delay slot instruction is left, but should have no * effect. Otherwise we change the call to be a nop. We * identify the subsequent instruction as the probe point in * all but the leaf tail-call case to ensure that arguments to * the probe are complete and consistent. An astute, though * largely hypothetical, observer would note that there is the * possibility of a false-positive probe firing if the function * contained a branch to the instruction in the delay slot of * the call. Fixing this would require significant in-kernel * modifications, and isn't worth doing until we see it in the * wild. */ if (DT_IS_RESTORE(ip[1])) { ip[0] = DT_OP_RET; (*off) += sizeof (ip[0]); } else if (DT_IS_MOV_O7(ip[1])) { ip[0] = DT_MAKE_RETL(DT_RS2(ip[1])); } else { ip[0] = DT_OP_NOP; (*off) += sizeof (ip[0]); } } return (0); } #elif defined(__i386) || defined(__amd64) #define DT_OP_NOP 0x90 #define DT_OP_RET 0xc3 #define DT_OP_CALL 0xe8 #define DT_OP_JMP32 0xe9 #define DT_OP_REX_RAX 0x48 #define DT_OP_XOR_EAX_0 0x33 #define DT_OP_XOR_EAX_1 0xc0 static int dt_modtext(dtrace_hdl_t *dtp, char *p, int isenabled, GElf_Rela *rela, uint32_t *off) { uint8_t *ip = (uint8_t *)(p + rela->r_offset - 1); uint8_t ret; /* * On x86, the first byte of the instruction is the call opcode and * the next four bytes are the 32-bit address; the relocation is for * the address operand. We back up the offset to the first byte of * the instruction. For is-enabled probes, we later advance the offset * so that it hits the first nop in the instruction sequence. */ (*off) -= 1; /* * We only know about some specific relocation types. Luckily * these types have the same values on both 32-bit and 64-bit * x86 architectures. */ if (GELF_R_TYPE(rela->r_info) != R_386_PC32 && GELF_R_TYPE(rela->r_info) != R_386_PLT32) return (-1); /* * We may have already processed this object file in an earlier linker * invocation. Check to see if the present instruction sequence matches * the one we would install. For is-enabled probes, we advance the * offset to the first nop instruction in the sequence to match the * text modification code below. */ if (!isenabled) { if ((ip[0] == DT_OP_NOP || ip[0] == DT_OP_RET) && ip[1] == DT_OP_NOP && ip[2] == DT_OP_NOP && ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) return (0); } else if (dtp->dt_oflags & DTRACE_O_LP64) { if (ip[0] == DT_OP_REX_RAX && ip[1] == DT_OP_XOR_EAX_0 && ip[2] == DT_OP_XOR_EAX_1 && (ip[3] == DT_OP_NOP || ip[3] == DT_OP_RET) && ip[4] == DT_OP_NOP) { (*off) += 3; return (0); } } else { if (ip[0] == DT_OP_XOR_EAX_0 && ip[1] == DT_OP_XOR_EAX_1 && (ip[2] == DT_OP_NOP || ip[2] == DT_OP_RET) && ip[3] == DT_OP_NOP && ip[4] == DT_OP_NOP) { (*off) += 2; return (0); } } /* * We expect either a call instrution with a 32-bit displacement or a * jmp instruction with a 32-bit displacement acting as a tail-call. */ if (ip[0] != DT_OP_CALL && ip[0] != DT_OP_JMP32) { dt_dprintf("found %x instead of a call or jmp instruction at " "%llx\n", ip[0], (u_longlong_t)rela->r_offset); return (-1); } ret = (ip[0] == DT_OP_JMP32) ? DT_OP_RET : DT_OP_NOP; /* * Establish the instruction sequence -- all nops for probes, and an * instruction to clear the return value register (%eax/%rax) followed * by nops for is-enabled probes. For is-enabled probes, we advance * the offset to the first nop. This isn't stricly necessary but makes * for more readable disassembly when the probe is enabled. */ if (!isenabled) { ip[0] = ret; ip[1] = DT_OP_NOP; ip[2] = DT_OP_NOP; ip[3] = DT_OP_NOP; ip[4] = DT_OP_NOP; } else if (dtp->dt_oflags & DTRACE_O_LP64) { ip[0] = DT_OP_REX_RAX; ip[1] = DT_OP_XOR_EAX_0; ip[2] = DT_OP_XOR_EAX_1; ip[3] = ret; ip[4] = DT_OP_NOP; (*off) += 3; } else { ip[0] = DT_OP_XOR_EAX_0; ip[1] = DT_OP_XOR_EAX_1; ip[2] = ret; ip[3] = DT_OP_NOP; ip[4] = DT_OP_NOP; (*off) += 2; } return (0); } #else #error unknown ISA #endif /*PRINTFLIKE5*/ static int dt_link_error(dtrace_hdl_t *dtp, Elf *elf, int fd, dt_link_pair_t *bufs, const char *format, ...) { va_list ap; dt_link_pair_t *pair; va_start(ap, format); dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap); va_end(ap); if (elf != NULL) (void) elf_end(elf); if (fd >= 0) (void) close(fd); while ((pair = bufs) != NULL) { bufs = pair->dlp_next; dt_free(dtp, pair->dlp_str); dt_free(dtp, pair->dlp_sym); dt_free(dtp, pair); } return (dt_set_errno(dtp, EDT_COMPILER)); } static int process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp) { static const char dt_prefix[] = "__dtrace"; static const char dt_enabled[] = "enabled"; static const char dt_symprefix[] = "$dtrace"; static const char dt_symfmt[] = "%s%ld.%s"; int fd, i, ndx, eprobe, mod = 0; Elf *elf = NULL; GElf_Ehdr ehdr; Elf_Scn *scn_rel, *scn_sym, *scn_str, *scn_tgt; Elf_Data *data_rel, *data_sym, *data_str, *data_tgt; GElf_Shdr shdr_rel, shdr_sym, shdr_str, shdr_tgt; GElf_Sym rsym, fsym, dsym; GElf_Rela rela; char *s, *p, *r; char pname[DTRACE_PROVNAMELEN]; dt_provider_t *pvp; dt_probe_t *prp; uint32_t off, eclass, emachine1, emachine2; size_t symsize, nsym, isym, istr, len; key_t objkey; dt_link_pair_t *pair, *bufs = NULL; dt_strtab_t *strtab; if ((fd = open64(obj, O_RDWR)) == -1) { return (dt_link_error(dtp, elf, fd, bufs, "failed to open %s: %s", obj, strerror(errno))); } if ((elf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL) { return (dt_link_error(dtp, elf, fd, bufs, "failed to process %s: %s", obj, elf_errmsg(elf_errno()))); } switch (elf_kind(elf)) { case ELF_K_ELF: break; case ELF_K_AR: return (dt_link_error(dtp, elf, fd, bufs, "archives are not " "permitted; use the contents of the archive instead: %s", obj)); default: return (dt_link_error(dtp, elf, fd, bufs, "invalid file type: %s", obj)); } if (gelf_getehdr(elf, &ehdr) == NULL) { return (dt_link_error(dtp, elf, fd, bufs, "corrupt file: %s", obj)); } if (dtp->dt_oflags & DTRACE_O_LP64) { eclass = ELFCLASS64; #if defined(__mips__) emachine1 = emachine2 = EM_MIPS; #elif defined(__powerpc__) emachine1 = emachine2 = EM_PPC64; #elif defined(__sparc) emachine1 = emachine2 = EM_SPARCV9; #elif defined(__i386) || defined(__amd64) emachine1 = emachine2 = EM_AMD64; #endif symsize = sizeof (Elf64_Sym); } else { eclass = ELFCLASS32; #if defined(__arm__) emachine1 = emachine2 = EM_ARM; #elif defined(__mips__) emachine1 = emachine2 = EM_MIPS; #elif defined(__powerpc__) emachine1 = emachine2 = EM_PPC; #elif defined(__sparc) emachine1 = EM_SPARC; emachine2 = EM_SPARC32PLUS; #elif defined(__i386) || defined(__amd64) emachine1 = emachine2 = EM_386; #endif symsize = sizeof (Elf32_Sym); } if (ehdr.e_ident[EI_CLASS] != eclass) { return (dt_link_error(dtp, elf, fd, bufs, "incorrect ELF class for object file: %s", obj)); } if (ehdr.e_machine != emachine1 && ehdr.e_machine != emachine2) { return (dt_link_error(dtp, elf, fd, bufs, "incorrect ELF machine type for object file: %s", obj)); } /* * We use this token as a relatively unique handle for this file on the * system in order to disambiguate potential conflicts between files of * the same name which contain identially named local symbols. */ if ((objkey = ftok(obj, 0)) == (key_t)-1) { return (dt_link_error(dtp, elf, fd, bufs, "failed to generate unique key for object file: %s", obj)); } scn_rel = NULL; while ((scn_rel = elf_nextscn(elf, scn_rel)) != NULL) { if (gelf_getshdr(scn_rel, &shdr_rel) == NULL) goto err; /* * Skip any non-relocation sections. */ if (shdr_rel.sh_type != SHT_RELA && shdr_rel.sh_type != SHT_REL) continue; if ((data_rel = elf_getdata(scn_rel, NULL)) == NULL) goto err; /* * Grab the section, section header and section data for the * symbol table that this relocation section references. */ if ((scn_sym = elf_getscn(elf, shdr_rel.sh_link)) == NULL || gelf_getshdr(scn_sym, &shdr_sym) == NULL || (data_sym = elf_getdata(scn_sym, NULL)) == NULL) goto err; /* * Ditto for that symbol table's string table. */ if ((scn_str = elf_getscn(elf, shdr_sym.sh_link)) == NULL || gelf_getshdr(scn_str, &shdr_str) == NULL || (data_str = elf_getdata(scn_str, NULL)) == NULL) goto err; /* * Grab the section, section header and section data for the * target section for the relocations. For the relocations * we're looking for -- this will typically be the text of the * object file. */ if ((scn_tgt = elf_getscn(elf, shdr_rel.sh_info)) == NULL || gelf_getshdr(scn_tgt, &shdr_tgt) == NULL || (data_tgt = elf_getdata(scn_tgt, NULL)) == NULL) goto err; /* * We're looking for relocations to symbols matching this form: * * __dtrace[enabled]____ * * For the generated object, we need to record the location * identified by the relocation, and create a new relocation * in the generated object that will be resolved at link time * to the location of the function in which the probe is * embedded. In the target object, we change the matched symbol * so that it will be ignored at link time, and we modify the * target (text) section to replace the call instruction with * one or more nops. * * If the function containing the probe is locally scoped * (static), we create an alias used by the relocation in the * generated object. The alias, a new symbol, will be global * (so that the relocation from the generated object can be * resolved), and hidden (so that it is converted to a local * symbol at link time). Such aliases have this form: * * $dtrace. * * We take a first pass through all the relocations to * populate our string table and count the number of extra * symbols we'll require. */ strtab = dt_strtab_create(1); nsym = 0; isym = data_sym->d_size / symsize; istr = data_str->d_size; for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { if (shdr_rel.sh_type == SHT_RELA) { if (gelf_getrela(data_rel, i, &rela) == NULL) continue; } else { GElf_Rel rel; if (gelf_getrel(data_rel, i, &rel) == NULL) continue; rela.r_offset = rel.r_offset; rela.r_info = rel.r_info; rela.r_addend = 0; } if (gelf_getsym(data_sym, GELF_R_SYM(rela.r_info), &rsym) == NULL) { dt_strtab_destroy(strtab); goto err; } s = (char *)data_str->d_buf + rsym.st_name; if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0) continue; if (dt_symtab_lookup(data_sym, isym, rela.r_offset, shdr_rel.sh_info, &fsym, (emachine1 == EM_PPC64), elf) != 0) { dt_strtab_destroy(strtab); goto err; } if (GELF_ST_BIND(fsym.st_info) != STB_LOCAL) continue; if (fsym.st_name > data_str->d_size) { dt_strtab_destroy(strtab); goto err; } s = (char *)data_str->d_buf + fsym.st_name; /* * If this symbol isn't of type function, we've really * driven off the rails or the object file is corrupt. */ if (GELF_ST_TYPE(fsym.st_info) != STT_FUNC) { dt_strtab_destroy(strtab); return (dt_link_error(dtp, elf, fd, bufs, "expected %s to be of type function", s)); } len = snprintf(NULL, 0, dt_symfmt, dt_symprefix, objkey, s) + 1; if ((p = dt_alloc(dtp, len)) == NULL) { dt_strtab_destroy(strtab); goto err; } (void) snprintf(p, len, dt_symfmt, dt_symprefix, objkey, s); if (dt_strtab_index(strtab, p) == -1) { nsym++; (void) dt_strtab_insert(strtab, p); } dt_free(dtp, p); } /* * If needed, allocate the additional space for the symbol * table and string table copying the old data into the new * buffers, and marking the buffers as dirty. We inject those * newly allocated buffers into the libelf data structures, but * are still responsible for freeing them once we're done with * the elf handle. */ if (nsym > 0) { /* * The first byte of the string table is reserved for * the \0 entry. */ len = dt_strtab_size(strtab) - 1; assert(len > 0); assert(dt_strtab_index(strtab, "") == 0); dt_strtab_destroy(strtab); if ((pair = dt_alloc(dtp, sizeof (*pair))) == NULL) goto err; if ((pair->dlp_str = dt_alloc(dtp, data_str->d_size + len)) == NULL) { dt_free(dtp, pair); goto err; } if ((pair->dlp_sym = dt_alloc(dtp, data_sym->d_size + nsym * symsize)) == NULL) { dt_free(dtp, pair->dlp_str); dt_free(dtp, pair); goto err; } pair->dlp_next = bufs; bufs = pair; bcopy(data_str->d_buf, pair->dlp_str, data_str->d_size); data_str->d_buf = pair->dlp_str; data_str->d_size += len; (void) elf_flagdata(data_str, ELF_C_SET, ELF_F_DIRTY); shdr_str.sh_size += len; (void) gelf_update_shdr(scn_str, &shdr_str); bcopy(data_sym->d_buf, pair->dlp_sym, data_sym->d_size); data_sym->d_buf = pair->dlp_sym; data_sym->d_size += nsym * symsize; (void) elf_flagdata(data_sym, ELF_C_SET, ELF_F_DIRTY); shdr_sym.sh_size += nsym * symsize; (void) gelf_update_shdr(scn_sym, &shdr_sym); nsym += isym; } else { dt_strtab_destroy(strtab); } /* * Now that the tables have been allocated, perform the * modifications described above. */ for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { if (shdr_rel.sh_type == SHT_RELA) { if (gelf_getrela(data_rel, i, &rela) == NULL) continue; } else { GElf_Rel rel; if (gelf_getrel(data_rel, i, &rel) == NULL) continue; rela.r_offset = rel.r_offset; rela.r_info = rel.r_info; rela.r_addend = 0; } ndx = GELF_R_SYM(rela.r_info); if (gelf_getsym(data_sym, ndx, &rsym) == NULL || rsym.st_name > data_str->d_size) goto err; s = (char *)data_str->d_buf + rsym.st_name; if (strncmp(s, dt_prefix, sizeof (dt_prefix) - 1) != 0) continue; s += sizeof (dt_prefix) - 1; /* * Check to see if this is an 'is-enabled' check as * opposed to a normal probe. */ if (strncmp(s, dt_enabled, sizeof (dt_enabled) - 1) == 0) { s += sizeof (dt_enabled) - 1; eprobe = 1; *eprobesp = 1; dt_dprintf("is-enabled probe\n"); } else { eprobe = 0; dt_dprintf("normal probe\n"); } if (*s++ != '_') goto err; if ((p = strstr(s, "___")) == NULL || p - s >= sizeof (pname)) goto err; bcopy(s, pname, p - s); pname[p - s] = '\0'; p = strhyphenate(p + 3); /* strlen("___") */ if (dt_symtab_lookup(data_sym, isym, rela.r_offset, shdr_rel.sh_info, &fsym, (emachine1 == EM_PPC64), elf) != 0) goto err; if (fsym.st_name > data_str->d_size) goto err; assert(GELF_ST_TYPE(fsym.st_info) == STT_FUNC); /* * If a NULL relocation name is passed to * dt_probe_define(), the function name is used for the * relocation. The relocation needs to use a mangled * name if the symbol is locally scoped; the function * name may need to change if we've found the global * alias for the locally scoped symbol (we prefer * global symbols to locals in dt_symtab_lookup()). */ s = (char *)data_str->d_buf + fsym.st_name; r = NULL; if (GELF_ST_BIND(fsym.st_info) == STB_LOCAL) { dsym = fsym; dsym.st_name = istr; dsym.st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC); dsym.st_other = ELF64_ST_VISIBILITY(STV_ELIMINATE); (void) gelf_update_sym(data_sym, isym, &dsym); r = (char *)data_str->d_buf + istr; istr += 1 + sprintf(r, dt_symfmt, dt_symprefix, objkey, s); isym++; assert(isym <= nsym); } else if (strncmp(s, dt_symprefix, strlen(dt_symprefix)) == 0) { r = s; if ((s = strchr(s, '.')) == NULL) goto err; s++; } if ((pvp = dt_provider_lookup(dtp, pname)) == NULL) { return (dt_link_error(dtp, elf, fd, bufs, "no such provider %s", pname)); } if ((prp = dt_probe_lookup(pvp, p)) == NULL) { return (dt_link_error(dtp, elf, fd, bufs, "no such probe %s", p)); } assert(fsym.st_value <= rela.r_offset); off = rela.r_offset - fsym.st_value; if (dt_modtext(dtp, data_tgt->d_buf, eprobe, &rela, &off) != 0) goto err; if (dt_probe_define(pvp, prp, s, r, off, eprobe) != 0) { return (dt_link_error(dtp, elf, fd, bufs, "failed to allocate space for probe")); } #ifndef illumos /* * Our linker doesn't understand the SUNW_IGNORE ndx and * will try to use this relocation when we build the * final executable. Since we are done processing this * relocation, mark it as inexistant and let libelf * remove it from the file. * If this wasn't done, we would have garbage added to * the executable file as the symbol is going to be * change from UND to ABS. */ if (shdr_rel.sh_type == SHT_RELA) { rela.r_offset = 0; rela.r_info = 0; rela.r_addend = 0; (void) gelf_update_rela(data_rel, i, &rela); } else { GElf_Rel rel; rel.r_offset = 0; rel.r_info = 0; (void) gelf_update_rel(data_rel, i, &rel); } #endif mod = 1; (void) elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY); /* * This symbol may already have been marked to * be ignored by another relocation referencing * the same symbol or if this object file has * already been processed by an earlier link * invocation. */ #ifndef illumos #define SHN_SUNW_IGNORE SHN_ABS #endif if (rsym.st_shndx != SHN_SUNW_IGNORE) { rsym.st_shndx = SHN_SUNW_IGNORE; (void) gelf_update_sym(data_sym, ndx, &rsym); } } } if (mod && elf_update(elf, ELF_C_WRITE) == -1) goto err; (void) elf_end(elf); (void) close(fd); #ifndef illumos if (nsym > 0) #endif while ((pair = bufs) != NULL) { bufs = pair->dlp_next; dt_free(dtp, pair->dlp_str); dt_free(dtp, pair->dlp_sym); dt_free(dtp, pair); } return (0); err: return (dt_link_error(dtp, elf, fd, bufs, "an error was encountered while processing %s", obj)); } int dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags, const char *file, int objc, char *const objv[]) { #ifndef illumos char tfile[PATH_MAX]; #endif char drti[PATH_MAX]; dof_hdr_t *dof; int fd, status, i, cur; char *cmd, tmp; size_t len; int eprobes = 0, ret = 0; #ifndef illumos if (access(file, R_OK) == 0) { fprintf(stderr, "dtrace: target object (%s) already exists. " "Please remove the target\ndtrace: object and rebuild all " "the source objects if you wish to run the DTrace\n" "dtrace: linking process again\n", file); /* * Several build infrastructures run DTrace twice (e.g. * postgres) and we don't want the build to fail. Return * 0 here since this isn't really a fatal error. */ return (0); } #endif /* * A NULL program indicates a special use in which we just link * together a bunch of object files specified in objv and then * unlink(2) those object files. */ if (pgp == NULL) { const char *fmt = "%s -o %s -r"; len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file) + 1; for (i = 0; i < objc; i++) len += strlen(objv[i]) + 1; cmd = alloca(len); cur = snprintf(cmd, len, fmt, dtp->dt_ld_path, file); for (i = 0; i < objc; i++) cur += snprintf(cmd + cur, len - cur, " %s", objv[i]); if ((status = system(cmd)) == -1) { return (dt_link_error(dtp, NULL, -1, NULL, "failed to run %s: %s", dtp->dt_ld_path, strerror(errno))); } if (WIFSIGNALED(status)) { return (dt_link_error(dtp, NULL, -1, NULL, "failed to link %s: %s failed due to signal %d", file, dtp->dt_ld_path, WTERMSIG(status))); } if (WEXITSTATUS(status) != 0) { return (dt_link_error(dtp, NULL, -1, NULL, "failed to link %s: %s exited with status %d\n", file, dtp->dt_ld_path, WEXITSTATUS(status))); } for (i = 0; i < objc; i++) { if (strcmp(objv[i], file) != 0) (void) unlink(objv[i]); } return (0); } for (i = 0; i < objc; i++) { if (process_obj(dtp, objv[i], &eprobes) != 0) return (-1); /* errno is set for us */ } /* * If there are is-enabled probes then we need to force use of DOF * version 2. */ if (eprobes && pgp->dp_dofversion < DOF_VERSION_2) pgp->dp_dofversion = DOF_VERSION_2; if ((dof = dtrace_dof_create(dtp, pgp, dflags)) == NULL) return (-1); /* errno is set for us */ #ifdef illumos /* * Create a temporary file and then unlink it if we're going to * combine it with drti.o later. We can still refer to it in child * processes as /dev/fd/. */ if ((fd = open64(file, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) { return (dt_link_error(dtp, NULL, -1, NULL, "failed to open %s: %s", file, strerror(errno))); } #else - if (dtp->dt_lazyload) { - if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0666)) < 0) - return (dt_link_error(dtp, NULL, -1, NULL, - "failed to open %s: %s", file, strerror(errno))); - } else { - snprintf(tfile, sizeof(tfile), "%s.XXXXXX", file); - if ((fd = mkstemp(tfile)) == -1) - return (dt_link_error(dtp, NULL, -1, NULL, - "failed to create temporary file %s: %s", - tfile, strerror(errno))); - } + snprintf(tfile, sizeof(tfile), "%s.XXXXXX", file); + if ((fd = mkostemp(tfile, O_CLOEXEC)) == -1) + return (dt_link_error(dtp, NULL, -1, NULL, + "failed to create temporary file %s: %s", + tfile, strerror(errno))); #endif /* * If -xlinktype=DOF has been selected, just write out the DOF. * Otherwise proceed to the default of generating and linking ELF. */ switch (dtp->dt_linktype) { case DT_LTYP_DOF: if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz) ret = errno; if (close(fd) != 0 && ret == 0) ret = errno; if (ret != 0) { return (dt_link_error(dtp, NULL, -1, NULL, "failed to write %s: %s", file, strerror(ret))); } return (0); case DT_LTYP_ELF: break; /* fall through to the rest of dtrace_program_link() */ default: return (dt_link_error(dtp, NULL, -1, NULL, "invalid link type %u\n", dtp->dt_linktype)); } #ifdef illumos if (!dtp->dt_lazyload) (void) unlink(file); #endif if (dtp->dt_oflags & DTRACE_O_LP64) status = dump_elf64(dtp, dof, fd); else status = dump_elf32(dtp, dof, fd); #ifdef illumos if (status != 0 || lseek(fd, 0, SEEK_SET) != 0) { return (dt_link_error(dtp, NULL, -1, NULL, "failed to write %s: %s", file, strerror(errno))); } #else if (status != 0) return (dt_link_error(dtp, NULL, -1, NULL, "failed to write %s: %s", tfile, strerror(dtrace_errno(dtp)))); #endif if (!dtp->dt_lazyload) { #ifdef illumos const char *fmt = "%s -o %s -r -Blocal -Breduce /dev/fd/%d %s"; if (dtp->dt_oflags & DTRACE_O_LP64) { (void) snprintf(drti, sizeof (drti), "%s/64/drti.o", _dtrace_libdir); } else { (void) snprintf(drti, sizeof (drti), "%s/drti.o", _dtrace_libdir); } len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, fd, drti) + 1; cmd = alloca(len); (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, fd, drti); #else const char *fmt = "%s -o %s -r %s %s"; #if defined(__amd64__) /* * Arches which default to 64-bit need to explicitly use * the 32-bit library path. */ int use_32 = (dtp->dt_oflags & DTRACE_O_ILP32); #else /* * Arches which are 32-bit only just use the normal * library path. */ int use_32 = 0; #endif (void) snprintf(drti, sizeof (drti), "/usr/lib%s/dtrace/drti.o", use_32 ? "32" : ""); len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile, drti) + 1; cmd = alloca(len); (void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, tfile, drti); #endif if ((status = system(cmd)) == -1) { ret = dt_link_error(dtp, NULL, fd, NULL, "failed to run %s: %s", dtp->dt_ld_path, strerror(errno)); goto done; } if (WIFSIGNALED(status)) { ret = dt_link_error(dtp, NULL, fd, NULL, "failed to link %s: %s failed due to signal %d", file, dtp->dt_ld_path, WTERMSIG(status)); goto done; } if (WEXITSTATUS(status) != 0) { ret = dt_link_error(dtp, NULL, fd, NULL, "failed to link %s: %s exited with status %d\n", file, dtp->dt_ld_path, WEXITSTATUS(status)); goto done; } (void) close(fd); /* release temporary file */ #ifdef __FreeBSD__ /* * Now that we've linked drti.o, reduce the global __SUNW_dof * symbol to a local symbol. This is needed to so that multiple * generated object files (for different providers, for * instance) can be linked together. This is accomplished using * the -Blocal flag with Sun's linker, but GNU ld doesn't appear * to have an equivalent option. */ asprintf(&cmd, "%s --localize-hidden %s", dtp->dt_objcopy_path, file); if ((status = system(cmd)) == -1) { ret = dt_link_error(dtp, NULL, -1, NULL, "failed to run %s: %s", dtp->dt_objcopy_path, strerror(errno)); free(cmd); goto done; } free(cmd); if (WIFSIGNALED(status)) { ret = dt_link_error(dtp, NULL, -1, NULL, "failed to link %s: %s failed due to signal %d", file, dtp->dt_objcopy_path, WTERMSIG(status)); goto done; } if (WEXITSTATUS(status) != 0) { ret = dt_link_error(dtp, NULL, -1, NULL, "failed to link %s: %s exited with status %d\n", file, dtp->dt_objcopy_path, WEXITSTATUS(status)); goto done; } #endif } else { +#ifdef __FreeBSD__ + if (rename(tfile, file) != 0) { + ret = dt_link_error(dtp, NULL, fd, NULL, + "failed to rename %s to %s: %s", tfile, file, + strerror(errno)); + goto done; + } +#endif (void) close(fd); } done: dtrace_dof_destroy(dtp, dof); -#ifndef illumos - unlink(tfile); +#ifdef illumos + if (!dtp->dt_lazyload) + (void) unlink(tfile); #endif return (ret); } Index: projects/ci20_mips/cddl/contrib/opensolaris =================================================================== --- projects/ci20_mips/cddl/contrib/opensolaris (revision 283030) +++ projects/ci20_mips/cddl/contrib/opensolaris (revision 283031) Property changes on: projects/ci20_mips/cddl/contrib/opensolaris ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/cddl/contrib/opensolaris:r282931-283030 Index: projects/ci20_mips/cddl/lib/libdtrace/Makefile =================================================================== --- projects/ci20_mips/cddl/lib/libdtrace/Makefile (revision 283030) +++ projects/ci20_mips/cddl/lib/libdtrace/Makefile (revision 283031) @@ -1,123 +1,124 @@ # $FreeBSD$ .PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/common .PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libgen/common LIB= dtrace SRCS= dt_aggregate.c \ dt_as.c \ dt_buf.c \ dt_cc.c \ dt_cg.c \ dt_consume.c \ dt_decl.c \ dt_dis.c \ dt_dof.c \ dt_error.c \ dt_errtags.c \ dt_grammar.y \ dt_handle.c \ dt_ident.c \ dt_isadep.c \ dt_inttab.c \ dt_lex.l \ dt_link.c \ dt_list.c \ dt_map.c \ dt_module.c \ dt_names.c \ dt_open.c \ dt_options.c \ dt_parser.c \ dt_pcb.c \ dt_pid.c \ dt_pq.c \ dt_pragma.c \ dt_print.c \ dt_printf.c \ dt_proc.c \ dt_program.c \ dt_provider.c \ dt_regset.c \ dt_string.c \ dt_strtab.c \ dt_subr.c \ dt_work.c \ dt_xlator.c \ gmatch.c DSRCS= errno.d \ io.d \ ip.d \ psinfo.d \ + siftr.d \ signal.d \ tcp.d \ udp.d \ unistd.d WARNS?= 1 CFLAGS+= -I${.OBJDIR} -I${.CURDIR} \ -I${.CURDIR}/../../../sys/cddl/dev/dtrace/${MACHINE_ARCH} \ -I${.CURDIR}/../../../sys/cddl/compat/opensolaris \ -I${.CURDIR}/../../../cddl/compat/opensolaris/include \ -I${OPENSOLARIS_USR_DISTDIR}/head \ -I${OPENSOLARIS_USR_DISTDIR}/lib/libctf/common \ -I${OPENSOLARIS_USR_DISTDIR}/lib/libdtrace/common \ -I${OPENSOLARIS_SYS_DISTDIR}/uts/common #CFLAGS+= -DYYDEBUG .if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" CFLAGS+= -I${.CURDIR}/../../../sys/cddl/dev/dtrace/x86 CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/intel -DDIS_MEM .PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/i386 .PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/${MACHINE_ARCH} .PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/x86 .elif ${MACHINE_CPUARCH} == "sparc64" CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/sparc .PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/sparc .elif ${MACHINE_CPUARCH} == "mips" CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/mips .PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/mips .PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/mips .elif ${MACHINE_CPUARCH} == "arm" CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/arm .PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/arm .PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/arm .elif ${MACHINE_CPUARCH} == "powerpc" CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/powerpc .PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/powerpc .PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/powerpc .else # temporary hack CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/intel .endif .if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64" SRCS+= dis_tables.c DSRCS+= regs_x86.d .endif LFLAGS+=-l YFLAGS+=-d CLEANFILES= dt_errtags.c dt_names.c dt_errtags.c: sh ${OPENSOLARIS_USR_DISTDIR}/lib/libdtrace/common/mkerrtags.sh < ${OPENSOLARIS_USR_DISTDIR}/lib/libdtrace/common/dt_errtags.h > dt_errtags.c dt_names.c: sh ${OPENSOLARIS_USR_DISTDIR}/lib/libdtrace/common/mknames.sh < ${OPENSOLARIS_SYS_DISTDIR}/uts/common/sys/dtrace.h > dt_names.c beforedepend: dt_errtags.c dt_names.c beforeinstall: .if !defined(LIBRARIES_ONLY) && exists(${DESTDIR}/usr/lib/dtrace) .for file in ${DSRCS} ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m ${NOBINMODE} ${.CURDIR}/${file} ${DESTDIR}/usr/lib/dtrace .endfor .endif .include Index: projects/ci20_mips/cddl/lib/libdtrace/siftr.d =================================================================== --- projects/ci20_mips/cddl/lib/libdtrace/siftr.d (nonexistent) +++ projects/ci20_mips/cddl/lib/libdtrace/siftr.d (revision 283031) @@ -0,0 +1,100 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * $FreeBSD$ + */ + +#pragma D depends_on module siftr +#pragma D depends_on provider tcp + +/* + * Convert a SIFTR direction value to a string + */ +#pragma D binding "1.12.1" SIFTR_IN +inline int SIFTR_IN = 1; +#pragma D binding "1.12.1" SIFTR_OUT +inline int SIFTR_OUT = 2; + +/* SIFTR direction strings. */ +#pragma D binding "1.12.1" siftr_dir_string +inline string siftr_dir_string[uint8_t direction] = + direction == SIFTR_IN ? "in" : + direction == SIFTR_OUT ? "out" : + "unknown" ; + +typedef struct siftrinfo { + struct timeval tval; + uint8_t direction; + uint8_t ipver; + uint32_t hash; + uint16_t tcp_localport; + uint16_t tcp_foreignport; + uint64_t snd_cwnd; + u_long snd_wnd; + u_long rcv_wnd; + u_long snd_bwnd; + u_long snd_ssthresh; + int conn_state; + u_int max_seg_size; + int smoothed_rtt; + u_char sack_enabled; + u_char snd_scale; + u_char rcv_scale; + u_int flags; + int rxt_length; + u_int snd_buf_hiwater; + u_int snd_buf_cc; + u_int rcv_buf_hiwater; + u_int rcv_buf_cc; + u_int sent_inflight_bytes; + int t_segqlen; + u_int flowid; + u_int flowtype; +} siftrinfo_t; + +#pragma D binding "1.12.1" translator +translator siftrinfo_t < struct pkt_node *p > { + direction = p == NULL ? 0 : p->direction; + ipver = p == NULL ? 0 : p->ipver; + hash = p == NULL ? 0 : p->hash; + tcp_localport = p == NULL ? 0 : ntohs(p->tcp_localport); + tcp_foreignport = p == NULL ? 0 : ntohs(p->tcp_foreignport); + snd_cwnd = p == NULL ? 0 : p->snd_cwnd; + snd_wnd = p == NULL ? 0 : p->snd_wnd; + rcv_wnd = p == NULL ? 0 : p->rcv_wnd; + snd_bwnd = p == NULL ? 0 : p->snd_bwnd; + snd_ssthresh = p == NULL ? 0 : p->snd_ssthresh; + conn_state = p == NULL ? 0 : p->conn_state; + max_seg_size = p == NULL ? 0 : p->max_seg_size; + smoothed_rtt = p == NULL ? 0 : p->smoothed_rtt; + sack_enabled = p == NULL ? 0 : p->sack_enabled; + snd_scale = p == NULL ? 0 : p->snd_scale; + rcv_scale = p == NULL ? 0 : p->rcv_scale; + flags = p == NULL ? 0 : p->flags; + rxt_length = p == NULL ? 0 : p->rxt_length; + snd_buf_hiwater = p == NULL ? 0 : p->snd_buf_hiwater; + snd_buf_cc = p == NULL ? 0 : p->snd_buf_cc; + rcv_buf_hiwater = p == NULL ? 0 : p->rcv_buf_hiwater; + rcv_buf_cc = p == NULL ? 0 : p->rcv_buf_cc; + sent_inflight_bytes = p == NULL ? 0 : p->sent_inflight_bytes; + t_segqlen = p == NULL ? 0 : p->t_segqlen; + flowid = p == NULL ? 0 : p->flowid; + flowtype = p == NULL ? 0 : p->flowtype; +}; Property changes on: projects/ci20_mips/cddl/lib/libdtrace/siftr.d ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/cddl/lib/libdtrace/tcp.d =================================================================== --- projects/ci20_mips/cddl/lib/libdtrace/tcp.d (revision 283030) +++ projects/ci20_mips/cddl/lib/libdtrace/tcp.d (revision 283031) @@ -1,318 +1,243 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * $FreeBSD$ */ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 Mark Johnston */ #pragma D depends_on library ip.d #pragma D depends_on provider tcp /* * Convert a TCP state value to a string. */ #pragma D binding "1.6.3" TCPS_CLOSED inline int TCPS_CLOSED = 0; #pragma D binding "1.6.3" TCPS_LISTEN inline int TCPS_LISTEN = 1; #pragma D binding "1.6.3" TCPS_SYN_SENT inline int TCPS_SYN_SENT = 2; #pragma D binding "1.6.3" TCPS_SYN_RECEIVED inline int TCPS_SYN_RECEIVED = 3; #pragma D binding "1.6.3" TCPS_ESTABLISHED inline int TCPS_ESTABLISHED = 4; #pragma D binding "1.6.3" TCPS_CLOSE_WAIT inline int TCPS_CLOSE_WAIT = 5; #pragma D binding "1.6.3" TCPS_FIN_WAIT_1 inline int TCPS_FIN_WAIT_1 = 6; #pragma D binding "1.6.3" TCPS_CLOSING inline int TCPS_CLOSING = 7; #pragma D binding "1.6.3" TCPS_LAST_ACK inline int TCPS_LAST_ACK = 8; #pragma D binding "1.6.3" TCPS_FIN_WAIT_2 inline int TCPS_FIN_WAIT_2 = 9; #pragma D binding "1.6.3" TCPS_TIME_WAIT inline int TCPS_TIME_WAIT = 10; /* TCP segment flags. */ #pragma D binding "1.6.3" TH_FIN inline uint8_t TH_FIN = 0x01; #pragma D binding "1.6.3" TH_SYN inline uint8_t TH_SYN = 0x02; #pragma D binding "1.6.3" TH_RST inline uint8_t TH_RST = 0x04; #pragma D binding "1.6.3" TH_PUSH inline uint8_t TH_PUSH = 0x08; #pragma D binding "1.6.3" TH_ACK inline uint8_t TH_ACK = 0x10; #pragma D binding "1.6.3" TH_URG inline uint8_t TH_URG = 0x20; #pragma D binding "1.6.3" TH_ECE inline uint8_t TH_ECE = 0x40; #pragma D binding "1.6.3" TH_CWR inline uint8_t TH_CWR = 0x80; /* TCP connection state strings. */ #pragma D binding "1.6.3" tcp_state_string inline string tcp_state_string[int32_t state] = state == TCPS_CLOSED ? "state-closed" : state == TCPS_LISTEN ? "state-listen" : state == TCPS_SYN_SENT ? "state-syn-sent" : state == TCPS_SYN_RECEIVED ? "state-syn-received" : state == TCPS_ESTABLISHED ? "state-established" : state == TCPS_CLOSE_WAIT ? "state-close-wait" : state == TCPS_FIN_WAIT_1 ? "state-fin-wait-1" : state == TCPS_CLOSING ? "state-closing" : state == TCPS_LAST_ACK ? "state-last-ack" : state == TCPS_FIN_WAIT_2 ? "state-fin-wait-2" : state == TCPS_TIME_WAIT ? "state-time-wait" : ""; /* * tcpsinfo contains stable TCP details from tcp_t. */ typedef struct tcpsinfo { uintptr_t tcps_addr; int tcps_local; /* is delivered locally, boolean */ int tcps_active; /* active open (from here), boolean */ uint16_t tcps_lport; /* local port */ uint16_t tcps_rport; /* remote port */ string tcps_laddr; /* local address, as a string */ string tcps_raddr; /* remote address, as a string */ int32_t tcps_state; /* TCP state */ uint32_t tcps_iss; /* Initial sequence # sent */ uint32_t tcps_suna; /* sequence # sent but unacked */ uint32_t tcps_snxt; /* next sequence # to send */ uint32_t tcps_rack; /* sequence # we have acked */ uint32_t tcps_rnxt; /* next sequence # expected */ uint32_t tcps_swnd; /* send window size */ int32_t tcps_snd_ws; /* send window scaling */ uint32_t tcps_rwnd; /* receive window size */ int32_t tcps_rcv_ws; /* receive window scaling */ uint32_t tcps_cwnd; /* congestion window */ uint32_t tcps_cwnd_ssthresh; /* threshold for congestion avoidance */ uint32_t tcps_sack_fack; /* SACK sequence # we have acked */ uint32_t tcps_sack_snxt; /* next SACK seq # for retransmission */ uint32_t tcps_rto; /* round-trip timeout, msec */ uint32_t tcps_mss; /* max segment size */ int tcps_retransmit; /* retransmit send event, boolean */ int tcps_srtt; /* smoothed RTT in units of (TCP_RTT_SCALE*hz) */ } tcpsinfo_t; /* * tcplsinfo provides the old tcp state for state changes. */ typedef struct tcplsinfo { int32_t tcps_state; /* previous TCP state */ } tcplsinfo_t; /* * tcpinfo is the TCP header fields. */ typedef struct tcpinfo { uint16_t tcp_sport; /* source port */ uint16_t tcp_dport; /* destination port */ uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ uint8_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ struct tcphdr *tcp_hdr; /* raw TCP header */ } tcpinfo_t; /* * A clone of tcpinfo_t used to handle the fact that the TCP input path * overwrites some fields of the TCP header with their host-order equivalents. * Unfortunately, DTrace doesn't let us simply typedef a new name for struct * tcpinfo and define a separate translator for it. */ typedef struct tcpinfoh { uint16_t tcp_sport; /* source port */ uint16_t tcp_dport; /* destination port */ uint32_t tcp_seq; /* sequence number */ uint32_t tcp_ack; /* acknowledgment number */ uint8_t tcp_offset; /* data offset, in bytes */ uint8_t tcp_flags; /* flags */ uint16_t tcp_window; /* window size */ uint16_t tcp_checksum; /* checksum */ uint16_t tcp_urgent; /* urgent data pointer */ struct tcphdr *tcp_hdr; /* raw TCP header */ } tcpinfoh_t; #pragma D binding "1.6.3" translator translator csinfo_t < struct tcpcb *p > { cs_addr = NULL; cs_cid = (uint64_t)(p == NULL ? 0 : p->t_inpcb); cs_pid = 0; cs_zoneid = 0; }; #pragma D binding "1.6.3" translator translator tcpsinfo_t < struct tcpcb *p > { tcps_addr = (uintptr_t)p; tcps_local = -1; /* XXX */ tcps_active = -1; /* XXX */ tcps_lport = p == NULL ? 0 : ntohs(p->t_inpcb->inp_inc.inc_ie.ie_lport); tcps_rport = p == NULL ? 0 : ntohs(p->t_inpcb->inp_inc.inc_ie.ie_fport); tcps_laddr = p == NULL ? 0 : p->t_inpcb->inp_vflag == INP_IPV4 ? inet_ntoa(&p->t_inpcb->inp_inc.inc_ie.ie_dependladdr.ie46_local.ia46_addr4.s_addr) : inet_ntoa6(&p->t_inpcb->inp_inc.inc_ie.ie_dependladdr.ie6_local); tcps_raddr = p == NULL ? 0 : p->t_inpcb->inp_vflag == INP_IPV4 ? inet_ntoa(&p->t_inpcb->inp_inc.inc_ie.ie_dependfaddr.ie46_foreign.ia46_addr4.s_addr) : inet_ntoa6(&p->t_inpcb->inp_inc.inc_ie.ie_dependfaddr.ie6_foreign); tcps_state = p == NULL ? -1 : p->t_state; tcps_iss = p == NULL ? 0 : p->iss; tcps_suna = p == NULL ? 0 : p->snd_una; tcps_snxt = p == NULL ? 0 : p->snd_nxt; tcps_rack = p == NULL ? 0 : p->last_ack_sent; tcps_rnxt = p == NULL ? 0 : p->rcv_nxt; tcps_swnd = p == NULL ? -1 : p->snd_wnd; tcps_snd_ws = p == NULL ? -1 : p->snd_scale; tcps_rwnd = p == NULL ? -1 : p->rcv_wnd; tcps_rcv_ws = p == NULL ? -1 : p->rcv_scale; tcps_cwnd = p == NULL ? -1 : p->snd_cwnd; tcps_cwnd_ssthresh = p == NULL ? -1 : p->snd_ssthresh; tcps_sack_fack = p == NULL ? 0 : p->snd_fack; tcps_sack_snxt = p == NULL ? 0 : p->sack_newdata; tcps_rto = p == NULL ? -1 : (p->t_rxtcur * 1000) / `hz; tcps_mss = p == NULL ? -1 : p->t_maxseg; tcps_retransmit = p == NULL ? -1 : p->t_rxtshift > 0 ? 1 : 0; tcps_srtt = p == NULL ? -1 : p->t_srtt; /* smoothed RTT in units of (TCP_RTT_SCALE*hz) */ }; #pragma D binding "1.6.3" translator translator tcpinfo_t < struct tcphdr *p > { tcp_sport = p == NULL ? 0 : ntohs(p->th_sport); tcp_dport = p == NULL ? 0 : ntohs(p->th_dport); tcp_seq = p == NULL ? -1 : ntohl(p->th_seq); tcp_ack = p == NULL ? -1 : ntohl(p->th_ack); tcp_offset = p == NULL ? -1 : (p->th_off >> 2); tcp_flags = p == NULL ? 0 : p->th_flags; tcp_window = p == NULL ? 0 : ntohs(p->th_win); tcp_checksum = p == NULL ? 0 : ntohs(p->th_sum); tcp_urgent = p == NULL ? 0 : ntohs(p->th_urp); tcp_hdr = (struct tcphdr *)p; }; /* * This translator differs from the one for tcpinfo_t in that the sequence * number, acknowledgement number, window size and urgent pointer are already * in host order and thus don't need to be converted. */ #pragma D binding "1.6.3" translator translator tcpinfoh_t < struct tcphdr *p > { tcp_sport = p == NULL ? 0 : ntohs(p->th_sport); tcp_dport = p == NULL ? 0 : ntohs(p->th_dport); tcp_seq = p == NULL ? -1 : p->th_seq; tcp_ack = p == NULL ? -1 : p->th_ack; tcp_offset = p == NULL ? -1 : (p->th_off >> 2); tcp_flags = p == NULL ? 0 : p->th_flags; tcp_window = p == NULL ? 0 : (p->th_win); tcp_checksum = p == NULL ? 0 : ntohs(p->th_sum); tcp_urgent = p == NULL ? 0 : p->th_urp; tcp_hdr = (struct tcphdr *)p; }; #pragma D binding "1.6.3" translator translator tcplsinfo_t < int s > { tcps_state = s; }; - -/* - * Convert a SIFTR direction value to a string - */ -#pragma D binding "1.12.1" SIFTR_IN -inline int SIFTR_IN = 1; -#pragma D binding "1.12.1" SIFTR_OUT -inline int SIFTR_OUT = 2; - -/* SIFTR direction strings. */ -#pragma D binding "1.12.1" siftr_dir_string -inline string siftr_dir_string[uint8_t direction] = - direction == SIFTR_IN ? "in" : - direction == SIFTR_OUT ? "out" : - "unknown" ; - -typedef struct siftrinfo { - struct timeval tval; - uint8_t direction; - uint8_t ipver; - uint32_t hash; - uint16_t tcp_localport; - uint16_t tcp_foreignport; - uint64_t snd_cwnd; - u_long snd_wnd; - u_long rcv_wnd; - u_long snd_bwnd; - u_long snd_ssthresh; - int conn_state; - u_int max_seg_size; - int smoothed_rtt; - u_char sack_enabled; - u_char snd_scale; - u_char rcv_scale; - u_int flags; - int rxt_length; - u_int snd_buf_hiwater; - u_int snd_buf_cc; - u_int rcv_buf_hiwater; - u_int rcv_buf_cc; - u_int sent_inflight_bytes; - int t_segqlen; - u_int flowid; - u_int flowtype; -} siftrinfo_t; - -#pragma D binding "1.12.1" translator -translator siftrinfo_t < struct pkt_node *p > { - direction = p == NULL ? 0 : p->direction; - ipver = p == NULL ? 0 : p->ipver; - hash = p == NULL ? 0 : p->hash; - tcp_localport = p == NULL ? 0 : ntohs(p->tcp_localport); - tcp_foreignport = p == NULL ? 0 : ntohs(p->tcp_foreignport); - snd_cwnd = p == NULL ? 0 : p->snd_cwnd; - snd_wnd = p == NULL ? 0 : p->snd_wnd; - rcv_wnd = p == NULL ? 0 : p->rcv_wnd; - snd_bwnd = p == NULL ? 0 : p->snd_bwnd; - snd_ssthresh = p == NULL ? 0 : p->snd_ssthresh; - conn_state = p == NULL ? 0 : p->conn_state; - max_seg_size = p == NULL ? 0 : p->max_seg_size; - smoothed_rtt = p == NULL ? 0 : p->smoothed_rtt; - sack_enabled = p == NULL ? 0 : p->sack_enabled; - snd_scale = p == NULL ? 0 : p->snd_scale; - rcv_scale = p == NULL ? 0 : p->rcv_scale; - flags = p == NULL ? 0 : p->flags; - rxt_length = p == NULL ? 0 : p->rxt_length; - snd_buf_hiwater = p == NULL ? 0 : p->snd_buf_hiwater; - snd_buf_cc = p == NULL ? 0 : p->snd_buf_cc; - rcv_buf_hiwater = p == NULL ? 0 : p->rcv_buf_hiwater; - rcv_buf_cc = p == NULL ? 0 : p->rcv_buf_cc; - sent_inflight_bytes = p == NULL ? 0 : p->sent_inflight_bytes; - t_segqlen = p == NULL ? 0 : p->t_segqlen; - flowid = p == NULL ? 0 : p->flowid; - flowtype = p == NULL ? 0 : p->flowtype; -}; Index: projects/ci20_mips/cddl =================================================================== --- projects/ci20_mips/cddl (revision 283030) +++ projects/ci20_mips/cddl (revision 283031) Property changes on: projects/ci20_mips/cddl ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/cddl:r282931-283030 Index: projects/ci20_mips/contrib/gcc/dwarf2.h =================================================================== --- projects/ci20_mips/contrib/gcc/dwarf2.h (revision 283030) +++ projects/ci20_mips/contrib/gcc/dwarf2.h (revision 283031) @@ -1,844 +1,845 @@ /* Declarations and definitions of codes relating to the DWARF2 and DWARF3 symbolic debugging information formats. Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. Written by Gary Funck (gary@intrepid.com) The Ada Joint Program Office (AJPO), Florida State University and Silicon Graphics Inc. provided support for this effort -- June 21, 1995. Derived from the DWARF 1 implementation written by Ron Guilmette (rfg@netcom.com), November 1990. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* This file is derived from the DWARF specification (a public document) Revision 2.0.0 (July 27, 1993) developed by the UNIX International Programming Languages Special Interest Group (UI/PLSIG) and distributed by UNIX International. Copies of this specification are available from UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. This file also now contains definitions from the DWARF 3 specification. */ /* This file is shared between GCC and GDB, and should not contain prototypes. */ #ifndef GCC_DWARF2_H #define GCC_DWARF2_H /* Structure found in the .debug_line section. */ typedef struct { unsigned char li_length [4]; unsigned char li_version [2]; unsigned char li_prologue_length [4]; unsigned char li_min_insn_length [1]; unsigned char li_default_is_stmt [1]; unsigned char li_line_base [1]; unsigned char li_line_range [1]; unsigned char li_opcode_base [1]; } DWARF2_External_LineInfo; typedef struct { unsigned long li_length; unsigned short li_version; unsigned int li_prologue_length; unsigned char li_min_insn_length; unsigned char li_default_is_stmt; int li_line_base; unsigned char li_line_range; unsigned char li_opcode_base; } DWARF2_Internal_LineInfo; /* Structure found in .debug_pubnames section. */ typedef struct { unsigned char pn_length [4]; unsigned char pn_version [2]; unsigned char pn_offset [4]; unsigned char pn_size [4]; } DWARF2_External_PubNames; typedef struct { unsigned long pn_length; unsigned short pn_version; unsigned long pn_offset; unsigned long pn_size; } DWARF2_Internal_PubNames; /* Structure found in .debug_info section. */ typedef struct { unsigned char cu_length [4]; unsigned char cu_version [2]; unsigned char cu_abbrev_offset [4]; unsigned char cu_pointer_size [1]; } DWARF2_External_CompUnit; typedef struct { unsigned long cu_length; unsigned short cu_version; unsigned long cu_abbrev_offset; unsigned char cu_pointer_size; } DWARF2_Internal_CompUnit; typedef struct { unsigned char ar_length [4]; unsigned char ar_version [2]; unsigned char ar_info_offset [4]; unsigned char ar_pointer_size [1]; unsigned char ar_segment_size [1]; } DWARF2_External_ARange; typedef struct { unsigned long ar_length; unsigned short ar_version; unsigned long ar_info_offset; unsigned char ar_pointer_size; unsigned char ar_segment_size; } DWARF2_Internal_ARange; /* Tag names and codes. */ enum dwarf_tag { DW_TAG_padding = 0x00, DW_TAG_array_type = 0x01, DW_TAG_class_type = 0x02, DW_TAG_entry_point = 0x03, DW_TAG_enumeration_type = 0x04, DW_TAG_formal_parameter = 0x05, DW_TAG_imported_declaration = 0x08, DW_TAG_label = 0x0a, DW_TAG_lexical_block = 0x0b, DW_TAG_member = 0x0d, DW_TAG_pointer_type = 0x0f, DW_TAG_reference_type = 0x10, DW_TAG_compile_unit = 0x11, DW_TAG_string_type = 0x12, DW_TAG_structure_type = 0x13, DW_TAG_subroutine_type = 0x15, DW_TAG_typedef = 0x16, DW_TAG_union_type = 0x17, DW_TAG_unspecified_parameters = 0x18, DW_TAG_variant = 0x19, DW_TAG_common_block = 0x1a, DW_TAG_common_inclusion = 0x1b, DW_TAG_inheritance = 0x1c, DW_TAG_inlined_subroutine = 0x1d, DW_TAG_module = 0x1e, DW_TAG_ptr_to_member_type = 0x1f, DW_TAG_set_type = 0x20, DW_TAG_subrange_type = 0x21, DW_TAG_with_stmt = 0x22, DW_TAG_access_declaration = 0x23, DW_TAG_base_type = 0x24, DW_TAG_catch_block = 0x25, DW_TAG_const_type = 0x26, DW_TAG_constant = 0x27, DW_TAG_enumerator = 0x28, DW_TAG_file_type = 0x29, DW_TAG_friend = 0x2a, DW_TAG_namelist = 0x2b, DW_TAG_namelist_item = 0x2c, DW_TAG_packed_type = 0x2d, DW_TAG_subprogram = 0x2e, DW_TAG_template_type_param = 0x2f, DW_TAG_template_value_param = 0x30, DW_TAG_thrown_type = 0x31, DW_TAG_try_block = 0x32, DW_TAG_variant_part = 0x33, DW_TAG_variable = 0x34, DW_TAG_volatile_type = 0x35, /* DWARF 3. */ DW_TAG_dwarf_procedure = 0x36, DW_TAG_restrict_type = 0x37, DW_TAG_interface_type = 0x38, DW_TAG_namespace = 0x39, DW_TAG_imported_module = 0x3a, DW_TAG_unspecified_type = 0x3b, DW_TAG_partial_unit = 0x3c, DW_TAG_imported_unit = 0x3d, DW_TAG_condition = 0x3f, DW_TAG_shared_type = 0x40, /* SGI/MIPS Extensions. */ DW_TAG_MIPS_loop = 0x4081, /* HP extensions. See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz . */ DW_TAG_HP_array_descriptor = 0x4090, /* GNU extensions. */ DW_TAG_format_label = 0x4101, /* For FORTRAN 77 and Fortran 90. */ DW_TAG_function_template = 0x4102, /* For C++. */ DW_TAG_class_template = 0x4103, /* For C++. */ DW_TAG_GNU_BINCL = 0x4104, DW_TAG_GNU_EINCL = 0x4105, /* Extensions for UPC. See: http://upc.gwu.edu/~upc. */ DW_TAG_upc_shared_type = 0x8765, DW_TAG_upc_strict_type = 0x8766, DW_TAG_upc_relaxed_type = 0x8767, /* PGI (STMicroelectronics) extensions. No documentation available. */ DW_TAG_PGI_kanji_type = 0xA000, DW_TAG_PGI_interface_block = 0xA020 }; #define DW_TAG_lo_user 0x4080 #define DW_TAG_hi_user 0xffff /* Flag that tells whether entry has a child or not. */ #define DW_children_no 0 #define DW_children_yes 1 /* Form names and codes. */ enum dwarf_form { DW_FORM_addr = 0x01, DW_FORM_block2 = 0x03, DW_FORM_block4 = 0x04, DW_FORM_data2 = 0x05, DW_FORM_data4 = 0x06, DW_FORM_data8 = 0x07, DW_FORM_string = 0x08, DW_FORM_block = 0x09, DW_FORM_block1 = 0x0a, DW_FORM_data1 = 0x0b, DW_FORM_flag = 0x0c, DW_FORM_sdata = 0x0d, DW_FORM_strp = 0x0e, DW_FORM_udata = 0x0f, DW_FORM_ref_addr = 0x10, DW_FORM_ref1 = 0x11, DW_FORM_ref2 = 0x12, DW_FORM_ref4 = 0x13, DW_FORM_ref8 = 0x14, DW_FORM_ref_udata = 0x15, DW_FORM_indirect = 0x16 }; /* Attribute names and codes. */ enum dwarf_attribute { DW_AT_sibling = 0x01, DW_AT_location = 0x02, DW_AT_name = 0x03, DW_AT_ordering = 0x09, DW_AT_subscr_data = 0x0a, DW_AT_byte_size = 0x0b, DW_AT_bit_offset = 0x0c, DW_AT_bit_size = 0x0d, DW_AT_element_list = 0x0f, DW_AT_stmt_list = 0x10, DW_AT_low_pc = 0x11, DW_AT_high_pc = 0x12, DW_AT_language = 0x13, DW_AT_member = 0x14, DW_AT_discr = 0x15, DW_AT_discr_value = 0x16, DW_AT_visibility = 0x17, DW_AT_import = 0x18, DW_AT_string_length = 0x19, DW_AT_common_reference = 0x1a, DW_AT_comp_dir = 0x1b, DW_AT_const_value = 0x1c, DW_AT_containing_type = 0x1d, DW_AT_default_value = 0x1e, DW_AT_inline = 0x20, DW_AT_is_optional = 0x21, DW_AT_lower_bound = 0x22, DW_AT_producer = 0x25, DW_AT_prototyped = 0x27, DW_AT_return_addr = 0x2a, DW_AT_start_scope = 0x2c, DW_AT_stride_size = 0x2e, DW_AT_upper_bound = 0x2f, DW_AT_abstract_origin = 0x31, DW_AT_accessibility = 0x32, DW_AT_address_class = 0x33, DW_AT_artificial = 0x34, DW_AT_base_types = 0x35, DW_AT_calling_convention = 0x36, DW_AT_count = 0x37, DW_AT_data_member_location = 0x38, DW_AT_decl_column = 0x39, DW_AT_decl_file = 0x3a, DW_AT_decl_line = 0x3b, DW_AT_declaration = 0x3c, DW_AT_discr_list = 0x3d, DW_AT_encoding = 0x3e, DW_AT_external = 0x3f, DW_AT_frame_base = 0x40, DW_AT_friend = 0x41, DW_AT_identifier_case = 0x42, DW_AT_macro_info = 0x43, DW_AT_namelist_items = 0x44, DW_AT_priority = 0x45, DW_AT_segment = 0x46, DW_AT_specification = 0x47, DW_AT_static_link = 0x48, DW_AT_type = 0x49, DW_AT_use_location = 0x4a, DW_AT_variable_parameter = 0x4b, DW_AT_virtuality = 0x4c, DW_AT_vtable_elem_location = 0x4d, /* DWARF 3 values. */ DW_AT_allocated = 0x4e, DW_AT_associated = 0x4f, DW_AT_data_location = 0x50, DW_AT_stride = 0x51, DW_AT_entry_pc = 0x52, DW_AT_use_UTF8 = 0x53, DW_AT_extension = 0x54, DW_AT_ranges = 0x55, DW_AT_trampoline = 0x56, DW_AT_call_column = 0x57, DW_AT_call_file = 0x58, DW_AT_call_line = 0x59, DW_AT_description = 0x5a, DW_AT_binary_scale = 0x5b, DW_AT_decimal_scale = 0x5c, DW_AT_small = 0x5d, DW_AT_decimal_sign = 0x5e, DW_AT_digit_count = 0x5f, DW_AT_picture_string = 0x60, DW_AT_mutable = 0x61, DW_AT_threads_scaled = 0x62, DW_AT_explicit = 0x63, DW_AT_object_pointer = 0x64, DW_AT_endianity = 0x65, DW_AT_elemental = 0x66, DW_AT_pure = 0x67, DW_AT_recursive = 0x68, /* SGI/MIPS extensions. */ DW_AT_MIPS_fde = 0x2001, DW_AT_MIPS_loop_begin = 0x2002, DW_AT_MIPS_tail_loop_begin = 0x2003, DW_AT_MIPS_epilog_begin = 0x2004, DW_AT_MIPS_loop_unroll_factor = 0x2005, DW_AT_MIPS_software_pipeline_depth = 0x2006, DW_AT_MIPS_linkage_name = 0x2007, DW_AT_MIPS_stride = 0x2008, DW_AT_MIPS_abstract_name = 0x2009, DW_AT_MIPS_clone_origin = 0x200a, DW_AT_MIPS_has_inlines = 0x200b, /* HP extensions. */ DW_AT_HP_block_index = 0x2000, DW_AT_HP_unmodifiable = 0x2001, /* Same as DW_AT_MIPS_fde. */ DW_AT_HP_actuals_stmt_list = 0x2010, DW_AT_HP_proc_per_section = 0x2011, DW_AT_HP_raw_data_ptr = 0x2012, DW_AT_HP_pass_by_reference = 0x2013, DW_AT_HP_opt_level = 0x2014, DW_AT_HP_prof_version_id = 0x2015, DW_AT_HP_opt_flags = 0x2016, DW_AT_HP_cold_region_low_pc = 0x2017, DW_AT_HP_cold_region_high_pc = 0x2018, DW_AT_HP_all_variables_modifiable = 0x2019, DW_AT_HP_linkage_name = 0x201a, DW_AT_HP_prof_flags = 0x201b, /* In comp unit of procs_info for -g. */ /* GNU extensions. */ DW_AT_sf_names = 0x2101, DW_AT_src_info = 0x2102, DW_AT_mac_info = 0x2103, DW_AT_src_coords = 0x2104, DW_AT_body_begin = 0x2105, DW_AT_body_end = 0x2106, DW_AT_GNU_vector = 0x2107, /* VMS extensions. */ DW_AT_VMS_rtnbeg_pd_address = 0x2201, /* UPC extension. */ DW_AT_upc_threads_scaled = 0x3210, /* PGI (STMicroelectronics) extensions. */ DW_AT_PGI_lbase = 0x3a00, DW_AT_PGI_soffset = 0x3a01, /* APPLE LOCAL begin radar 5811943 - Fix type of pointers to blocks */ DW_AT_PGI_lstride = 0x3a02, /* APPLE LOCAL begin radar 6386976 */ DW_AT_APPLE_block = 0x3fe4, /* APPLE LOCAL end radar 5811943 - Fix type of pointers to blocks */ DW_AT_APPLE_major_runtime_vers = 0x3fe5, DW_AT_APPLE_runtime_class = 0x3fe6 /* APPLE LOCAL end radar 6386976 */ }; #define DW_AT_lo_user 0x2000 /* Implementation-defined range start. */ #define DW_AT_hi_user 0x3ff0 /* Implementation-defined range end. */ /* Location atom names and codes. */ enum dwarf_location_atom { DW_OP_addr = 0x03, DW_OP_deref = 0x06, DW_OP_const1u = 0x08, DW_OP_const1s = 0x09, DW_OP_const2u = 0x0a, DW_OP_const2s = 0x0b, DW_OP_const4u = 0x0c, DW_OP_const4s = 0x0d, DW_OP_const8u = 0x0e, DW_OP_const8s = 0x0f, DW_OP_constu = 0x10, DW_OP_consts = 0x11, DW_OP_dup = 0x12, DW_OP_drop = 0x13, DW_OP_over = 0x14, DW_OP_pick = 0x15, DW_OP_swap = 0x16, DW_OP_rot = 0x17, DW_OP_xderef = 0x18, DW_OP_abs = 0x19, DW_OP_and = 0x1a, DW_OP_div = 0x1b, DW_OP_minus = 0x1c, DW_OP_mod = 0x1d, DW_OP_mul = 0x1e, DW_OP_neg = 0x1f, DW_OP_not = 0x20, DW_OP_or = 0x21, DW_OP_plus = 0x22, DW_OP_plus_uconst = 0x23, DW_OP_shl = 0x24, DW_OP_shr = 0x25, DW_OP_shra = 0x26, DW_OP_xor = 0x27, DW_OP_bra = 0x28, DW_OP_eq = 0x29, DW_OP_ge = 0x2a, DW_OP_gt = 0x2b, DW_OP_le = 0x2c, DW_OP_lt = 0x2d, DW_OP_ne = 0x2e, DW_OP_skip = 0x2f, DW_OP_lit0 = 0x30, DW_OP_lit1 = 0x31, DW_OP_lit2 = 0x32, DW_OP_lit3 = 0x33, DW_OP_lit4 = 0x34, DW_OP_lit5 = 0x35, DW_OP_lit6 = 0x36, DW_OP_lit7 = 0x37, DW_OP_lit8 = 0x38, DW_OP_lit9 = 0x39, DW_OP_lit10 = 0x3a, DW_OP_lit11 = 0x3b, DW_OP_lit12 = 0x3c, DW_OP_lit13 = 0x3d, DW_OP_lit14 = 0x3e, DW_OP_lit15 = 0x3f, DW_OP_lit16 = 0x40, DW_OP_lit17 = 0x41, DW_OP_lit18 = 0x42, DW_OP_lit19 = 0x43, DW_OP_lit20 = 0x44, DW_OP_lit21 = 0x45, DW_OP_lit22 = 0x46, DW_OP_lit23 = 0x47, DW_OP_lit24 = 0x48, DW_OP_lit25 = 0x49, DW_OP_lit26 = 0x4a, DW_OP_lit27 = 0x4b, DW_OP_lit28 = 0x4c, DW_OP_lit29 = 0x4d, DW_OP_lit30 = 0x4e, DW_OP_lit31 = 0x4f, DW_OP_reg0 = 0x50, DW_OP_reg1 = 0x51, DW_OP_reg2 = 0x52, DW_OP_reg3 = 0x53, DW_OP_reg4 = 0x54, DW_OP_reg5 = 0x55, DW_OP_reg6 = 0x56, DW_OP_reg7 = 0x57, DW_OP_reg8 = 0x58, DW_OP_reg9 = 0x59, DW_OP_reg10 = 0x5a, DW_OP_reg11 = 0x5b, DW_OP_reg12 = 0x5c, DW_OP_reg13 = 0x5d, DW_OP_reg14 = 0x5e, DW_OP_reg15 = 0x5f, DW_OP_reg16 = 0x60, DW_OP_reg17 = 0x61, DW_OP_reg18 = 0x62, DW_OP_reg19 = 0x63, DW_OP_reg20 = 0x64, DW_OP_reg21 = 0x65, DW_OP_reg22 = 0x66, DW_OP_reg23 = 0x67, DW_OP_reg24 = 0x68, DW_OP_reg25 = 0x69, DW_OP_reg26 = 0x6a, DW_OP_reg27 = 0x6b, DW_OP_reg28 = 0x6c, DW_OP_reg29 = 0x6d, DW_OP_reg30 = 0x6e, DW_OP_reg31 = 0x6f, DW_OP_breg0 = 0x70, DW_OP_breg1 = 0x71, DW_OP_breg2 = 0x72, DW_OP_breg3 = 0x73, DW_OP_breg4 = 0x74, DW_OP_breg5 = 0x75, DW_OP_breg6 = 0x76, DW_OP_breg7 = 0x77, DW_OP_breg8 = 0x78, DW_OP_breg9 = 0x79, DW_OP_breg10 = 0x7a, DW_OP_breg11 = 0x7b, DW_OP_breg12 = 0x7c, DW_OP_breg13 = 0x7d, DW_OP_breg14 = 0x7e, DW_OP_breg15 = 0x7f, DW_OP_breg16 = 0x80, DW_OP_breg17 = 0x81, DW_OP_breg18 = 0x82, DW_OP_breg19 = 0x83, DW_OP_breg20 = 0x84, DW_OP_breg21 = 0x85, DW_OP_breg22 = 0x86, DW_OP_breg23 = 0x87, DW_OP_breg24 = 0x88, DW_OP_breg25 = 0x89, DW_OP_breg26 = 0x8a, DW_OP_breg27 = 0x8b, DW_OP_breg28 = 0x8c, DW_OP_breg29 = 0x8d, DW_OP_breg30 = 0x8e, DW_OP_breg31 = 0x8f, DW_OP_regx = 0x90, DW_OP_fbreg = 0x91, DW_OP_bregx = 0x92, DW_OP_piece = 0x93, DW_OP_deref_size = 0x94, DW_OP_xderef_size = 0x95, DW_OP_nop = 0x96, /* DWARF 3 extensions. */ DW_OP_push_object_address = 0x97, DW_OP_call2 = 0x98, DW_OP_call4 = 0x99, DW_OP_call_ref = 0x9a, DW_OP_form_tls_address = 0x9b, DW_OP_call_frame_cfa = 0x9c, DW_OP_bit_piece = 0x9d, /* GNU extensions. */ DW_OP_GNU_push_tls_address = 0xe0, + DW_OP_GNU_uninit = 0xf0, /* HP extensions. */ DW_OP_HP_unknown = 0xe0, /* Ouch, the same as GNU_push_tls_address. */ DW_OP_HP_is_value = 0xe1, DW_OP_HP_fltconst4 = 0xe2, DW_OP_HP_fltconst8 = 0xe3, DW_OP_HP_mod_range = 0xe4, DW_OP_HP_unmod_range = 0xe5, DW_OP_HP_tls = 0xe6 }; #define DW_OP_lo_user 0xe0 /* Implementation-defined range start. */ #define DW_OP_hi_user 0xff /* Implementation-defined range end. */ /* Type encodings. */ enum dwarf_type { DW_ATE_void = 0x0, DW_ATE_address = 0x1, DW_ATE_boolean = 0x2, DW_ATE_complex_float = 0x3, DW_ATE_float = 0x4, DW_ATE_signed = 0x5, DW_ATE_signed_char = 0x6, DW_ATE_unsigned = 0x7, DW_ATE_unsigned_char = 0x8, /* DWARF 3. */ DW_ATE_imaginary_float = 0x9, DW_ATE_packed_decimal = 0xa, DW_ATE_numeric_string = 0xb, DW_ATE_edited = 0xc, DW_ATE_signed_fixed = 0xd, DW_ATE_unsigned_fixed = 0xe, DW_ATE_decimal_float = 0xf, /* HP extensions. */ DW_ATE_HP_float80 = 0x80, /* Floating-point (80 bit). */ DW_ATE_HP_complex_float80 = 0x81, /* Complex floating-point (80 bit). */ DW_ATE_HP_float128 = 0x82, /* Floating-point (128 bit). */ DW_ATE_HP_complex_float128 = 0x83, /* Complex floating-point (128 bit). */ DW_ATE_HP_floathpintel = 0x84, /* Floating-point (82 bit IA64). */ DW_ATE_HP_imaginary_float80 = 0x85, DW_ATE_HP_imaginary_float128 = 0x86 }; #define DW_ATE_lo_user 0x80 #define DW_ATE_hi_user 0xff /* Decimal sign encodings. */ enum dwarf_decimal_sign_encoding { /* DWARF 3. */ DW_DS_unsigned = 0x01, DW_DS_leading_overpunch = 0x02, DW_DS_trailing_overpunch = 0x03, DW_DS_leading_separate = 0x04, DW_DS_trailing_separate = 0x05 }; /* Endianity encodings. */ enum dwarf_endianity_encoding { /* DWARF 3. */ DW_END_default = 0x00, DW_END_big = 0x01, DW_END_little = 0x02 }; #define DW_END_lo_user 0x40 #define DW_END_hi_user 0xff /* Array ordering names and codes. */ enum dwarf_array_dim_ordering { DW_ORD_row_major = 0, DW_ORD_col_major = 1 }; /* Access attribute. */ enum dwarf_access_attribute { DW_ACCESS_public = 1, DW_ACCESS_protected = 2, DW_ACCESS_private = 3 }; /* Visibility. */ enum dwarf_visibility_attribute { DW_VIS_local = 1, DW_VIS_exported = 2, DW_VIS_qualified = 3 }; /* Virtuality. */ enum dwarf_virtuality_attribute { DW_VIRTUALITY_none = 0, DW_VIRTUALITY_virtual = 1, DW_VIRTUALITY_pure_virtual = 2 }; /* Case sensitivity. */ enum dwarf_id_case { DW_ID_case_sensitive = 0, DW_ID_up_case = 1, DW_ID_down_case = 2, DW_ID_case_insensitive = 3 }; /* Calling convention. */ enum dwarf_calling_convention { DW_CC_normal = 0x1, DW_CC_program = 0x2, DW_CC_nocall = 0x3, DW_CC_GNU_renesas_sh = 0x40 }; #define DW_CC_lo_user 0x40 #define DW_CC_hi_user 0xff /* Inline attribute. */ enum dwarf_inline_attribute { DW_INL_not_inlined = 0, DW_INL_inlined = 1, DW_INL_declared_not_inlined = 2, DW_INL_declared_inlined = 3 }; /* Discriminant lists. */ enum dwarf_discrim_list { DW_DSC_label = 0, DW_DSC_range = 1 }; /* Line number opcodes. */ enum dwarf_line_number_ops { DW_LNS_extended_op = 0, DW_LNS_copy = 1, DW_LNS_advance_pc = 2, DW_LNS_advance_line = 3, DW_LNS_set_file = 4, DW_LNS_set_column = 5, DW_LNS_negate_stmt = 6, DW_LNS_set_basic_block = 7, DW_LNS_const_add_pc = 8, DW_LNS_fixed_advance_pc = 9, /* DWARF 3. */ DW_LNS_set_prologue_end = 10, DW_LNS_set_epilogue_begin = 11, DW_LNS_set_isa = 12 }; /* Line number extended opcodes. */ enum dwarf_line_number_x_ops { DW_LNE_end_sequence = 1, DW_LNE_set_address = 2, DW_LNE_define_file = 3, /* HP extensions. */ DW_LNE_HP_negate_is_UV_update = 0x11, DW_LNE_HP_push_context = 0x12, DW_LNE_HP_pop_context = 0x13, DW_LNE_HP_set_file_line_column = 0x14, DW_LNE_HP_set_routine_name = 0x15, DW_LNE_HP_set_sequence = 0x16, DW_LNE_HP_negate_post_semantics = 0x17, DW_LNE_HP_negate_function_exit = 0x18, DW_LNE_HP_negate_front_end_logical = 0x19, DW_LNE_HP_define_proc = 0x20 }; #define DW_LNE_lo_user 0x80 #define DW_LNE_hi_user 0xff /* Call frame information. */ enum dwarf_call_frame_info { DW_CFA_advance_loc = 0x40, DW_CFA_offset = 0x80, DW_CFA_restore = 0xc0, DW_CFA_nop = 0x00, DW_CFA_set_loc = 0x01, DW_CFA_advance_loc1 = 0x02, DW_CFA_advance_loc2 = 0x03, DW_CFA_advance_loc4 = 0x04, DW_CFA_offset_extended = 0x05, DW_CFA_restore_extended = 0x06, DW_CFA_undefined = 0x07, DW_CFA_same_value = 0x08, DW_CFA_register = 0x09, DW_CFA_remember_state = 0x0a, DW_CFA_restore_state = 0x0b, DW_CFA_def_cfa = 0x0c, DW_CFA_def_cfa_register = 0x0d, DW_CFA_def_cfa_offset = 0x0e, /* DWARF 3. */ DW_CFA_def_cfa_expression = 0x0f, DW_CFA_expression = 0x10, DW_CFA_offset_extended_sf = 0x11, DW_CFA_def_cfa_sf = 0x12, DW_CFA_def_cfa_offset_sf = 0x13, DW_CFA_val_offset = 0x14, DW_CFA_val_offset_sf = 0x15, DW_CFA_val_expression = 0x16, /* SGI/MIPS specific. */ DW_CFA_MIPS_advance_loc8 = 0x1d, /* GNU extensions. */ DW_CFA_GNU_window_save = 0x2d, DW_CFA_GNU_args_size = 0x2e, DW_CFA_GNU_negative_offset_extended = 0x2f }; #define DW_CIE_ID 0xffffffff #define DW64_CIE_ID 0xffffffffffffffffULL #define DW_CIE_VERSION 1 #define DW_CFA_extended 0 #define DW_CFA_lo_user 0x1c #define DW_CFA_hi_user 0x3f #define DW_CHILDREN_no 0x00 #define DW_CHILDREN_yes 0x01 #define DW_ADDR_none 0 /* Source language names and codes. */ enum dwarf_source_language { DW_LANG_C89 = 0x0001, DW_LANG_C = 0x0002, DW_LANG_Ada83 = 0x0003, DW_LANG_C_plus_plus = 0x0004, DW_LANG_Cobol74 = 0x0005, DW_LANG_Cobol85 = 0x0006, DW_LANG_Fortran77 = 0x0007, DW_LANG_Fortran90 = 0x0008, DW_LANG_Pascal83 = 0x0009, DW_LANG_Modula2 = 0x000a, /* DWARF 3. */ DW_LANG_Java = 0x000b, DW_LANG_C99 = 0x000c, DW_LANG_Ada95 = 0x000d, DW_LANG_Fortran95 = 0x000e, DW_LANG_PLI = 0x000f, DW_LANG_ObjC = 0x0010, DW_LANG_ObjC_plus_plus = 0x0011, DW_LANG_UPC = 0x0012, DW_LANG_D = 0x0013, /* MIPS. */ DW_LANG_Mips_Assembler = 0x8001, /* UPC. */ DW_LANG_Upc = 0x8765 }; #define DW_LANG_lo_user 0x8000 /* Implementation-defined range start. */ #define DW_LANG_hi_user 0xffff /* Implementation-defined range start. */ /* Names and codes for macro information. */ enum dwarf_macinfo_record_type { DW_MACINFO_define = 1, DW_MACINFO_undef = 2, DW_MACINFO_start_file = 3, DW_MACINFO_end_file = 4, DW_MACINFO_vendor_ext = 255 }; /* @@@ For use with GNU frame unwind information. */ #define DW_EH_PE_absptr 0x00 #define DW_EH_PE_omit 0xff #define DW_EH_PE_uleb128 0x01 #define DW_EH_PE_udata2 0x02 #define DW_EH_PE_udata4 0x03 #define DW_EH_PE_udata8 0x04 #define DW_EH_PE_sleb128 0x09 #define DW_EH_PE_sdata2 0x0A #define DW_EH_PE_sdata4 0x0B #define DW_EH_PE_sdata8 0x0C #define DW_EH_PE_signed 0x08 #define DW_EH_PE_pcrel 0x10 #define DW_EH_PE_textrel 0x20 #define DW_EH_PE_datarel 0x30 #define DW_EH_PE_funcrel 0x40 #define DW_EH_PE_aligned 0x50 #define DW_EH_PE_indirect 0x80 #endif /* dwarf2.h */ Index: projects/ci20_mips/contrib/gcc =================================================================== --- projects/ci20_mips/contrib/gcc (revision 283030) +++ projects/ci20_mips/contrib/gcc (revision 283031) Property changes on: projects/ci20_mips/contrib/gcc ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/contrib/gcc:r282737-283030 Index: projects/ci20_mips/contrib/gdb/gdb/c-valprint.c =================================================================== --- projects/ci20_mips/contrib/gdb/gdb/c-valprint.c (revision 283030) +++ projects/ci20_mips/contrib/gdb/gdb/c-valprint.c (revision 283031) @@ -1,594 +1,598 @@ /* Support for printing C values for GDB, the GNU debugger. Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "defs.h" #include "gdb_string.h" #include "symtab.h" #include "gdbtypes.h" #include "expression.h" #include "value.h" #include "valprint.h" #include "language.h" #include "c-lang.h" #include "cp-abi.h" #include "target.h" /* Print function pointer with inferior address ADDRESS onto stdio stream STREAM. */ static void print_function_pointer_address (CORE_ADDR address, struct ui_file *stream) { CORE_ADDR func_addr = gdbarch_convert_from_func_ptr_addr (current_gdbarch, address, ¤t_target); /* If the function pointer is represented by a description, print the address of the description. */ if (addressprint && func_addr != address) { fputs_filtered ("@", stream); print_address_numeric (address, 1, stream); fputs_filtered (": ", stream); } print_address_demangle (func_addr, stream, demangle); } /* Print data of type TYPE located at VALADDR (within GDB), which came from the inferior at address ADDRESS, onto stdio stream STREAM according to FORMAT (a letter or 0 for natural format). The data at VALADDR is in target byte order. If the data are a string pointer, returns the number of string characters printed. If DEREF_REF is nonzero, then dereference references, otherwise just print them like pointers. The PRETTY parameter controls prettyprinting. */ int c_val_print (struct type *type, char *valaddr, int embedded_offset, CORE_ADDR address, struct ui_file *stream, int format, int deref_ref, int recurse, enum val_prettyprint pretty) { unsigned int i = 0; /* Number of characters printed */ unsigned len; struct type *elttype; unsigned eltlen; LONGEST val; CORE_ADDR addr; CHECK_TYPEDEF (type); switch (TYPE_CODE (type)) { case TYPE_CODE_ARRAY: elttype = check_typedef (TYPE_TARGET_TYPE (type)); if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0) { eltlen = TYPE_LENGTH (elttype); len = TYPE_LENGTH (type) / eltlen; if (prettyprint_arrays) { print_spaces_filtered (2 + 2 * recurse, stream); } /* For an array of chars, print with string syntax. */ if (eltlen == 1 && ((TYPE_CODE (elttype) == TYPE_CODE_INT) || ((current_language->la_language == language_m2) && (TYPE_CODE (elttype) == TYPE_CODE_CHAR))) && (format == 0 || format == 's')) { /* If requested, look for the first null char and only print elements up to it. */ if (stop_print_at_null) { unsigned int temp_len; /* Look for a NULL char. */ for (temp_len = 0; (valaddr + embedded_offset)[temp_len] && temp_len < len && temp_len < print_max; temp_len++); len = temp_len; } LA_PRINT_STRING (stream, valaddr + embedded_offset, len, eltlen, 0); i = len; } else { fprintf_filtered (stream, "{"); /* If this is a virtual function table, print the 0th entry specially, and the rest of the members normally. */ if (cp_is_vtbl_ptr_type (elttype)) { i = 1; fprintf_filtered (stream, "%d vtable entries", len - 1); } else { i = 0; } val_print_array_elements (type, valaddr + embedded_offset, address, stream, format, deref_ref, recurse, pretty, i); fprintf_filtered (stream, "}"); } break; } /* Array of unspecified length: treat like pointer to first elt. */ addr = address; goto print_unpacked_pointer; case TYPE_CODE_PTR: if (format && format != 's') { print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream); break; } if (vtblprint && cp_is_vtbl_ptr_type (type)) { /* Print the unmangled name if desired. */ /* Print vtable entry - we only get here if we ARE using -fvtable_thunks. (Otherwise, look under TYPE_CODE_STRUCT.) */ CORE_ADDR addr = extract_typed_address (valaddr + embedded_offset, type); print_function_pointer_address (addr, stream); break; } elttype = check_typedef (TYPE_TARGET_TYPE (type)); if (TYPE_CODE (elttype) == TYPE_CODE_METHOD) { cp_print_class_method (valaddr + embedded_offset, type, stream); } else if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER) { cp_print_class_member (valaddr + embedded_offset, TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)), stream, "&"); } else { addr = unpack_pointer (type, valaddr + embedded_offset); print_unpacked_pointer: if (TYPE_CODE (elttype) == TYPE_CODE_FUNC) { /* Try to print what function it points to. */ print_function_pointer_address (addr, stream); /* Return value is irrelevant except for string pointers. */ return (0); } if (addressprint && format != 's') { print_address_numeric (addr, 1, stream); } /* For a pointer to char or unsigned char, also print the string pointed to, unless pointer is null. */ /* FIXME: need to handle wchar_t here... */ if (TYPE_LENGTH (elttype) == 1 && TYPE_CODE (elttype) == TYPE_CODE_INT && (format == 0 || format == 's') && addr != 0) { i = val_print_string (addr, -1, TYPE_LENGTH (elttype), stream); } else if (cp_is_vtbl_member (type)) { /* print vtbl's nicely */ CORE_ADDR vt_address = unpack_pointer (type, valaddr + embedded_offset); struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (vt_address); if ((msymbol != NULL) && (vt_address == SYMBOL_VALUE_ADDRESS (msymbol))) { fputs_filtered (" <", stream); fputs_filtered (SYMBOL_PRINT_NAME (msymbol), stream); fputs_filtered (">", stream); } if (vt_address && vtblprint) { struct value *vt_val; struct symbol *wsym = (struct symbol *) NULL; struct type *wtype; struct block *block = (struct block *) NULL; int is_this_fld; if (msymbol != NULL) wsym = lookup_symbol (DEPRECATED_SYMBOL_NAME (msymbol), block, VAR_DOMAIN, &is_this_fld, NULL); if (wsym) { wtype = SYMBOL_TYPE (wsym); } else { wtype = TYPE_TARGET_TYPE (type); } vt_val = value_at (wtype, vt_address, NULL); common_val_print (vt_val, stream, format, deref_ref, recurse + 1, pretty); if (pretty) { fprintf_filtered (stream, "\n"); print_spaces_filtered (2 + 2 * recurse, stream); } } } /* Return number of characters printed, including the terminating '\0' if we reached the end. val_print_string takes care including the terminating '\0' if necessary. */ return i; } break; case TYPE_CODE_MEMBER: error ("not implemented: member type in c_val_print"); break; case TYPE_CODE_REF: elttype = check_typedef (TYPE_TARGET_TYPE (type)); if (TYPE_CODE (elttype) == TYPE_CODE_MEMBER) { cp_print_class_member (valaddr + embedded_offset, TYPE_DOMAIN_TYPE (elttype), stream, ""); break; } if (addressprint) { CORE_ADDR addr = extract_typed_address (valaddr + embedded_offset, type); fprintf_filtered (stream, "@"); print_address_numeric (addr, 1, stream); if (deref_ref) fputs_filtered (": ", stream); } /* De-reference the reference. */ if (deref_ref) { if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF) { struct value *deref_val = value_at (TYPE_TARGET_TYPE (type), unpack_pointer (lookup_pointer_type (builtin_type_void), valaddr + embedded_offset), NULL); common_val_print (deref_val, stream, format, deref_ref, recurse, pretty); } else fputs_filtered ("???", stream); } break; case TYPE_CODE_UNION: if (recurse && !unionprint) { fprintf_filtered (stream, "{...}"); break; } /* Fall through. */ case TYPE_CODE_STRUCT: /*FIXME: Abstract this away */ if (vtblprint && cp_is_vtbl_ptr_type (type)) { /* Print the unmangled name if desired. */ /* Print vtable entry - we only get here if NOT using -fvtable_thunks. (Otherwise, look under TYPE_CODE_PTR.) */ int offset = (embedded_offset + TYPE_FIELD_BITPOS (type, VTBL_FNADDR_OFFSET) / 8); struct type *field_type = TYPE_FIELD_TYPE (type, VTBL_FNADDR_OFFSET); CORE_ADDR addr = extract_typed_address (valaddr + offset, field_type); print_function_pointer_address (addr, stream); } else cp_print_value_fields (type, type, valaddr, embedded_offset, address, stream, format, recurse, pretty, NULL, 0); break; case TYPE_CODE_ENUM: if (format) { print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream); break; } len = TYPE_NFIELDS (type); val = unpack_long (type, valaddr + embedded_offset); for (i = 0; i < len; i++) { QUIT; if (val == TYPE_FIELD_BITPOS (type, i)) { break; } } if (i < len) { fputs_filtered (TYPE_FIELD_NAME (type, i), stream); } else { print_longest (stream, 'd', 0, val); } break; case TYPE_CODE_FUNC: if (format) { print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream); break; } /* FIXME, we should consider, at least for ANSI C language, eliminating the distinction made between FUNCs and POINTERs to FUNCs. */ fprintf_filtered (stream, "{"); type_print (type, "", stream, -1); fprintf_filtered (stream, "} "); /* Try to print what function it points to, and its address. */ print_address_demangle (address, stream, demangle); break; case TYPE_CODE_BOOL: format = format ? format : output_format; if (format) print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream); else { val = unpack_long (type, valaddr + embedded_offset); if (val == 0) fputs_filtered ("false", stream); else if (val == 1) fputs_filtered ("true", stream); else print_longest (stream, 'd', 0, val); } break; case TYPE_CODE_RANGE: /* FIXME: create_range_type does not set the unsigned bit in a range type (I think it probably should copy it from the target type), so we won't print values which are too large to fit in a signed integer correctly. */ /* FIXME: Doesn't handle ranges of enums correctly. (Can't just print with the target type, though, because the size of our type and the target type might differ). */ /* FALLTHROUGH */ case TYPE_CODE_INT: format = format ? format : output_format; if (format) { print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream); } else { val_print_type_code_int (type, valaddr + embedded_offset, stream); /* C and C++ has no single byte int type, char is used instead. Since we don't know whether the value is really intended to be used as an integer or a character, print the character equivalent as well. */ if (TYPE_LENGTH (type) == 1) { fputs_filtered (" ", stream); LA_PRINT_CHAR ((unsigned char) unpack_long (type, valaddr + embedded_offset), stream); } } break; case TYPE_CODE_CHAR: format = format ? format : output_format; if (format) { print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream); } else { val = unpack_long (type, valaddr + embedded_offset); if (TYPE_UNSIGNED (type)) fprintf_filtered (stream, "%u", (unsigned int) val); else fprintf_filtered (stream, "%d", (int) val); fputs_filtered (" ", stream); LA_PRINT_CHAR ((unsigned char) val, stream); } break; case TYPE_CODE_FLT: if (format) { print_scalar_formatted (valaddr + embedded_offset, type, format, 0, stream); } else { print_floating (valaddr + embedded_offset, type, stream); } break; case TYPE_CODE_METHOD: { struct value *v = value_at (type, address, NULL); cp_print_class_method (VALUE_CONTENTS (value_addr (v)), lookup_pointer_type (type), stream); break; } case TYPE_CODE_VOID: fprintf_filtered (stream, "void"); break; case TYPE_CODE_ERROR: fprintf_filtered (stream, ""); break; case TYPE_CODE_UNDEF: /* This happens (without TYPE_FLAG_STUB set) on systems which don't use dbx xrefs (NO_DBX_XREFS in gcc) if a file has a "struct foo *bar" and no complete type for struct foo in that file. */ fprintf_filtered (stream, ""); break; case TYPE_CODE_COMPLEX: if (format) print_scalar_formatted (valaddr + embedded_offset, TYPE_TARGET_TYPE (type), format, 0, stream); else print_floating (valaddr + embedded_offset, TYPE_TARGET_TYPE (type), stream); fprintf_filtered (stream, " + "); if (format) print_scalar_formatted (valaddr + embedded_offset + TYPE_LENGTH (TYPE_TARGET_TYPE (type)), TYPE_TARGET_TYPE (type), format, 0, stream); else print_floating (valaddr + embedded_offset + TYPE_LENGTH (TYPE_TARGET_TYPE (type)), TYPE_TARGET_TYPE (type), stream); fprintf_filtered (stream, " * I"); break; default: error ("Invalid C/C++ type code %d in symbol table.", TYPE_CODE (type)); } gdb_flush (stream); return (0); } int c_value_print (struct value *val, struct ui_file *stream, int format, enum val_prettyprint pretty) { struct type *type = VALUE_TYPE (val); struct type *real_type; int full, top, using_enc; /* If it is a pointer, indicate what it points to. Print type also if it is a reference. C++: if it is a member pointer, we will take care of that when we print it. */ if (TYPE_CODE (type) == TYPE_CODE_PTR || TYPE_CODE (type) == TYPE_CODE_REF) { /* Hack: remove (char *) for char strings. Their type is indicated by the quoted string anyway. */ if (TYPE_CODE (type) == TYPE_CODE_PTR && TYPE_NAME (type) == NULL && TYPE_NAME (TYPE_TARGET_TYPE (type)) != NULL && strcmp (TYPE_NAME (TYPE_TARGET_TYPE (type)), "char") == 0) { /* Print nothing */ } else if (objectprint && (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CLASS)) { if (TYPE_CODE(type) == TYPE_CODE_REF) { /* Copy value, change to pointer, so we don't get an * error about a non-pointer type in value_rtti_target_type */ struct value *temparg; temparg=value_copy(val); VALUE_TYPE (temparg) = lookup_pointer_type(TYPE_TARGET_TYPE(type)); val=temparg; } /* Pointer to class, check real type of object */ fprintf_filtered (stream, "("); real_type = value_rtti_target_type (val, &full, &top, &using_enc); if (real_type) { /* RTTI entry found */ if (TYPE_CODE (type) == TYPE_CODE_PTR) { /* create a pointer type pointing to the real type */ type = lookup_pointer_type (real_type); } else { /* create a reference type referencing the real type */ type = lookup_reference_type (real_type); } /* JYG: Need to adjust pointer value. */ val->aligner.contents[0] -= top; /* Note: When we look up RTTI entries, we don't get any information on const or volatile attributes */ } type_print (type, "", stream, -1); fprintf_filtered (stream, ") "); } else { /* normal case */ fprintf_filtered (stream, "("); type_print (type, "", stream, -1); fprintf_filtered (stream, ") "); } } + + if (!value_initialized (val)) + fprintf_filtered (stream, " [uninitialized] "); + if (objectprint && (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_CLASS)) { /* Attempt to determine real type of object */ real_type = value_rtti_type (val, &full, &top, &using_enc); if (real_type) { /* We have RTTI information, so use it */ val = value_full_object (val, real_type, full, top, using_enc); fprintf_filtered (stream, "(%s%s) ", TYPE_NAME (real_type), full ? "" : " [incomplete object]"); /* Print out object: enclosing type is same as real_type if full */ return val_print (VALUE_ENCLOSING_TYPE (val), VALUE_CONTENTS_ALL (val), 0, VALUE_ADDRESS (val), stream, format, 1, 0, pretty); /* Note: When we look up RTTI entries, we don't get any information on const or volatile attributes */ } else if (type != VALUE_ENCLOSING_TYPE (val)) { /* No RTTI information, so let's do our best */ fprintf_filtered (stream, "(%s ?) ", TYPE_NAME (VALUE_ENCLOSING_TYPE (val))); return val_print (VALUE_ENCLOSING_TYPE (val), VALUE_CONTENTS_ALL (val), 0, VALUE_ADDRESS (val), stream, format, 1, 0, pretty); } /* Otherwise, we end up at the return outside this "if" */ } return val_print (type, VALUE_CONTENTS_ALL (val), VALUE_EMBEDDED_OFFSET (val), VALUE_ADDRESS (val) + VALUE_OFFSET (val), stream, format, 1, 0, pretty); } Index: projects/ci20_mips/contrib/gdb/gdb/dwarf2expr.c =================================================================== --- projects/ci20_mips/contrib/gdb/gdb/dwarf2expr.c (revision 283030) +++ projects/ci20_mips/contrib/gdb/gdb/dwarf2expr.c (revision 283031) @@ -1,672 +1,726 @@ /* Dwarf2 Expression Evaluator Copyright 2001, 2002, 2003 Free Software Foundation, Inc. Contributed by Daniel Berlin (dan@dberlin.org) This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "defs.h" #include "symtab.h" #include "gdbtypes.h" #include "value.h" #include "gdbcore.h" #include "elf/dwarf2.h" #include "dwarf2expr.h" /* Local prototypes. */ static void execute_stack_op (struct dwarf_expr_context *, unsigned char *, unsigned char *); /* Create a new context for the expression evaluator. */ struct dwarf_expr_context * new_dwarf_expr_context (void) { struct dwarf_expr_context *retval; retval = xcalloc (1, sizeof (struct dwarf_expr_context)); retval->stack_len = 0; retval->stack_allocated = 10; retval->stack = xmalloc (retval->stack_allocated * sizeof (CORE_ADDR)); + retval->num_pieces = 0; + retval->pieces = 0; return retval; } /* Release the memory allocated to CTX. */ void free_dwarf_expr_context (struct dwarf_expr_context *ctx) { xfree (ctx->stack); + xfree (ctx->pieces); xfree (ctx); } /* Expand the memory allocated to CTX's stack to contain at least NEED more elements than are currently used. */ static void dwarf_expr_grow_stack (struct dwarf_expr_context *ctx, size_t need) { if (ctx->stack_len + need > ctx->stack_allocated) { size_t newlen = ctx->stack_len + need + 10; ctx->stack = xrealloc (ctx->stack, newlen * sizeof (CORE_ADDR)); ctx->stack_allocated = newlen; } } /* Push VALUE onto CTX's stack. */ void dwarf_expr_push (struct dwarf_expr_context *ctx, CORE_ADDR value) { dwarf_expr_grow_stack (ctx, 1); ctx->stack[ctx->stack_len++] = value; } /* Pop the top item off of CTX's stack. */ void dwarf_expr_pop (struct dwarf_expr_context *ctx) { if (ctx->stack_len <= 0) error ("dwarf expression stack underflow"); ctx->stack_len--; } /* Retrieve the N'th item on CTX's stack. */ CORE_ADDR dwarf_expr_fetch (struct dwarf_expr_context *ctx, int n) { if (ctx->stack_len < n) error ("Asked for position %d of stack, stack only has %d elements on it\n", n, ctx->stack_len); return ctx->stack[ctx->stack_len - (1 + n)]; } +/* Add a new piece to CTX's piece list. */ +static void +add_piece (struct dwarf_expr_context *ctx, + int in_reg, CORE_ADDR value, ULONGEST size) +{ + struct dwarf_expr_piece *p; + + ctx->num_pieces++; + + if (ctx->pieces) + ctx->pieces = xrealloc (ctx->pieces, + (ctx->num_pieces + * sizeof (struct dwarf_expr_piece))); + else + ctx->pieces = xmalloc (ctx->num_pieces + * sizeof (struct dwarf_expr_piece)); + + p = &ctx->pieces[ctx->num_pieces - 1]; + p->in_reg = in_reg; + p->value = value; + p->size = size; +} + /* Evaluate the expression at ADDR (LEN bytes long) using the context CTX. */ void dwarf_expr_eval (struct dwarf_expr_context *ctx, unsigned char *addr, size_t len) { execute_stack_op (ctx, addr, addr + len); } /* Decode the unsigned LEB128 constant at BUF into the variable pointed to by R, and return the new value of BUF. Verify that it doesn't extend past BUF_END. */ unsigned char * read_uleb128 (unsigned char *buf, unsigned char *buf_end, ULONGEST * r) { unsigned shift = 0; ULONGEST result = 0; unsigned char byte; while (1) { if (buf >= buf_end) error ("read_uleb128: Corrupted DWARF expression."); byte = *buf++; result |= (byte & 0x7f) << shift; if ((byte & 0x80) == 0) break; shift += 7; } *r = result; return buf; } /* Decode the signed LEB128 constant at BUF into the variable pointed to by R, and return the new value of BUF. Verify that it doesn't extend past BUF_END. */ unsigned char * read_sleb128 (unsigned char *buf, unsigned char *buf_end, LONGEST * r) { unsigned shift = 0; LONGEST result = 0; unsigned char byte; while (1) { if (buf >= buf_end) error ("read_sleb128: Corrupted DWARF expression."); byte = *buf++; result |= (byte & 0x7f) << shift; shift += 7; if ((byte & 0x80) == 0) break; } if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0) result |= -(1 << shift); *r = result; return buf; } /* Read an address from BUF, and verify that it doesn't extend past BUF_END. The address is returned, and *BYTES_READ is set to the number of bytes read from BUF. */ CORE_ADDR dwarf2_read_address (unsigned char *buf, unsigned char *buf_end, int *bytes_read) { CORE_ADDR result; if (buf_end - buf < TARGET_ADDR_BIT / TARGET_CHAR_BIT) error ("dwarf2_read_address: Corrupted DWARF expression."); *bytes_read = TARGET_ADDR_BIT / TARGET_CHAR_BIT; /* NOTE: cagney/2003-05-22: This extract is assuming that a DWARF 2 address is always unsigned. That may or may not be true. */ result = extract_unsigned_integer (buf, TARGET_ADDR_BIT / TARGET_CHAR_BIT); return result; } /* Return the type of an address, for unsigned arithmetic. */ static struct type * unsigned_address_type (void) { switch (TARGET_ADDR_BIT / TARGET_CHAR_BIT) { case 2: return builtin_type_uint16; case 4: return builtin_type_uint32; case 8: return builtin_type_uint64; default: internal_error (__FILE__, __LINE__, "Unsupported address size.\n"); } } /* Return the type of an address, for signed arithmetic. */ static struct type * signed_address_type (void) { switch (TARGET_ADDR_BIT / TARGET_CHAR_BIT) { case 2: return builtin_type_int16; case 4: return builtin_type_int32; case 8: return builtin_type_int64; default: internal_error (__FILE__, __LINE__, "Unsupported address size.\n"); } } /* The engine for the expression evaluator. Using the context in CTX, evaluate the expression between OP_PTR and OP_END. */ static void execute_stack_op (struct dwarf_expr_context *ctx, unsigned char *op_ptr, unsigned char *op_end) { ctx->in_reg = 0; + ctx->initialized = 1; /* Default is initialized. */ while (op_ptr < op_end) { enum dwarf_location_atom op = *op_ptr++; CORE_ADDR result; ULONGEST uoffset, reg; LONGEST offset; int bytes_read; switch (op) { case DW_OP_lit0: case DW_OP_lit1: case DW_OP_lit2: case DW_OP_lit3: case DW_OP_lit4: case DW_OP_lit5: case DW_OP_lit6: case DW_OP_lit7: case DW_OP_lit8: case DW_OP_lit9: case DW_OP_lit10: case DW_OP_lit11: case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14: case DW_OP_lit15: case DW_OP_lit16: case DW_OP_lit17: case DW_OP_lit18: case DW_OP_lit19: case DW_OP_lit20: case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23: case DW_OP_lit24: case DW_OP_lit25: case DW_OP_lit26: case DW_OP_lit27: case DW_OP_lit28: case DW_OP_lit29: case DW_OP_lit30: case DW_OP_lit31: result = op - DW_OP_lit0; break; case DW_OP_addr: result = dwarf2_read_address (op_ptr, op_end, &bytes_read); op_ptr += bytes_read; break; case DW_OP_const1u: result = extract_unsigned_integer (op_ptr, 1); op_ptr += 1; break; case DW_OP_const1s: result = extract_signed_integer (op_ptr, 1); op_ptr += 1; break; case DW_OP_const2u: result = extract_unsigned_integer (op_ptr, 2); op_ptr += 2; break; case DW_OP_const2s: result = extract_signed_integer (op_ptr, 2); op_ptr += 2; break; case DW_OP_const4u: result = extract_unsigned_integer (op_ptr, 4); op_ptr += 4; break; case DW_OP_const4s: result = extract_signed_integer (op_ptr, 4); op_ptr += 4; break; case DW_OP_const8u: result = extract_unsigned_integer (op_ptr, 8); op_ptr += 8; break; case DW_OP_const8s: result = extract_signed_integer (op_ptr, 8); op_ptr += 8; break; case DW_OP_constu: op_ptr = read_uleb128 (op_ptr, op_end, &uoffset); result = uoffset; break; case DW_OP_consts: op_ptr = read_sleb128 (op_ptr, op_end, &offset); result = offset; break; /* The DW_OP_reg operations are required to occur alone in location expressions. */ case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2: case DW_OP_reg3: case DW_OP_reg4: case DW_OP_reg5: case DW_OP_reg6: case DW_OP_reg7: case DW_OP_reg8: case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11: case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14: case DW_OP_reg15: case DW_OP_reg16: case DW_OP_reg17: case DW_OP_reg18: case DW_OP_reg19: case DW_OP_reg20: case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23: case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26: case DW_OP_reg27: case DW_OP_reg28: case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31: - if (op_ptr != op_end && *op_ptr != DW_OP_piece) - error ("DWARF-2 expression error: DW_OP_reg operations must be " - "used either alone or in conjuction with DW_OP_piece."); + if (op_ptr != op_end + && *op_ptr != DW_OP_piece + && *op_ptr != DW_OP_bit_piece + && *op_ptr != DW_OP_GNU_uninit) + error (_("DWARF-2 expression error: DW_OP_reg operations must be " + "used either alone or in conjuction with DW_OP_piece.")); result = op - DW_OP_reg0; ctx->in_reg = 1; break; case DW_OP_regx: op_ptr = read_uleb128 (op_ptr, op_end, ®); if (op_ptr != op_end && *op_ptr != DW_OP_piece) error ("DWARF-2 expression error: DW_OP_reg operations must be " "used either alone or in conjuction with DW_OP_piece."); result = reg; ctx->in_reg = 1; break; case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: case DW_OP_breg3: case DW_OP_breg4: case DW_OP_breg5: case DW_OP_breg6: case DW_OP_breg7: case DW_OP_breg8: case DW_OP_breg9: case DW_OP_breg10: case DW_OP_breg11: case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14: case DW_OP_breg15: case DW_OP_breg16: case DW_OP_breg17: case DW_OP_breg18: case DW_OP_breg19: case DW_OP_breg20: case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23: case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: case DW_OP_breg27: case DW_OP_breg28: case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31: { op_ptr = read_sleb128 (op_ptr, op_end, &offset); result = (ctx->read_reg) (ctx->baton, op - DW_OP_breg0); result += offset; } break; case DW_OP_bregx: { op_ptr = read_uleb128 (op_ptr, op_end, ®); op_ptr = read_sleb128 (op_ptr, op_end, &offset); result = (ctx->read_reg) (ctx->baton, reg); result += offset; } break; case DW_OP_fbreg: { unsigned char *datastart; size_t datalen; unsigned int before_stack_len; op_ptr = read_sleb128 (op_ptr, op_end, &offset); /* Rather than create a whole new context, we simply record the stack length before execution, then reset it afterwards, effectively erasing whatever the recursive call put there. */ before_stack_len = ctx->stack_len; /* FIXME: cagney/2003-03-26: This code should be using get_frame_base_address(), and then implement a dwarf2 specific this_base method. */ (ctx->get_frame_base) (ctx->baton, &datastart, &datalen); dwarf_expr_eval (ctx, datastart, datalen); result = dwarf_expr_fetch (ctx, 0); if (ctx->in_reg) result = (ctx->read_reg) (ctx->baton, result); result = result + offset; ctx->stack_len = before_stack_len; ctx->in_reg = 0; } break; case DW_OP_dup: result = dwarf_expr_fetch (ctx, 0); break; case DW_OP_drop: dwarf_expr_pop (ctx); goto no_push; case DW_OP_pick: offset = *op_ptr++; result = dwarf_expr_fetch (ctx, offset); break; case DW_OP_over: result = dwarf_expr_fetch (ctx, 1); break; case DW_OP_rot: { CORE_ADDR t1, t2, t3; if (ctx->stack_len < 3) error ("Not enough elements for DW_OP_rot. Need 3, have %d\n", ctx->stack_len); t1 = ctx->stack[ctx->stack_len - 1]; t2 = ctx->stack[ctx->stack_len - 2]; t3 = ctx->stack[ctx->stack_len - 3]; ctx->stack[ctx->stack_len - 1] = t2; ctx->stack[ctx->stack_len - 2] = t3; ctx->stack[ctx->stack_len - 3] = t1; goto no_push; } case DW_OP_deref: case DW_OP_deref_size: case DW_OP_abs: case DW_OP_neg: case DW_OP_not: case DW_OP_plus_uconst: /* Unary operations. */ result = dwarf_expr_fetch (ctx, 0); dwarf_expr_pop (ctx); switch (op) { case DW_OP_deref: { char *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT); int bytes_read; (ctx->read_mem) (ctx->baton, buf, result, TARGET_ADDR_BIT / TARGET_CHAR_BIT); result = dwarf2_read_address (buf, buf + (TARGET_ADDR_BIT / TARGET_CHAR_BIT), &bytes_read); } break; case DW_OP_deref_size: { char *buf = alloca (TARGET_ADDR_BIT / TARGET_CHAR_BIT); int bytes_read; (ctx->read_mem) (ctx->baton, buf, result, *op_ptr++); result = dwarf2_read_address (buf, buf + (TARGET_ADDR_BIT / TARGET_CHAR_BIT), &bytes_read); } break; case DW_OP_abs: if ((signed int) result < 0) result = -result; break; case DW_OP_neg: result = -result; break; case DW_OP_not: result = ~result; break; case DW_OP_plus_uconst: op_ptr = read_uleb128 (op_ptr, op_end, ®); result += reg; break; } break; case DW_OP_and: case DW_OP_div: case DW_OP_minus: case DW_OP_mod: case DW_OP_mul: case DW_OP_or: case DW_OP_plus: case DW_OP_shl: case DW_OP_shr: case DW_OP_shra: case DW_OP_xor: case DW_OP_le: case DW_OP_ge: case DW_OP_eq: case DW_OP_lt: case DW_OP_gt: case DW_OP_ne: { /* Binary operations. Use the value engine to do computations in the right width. */ CORE_ADDR first, second; enum exp_opcode binop; struct value *val1, *val2; second = dwarf_expr_fetch (ctx, 0); dwarf_expr_pop (ctx); first = dwarf_expr_fetch (ctx, 0); dwarf_expr_pop (ctx); val1 = value_from_longest (unsigned_address_type (), first); val2 = value_from_longest (unsigned_address_type (), second); switch (op) { case DW_OP_and: binop = BINOP_BITWISE_AND; break; case DW_OP_div: binop = BINOP_DIV; break; case DW_OP_minus: binop = BINOP_SUB; break; case DW_OP_mod: binop = BINOP_MOD; break; case DW_OP_mul: binop = BINOP_MUL; break; case DW_OP_or: binop = BINOP_BITWISE_IOR; break; case DW_OP_plus: binop = BINOP_ADD; break; case DW_OP_shl: binop = BINOP_LSH; break; case DW_OP_shr: binop = BINOP_RSH; break; case DW_OP_shra: binop = BINOP_RSH; val1 = value_from_longest (signed_address_type (), first); break; case DW_OP_xor: binop = BINOP_BITWISE_XOR; break; case DW_OP_le: binop = BINOP_LEQ; break; case DW_OP_ge: binop = BINOP_GEQ; break; case DW_OP_eq: binop = BINOP_EQUAL; break; case DW_OP_lt: binop = BINOP_LESS; break; case DW_OP_gt: binop = BINOP_GTR; break; case DW_OP_ne: binop = BINOP_NOTEQUAL; break; default: internal_error (__FILE__, __LINE__, "Can't be reached."); } result = value_as_long (value_binop (val1, val2, binop)); } break; case DW_OP_GNU_push_tls_address: /* Variable is at a constant offset in the thread-local storage block into the objfile for the current thread and the dynamic linker module containing this expression. Here we return returns the offset from that base. The top of the stack has the offset from the beginning of the thread control block at which the variable is located. Nothing should follow this operator, so the top of stack would be returned. */ result = dwarf_expr_fetch (ctx, 0); dwarf_expr_pop (ctx); result = (ctx->get_tls_address) (ctx->baton, result); break; case DW_OP_skip: offset = extract_signed_integer (op_ptr, 2); op_ptr += 2; op_ptr += offset; goto no_push; case DW_OP_bra: offset = extract_signed_integer (op_ptr, 2); op_ptr += 2; if (dwarf_expr_fetch (ctx, 0) != 0) op_ptr += offset; dwarf_expr_pop (ctx); goto no_push; case DW_OP_nop: goto no_push; + + case DW_OP_piece: + { + ULONGEST size; + CORE_ADDR addr_or_regnum; + + /* Record the piece. */ + op_ptr = read_uleb128 (op_ptr, op_end, &size); + addr_or_regnum = dwarf_expr_fetch (ctx, 0); + add_piece (ctx, ctx->in_reg, addr_or_regnum, size); + + /* Pop off the address/regnum, and clear the in_reg flag. */ + dwarf_expr_pop (ctx); + ctx->in_reg = 0; + } + goto no_push; + + case DW_OP_GNU_uninit: + if (op_ptr != op_end) + error (_("DWARF-2 expression error: DW_OP_GNU_unint must always " + "be the very last op.")); + + ctx->initialized = 0; + goto no_push; default: error ("Unhandled dwarf expression opcode 0x%x", op); } /* Most things push a result value. */ dwarf_expr_push (ctx, result); no_push:; } } Index: projects/ci20_mips/contrib/gdb/gdb/dwarf2expr.h =================================================================== --- projects/ci20_mips/contrib/gdb/gdb/dwarf2expr.h (revision 283030) +++ projects/ci20_mips/contrib/gdb/gdb/dwarf2expr.h (revision 283031) @@ -1,96 +1,141 @@ /* Dwarf2 Expression Evaluator Copyright 2001, 2002, 2003 Free Software Foundation, Inc. Contributed by Daniel Berlin (dan@dberlin.org) This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if !defined (DWARF2EXPR_H) #define DWARF2EXPR_H /* The expression evaluator works with a dwarf_expr_context, describing its current state and its callbacks. */ struct dwarf_expr_context { /* The stack of values, allocated with xmalloc. */ CORE_ADDR *stack; /* The number of values currently pushed on the stack, and the number of elements allocated to the stack. */ int stack_len, stack_allocated; /* An opaque argument provided by the caller, which will be passed to all of the callback functions. */ void *baton; /* Return the value of register number REGNUM. */ CORE_ADDR (*read_reg) (void *baton, int regnum); /* Read LENGTH bytes at ADDR into BUF. */ void (*read_mem) (void *baton, char *buf, CORE_ADDR addr, size_t length); /* Return the location expression for the frame base attribute, in START and LENGTH. The result must be live until the current expression evaluation is complete. */ void (*get_frame_base) (void *baton, unsigned char **start, size_t *length); /* Return the thread-local storage address for DW_OP_GNU_push_tls_address. */ CORE_ADDR (*get_tls_address) (void *baton, CORE_ADDR offset); #if 0 /* Not yet implemented. */ /* Return the location expression for the dwarf expression subroutine in the die at OFFSET in the current compilation unit. The result must be live until the current expression evaluation is complete. */ unsigned char *(*get_subr) (void *baton, off_t offset, size_t *length); /* Return the `object address' for DW_OP_push_object_address. */ CORE_ADDR (*get_object_address) (void *baton); #endif /* The current depth of dwarf expression recursion, via DW_OP_call*, DW_OP_fbreg, DW_OP_push_object_address, etc., and the maximum depth we'll tolerate before raising an error. */ int recursion_depth, max_recursion_depth; /* Non-zero if the result is in a register. The register number will be on the expression stack. */ int in_reg; + /* Initialization status of variable: Non-zero if variable has been + initialized; zero otherwise. */ + int initialized; + + /* An array of pieces. PIECES points to its first element; + NUM_PIECES is its length. + + Each time DW_OP_piece is executed, we add a new element to the + end of this array, recording the current top of the stack, the + current in_reg flag, and the size given as the operand to + DW_OP_piece. We then pop the top value from the stack, clear the + in_reg flag, and resume evaluation. + + The Dwarf spec doesn't say whether DW_OP_piece pops the top value + from the stack. We do, ensuring that clients of this interface + expecting to see a value left on the top of the stack (say, code + evaluating frame base expressions or CFA's specified with + DW_CFA_def_cfa_expression) will get an error if the expression + actually marks all the values it computes as pieces. + + If an expression never uses DW_OP_piece, num_pieces will be zero. + (It would be nice to present these cases as expressions yielding + a single piece, with in_reg clear, so that callers need not + distinguish between the no-DW_OP_piece and one-DW_OP_piece cases. + But expressions with no DW_OP_piece operations have no value to + place in a piece's 'size' field; the size comes from the + surrounding data. So the two cases need to be handled + separately.) */ + int num_pieces; + struct dwarf_expr_piece *pieces; +}; + +/* A piece of an object, as recorded by DW_OP_piece or DW_OP_bit_piece. */ +struct dwarf_expr_piece +{ + /* If IN_REG is zero, then the piece is in memory, and VALUE is its address. + If IN_REG is non-zero, then the piece is in a register, and VALUE + is the register number. */ + int in_reg; + + /* This piece's address or register number. */ + CORE_ADDR value; + + /* The length of the piece, in bytes. */ + ULONGEST size; }; struct dwarf_expr_context *new_dwarf_expr_context (void); void free_dwarf_expr_context (struct dwarf_expr_context *ctx); void dwarf_expr_push (struct dwarf_expr_context *ctx, CORE_ADDR value); void dwarf_expr_pop (struct dwarf_expr_context *ctx); void dwarf_expr_eval (struct dwarf_expr_context *ctx, unsigned char *addr, size_t len); CORE_ADDR dwarf_expr_fetch (struct dwarf_expr_context *ctx, int n); unsigned char *read_uleb128 (unsigned char *buf, unsigned char *buf_end, ULONGEST * r); unsigned char *read_sleb128 (unsigned char *buf, unsigned char *buf_end, LONGEST * r); CORE_ADDR dwarf2_read_address (unsigned char *buf, unsigned char *buf_end, int *bytes_read); #endif Index: projects/ci20_mips/contrib/gdb/gdb/dwarf2loc.c =================================================================== --- projects/ci20_mips/contrib/gdb/gdb/dwarf2loc.c (revision 283030) +++ projects/ci20_mips/contrib/gdb/gdb/dwarf2loc.c (revision 283031) @@ -1,553 +1,592 @@ /* DWARF 2 location expression support for GDB. Copyright 2003 Free Software Foundation, Inc. Contributed by Daniel Jacobowitz, MontaVista Software, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "defs.h" #include "ui-out.h" #include "value.h" #include "frame.h" #include "gdbcore.h" #include "target.h" #include "inferior.h" #include "ax.h" #include "ax-gdb.h" #include "regcache.h" #include "objfiles.h" #include "elf/dwarf2.h" #include "dwarf2expr.h" #include "dwarf2loc.h" #include "gdb_string.h" #ifndef DWARF2_REG_TO_REGNUM #define DWARF2_REG_TO_REGNUM(REG) (REG) #endif /* A helper function for dealing with location lists. Given a symbol baton (BATON) and a pc value (PC), find the appropriate location expression, set *LOCEXPR_LENGTH, and return a pointer to the beginning of the expression. Returns NULL on failure. For now, only return the first matching location expression; there can be more than one in the list. */ static char * find_location_expression (struct dwarf2_loclist_baton *baton, size_t *locexpr_length, CORE_ADDR pc) { CORE_ADDR low, high; char *loc_ptr, *buf_end; unsigned int addr_size = TARGET_ADDR_BIT / TARGET_CHAR_BIT, length; CORE_ADDR base_mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1)); /* Adjust base_address for relocatable objects. */ CORE_ADDR base_offset = ANOFFSET (baton->objfile->section_offsets, SECT_OFF_TEXT (baton->objfile)); CORE_ADDR base_address = baton->base_address + base_offset; loc_ptr = baton->data; buf_end = baton->data + baton->size; while (1) { low = dwarf2_read_address (loc_ptr, buf_end, &length); loc_ptr += length; high = dwarf2_read_address (loc_ptr, buf_end, &length); loc_ptr += length; /* An end-of-list entry. */ if (low == 0 && high == 0) return NULL; /* A base-address-selection entry. */ if ((low & base_mask) == base_mask) { base_address = high; continue; } /* Otherwise, a location expression entry. */ low += base_address; high += base_address; length = extract_unsigned_integer (loc_ptr, 2); loc_ptr += 2; if (pc >= low && pc < high) { *locexpr_length = length; return loc_ptr; } loc_ptr += length; } } /* This is the baton used when performing dwarf2 expression evaluation. */ struct dwarf_expr_baton { struct frame_info *frame; struct objfile *objfile; }; /* Helper functions for dwarf2_evaluate_loc_desc. */ /* Using the frame specified in BATON, read register REGNUM. The lval type will be returned in LVALP, and for lval_memory the register save address will be returned in ADDRP. */ static CORE_ADDR dwarf_expr_read_reg (void *baton, int dwarf_regnum) { struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton; CORE_ADDR result, save_addr; enum lval_type lval_type; char *buf; int optimized, regnum, realnum, regsize; regnum = DWARF2_REG_TO_REGNUM (dwarf_regnum); regsize = register_size (current_gdbarch, regnum); buf = (char *) alloca (regsize); frame_register (debaton->frame, regnum, &optimized, &lval_type, &save_addr, &realnum, buf); /* NOTE: cagney/2003-05-22: This extract is assuming that a DWARF 2 address is always unsigned. That may or may not be true. */ result = extract_unsigned_integer (buf, regsize); return result; } /* Read memory at ADDR (length LEN) into BUF. */ static void dwarf_expr_read_mem (void *baton, char *buf, CORE_ADDR addr, size_t len) { read_memory (addr, buf, len); } /* Using the frame specified in BATON, find the location expression describing the frame base. Return a pointer to it in START and its length in LENGTH. */ static void dwarf_expr_frame_base (void *baton, unsigned char **start, size_t * length) { /* FIXME: cagney/2003-03-26: This code should be using get_frame_base_address(), and then implement a dwarf2 specific this_base method. */ struct symbol *framefunc; struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton; framefunc = get_frame_function (debaton->frame); if (SYMBOL_OPS (framefunc) == &dwarf2_loclist_funcs) { struct dwarf2_loclist_baton *symbaton; symbaton = SYMBOL_LOCATION_BATON (framefunc); *start = find_location_expression (symbaton, length, get_frame_pc (debaton->frame)); } else { struct dwarf2_locexpr_baton *symbaton; symbaton = SYMBOL_LOCATION_BATON (framefunc); *length = symbaton->size; *start = symbaton->data; } if (*start == NULL) error ("Could not find the frame base for \"%s\".", SYMBOL_NATURAL_NAME (framefunc)); } /* Using the objfile specified in BATON, find the address for the current thread's thread-local storage with offset OFFSET. */ static CORE_ADDR dwarf_expr_tls_address (void *baton, CORE_ADDR offset) { struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton; CORE_ADDR addr; if (target_get_thread_local_address_p ()) addr = target_get_thread_local_address (inferior_ptid, debaton->objfile, offset); /* It wouldn't be wrong here to try a gdbarch method, too; finding TLS is an ABI-specific thing. But we don't do that yet. */ else error ("Cannot find thread-local variables on this target"); return addr; } /* Evaluate a location description, starting at DATA and with length SIZE, to find the current location of variable VAR in the context of FRAME. */ static struct value * dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame, unsigned char *data, unsigned short size, struct objfile *objfile) { CORE_ADDR result; + struct gdbarch *arch = get_frame_arch (frame); struct value *retval; struct dwarf_expr_baton baton; struct dwarf_expr_context *ctx; if (size == 0) { retval = allocate_value (SYMBOL_TYPE (var)); VALUE_LVAL (retval) = not_lval; VALUE_OPTIMIZED_OUT (retval) = 1; } baton.frame = frame; baton.objfile = objfile; ctx = new_dwarf_expr_context (); ctx->baton = &baton; ctx->read_reg = dwarf_expr_read_reg; ctx->read_mem = dwarf_expr_read_mem; ctx->get_frame_base = dwarf_expr_frame_base; ctx->get_tls_address = dwarf_expr_tls_address; dwarf_expr_eval (ctx, data, size); result = dwarf_expr_fetch (ctx, 0); - if (ctx->in_reg) + if (ctx->num_pieces > 0) { + int i; + long offset = 0; + bfd_byte *contents; + + retval = allocate_value (SYMBOL_TYPE (var)); + contents = VALUE_CONTENTS_RAW (retval); + for (i = 0; i < ctx->num_pieces; i++) + { + struct dwarf_expr_piece *p = &ctx->pieces[i]; + if (p->in_reg) + { + bfd_byte regval[MAX_REGISTER_SIZE]; + int gdb_regnum = DWARF2_REG_TO_REGNUM (p->value); + get_frame_register (frame, gdb_regnum, regval); + memcpy (contents + offset, regval, p->size); + } + else /* In memory? */ + { + read_memory (p->value, contents + offset, p->size); + } + offset += p->size; + } + } + else if (ctx->in_reg) + { int regnum = DWARF2_REG_TO_REGNUM (result); retval = value_from_register (SYMBOL_TYPE (var), regnum, frame); } else { retval = allocate_value (SYMBOL_TYPE (var)); VALUE_BFD_SECTION (retval) = SYMBOL_BFD_SECTION (var); VALUE_LVAL (retval) = lval_memory; VALUE_LAZY (retval) = 1; VALUE_ADDRESS (retval) = result; } + set_value_initialized (retval, ctx->initialized); + free_dwarf_expr_context (ctx); return retval; } /* Helper functions and baton for dwarf2_loc_desc_needs_frame. */ struct needs_frame_baton { int needs_frame; }; /* Reads from registers do require a frame. */ static CORE_ADDR needs_frame_read_reg (void *baton, int regnum) { struct needs_frame_baton *nf_baton = baton; nf_baton->needs_frame = 1; return 1; } /* Reads from memory do not require a frame. */ static void needs_frame_read_mem (void *baton, char *buf, CORE_ADDR addr, size_t len) { memset (buf, 0, len); } /* Frame-relative accesses do require a frame. */ static void needs_frame_frame_base (void *baton, unsigned char **start, size_t * length) { static char lit0 = DW_OP_lit0; struct needs_frame_baton *nf_baton = baton; *start = &lit0; *length = 1; nf_baton->needs_frame = 1; } /* Thread-local accesses do require a frame. */ static CORE_ADDR needs_frame_tls_address (void *baton, CORE_ADDR offset) { struct needs_frame_baton *nf_baton = baton; nf_baton->needs_frame = 1; return 1; } /* Return non-zero iff the location expression at DATA (length SIZE) requires a frame to evaluate. */ static int dwarf2_loc_desc_needs_frame (unsigned char *data, unsigned short size) { struct needs_frame_baton baton; struct dwarf_expr_context *ctx; int in_reg; baton.needs_frame = 0; ctx = new_dwarf_expr_context (); ctx->baton = &baton; ctx->read_reg = needs_frame_read_reg; ctx->read_mem = needs_frame_read_mem; ctx->get_frame_base = needs_frame_frame_base; ctx->get_tls_address = needs_frame_tls_address; dwarf_expr_eval (ctx, data, size); in_reg = ctx->in_reg; + + if (ctx->num_pieces > 0) + { + int i; + + /* If the location has several pieces, and any of them are in + registers, then we will need a frame to fetch them from. */ + for (i = 0; i < ctx->num_pieces; i++) + if (ctx->pieces[i].in_reg) + in_reg = 1; + } free_dwarf_expr_context (ctx); return baton.needs_frame || in_reg; } static void dwarf2_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax, struct axs_value * value, unsigned char *data, int size) { if (size == 0) error ("Symbol \"%s\" has been optimized out.", SYMBOL_PRINT_NAME (symbol)); if (size == 1 && data[0] >= DW_OP_reg0 && data[0] <= DW_OP_reg31) { value->kind = axs_lvalue_register; value->u.reg = data[0] - DW_OP_reg0; } else if (data[0] == DW_OP_regx) { ULONGEST reg; read_uleb128 (data + 1, data + size, ®); value->kind = axs_lvalue_register; value->u.reg = reg; } else if (data[0] == DW_OP_fbreg) { /* And this is worse than just minimal; we should honor the frame base as above. */ int frame_reg; LONGEST frame_offset; unsigned char *buf_end; buf_end = read_sleb128 (data + 1, data + size, &frame_offset); if (buf_end != data + size) error ("Unexpected opcode after DW_OP_fbreg for symbol \"%s\".", SYMBOL_PRINT_NAME (symbol)); TARGET_VIRTUAL_FRAME_POINTER (ax->scope, &frame_reg, &frame_offset); ax_reg (ax, frame_reg); ax_const_l (ax, frame_offset); ax_simple (ax, aop_add); ax_const_l (ax, frame_offset); ax_simple (ax, aop_add); value->kind = axs_lvalue_memory; } else error ("Unsupported DWARF opcode in the location of \"%s\".", SYMBOL_PRINT_NAME (symbol)); } /* Return the value of SYMBOL in FRAME using the DWARF-2 expression evaluator to calculate the location. */ static struct value * locexpr_read_variable (struct symbol *symbol, struct frame_info *frame) { struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); struct value *val; val = dwarf2_evaluate_loc_desc (symbol, frame, dlbaton->data, dlbaton->size, dlbaton->objfile); return val; } /* Return non-zero iff we need a frame to evaluate SYMBOL. */ static int locexpr_read_needs_frame (struct symbol *symbol) { struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); return dwarf2_loc_desc_needs_frame (dlbaton->data, dlbaton->size); } /* Print a natural-language description of SYMBOL to STREAM. */ static int locexpr_describe_location (struct symbol *symbol, struct ui_file *stream) { /* FIXME: be more extensive. */ struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); if (dlbaton->size == 1 && dlbaton->data[0] >= DW_OP_reg0 && dlbaton->data[0] <= DW_OP_reg31) { int regno = DWARF2_REG_TO_REGNUM (dlbaton->data[0] - DW_OP_reg0); fprintf_filtered (stream, "a variable in register %s", REGISTER_NAME (regno)); return 1; } /* The location expression for a TLS variable looks like this (on a 64-bit LE machine): DW_AT_location : 10 byte block: 3 4 0 0 0 0 0 0 0 e0 (DW_OP_addr: 4; DW_OP_GNU_push_tls_address) 0x3 is the encoding for DW_OP_addr, which has an operand as long as the size of an address on the target machine (here is 8 bytes). 0xe0 is the encoding for DW_OP_GNU_push_tls_address. The operand represents the offset at which the variable is within the thread local storage. */ if (dlbaton->size > 1 && dlbaton->data[dlbaton->size - 1] == DW_OP_GNU_push_tls_address) if (dlbaton->data[0] == DW_OP_addr) { int bytes_read; CORE_ADDR offset = dwarf2_read_address (&dlbaton->data[1], &dlbaton->data[dlbaton->size - 1], &bytes_read); fprintf_filtered (stream, "a thread-local variable at offset %s in the " "thread-local storage for `%s'", paddr_nz (offset), dlbaton->objfile->name); return 1; } fprintf_filtered (stream, "a variable with complex or multiple locations (DWARF2)"); return 1; } /* Describe the location of SYMBOL as an agent value in VALUE, generating any necessary bytecode in AX. NOTE drow/2003-02-26: This function is extremely minimal, because doing it correctly is extremely complicated and there is no publicly available stub with tracepoint support for me to test against. When there is one this function should be revisited. */ static void locexpr_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax, struct axs_value * value) { struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); dwarf2_tracepoint_var_ref (symbol, ax, value, dlbaton->data, dlbaton->size); } /* The set of location functions used with the DWARF-2 expression evaluator. */ const struct symbol_ops dwarf2_locexpr_funcs = { locexpr_read_variable, locexpr_read_needs_frame, locexpr_describe_location, locexpr_tracepoint_var_ref }; /* Wrapper functions for location lists. These generally find the appropriate location expression and call something above. */ /* Return the value of SYMBOL in FRAME using the DWARF-2 expression evaluator to calculate the location. */ static struct value * loclist_read_variable (struct symbol *symbol, struct frame_info *frame) { struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); struct value *val; unsigned char *data; size_t size; data = find_location_expression (dlbaton, &size, frame ? get_frame_pc (frame) : 0); if (data == NULL) { val = allocate_value (SYMBOL_TYPE (symbol)); VALUE_LVAL (val) = not_lval; VALUE_OPTIMIZED_OUT (val) = 1; } else val = dwarf2_evaluate_loc_desc (symbol, frame, data, size, dlbaton->objfile); return val; } /* Return non-zero iff we need a frame to evaluate SYMBOL. */ static int loclist_read_needs_frame (struct symbol *symbol) { /* If there's a location list, then assume we need to have a frame to choose the appropriate location expression. With tracking of global variables this is not necessarily true, but such tracking is disabled in GCC at the moment until we figure out how to represent it. */ return 1; } /* Print a natural-language description of SYMBOL to STREAM. */ static int loclist_describe_location (struct symbol *symbol, struct ui_file *stream) { /* FIXME: Could print the entire list of locations. */ fprintf_filtered (stream, "a variable with multiple locations"); return 1; } /* Describe the location of SYMBOL as an agent value in VALUE, generating any necessary bytecode in AX. */ static void loclist_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax, struct axs_value * value) { struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol); unsigned char *data; size_t size; data = find_location_expression (dlbaton, &size, ax->scope); if (data == NULL) error ("Variable \"%s\" is not available.", SYMBOL_NATURAL_NAME (symbol)); dwarf2_tracepoint_var_ref (symbol, ax, value, data, size); } /* The set of location functions used with the DWARF-2 expression evaluator and location lists. */ const struct symbol_ops dwarf2_loclist_funcs = { loclist_read_variable, loclist_read_needs_frame, loclist_describe_location, loclist_tracepoint_var_ref }; Index: projects/ci20_mips/contrib/gdb/gdb/dwarf2read.c =================================================================== --- projects/ci20_mips/contrib/gdb/gdb/dwarf2read.c (revision 283030) +++ projects/ci20_mips/contrib/gdb/gdb/dwarf2read.c (revision 283031) @@ -1,8125 +1,8130 @@ /* DWARF 2 debugging format support for GDB. Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology, Inc. with support from Florida State University (under contract with the Ada Joint Program Office), and Silicon Graphics, Inc. Initial contribution by Brent Benson, Harris Computer Systems, Inc., based on Fred Fish's (Cygnus Support) implementation of DWARF 1 support in dwarfread.c This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "defs.h" #include "bfd.h" #include "symtab.h" #include "gdbtypes.h" #include "objfiles.h" #include "elf/dwarf2.h" #include "buildsym.h" #include "demangle.h" #include "expression.h" #include "filenames.h" /* for DOSish file names */ #include "macrotab.h" #include "language.h" #include "complaints.h" #include "bcache.h" #include "dwarf2expr.h" #include "dwarf2loc.h" #include "cp-support.h" #include #include "gdb_string.h" #include "gdb_assert.h" #include #ifndef DWARF2_REG_TO_REGNUM #define DWARF2_REG_TO_REGNUM(REG) (REG) #endif #if 0 /* .debug_info header for a compilation unit Because of alignment constraints, this structure has padding and cannot be mapped directly onto the beginning of the .debug_info section. */ typedef struct comp_unit_header { unsigned int length; /* length of the .debug_info contribution */ unsigned short version; /* version number -- 2 for DWARF version 2 */ unsigned int abbrev_offset; /* offset into .debug_abbrev section */ unsigned char addr_size; /* byte size of an address -- 4 */ } _COMP_UNIT_HEADER; #define _ACTUAL_COMP_UNIT_HEADER_SIZE 11 #endif /* .debug_pubnames header Because of alignment constraints, this structure has padding and cannot be mapped directly onto the beginning of the .debug_info section. */ typedef struct pubnames_header { unsigned int length; /* length of the .debug_pubnames contribution */ unsigned char version; /* version number -- 2 for DWARF version 2 */ unsigned int info_offset; /* offset into .debug_info section */ unsigned int info_size; /* byte size of .debug_info section portion */ } _PUBNAMES_HEADER; #define _ACTUAL_PUBNAMES_HEADER_SIZE 13 /* .debug_pubnames header Because of alignment constraints, this structure has padding and cannot be mapped directly onto the beginning of the .debug_info section. */ typedef struct aranges_header { unsigned int length; /* byte len of the .debug_aranges contribution */ unsigned short version; /* version number -- 2 for DWARF version 2 */ unsigned int info_offset; /* offset into .debug_info section */ unsigned char addr_size; /* byte size of an address */ unsigned char seg_size; /* byte size of segment descriptor */ } _ARANGES_HEADER; #define _ACTUAL_ARANGES_HEADER_SIZE 12 /* .debug_line statement program prologue Because of alignment constraints, this structure has padding and cannot be mapped directly onto the beginning of the .debug_info section. */ typedef struct statement_prologue { unsigned int total_length; /* byte length of the statement information */ unsigned short version; /* version number -- 2 for DWARF version 2 */ unsigned int prologue_length; /* # bytes between prologue & stmt program */ unsigned char minimum_instruction_length; /* byte size of smallest instr */ unsigned char default_is_stmt; /* initial value of is_stmt register */ char line_base; unsigned char line_range; unsigned char opcode_base; /* number assigned to first special opcode */ unsigned char *standard_opcode_lengths; } _STATEMENT_PROLOGUE; /* offsets and sizes of debugging sections */ static unsigned int dwarf_info_size; static unsigned int dwarf_abbrev_size; static unsigned int dwarf_line_size; static unsigned int dwarf_pubnames_size; static unsigned int dwarf_aranges_size; static unsigned int dwarf_loc_size; static unsigned int dwarf_macinfo_size; static unsigned int dwarf_str_size; static unsigned int dwarf_ranges_size; unsigned int dwarf_frame_size; unsigned int dwarf_eh_frame_size; static asection *dwarf_info_section; static asection *dwarf_abbrev_section; static asection *dwarf_line_section; static asection *dwarf_pubnames_section; static asection *dwarf_aranges_section; static asection *dwarf_loc_section; static asection *dwarf_macinfo_section; static asection *dwarf_str_section; static asection *dwarf_ranges_section; asection *dwarf_frame_section; asection *dwarf_eh_frame_section; /* names of the debugging sections */ #define INFO_SECTION ".debug_info" #define ABBREV_SECTION ".debug_abbrev" #define LINE_SECTION ".debug_line" #define PUBNAMES_SECTION ".debug_pubnames" #define ARANGES_SECTION ".debug_aranges" #define LOC_SECTION ".debug_loc" #define MACINFO_SECTION ".debug_macinfo" #define STR_SECTION ".debug_str" #define RANGES_SECTION ".debug_ranges" #define FRAME_SECTION ".debug_frame" #define EH_FRAME_SECTION ".eh_frame" /* local data types */ /* We hold several abbreviation tables in memory at the same time. */ #ifndef ABBREV_HASH_SIZE #define ABBREV_HASH_SIZE 121 #endif /* The data in a compilation unit header, after target2host translation, looks like this. */ struct comp_unit_head { unsigned long length; short version; unsigned int abbrev_offset; unsigned char addr_size; unsigned char signed_addr_p; unsigned int offset_size; /* size of file offsets; either 4 or 8 */ unsigned int initial_length_size; /* size of the length field; either 4 or 12 */ /* Offset to the first byte of this compilation unit header in the * .debug_info section, for resolving relative reference dies. */ unsigned int offset; /* Pointer to this compilation unit header in the .debug_info * section */ char *cu_head_ptr; /* Pointer to the first die of this compilatio unit. This will * be the first byte following the compilation unit header. */ char *first_die_ptr; /* Pointer to the next compilation unit header in the program. */ struct comp_unit_head *next; /* DWARF abbreviation table associated with this compilation unit */ struct abbrev_info *dwarf2_abbrevs[ABBREV_HASH_SIZE]; /* Base address of this compilation unit. */ CORE_ADDR base_address; /* Non-zero if base_address has been set. */ int base_known; }; /* Internal state when decoding a particular compilation unit. */ struct dwarf2_cu { /* The objfile containing this compilation unit. */ struct objfile *objfile; /* The header of the compilation unit. FIXME drow/2003-11-10: Some of the things from the comp_unit_head should be moved to the dwarf2_cu structure; for instance the abbrevs hash table. */ struct comp_unit_head header; struct function_range *first_fn, *last_fn, *cached_fn; /* The language we are debugging. */ enum language language; const struct language_defn *language_defn; /* The generic symbol table building routines have separate lists for file scope symbols and all all other scopes (local scopes). So we need to select the right one to pass to add_symbol_to_list(). We do it by keeping a pointer to the correct list in list_in_scope. FIXME: The original dwarf code just treated the file scope as the first local scope, and all other local scopes as nested local scopes, and worked fine. Check to see if we really need to distinguish these in buildsym.c. */ struct pending **list_in_scope; /* Maintain an array of referenced fundamental types for the current compilation unit being read. For DWARF version 1, we have to construct the fundamental types on the fly, since no information about the fundamental types is supplied. Each such fundamental type is created by calling a language dependent routine to create the type, and then a pointer to that type is then placed in the array at the index specified by it's FT_ value. The array has a fixed size set by the FT_NUM_MEMBERS compile time constant, which is the number of predefined fundamental types gdb knows how to construct. */ struct type *ftypes[FT_NUM_MEMBERS]; /* Fundamental types */ }; /* The line number information for a compilation unit (found in the .debug_line section) begins with a "statement program header", which contains the following information. */ struct line_header { unsigned int total_length; unsigned short version; unsigned int header_length; unsigned char minimum_instruction_length; unsigned char default_is_stmt; int line_base; unsigned char line_range; unsigned char opcode_base; /* standard_opcode_lengths[i] is the number of operands for the standard opcode whose value is i. This means that standard_opcode_lengths[0] is unused, and the last meaningful element is standard_opcode_lengths[opcode_base - 1]. */ unsigned char *standard_opcode_lengths; /* The include_directories table. NOTE! These strings are not allocated with xmalloc; instead, they are pointers into debug_line_buffer. If you try to free them, `free' will get indigestion. */ unsigned int num_include_dirs, include_dirs_size; char **include_dirs; /* The file_names table. NOTE! These strings are not allocated with xmalloc; instead, they are pointers into debug_line_buffer. Don't try to free them directly. */ unsigned int num_file_names, file_names_size; struct file_entry { char *name; unsigned int dir_index; unsigned int mod_time; unsigned int length; } *file_names; /* The start and end of the statement program following this header. These point into dwarf_line_buffer. */ char *statement_program_start, *statement_program_end; }; /* When we construct a partial symbol table entry we only need this much information. */ struct partial_die_info { enum dwarf_tag tag; unsigned char has_children; unsigned char is_external; unsigned char is_declaration; unsigned char has_type; unsigned int offset; unsigned int abbrev; char *name; int has_pc_info; CORE_ADDR lowpc; CORE_ADDR highpc; struct dwarf_block *locdesc; unsigned int language; char *sibling; }; /* This data structure holds the information of an abbrev. */ struct abbrev_info { unsigned int number; /* number identifying abbrev */ enum dwarf_tag tag; /* dwarf tag */ int has_children; /* boolean */ unsigned int num_attrs; /* number of attributes */ struct attr_abbrev *attrs; /* an array of attribute descriptions */ struct abbrev_info *next; /* next in chain */ }; struct attr_abbrev { enum dwarf_attribute name; enum dwarf_form form; }; /* This data structure holds a complete die structure. */ struct die_info { enum dwarf_tag tag; /* Tag indicating type of die */ unsigned int abbrev; /* Abbrev number */ unsigned int offset; /* Offset in .debug_info section */ unsigned int num_attrs; /* Number of attributes */ struct attribute *attrs; /* An array of attributes */ struct die_info *next_ref; /* Next die in ref hash table */ /* The dies in a compilation unit form an n-ary tree. PARENT points to this die's parent; CHILD points to the first child of this node; and all the children of a given node are chained together via their SIBLING fields, terminated by a die whose tag is zero. */ struct die_info *child; /* Its first child, if any. */ struct die_info *sibling; /* Its next sibling, if any. */ struct die_info *parent; /* Its parent, if any. */ struct type *type; /* Cached type information */ }; /* Attributes have a name and a value */ struct attribute { enum dwarf_attribute name; enum dwarf_form form; union { char *str; struct dwarf_block *blk; unsigned long unsnd; long int snd; CORE_ADDR addr; } u; }; struct function_range { const char *name; CORE_ADDR lowpc, highpc; int seen_line; struct function_range *next; }; /* Get at parts of an attribute structure */ #define DW_STRING(attr) ((attr)->u.str) #define DW_UNSND(attr) ((attr)->u.unsnd) #define DW_BLOCK(attr) ((attr)->u.blk) #define DW_SND(attr) ((attr)->u.snd) #define DW_ADDR(attr) ((attr)->u.addr) /* Blocks are a bunch of untyped bytes. */ struct dwarf_block { unsigned int size; char *data; }; #ifndef ATTR_ALLOC_CHUNK #define ATTR_ALLOC_CHUNK 4 #endif /* A hash table of die offsets for following references. */ #ifndef REF_HASH_SIZE #define REF_HASH_SIZE 1021 #endif static struct die_info *die_ref_table[REF_HASH_SIZE]; /* Obstack for allocating temporary storage used during symbol reading. */ static struct obstack dwarf2_tmp_obstack; /* Allocate fields for structs, unions and enums in this size. */ #ifndef DW_FIELD_ALLOC_CHUNK #define DW_FIELD_ALLOC_CHUNK 4 #endif /* Actually data from the sections. */ static char *dwarf_info_buffer; static char *dwarf_abbrev_buffer; static char *dwarf_line_buffer; static char *dwarf_str_buffer; static char *dwarf_macinfo_buffer; static char *dwarf_ranges_buffer; static char *dwarf_loc_buffer; /* A zeroed version of a partial die for initialization purposes. */ static struct partial_die_info zeroed_partial_die; /* FIXME: decode_locdesc sets these variables to describe the location to the caller. These ought to be a structure or something. If none of the flags are set, the object lives at the address returned by decode_locdesc. */ static int isreg; /* Object lives in register. decode_locdesc's return value is the register number. */ /* We put a pointer to this structure in the read_symtab_private field of the psymtab. The complete dwarf information for an objfile is kept in the objfile_obstack, so that absolute die references can be handled. Most of the information in this structure is related to an entire object file and could be passed via the sym_private field of the objfile. It is however conceivable that dwarf2 might not be the only type of symbols read from an object file. */ struct dwarf2_pinfo { /* Pointer to start of dwarf info buffer for the objfile. */ char *dwarf_info_buffer; /* Offset in dwarf_info_buffer for this compilation unit. */ unsigned long dwarf_info_offset; /* Pointer to start of dwarf abbreviation buffer for the objfile. */ char *dwarf_abbrev_buffer; /* Size of dwarf abbreviation section for the objfile. */ unsigned int dwarf_abbrev_size; /* Pointer to start of dwarf line buffer for the objfile. */ char *dwarf_line_buffer; /* Size of dwarf_line_buffer, in bytes. */ unsigned int dwarf_line_size; /* Pointer to start of dwarf string buffer for the objfile. */ char *dwarf_str_buffer; /* Size of dwarf string section for the objfile. */ unsigned int dwarf_str_size; /* Pointer to start of dwarf macro buffer for the objfile. */ char *dwarf_macinfo_buffer; /* Size of dwarf macinfo section for the objfile. */ unsigned int dwarf_macinfo_size; /* Pointer to start of dwarf ranges buffer for the objfile. */ char *dwarf_ranges_buffer; /* Size of dwarf ranges buffer for the objfile. */ unsigned int dwarf_ranges_size; /* Pointer to start of dwarf locations buffer for the objfile. */ char *dwarf_loc_buffer; /* Size of dwarf locations buffer for the objfile. */ unsigned int dwarf_loc_size; }; #define PST_PRIVATE(p) ((struct dwarf2_pinfo *)(p)->read_symtab_private) #define DWARF_INFO_BUFFER(p) (PST_PRIVATE(p)->dwarf_info_buffer) #define DWARF_INFO_OFFSET(p) (PST_PRIVATE(p)->dwarf_info_offset) #define DWARF_ABBREV_BUFFER(p) (PST_PRIVATE(p)->dwarf_abbrev_buffer) #define DWARF_ABBREV_SIZE(p) (PST_PRIVATE(p)->dwarf_abbrev_size) #define DWARF_LINE_BUFFER(p) (PST_PRIVATE(p)->dwarf_line_buffer) #define DWARF_LINE_SIZE(p) (PST_PRIVATE(p)->dwarf_line_size) #define DWARF_STR_BUFFER(p) (PST_PRIVATE(p)->dwarf_str_buffer) #define DWARF_STR_SIZE(p) (PST_PRIVATE(p)->dwarf_str_size) #define DWARF_MACINFO_BUFFER(p) (PST_PRIVATE(p)->dwarf_macinfo_buffer) #define DWARF_MACINFO_SIZE(p) (PST_PRIVATE(p)->dwarf_macinfo_size) #define DWARF_RANGES_BUFFER(p) (PST_PRIVATE(p)->dwarf_ranges_buffer) #define DWARF_RANGES_SIZE(p) (PST_PRIVATE(p)->dwarf_ranges_size) #define DWARF_LOC_BUFFER(p) (PST_PRIVATE(p)->dwarf_loc_buffer) #define DWARF_LOC_SIZE(p) (PST_PRIVATE(p)->dwarf_loc_size) /* FIXME: We might want to set this from BFD via bfd_arch_bits_per_byte, but this would require a corresponding change in unpack_field_as_long and friends. */ static int bits_per_byte = 8; /* The routines that read and process dies for a C struct or C++ class pass lists of data member fields and lists of member function fields in an instance of a field_info structure, as defined below. */ struct field_info { /* List of data member and baseclasses fields. */ struct nextfield { struct nextfield *next; int accessibility; int virtuality; struct field field; } *fields; /* Number of fields. */ int nfields; /* Number of baseclasses. */ int nbaseclasses; /* Set if the accesibility of one of the fields is not public. */ int non_public_fields; /* Member function fields array, entries are allocated in the order they are encountered in the object file. */ struct nextfnfield { struct nextfnfield *next; struct fn_field fnfield; } *fnfields; /* Member function fieldlist array, contains name of possibly overloaded member function, number of overloaded member functions and a pointer to the head of the member function field chain. */ struct fnfieldlist { char *name; int length; struct nextfnfield *head; } *fnfieldlists; /* Number of entries in the fnfieldlists array. */ int nfnfields; }; /* Various complaints about symbol reading that don't abort the process */ static void dwarf2_statement_list_fits_in_line_number_section_complaint (void) { complaint (&symfile_complaints, "statement list doesn't fit in .debug_line section"); } static void dwarf2_complex_location_expr_complaint (void) { complaint (&symfile_complaints, "location expression too complex"); } static void dwarf2_const_value_length_mismatch_complaint (const char *arg1, int arg2, int arg3) { complaint (&symfile_complaints, "const value length mismatch for '%s', got %d, expected %d", arg1, arg2, arg3); } static void dwarf2_macros_too_long_complaint (void) { complaint (&symfile_complaints, "macro info runs off end of `.debug_macinfo' section"); } static void dwarf2_macro_malformed_definition_complaint (const char *arg1) { complaint (&symfile_complaints, "macro debug info contains a malformed macro definition:\n`%s'", arg1); } static void dwarf2_invalid_attrib_class_complaint (const char *arg1, const char *arg2) { complaint (&symfile_complaints, "invalid attribute class or form for '%s' in '%s'", arg1, arg2); } /* local function prototypes */ static void dwarf2_locate_sections (bfd *, asection *, void *); #if 0 static void dwarf2_build_psymtabs_easy (struct objfile *, int); #endif static void dwarf2_build_psymtabs_hard (struct objfile *, int); static char *scan_partial_symbols (char *, CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *, const char *namespace); static void add_partial_symbol (struct partial_die_info *, struct dwarf2_cu *, const char *namespace); static int pdi_needs_namespace (enum dwarf_tag tag, const char *namespace); static char *add_partial_namespace (struct partial_die_info *pdi, char *info_ptr, CORE_ADDR *lowpc, CORE_ADDR *highpc, struct dwarf2_cu *cu, const char *namespace); static char *add_partial_structure (struct partial_die_info *struct_pdi, char *info_ptr, struct dwarf2_cu *cu, const char *namespace); static char *add_partial_enumeration (struct partial_die_info *enum_pdi, char *info_ptr, struct dwarf2_cu *cu, const char *namespace); static char *locate_pdi_sibling (struct partial_die_info *orig_pdi, char *info_ptr, bfd *abfd, struct dwarf2_cu *cu); static void dwarf2_psymtab_to_symtab (struct partial_symtab *); static void psymtab_to_symtab_1 (struct partial_symtab *); char *dwarf2_read_section (struct objfile *, asection *); static void dwarf2_read_abbrevs (bfd *abfd, struct dwarf2_cu *cu); static void dwarf2_empty_abbrev_table (void *); static struct abbrev_info *dwarf2_lookup_abbrev (unsigned int, struct dwarf2_cu *); static char *read_partial_die (struct partial_die_info *, bfd *, char *, struct dwarf2_cu *); static char *read_full_die (struct die_info **, bfd *, char *, struct dwarf2_cu *, int *); static char *read_attribute (struct attribute *, struct attr_abbrev *, bfd *, char *, struct dwarf2_cu *); static char *read_attribute_value (struct attribute *, unsigned, bfd *, char *, struct dwarf2_cu *); static unsigned int read_1_byte (bfd *, char *); static int read_1_signed_byte (bfd *, char *); static unsigned int read_2_bytes (bfd *, char *); static unsigned int read_4_bytes (bfd *, char *); static unsigned long read_8_bytes (bfd *, char *); static CORE_ADDR read_address (bfd *, char *ptr, struct dwarf2_cu *, int *bytes_read); static LONGEST read_initial_length (bfd *, char *, struct comp_unit_head *, int *bytes_read); static LONGEST read_offset (bfd *, char *, const struct comp_unit_head *, int *bytes_read); static char *read_n_bytes (bfd *, char *, unsigned int); static char *read_string (bfd *, char *, unsigned int *); static char *read_indirect_string (bfd *, char *, const struct comp_unit_head *, unsigned int *); static unsigned long read_unsigned_leb128 (bfd *, char *, unsigned int *); static long read_signed_leb128 (bfd *, char *, unsigned int *); static void set_cu_language (unsigned int, struct dwarf2_cu *); static struct attribute *dwarf2_attr (struct die_info *, unsigned int, struct dwarf2_cu *); static int die_is_declaration (struct die_info *, struct dwarf2_cu *cu); static struct die_info *die_specification (struct die_info *die, struct dwarf2_cu *); static void free_line_header (struct line_header *lh); static struct line_header *(dwarf_decode_line_header (unsigned int offset, bfd *abfd, struct dwarf2_cu *cu)); static void dwarf_decode_lines (struct line_header *, char *, bfd *, struct dwarf2_cu *); static void dwarf2_start_subfile (char *, char *); static struct symbol *new_symbol (struct die_info *, struct type *, struct dwarf2_cu *); static void dwarf2_const_value (struct attribute *, struct symbol *, struct dwarf2_cu *); static void dwarf2_const_value_data (struct attribute *attr, struct symbol *sym, int bits); static struct type *die_type (struct die_info *, struct dwarf2_cu *); static struct type *die_containing_type (struct die_info *, struct dwarf2_cu *); #if 0 static struct type *type_at_offset (unsigned int, struct objfile *); #endif static struct type *tag_type_to_type (struct die_info *, struct dwarf2_cu *); static void read_type_die (struct die_info *, struct dwarf2_cu *); static char *determine_prefix (struct die_info *die, struct dwarf2_cu *); static char *typename_concat (const char *prefix, const char *suffix); static void read_typedef (struct die_info *, struct dwarf2_cu *); static void read_base_type (struct die_info *, struct dwarf2_cu *); static void read_subrange_type (struct die_info *die, struct dwarf2_cu *cu); static void read_file_scope (struct die_info *, struct dwarf2_cu *); static void read_func_scope (struct die_info *, struct dwarf2_cu *); static void read_lexical_block_scope (struct die_info *, struct dwarf2_cu *); static int dwarf2_get_pc_bounds (struct die_info *, CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *); static void get_scope_pc_bounds (struct die_info *, CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *); static void dwarf2_add_field (struct field_info *, struct die_info *, struct dwarf2_cu *); static void dwarf2_attach_fields_to_type (struct field_info *, struct type *, struct dwarf2_cu *); static void dwarf2_add_member_fn (struct field_info *, struct die_info *, struct type *, struct dwarf2_cu *); static void dwarf2_attach_fn_fields_to_type (struct field_info *, struct type *, struct dwarf2_cu *); static void read_structure_type (struct die_info *, struct dwarf2_cu *); static void process_structure_scope (struct die_info *, struct dwarf2_cu *); static char *determine_class_name (struct die_info *die, struct dwarf2_cu *cu); static void read_common_block (struct die_info *, struct dwarf2_cu *); static void read_namespace (struct die_info *die, struct dwarf2_cu *); static const char *namespace_name (struct die_info *die, int *is_anonymous, struct dwarf2_cu *); static void read_enumeration_type (struct die_info *, struct dwarf2_cu *); static void process_enumeration_scope (struct die_info *, struct dwarf2_cu *); static struct type *dwarf_base_type (int, int, struct dwarf2_cu *); static CORE_ADDR decode_locdesc (struct dwarf_block *, struct dwarf2_cu *); static void read_array_type (struct die_info *, struct dwarf2_cu *); static void read_tag_pointer_type (struct die_info *, struct dwarf2_cu *); static void read_tag_unspecified_type (struct die_info *, struct dwarf2_cu *); static void read_tag_ptr_to_member_type (struct die_info *, struct dwarf2_cu *); static void read_tag_reference_type (struct die_info *, struct dwarf2_cu *); static void read_tag_const_type (struct die_info *, struct dwarf2_cu *); static void read_tag_volatile_type (struct die_info *, struct dwarf2_cu *); static void read_tag_restrict_type (struct die_info *, struct dwarf2_cu *); static void read_tag_string_type (struct die_info *, struct dwarf2_cu *); static void read_subroutine_type (struct die_info *, struct dwarf2_cu *); static struct die_info *read_comp_unit (char *, bfd *, struct dwarf2_cu *); static struct die_info *read_die_and_children (char *info_ptr, bfd *abfd, struct dwarf2_cu *, char **new_info_ptr, struct die_info *parent); static struct die_info *read_die_and_siblings (char *info_ptr, bfd *abfd, struct dwarf2_cu *, char **new_info_ptr, struct die_info *parent); static void free_die_list (struct die_info *); static struct cleanup *make_cleanup_free_die_list (struct die_info *); static void process_die (struct die_info *, struct dwarf2_cu *); static char *dwarf2_linkage_name (struct die_info *, struct dwarf2_cu *); static char *dwarf2_name (struct die_info *die, struct dwarf2_cu *); static struct die_info *dwarf2_extension (struct die_info *die, struct dwarf2_cu *); static char *dwarf_tag_name (unsigned int); static char *dwarf_attr_name (unsigned int); static char *dwarf_form_name (unsigned int); static char *dwarf_stack_op_name (unsigned int); static char *dwarf_bool_name (unsigned int); static char *dwarf_type_encoding_name (unsigned int); #if 0 static char *dwarf_cfi_name (unsigned int); struct die_info *copy_die (struct die_info *); #endif static struct die_info *sibling_die (struct die_info *); static void dump_die (struct die_info *); static void dump_die_list (struct die_info *); static void store_in_ref_table (unsigned int, struct die_info *); static void dwarf2_empty_hash_tables (void); static unsigned int dwarf2_get_ref_die_offset (struct attribute *, struct dwarf2_cu *); static int dwarf2_get_attr_constant_value (struct attribute *, int); static struct die_info *follow_die_ref (unsigned int); static struct type *dwarf2_fundamental_type (struct objfile *, int, struct dwarf2_cu *); /* memory allocation interface */ static void dwarf2_free_tmp_obstack (void *); static struct dwarf_block *dwarf_alloc_block (void); static struct abbrev_info *dwarf_alloc_abbrev (void); static struct die_info *dwarf_alloc_die (void); static void initialize_cu_func_list (struct dwarf2_cu *); static void add_to_cu_func_list (const char *, CORE_ADDR, CORE_ADDR, struct dwarf2_cu *); static void dwarf_decode_macros (struct line_header *, unsigned int, char *, bfd *, struct dwarf2_cu *); static int attr_form_is_block (struct attribute *); static void dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, struct dwarf2_cu *cu); /* Try to locate the sections we need for DWARF 2 debugging information and return true if we have enough to do something. */ int dwarf2_has_info (bfd *abfd) { dwarf_info_section = 0; dwarf_abbrev_section = 0; dwarf_line_section = 0; dwarf_str_section = 0; dwarf_macinfo_section = 0; dwarf_frame_section = 0; dwarf_eh_frame_section = 0; dwarf_ranges_section = 0; dwarf_loc_section = 0; bfd_map_over_sections (abfd, dwarf2_locate_sections, NULL); return (dwarf_info_section != NULL && dwarf_abbrev_section != NULL); } /* This function is mapped across the sections and remembers the offset and size of each of the debugging sections we are interested in. */ static void dwarf2_locate_sections (bfd *ignore_abfd, asection *sectp, void *ignore_ptr) { if (strcmp (sectp->name, INFO_SECTION) == 0) { dwarf_info_size = bfd_get_section_size (sectp); dwarf_info_section = sectp; } else if (strcmp (sectp->name, ABBREV_SECTION) == 0) { dwarf_abbrev_size = bfd_get_section_size (sectp); dwarf_abbrev_section = sectp; } else if (strcmp (sectp->name, LINE_SECTION) == 0) { dwarf_line_size = bfd_get_section_size (sectp); dwarf_line_section = sectp; } else if (strcmp (sectp->name, PUBNAMES_SECTION) == 0) { dwarf_pubnames_size = bfd_get_section_size (sectp); dwarf_pubnames_section = sectp; } else if (strcmp (sectp->name, ARANGES_SECTION) == 0) { dwarf_aranges_size = bfd_get_section_size (sectp); dwarf_aranges_section = sectp; } else if (strcmp (sectp->name, LOC_SECTION) == 0) { dwarf_loc_size = bfd_get_section_size (sectp); dwarf_loc_section = sectp; } else if (strcmp (sectp->name, MACINFO_SECTION) == 0) { dwarf_macinfo_size = bfd_get_section_size (sectp); dwarf_macinfo_section = sectp; } else if (strcmp (sectp->name, STR_SECTION) == 0) { dwarf_str_size = bfd_get_section_size (sectp); dwarf_str_section = sectp; } else if (strcmp (sectp->name, FRAME_SECTION) == 0) { dwarf_frame_size = bfd_get_section_size (sectp); dwarf_frame_section = sectp; } else if (strcmp (sectp->name, EH_FRAME_SECTION) == 0) { flagword aflag = bfd_get_section_flags (ignore_abfd, sectp); if (aflag & SEC_HAS_CONTENTS) { dwarf_eh_frame_size = bfd_get_section_size (sectp); dwarf_eh_frame_section = sectp; } } else if (strcmp (sectp->name, RANGES_SECTION) == 0) { dwarf_ranges_size = bfd_get_section_size (sectp); dwarf_ranges_section = sectp; } } /* Build a partial symbol table. */ void dwarf2_build_psymtabs (struct objfile *objfile, int mainline) { /* We definitely need the .debug_info and .debug_abbrev sections */ dwarf_info_buffer = dwarf2_read_section (objfile, dwarf_info_section); dwarf_abbrev_buffer = dwarf2_read_section (objfile, dwarf_abbrev_section); if (dwarf_line_section) dwarf_line_buffer = dwarf2_read_section (objfile, dwarf_line_section); else dwarf_line_buffer = NULL; if (dwarf_str_section) dwarf_str_buffer = dwarf2_read_section (objfile, dwarf_str_section); else dwarf_str_buffer = NULL; if (dwarf_macinfo_section) dwarf_macinfo_buffer = dwarf2_read_section (objfile, dwarf_macinfo_section); else dwarf_macinfo_buffer = NULL; if (dwarf_ranges_section) dwarf_ranges_buffer = dwarf2_read_section (objfile, dwarf_ranges_section); else dwarf_ranges_buffer = NULL; if (dwarf_loc_section) dwarf_loc_buffer = dwarf2_read_section (objfile, dwarf_loc_section); else dwarf_loc_buffer = NULL; if (mainline || (objfile->global_psymbols.size == 0 && objfile->static_psymbols.size == 0)) { init_psymbol_list (objfile, 1024); } #if 0 if (dwarf_aranges_offset && dwarf_pubnames_offset) { /* Things are significantly easier if we have .debug_aranges and .debug_pubnames sections */ dwarf2_build_psymtabs_easy (objfile, mainline); } else #endif /* only test this case for now */ { /* In this case we have to work a bit harder */ dwarf2_build_psymtabs_hard (objfile, mainline); } } #if 0 /* Build the partial symbol table from the information in the .debug_pubnames and .debug_aranges sections. */ static void dwarf2_build_psymtabs_easy (struct objfile *objfile, int mainline) { bfd *abfd = objfile->obfd; char *aranges_buffer, *pubnames_buffer; char *aranges_ptr, *pubnames_ptr; unsigned int entry_length, version, info_offset, info_size; pubnames_buffer = dwarf2_read_section (objfile, dwarf_pubnames_section); pubnames_ptr = pubnames_buffer; while ((pubnames_ptr - pubnames_buffer) < dwarf_pubnames_size) { struct comp_unit_head cu_header; int bytes_read; entry_length = read_initial_length (abfd, pubnames_ptr, &cu_header, &bytes_read); pubnames_ptr += bytes_read; version = read_1_byte (abfd, pubnames_ptr); pubnames_ptr += 1; info_offset = read_4_bytes (abfd, pubnames_ptr); pubnames_ptr += 4; info_size = read_4_bytes (abfd, pubnames_ptr); pubnames_ptr += 4; } aranges_buffer = dwarf2_read_section (objfile, dwarf_aranges_section); } #endif /* Read in the comp unit header information from the debug_info at info_ptr. */ static char * read_comp_unit_head (struct comp_unit_head *cu_header, char *info_ptr, bfd *abfd) { int signed_addr; int bytes_read; cu_header->length = read_initial_length (abfd, info_ptr, cu_header, &bytes_read); info_ptr += bytes_read; cu_header->version = read_2_bytes (abfd, info_ptr); info_ptr += 2; cu_header->abbrev_offset = read_offset (abfd, info_ptr, cu_header, &bytes_read); info_ptr += bytes_read; cu_header->addr_size = read_1_byte (abfd, info_ptr); info_ptr += 1; signed_addr = bfd_get_sign_extend_vma (abfd); if (signed_addr < 0) internal_error (__FILE__, __LINE__, "read_comp_unit_head: dwarf from non elf file"); cu_header->signed_addr_p = signed_addr; return info_ptr; } /* Build the partial symbol table by doing a quick pass through the .debug_info and .debug_abbrev sections. */ static void dwarf2_build_psymtabs_hard (struct objfile *objfile, int mainline) { /* Instead of reading this into a big buffer, we should probably use mmap() on architectures that support it. (FIXME) */ bfd *abfd = objfile->obfd; char *info_ptr, *abbrev_ptr; char *beg_of_comp_unit; struct partial_die_info comp_unit_die; struct partial_symtab *pst; struct cleanup *back_to; CORE_ADDR lowpc, highpc, baseaddr; info_ptr = dwarf_info_buffer; abbrev_ptr = dwarf_abbrev_buffer; /* We use dwarf2_tmp_obstack for objects that don't need to survive the partial symbol scan, like attribute values. We could reduce our peak memory consumption during partial symbol table construction by freeing stuff from this obstack more often --- say, after processing each compilation unit, or each die --- but it turns out that this saves almost nothing. For an executable with 11Mb of Dwarf 2 data, I found about 64k allocated on dwarf2_tmp_obstack. Some investigation showed: 1) 69% of the attributes used forms DW_FORM_addr, DW_FORM_data*, DW_FORM_flag, DW_FORM_[su]data, and DW_FORM_ref*. These are all fixed-length values not requiring dynamic allocation. 2) 30% of the attributes used the form DW_FORM_string. For DW_FORM_string, read_attribute simply hands back a pointer to the null-terminated string in dwarf_info_buffer, so no dynamic allocation is needed there either. 3) The remaining 1% of the attributes all used DW_FORM_block1. 75% of those were DW_AT_frame_base location lists for functions; the rest were DW_AT_location attributes, probably for the global variables. Anyway, what this all means is that the memory the dwarf2 reader uses as temporary space reading partial symbols is about 0.5% as much as we use for dwarf_*_buffer. That's noise. */ obstack_init (&dwarf2_tmp_obstack); back_to = make_cleanup (dwarf2_free_tmp_obstack, NULL); /* Since the objects we're extracting from dwarf_info_buffer vary in length, only the individual functions to extract them (like read_comp_unit_head and read_partial_die) can really know whether the buffer is large enough to hold another complete object. At the moment, they don't actually check that. If dwarf_info_buffer holds just one extra byte after the last compilation unit's dies, then read_comp_unit_head will happily read off the end of the buffer. read_partial_die is similarly casual. Those functions should be fixed. For this loop condition, simply checking whether there's any data left at all should be sufficient. */ while (info_ptr < dwarf_info_buffer + dwarf_info_size) { struct dwarf2_cu cu; beg_of_comp_unit = info_ptr; cu.objfile = objfile; info_ptr = read_comp_unit_head (&cu.header, info_ptr, abfd); if (cu.header.version != 2) { error ("Dwarf Error: wrong version in compilation unit header (is %d, should be %d) [in module %s]", cu.header.version, 2, bfd_get_filename (abfd)); return; } if (cu.header.abbrev_offset >= dwarf_abbrev_size) { error ("Dwarf Error: bad offset (0x%lx) in compilation unit header (offset 0x%lx + 6) [in module %s]", (long) cu.header.abbrev_offset, (long) (beg_of_comp_unit - dwarf_info_buffer), bfd_get_filename (abfd)); return; } if (beg_of_comp_unit + cu.header.length + cu.header.initial_length_size > dwarf_info_buffer + dwarf_info_size) { error ("Dwarf Error: bad length (0x%lx) in compilation unit header (offset 0x%lx + 0) [in module %s]", (long) cu.header.length, (long) (beg_of_comp_unit - dwarf_info_buffer), bfd_get_filename (abfd)); return; } /* Complete the cu_header */ cu.header.offset = beg_of_comp_unit - dwarf_info_buffer; cu.header.first_die_ptr = info_ptr; cu.header.cu_head_ptr = beg_of_comp_unit; cu.list_in_scope = &file_symbols; /* Read the abbrevs for this compilation unit into a table */ dwarf2_read_abbrevs (abfd, &cu); make_cleanup (dwarf2_empty_abbrev_table, cu.header.dwarf2_abbrevs); /* Read the compilation unit die */ info_ptr = read_partial_die (&comp_unit_die, abfd, info_ptr, &cu); /* Set the language we're debugging */ set_cu_language (comp_unit_die.language, &cu); /* Allocate a new partial symbol table structure */ pst = start_psymtab_common (objfile, objfile->section_offsets, comp_unit_die.name ? comp_unit_die.name : "", comp_unit_die.lowpc, objfile->global_psymbols.next, objfile->static_psymbols.next); pst->read_symtab_private = (char *) obstack_alloc (&objfile->objfile_obstack, sizeof (struct dwarf2_pinfo)); DWARF_INFO_BUFFER (pst) = dwarf_info_buffer; DWARF_INFO_OFFSET (pst) = beg_of_comp_unit - dwarf_info_buffer; DWARF_ABBREV_BUFFER (pst) = dwarf_abbrev_buffer; DWARF_ABBREV_SIZE (pst) = dwarf_abbrev_size; DWARF_LINE_BUFFER (pst) = dwarf_line_buffer; DWARF_LINE_SIZE (pst) = dwarf_line_size; DWARF_STR_BUFFER (pst) = dwarf_str_buffer; DWARF_STR_SIZE (pst) = dwarf_str_size; DWARF_MACINFO_BUFFER (pst) = dwarf_macinfo_buffer; DWARF_MACINFO_SIZE (pst) = dwarf_macinfo_size; DWARF_RANGES_BUFFER (pst) = dwarf_ranges_buffer; DWARF_RANGES_SIZE (pst) = dwarf_ranges_size; DWARF_LOC_BUFFER (pst) = dwarf_loc_buffer; DWARF_LOC_SIZE (pst) = dwarf_loc_size; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); /* Store the function that reads in the rest of the symbol table */ pst->read_symtab = dwarf2_psymtab_to_symtab; /* Check if comp unit has_children. If so, read the rest of the partial symbols from this comp unit. If not, there's no more debug_info for this comp unit. */ if (comp_unit_die.has_children) { lowpc = ((CORE_ADDR) -1); highpc = ((CORE_ADDR) 0); info_ptr = scan_partial_symbols (info_ptr, &lowpc, &highpc, &cu, NULL); /* If we didn't find a lowpc, set it to highpc to avoid complaints from `maint check'. */ if (lowpc == ((CORE_ADDR) -1)) lowpc = highpc; /* If the compilation unit didn't have an explicit address range, then use the information extracted from its child dies. */ if (! comp_unit_die.has_pc_info) { comp_unit_die.lowpc = lowpc; comp_unit_die.highpc = highpc; } } pst->textlow = comp_unit_die.lowpc + baseaddr; pst->texthigh = comp_unit_die.highpc + baseaddr; pst->n_global_syms = objfile->global_psymbols.next - (objfile->global_psymbols.list + pst->globals_offset); pst->n_static_syms = objfile->static_psymbols.next - (objfile->static_psymbols.list + pst->statics_offset); sort_pst_symbols (pst); /* If there is already a psymtab or symtab for a file of this name, remove it. (If there is a symtab, more drastic things also happen.) This happens in VxWorks. */ free_named_symtabs (pst->filename); info_ptr = beg_of_comp_unit + cu.header.length + cu.header.initial_length_size; } do_cleanups (back_to); } /* Read in all interesting dies to the end of the compilation unit or to the end of the current namespace. NAMESPACE is NULL if we haven't yet encountered any DW_TAG_namespace entries; otherwise, it's the name of the current namespace. In particular, it's the empty string if we're currently in the global namespace but have previously encountered a DW_TAG_namespace. */ static char * scan_partial_symbols (char *info_ptr, CORE_ADDR *lowpc, CORE_ADDR *highpc, struct dwarf2_cu *cu, const char *namespace) { struct objfile *objfile = cu->objfile; bfd *abfd = objfile->obfd; struct partial_die_info pdi; /* Now, march along the PDI's, descending into ones which have interesting children but skipping the children of the other ones, until we reach the end of the compilation unit. */ while (1) { /* This flag tells whether or not info_ptr has gotten updated inside the loop. */ int info_ptr_updated = 0; info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu); /* Anonymous namespaces have no name but have interesting children, so we need to look at them. Ditto for anonymous enums. */ if (pdi.name != NULL || pdi.tag == DW_TAG_namespace || pdi.tag == DW_TAG_enumeration_type) { switch (pdi.tag) { case DW_TAG_subprogram: if (pdi.has_pc_info) { if (pdi.lowpc < *lowpc) { *lowpc = pdi.lowpc; } if (pdi.highpc > *highpc) { *highpc = pdi.highpc; } if (!pdi.is_declaration) { add_partial_symbol (&pdi, cu, namespace); } } break; case DW_TAG_variable: case DW_TAG_typedef: case DW_TAG_union_type: if (!pdi.is_declaration) { add_partial_symbol (&pdi, cu, namespace); } break; case DW_TAG_class_type: case DW_TAG_structure_type: if (!pdi.is_declaration) { info_ptr = add_partial_structure (&pdi, info_ptr, cu, namespace); info_ptr_updated = 1; } break; case DW_TAG_enumeration_type: if (!pdi.is_declaration) { info_ptr = add_partial_enumeration (&pdi, info_ptr, cu, namespace); info_ptr_updated = 1; } break; case DW_TAG_base_type: case DW_TAG_subrange_type: /* File scope base type definitions are added to the partial symbol table. */ add_partial_symbol (&pdi, cu, namespace); break; case DW_TAG_namespace: /* We've hit a DW_TAG_namespace entry, so we know this file has been compiled using a compiler that generates them; update NAMESPACE to reflect that. */ if (namespace == NULL) namespace = ""; info_ptr = add_partial_namespace (&pdi, info_ptr, lowpc, highpc, cu, namespace); info_ptr_updated = 1; break; default: break; } } if (pdi.tag == 0) break; /* If the die has a sibling, skip to the sibling, unless another function has already updated info_ptr for us. */ /* NOTE: carlton/2003-06-16: This is a bit hackish, but whether or not we want to update this depends on enough stuff (not only pdi.tag but also whether or not pdi.name is NULL) that this seems like the easiest way to handle the issue. */ if (!info_ptr_updated) info_ptr = locate_pdi_sibling (&pdi, info_ptr, abfd, cu); } return info_ptr; } static void add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu, const char *namespace) { struct objfile *objfile = cu->objfile; CORE_ADDR addr = 0; char *actual_name = pdi->name; const struct partial_symbol *psym = NULL; CORE_ADDR baseaddr; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); /* If we're not in the global namespace and if the namespace name isn't encoded in a mangled actual_name, add it. */ if (pdi_needs_namespace (pdi->tag, namespace)) { actual_name = alloca (strlen (pdi->name) + 2 + strlen (namespace) + 1); strcpy (actual_name, namespace); strcat (actual_name, "::"); strcat (actual_name, pdi->name); } switch (pdi->tag) { case DW_TAG_subprogram: if (pdi->is_external) { /*prim_record_minimal_symbol (actual_name, pdi->lowpc + baseaddr, mst_text, objfile); */ psym = add_psymbol_to_list (actual_name, strlen (actual_name), VAR_DOMAIN, LOC_BLOCK, &objfile->global_psymbols, 0, pdi->lowpc + baseaddr, cu->language, objfile); } else { /*prim_record_minimal_symbol (actual_name, pdi->lowpc + baseaddr, mst_file_text, objfile); */ psym = add_psymbol_to_list (actual_name, strlen (actual_name), VAR_DOMAIN, LOC_BLOCK, &objfile->static_psymbols, 0, pdi->lowpc + baseaddr, cu->language, objfile); } break; case DW_TAG_variable: if (pdi->is_external) { /* Global Variable. Don't enter into the minimal symbol tables as there is a minimal symbol table entry from the ELF symbols already. Enter into partial symbol table if it has a location descriptor or a type. If the location descriptor is missing, new_symbol will create a LOC_UNRESOLVED symbol, the address of the variable will then be determined from the minimal symbol table whenever the variable is referenced. The address for the partial symbol table entry is not used by GDB, but it comes in handy for debugging partial symbol table building. */ if (pdi->locdesc) addr = decode_locdesc (pdi->locdesc, cu); if (pdi->locdesc || pdi->has_type) psym = add_psymbol_to_list (actual_name, strlen (actual_name), VAR_DOMAIN, LOC_STATIC, &objfile->global_psymbols, 0, addr + baseaddr, cu->language, objfile); } else { /* Static Variable. Skip symbols without location descriptors. */ if (pdi->locdesc == NULL) return; addr = decode_locdesc (pdi->locdesc, cu); /*prim_record_minimal_symbol (actual_name, addr + baseaddr, mst_file_data, objfile); */ psym = add_psymbol_to_list (actual_name, strlen (actual_name), VAR_DOMAIN, LOC_STATIC, &objfile->static_psymbols, 0, addr + baseaddr, cu->language, objfile); } break; case DW_TAG_typedef: case DW_TAG_base_type: case DW_TAG_subrange_type: add_psymbol_to_list (actual_name, strlen (actual_name), VAR_DOMAIN, LOC_TYPEDEF, &objfile->static_psymbols, 0, (CORE_ADDR) 0, cu->language, objfile); break; case DW_TAG_class_type: case DW_TAG_structure_type: case DW_TAG_union_type: case DW_TAG_enumeration_type: /* Skip aggregate types without children, these are external references. */ /* NOTE: carlton/2003-10-07: See comment in new_symbol about static vs. global. */ if (pdi->has_children == 0) return; add_psymbol_to_list (actual_name, strlen (actual_name), STRUCT_DOMAIN, LOC_TYPEDEF, cu->language == language_cplus ? &objfile->global_psymbols : &objfile->static_psymbols, 0, (CORE_ADDR) 0, cu->language, objfile); if (cu->language == language_cplus) { /* For C++, these implicitly act as typedefs as well. */ add_psymbol_to_list (actual_name, strlen (actual_name), VAR_DOMAIN, LOC_TYPEDEF, &objfile->global_psymbols, 0, (CORE_ADDR) 0, cu->language, objfile); } break; case DW_TAG_enumerator: add_psymbol_to_list (actual_name, strlen (actual_name), VAR_DOMAIN, LOC_CONST, cu->language == language_cplus ? &objfile->global_psymbols : &objfile->static_psymbols, 0, (CORE_ADDR) 0, cu->language, objfile); break; default: break; } /* Check to see if we should scan the name for possible namespace info. Only do this if this is C++, if we don't have namespace debugging info in the file, if the psym is of an appropriate type (otherwise we'll have psym == NULL), and if we actually had a mangled name to begin with. */ if (cu->language == language_cplus && namespace == NULL && psym != NULL && SYMBOL_CPLUS_DEMANGLED_NAME (psym) != NULL) cp_check_possible_namespace_symbols (SYMBOL_CPLUS_DEMANGLED_NAME (psym), objfile); } /* Determine whether a die of type TAG living in the C++ namespace NAMESPACE needs to have the name of the namespace prepended to the name listed in the die. */ static int pdi_needs_namespace (enum dwarf_tag tag, const char *namespace) { if (namespace == NULL || namespace[0] == '\0') return 0; switch (tag) { case DW_TAG_typedef: case DW_TAG_class_type: case DW_TAG_structure_type: case DW_TAG_union_type: case DW_TAG_enumeration_type: case DW_TAG_enumerator: return 1; default: return 0; } } /* Read a partial die corresponding to a namespace; also, add a symbol corresponding to that namespace to the symbol table. NAMESPACE is the name of the enclosing namespace. */ static char * add_partial_namespace (struct partial_die_info *pdi, char *info_ptr, CORE_ADDR *lowpc, CORE_ADDR *highpc, struct dwarf2_cu *cu, const char *namespace) { struct objfile *objfile = cu->objfile; const char *new_name = pdi->name; char *full_name; /* Calculate the full name of the namespace that we just entered. */ if (new_name == NULL) new_name = "(anonymous namespace)"; full_name = alloca (strlen (namespace) + 2 + strlen (new_name) + 1); strcpy (full_name, namespace); if (*namespace != '\0') strcat (full_name, "::"); strcat (full_name, new_name); /* FIXME: carlton/2003-10-07: We can't just replace this by a call to add_partial_symbol, because we don't have a way to pass in the full name to that function; that might be a flaw in add_partial_symbol's interface. */ add_psymbol_to_list (full_name, strlen (full_name), VAR_DOMAIN, LOC_TYPEDEF, &objfile->global_psymbols, 0, 0, cu->language, objfile); /* Now scan partial symbols in that namespace. */ if (pdi->has_children) info_ptr = scan_partial_symbols (info_ptr, lowpc, highpc, cu, full_name); return info_ptr; } /* Read a partial die corresponding to a class or structure. */ static char * add_partial_structure (struct partial_die_info *struct_pdi, char *info_ptr, struct dwarf2_cu *cu, const char *namespace) { bfd *abfd = cu->objfile->obfd; char *actual_class_name = NULL; if (cu->language == language_cplus && (namespace == NULL || namespace[0] == '\0') && struct_pdi->name != NULL && struct_pdi->has_children) { /* See if we can figure out if the class lives in a namespace (or is nested within another class.) We do this by looking for a member function; its demangled name will contain namespace info, if there is any. */ /* NOTE: carlton/2003-10-07: Getting the info this way changes what template types look like, because the demangler frequently doesn't give the same name as the debug info. We could fix this by only using the demangled name to get the prefix (but see comment in read_structure_type). */ /* FIXME: carlton/2004-01-23: If NAMESPACE equals "", we have the appropriate debug information, so it would be nice to be able to avoid this hack. But NAMESPACE may not be the namespace where this class was defined: NAMESPACE reflects where STRUCT_PDI occurs in the tree of dies, but because of DW_AT_specification, that may not actually tell us where the class is defined. (See the comment in read_func_scope for an example of how this could occur.) Unfortunately, our current partial symtab data structures are completely unable to deal with DW_AT_specification. So, for now, the best thing to do is to get nesting information from places other than the tree structure of dies if there's any chance that a DW_AT_specification is involved. :-( */ char *next_child = info_ptr; while (1) { struct partial_die_info child_pdi; next_child = read_partial_die (&child_pdi, abfd, next_child, cu); if (!child_pdi.tag) break; if (child_pdi.tag == DW_TAG_subprogram) { actual_class_name = class_name_from_physname (child_pdi.name); if (actual_class_name != NULL) struct_pdi->name = actual_class_name; break; } else { next_child = locate_pdi_sibling (&child_pdi, next_child, abfd, cu); } } } add_partial_symbol (struct_pdi, cu, namespace); xfree (actual_class_name); return locate_pdi_sibling (struct_pdi, info_ptr, abfd, cu); } /* Read a partial die corresponding to an enumeration type. */ static char * add_partial_enumeration (struct partial_die_info *enum_pdi, char *info_ptr, struct dwarf2_cu *cu, const char *namespace) { struct objfile *objfile = cu->objfile; bfd *abfd = objfile->obfd; struct partial_die_info pdi; if (enum_pdi->name != NULL) add_partial_symbol (enum_pdi, cu, namespace); while (1) { info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu); if (pdi.tag == 0) break; if (pdi.tag != DW_TAG_enumerator || pdi.name == NULL) complaint (&symfile_complaints, "malformed enumerator DIE ignored"); else add_partial_symbol (&pdi, cu, namespace); } return info_ptr; } /* Locate ORIG_PDI's sibling; INFO_PTR should point to the next DIE after ORIG_PDI. */ static char * locate_pdi_sibling (struct partial_die_info *orig_pdi, char *info_ptr, bfd *abfd, struct dwarf2_cu *cu) { /* Do we know the sibling already? */ if (orig_pdi->sibling) return orig_pdi->sibling; /* Are there any children to deal with? */ if (!orig_pdi->has_children) return info_ptr; /* Okay, we don't know the sibling, but we have children that we want to skip. So read children until we run into one without a tag; return whatever follows it. */ while (1) { struct partial_die_info pdi; info_ptr = read_partial_die (&pdi, abfd, info_ptr, cu); if (pdi.tag == 0) return info_ptr; else info_ptr = locate_pdi_sibling (&pdi, info_ptr, abfd, cu); } } /* Expand this partial symbol table into a full symbol table. */ static void dwarf2_psymtab_to_symtab (struct partial_symtab *pst) { /* FIXME: This is barely more than a stub. */ if (pst != NULL) { if (pst->readin) { warning ("bug: psymtab for %s is already read in.", pst->filename); } else { if (info_verbose) { printf_filtered ("Reading in symbols for %s...", pst->filename); gdb_flush (gdb_stdout); } psymtab_to_symtab_1 (pst); /* Finish up the debug error message. */ if (info_verbose) printf_filtered ("done.\n"); } } } static void psymtab_to_symtab_1 (struct partial_symtab *pst) { struct objfile *objfile = pst->objfile; bfd *abfd = objfile->obfd; struct dwarf2_cu cu; struct die_info *dies; unsigned long offset; CORE_ADDR lowpc, highpc; struct die_info *child_die; char *info_ptr; struct symtab *symtab; struct cleanup *back_to; struct attribute *attr; CORE_ADDR baseaddr; /* Set local variables from the partial symbol table info. */ offset = DWARF_INFO_OFFSET (pst); dwarf_info_buffer = DWARF_INFO_BUFFER (pst); dwarf_abbrev_buffer = DWARF_ABBREV_BUFFER (pst); dwarf_abbrev_size = DWARF_ABBREV_SIZE (pst); dwarf_line_buffer = DWARF_LINE_BUFFER (pst); dwarf_line_size = DWARF_LINE_SIZE (pst); dwarf_str_buffer = DWARF_STR_BUFFER (pst); dwarf_str_size = DWARF_STR_SIZE (pst); dwarf_macinfo_buffer = DWARF_MACINFO_BUFFER (pst); dwarf_macinfo_size = DWARF_MACINFO_SIZE (pst); dwarf_ranges_buffer = DWARF_RANGES_BUFFER (pst); dwarf_ranges_size = DWARF_RANGES_SIZE (pst); dwarf_loc_buffer = DWARF_LOC_BUFFER (pst); dwarf_loc_size = DWARF_LOC_SIZE (pst); info_ptr = dwarf_info_buffer + offset; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); /* We're in the global namespace. */ processing_current_prefix = ""; obstack_init (&dwarf2_tmp_obstack); back_to = make_cleanup (dwarf2_free_tmp_obstack, NULL); buildsym_init (); make_cleanup (really_free_pendings, NULL); cu.objfile = objfile; /* read in the comp_unit header */ info_ptr = read_comp_unit_head (&cu.header, info_ptr, abfd); /* Read the abbrevs for this compilation unit */ dwarf2_read_abbrevs (abfd, &cu); make_cleanup (dwarf2_empty_abbrev_table, cu.header.dwarf2_abbrevs); cu.header.offset = offset; cu.list_in_scope = &file_symbols; dies = read_comp_unit (info_ptr, abfd, &cu); make_cleanup_free_die_list (dies); /* Find the base address of the compilation unit for range lists and location lists. It will normally be specified by DW_AT_low_pc. In DWARF-3 draft 4, the base address could be overridden by DW_AT_entry_pc. It's been removed, but GCC still uses this for compilation units with discontinuous ranges. */ cu.header.base_known = 0; cu.header.base_address = 0; attr = dwarf2_attr (dies, DW_AT_entry_pc, &cu); if (attr) { cu.header.base_address = DW_ADDR (attr); cu.header.base_known = 1; } else { attr = dwarf2_attr (dies, DW_AT_low_pc, &cu); if (attr) { cu.header.base_address = DW_ADDR (attr); cu.header.base_known = 1; } } /* Do line number decoding in read_file_scope () */ process_die (dies, &cu); /* Some compilers don't define a DW_AT_high_pc attribute for the compilation unit. If the DW_AT_high_pc is missing, synthesize it, by scanning the DIE's below the compilation unit. */ get_scope_pc_bounds (dies, &lowpc, &highpc, &cu); symtab = end_symtab (highpc + baseaddr, objfile, SECT_OFF_TEXT (objfile)); /* Set symtab language to language from DW_AT_language. If the compilation is from a C file generated by language preprocessors, do not set the language if it was already deduced by start_subfile. */ if (symtab != NULL && !(cu.language == language_c && symtab->language != language_c)) { symtab->language = cu.language; } pst->symtab = symtab; pst->readin = 1; do_cleanups (back_to); } /* Process a die and its children. */ static void process_die (struct die_info *die, struct dwarf2_cu *cu) { switch (die->tag) { case DW_TAG_padding: break; case DW_TAG_compile_unit: read_file_scope (die, cu); break; case DW_TAG_subprogram: read_subroutine_type (die, cu); read_func_scope (die, cu); break; case DW_TAG_inlined_subroutine: /* FIXME: These are ignored for now. They could be used to set breakpoints on all inlined instances of a function and make GDB `next' properly over inlined functions. */ break; case DW_TAG_lexical_block: case DW_TAG_try_block: case DW_TAG_catch_block: read_lexical_block_scope (die, cu); break; case DW_TAG_class_type: case DW_TAG_structure_type: case DW_TAG_union_type: read_structure_type (die, cu); process_structure_scope (die, cu); break; case DW_TAG_enumeration_type: read_enumeration_type (die, cu); process_enumeration_scope (die, cu); break; /* FIXME drow/2004-03-14: These initialize die->type, but do not create a symbol or process any children. Therefore it doesn't do anything that won't be done on-demand by read_type_die. */ case DW_TAG_subroutine_type: read_subroutine_type (die, cu); break; case DW_TAG_array_type: read_array_type (die, cu); break; case DW_TAG_pointer_type: read_tag_pointer_type (die, cu); break; case DW_TAG_ptr_to_member_type: read_tag_ptr_to_member_type (die, cu); break; case DW_TAG_reference_type: case DW_TAG_rvalue_reference_type: read_tag_reference_type (die, cu); break; case DW_TAG_string_type: read_tag_string_type (die, cu); break; /* END FIXME */ case DW_TAG_base_type: read_base_type (die, cu); /* Add a typedef symbol for the type definition, if it has a DW_AT_name. */ new_symbol (die, die->type, cu); break; case DW_TAG_subrange_type: read_subrange_type (die, cu); /* Add a typedef symbol for the type definition, if it has a DW_AT_name. */ new_symbol (die, die->type, cu); break; case DW_TAG_common_block: read_common_block (die, cu); break; case DW_TAG_common_inclusion: break; case DW_TAG_namespace: processing_has_namespace_info = 1; read_namespace (die, cu); break; case DW_TAG_imported_declaration: case DW_TAG_imported_module: /* FIXME: carlton/2002-10-16: Eventually, we should use the information contained in these. DW_TAG_imported_declaration dies shouldn't have children; DW_TAG_imported_module dies shouldn't in the C++ case, but conceivably could in the Fortran case, so we'll have to replace this gdb_assert if Fortran compilers start generating that info. */ processing_has_namespace_info = 1; gdb_assert (die->child == NULL); break; default: new_symbol (die, NULL, cu); break; } } static void initialize_cu_func_list (struct dwarf2_cu *cu) { cu->first_fn = cu->last_fn = cu->cached_fn = NULL; } static void read_file_scope (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct comp_unit_head *cu_header = &cu->header; struct cleanup *back_to = make_cleanup (null_cleanup, 0); CORE_ADDR lowpc = ((CORE_ADDR) -1); CORE_ADDR highpc = ((CORE_ADDR) 0); struct attribute *attr; char *name = ""; char *comp_dir = NULL; struct die_info *child_die; bfd *abfd = objfile->obfd; struct line_header *line_header = 0; CORE_ADDR baseaddr; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); get_scope_pc_bounds (die, &lowpc, &highpc, cu); /* If we didn't find a lowpc, set it to highpc to avoid complaints from finish_block. */ if (lowpc == ((CORE_ADDR) -1)) lowpc = highpc; lowpc += baseaddr; highpc += baseaddr; attr = dwarf2_attr (die, DW_AT_name, cu); if (attr) { name = DW_STRING (attr); } attr = dwarf2_attr (die, DW_AT_comp_dir, cu); if (attr) { comp_dir = DW_STRING (attr); if (comp_dir) { /* Irix 6.2 native cc prepends .: to the compilation directory, get rid of it. */ char *cp = strchr (comp_dir, ':'); if (cp && cp != comp_dir && cp[-1] == '.' && cp[1] == '/') comp_dir = cp + 1; } } if (objfile->ei.entry_point >= lowpc && objfile->ei.entry_point < highpc) { objfile->ei.deprecated_entry_file_lowpc = lowpc; objfile->ei.deprecated_entry_file_highpc = highpc; } attr = dwarf2_attr (die, DW_AT_language, cu); if (attr) { set_cu_language (DW_UNSND (attr), cu); } /* We assume that we're processing GCC output. */ processing_gcc_compilation = 2; #if 0 /* FIXME:Do something here. */ if (dip->at_producer != NULL) { handle_producer (dip->at_producer); } #endif /* The compilation unit may be in a different language or objfile, zero out all remembered fundamental types. */ memset (cu->ftypes, 0, FT_NUM_MEMBERS * sizeof (struct type *)); start_symtab (name, comp_dir, lowpc); record_debugformat ("DWARF 2"); initialize_cu_func_list (cu); /* Process all dies in compilation unit. */ if (die->child != NULL) { child_die = die->child; while (child_die && child_die->tag) { process_die (child_die, cu); child_die = sibling_die (child_die); } } /* Decode line number information if present. */ attr = dwarf2_attr (die, DW_AT_stmt_list, cu); if (attr) { unsigned int line_offset = DW_UNSND (attr); line_header = dwarf_decode_line_header (line_offset, abfd, cu); if (line_header) { make_cleanup ((make_cleanup_ftype *) free_line_header, (void *) line_header); dwarf_decode_lines (line_header, comp_dir, abfd, cu); } } /* Decode macro information, if present. Dwarf 2 macro information refers to information in the line number info statement program header, so we can only read it if we've read the header successfully. */ attr = dwarf2_attr (die, DW_AT_macro_info, cu); if (attr && line_header) { unsigned int macro_offset = DW_UNSND (attr); dwarf_decode_macros (line_header, macro_offset, comp_dir, abfd, cu); } do_cleanups (back_to); } static void add_to_cu_func_list (const char *name, CORE_ADDR lowpc, CORE_ADDR highpc, struct dwarf2_cu *cu) { struct function_range *thisfn; thisfn = (struct function_range *) obstack_alloc (&dwarf2_tmp_obstack, sizeof (struct function_range)); thisfn->name = name; thisfn->lowpc = lowpc; thisfn->highpc = highpc; thisfn->seen_line = 0; thisfn->next = NULL; if (cu->last_fn == NULL) cu->first_fn = thisfn; else cu->last_fn->next = thisfn; cu->last_fn = thisfn; } static void read_func_scope (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct context_stack *new; CORE_ADDR lowpc; CORE_ADDR highpc; struct die_info *child_die; struct attribute *attr; char *name; const char *previous_prefix = processing_current_prefix; struct cleanup *back_to = NULL; CORE_ADDR baseaddr; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); name = dwarf2_linkage_name (die, cu); /* Ignore functions with missing or empty names and functions with missing or invalid low and high pc attributes. */ if (name == NULL || !dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu)) return; if (cu->language == language_cplus) { struct die_info *spec_die = die_specification (die, cu); /* NOTE: carlton/2004-01-23: We have to be careful in the presence of DW_AT_specification. For example, with GCC 3.4, given the code namespace N { void foo() { // Definition of N::foo. } } then we'll have a tree of DIEs like this: 1: DW_TAG_compile_unit 2: DW_TAG_namespace // N 3: DW_TAG_subprogram // declaration of N::foo 4: DW_TAG_subprogram // definition of N::foo DW_AT_specification // refers to die #3 Thus, when processing die #4, we have to pretend that we're in the context of its DW_AT_specification, namely the contex of die #3. */ if (spec_die != NULL) { char *specification_prefix = determine_prefix (spec_die, cu); processing_current_prefix = specification_prefix; back_to = make_cleanup (xfree, specification_prefix); } } lowpc += baseaddr; highpc += baseaddr; /* Record the function range for dwarf_decode_lines. */ add_to_cu_func_list (name, lowpc, highpc, cu); if (objfile->ei.entry_point >= lowpc && objfile->ei.entry_point < highpc) { objfile->ei.entry_func_lowpc = lowpc; objfile->ei.entry_func_highpc = highpc; } new = push_context (0, lowpc); new->name = new_symbol (die, die->type, cu); /* If there is a location expression for DW_AT_frame_base, record it. */ attr = dwarf2_attr (die, DW_AT_frame_base, cu); if (attr) /* FIXME: cagney/2004-01-26: The DW_AT_frame_base's location expression is being recorded directly in the function's symbol and not in a separate frame-base object. I guess this hack is to avoid adding some sort of frame-base adjunct/annex to the function's symbol :-(. The problem with doing this is that it results in a function symbol with a location expression that has nothing to do with the location of the function, ouch! The relationship should be: a function's symbol has-a frame base; a frame-base has-a location expression. */ dwarf2_symbol_mark_computed (attr, new->name, cu); cu->list_in_scope = &local_symbols; if (die->child != NULL) { child_die = die->child; while (child_die && child_die->tag) { process_die (child_die, cu); child_die = sibling_die (child_die); } } new = pop_context (); /* Make a block for the local symbols within. */ finish_block (new->name, &local_symbols, new->old_blocks, lowpc, highpc, objfile); /* In C++, we can have functions nested inside functions (e.g., when a function declares a class that has methods). This means that when we finish processing a function scope, we may need to go back to building a containing block's symbol lists. */ local_symbols = new->locals; param_symbols = new->params; /* If we've finished processing a top-level function, subsequent symbols go in the file symbol list. */ if (outermost_context_p ()) cu->list_in_scope = &file_symbols; processing_current_prefix = previous_prefix; if (back_to != NULL) do_cleanups (back_to); } /* Process all the DIES contained within a lexical block scope. Start a new scope, process the dies, and then close the scope. */ static void read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct context_stack *new; CORE_ADDR lowpc, highpc; struct die_info *child_die; CORE_ADDR baseaddr; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); /* Ignore blocks with missing or invalid low and high pc attributes. */ /* ??? Perhaps consider discontiguous blocks defined by DW_AT_ranges as multiple lexical blocks? Handling children in a sane way would be nasty. Might be easier to properly extend generic blocks to describe ranges. */ if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu)) return; lowpc += baseaddr; highpc += baseaddr; push_context (0, lowpc); if (die->child != NULL) { child_die = die->child; while (child_die && child_die->tag) { process_die (child_die, cu); child_die = sibling_die (child_die); } } new = pop_context (); if (local_symbols != NULL) { finish_block (0, &local_symbols, new->old_blocks, new->start_addr, highpc, objfile); } local_symbols = new->locals; } /* Get low and high pc attributes from a die. Return 1 if the attributes are present and valid, otherwise, return 0. Return -1 if the range is discontinuous, i.e. derived from DW_AT_ranges information. */ static int dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc, CORE_ADDR *highpc, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct comp_unit_head *cu_header = &cu->header; struct attribute *attr; bfd *obfd = objfile->obfd; CORE_ADDR low = 0; CORE_ADDR high = 0; int ret = 0; attr = dwarf2_attr (die, DW_AT_high_pc, cu); if (attr) { high = DW_ADDR (attr); attr = dwarf2_attr (die, DW_AT_low_pc, cu); if (attr) low = DW_ADDR (attr); else /* Found high w/o low attribute. */ return 0; /* Found consecutive range of addresses. */ ret = 1; } else { attr = dwarf2_attr (die, DW_AT_ranges, cu); if (attr != NULL) { unsigned int addr_size = cu_header->addr_size; CORE_ADDR mask = ~(~(CORE_ADDR)1 << (addr_size * 8 - 1)); /* Value of the DW_AT_ranges attribute is the offset in the .debug_ranges section. */ unsigned int offset = DW_UNSND (attr); /* Base address selection entry. */ CORE_ADDR base; int found_base; int dummy; char *buffer; CORE_ADDR marker; int low_set; found_base = cu_header->base_known; base = cu_header->base_address; if (offset >= dwarf_ranges_size) { complaint (&symfile_complaints, "Offset %d out of bounds for DW_AT_ranges attribute", offset); return 0; } buffer = dwarf_ranges_buffer + offset; /* Read in the largest possible address. */ marker = read_address (obfd, buffer, cu, &dummy); if ((marker & mask) == mask) { /* If we found the largest possible address, then read the base address. */ base = read_address (obfd, buffer + addr_size, cu, &dummy); buffer += 2 * addr_size; offset += 2 * addr_size; found_base = 1; } low_set = 0; while (1) { CORE_ADDR range_beginning, range_end; range_beginning = read_address (obfd, buffer, cu, &dummy); buffer += addr_size; range_end = read_address (obfd, buffer, cu, &dummy); buffer += addr_size; offset += 2 * addr_size; /* An end of list marker is a pair of zero addresses. */ if (range_beginning == 0 && range_end == 0) /* Found the end of list entry. */ break; /* Each base address selection entry is a pair of 2 values. The first is the largest possible address, the second is the base address. Check for a base address here. */ if ((range_beginning & mask) == mask) { /* If we found the largest possible address, then read the base address. */ base = read_address (obfd, buffer + addr_size, cu, &dummy); found_base = 1; continue; } if (!found_base) { /* We have no valid base address for the ranges data. */ complaint (&symfile_complaints, "Invalid .debug_ranges data (no base address)"); return 0; } range_beginning += base; range_end += base; /* FIXME: This is recording everything as a low-high segment of consecutive addresses. We should have a data structure for discontiguous block ranges instead. */ if (! low_set) { low = range_beginning; high = range_end; low_set = 1; } else { if (range_beginning < low) low = range_beginning; if (range_end > high) high = range_end; } } if (! low_set) /* If the first entry is an end-of-list marker, the range describes an empty scope, i.e. no instructions. */ return 0; ret = -1; } } if (high < low) return 0; /* When using the GNU linker, .gnu.linkonce. sections are used to eliminate duplicate copies of functions and vtables and such. The linker will arbitrarily choose one and discard the others. The AT_*_pc values for such functions refer to local labels in these sections. If the section from that file was discarded, the labels are not in the output, so the relocs get a value of 0. If this is a discarded function, mark the pc bounds as invalid, so that GDB will ignore it. */ if (low == 0 && (bfd_get_file_flags (obfd) & HAS_RELOC) == 0) return 0; *lowpc = low; *highpc = high; return ret; } /* Get the low and high pc's represented by the scope DIE, and store them in *LOWPC and *HIGHPC. If the correct values can't be determined, set *LOWPC to -1 and *HIGHPC to 0. */ static void get_scope_pc_bounds (struct die_info *die, CORE_ADDR *lowpc, CORE_ADDR *highpc, struct dwarf2_cu *cu) { CORE_ADDR best_low = (CORE_ADDR) -1; CORE_ADDR best_high = (CORE_ADDR) 0; CORE_ADDR current_low, current_high; if (dwarf2_get_pc_bounds (die, ¤t_low, ¤t_high, cu)) { best_low = current_low; best_high = current_high; } else { struct die_info *child = die->child; while (child && child->tag) { switch (child->tag) { case DW_TAG_subprogram: if (dwarf2_get_pc_bounds (child, ¤t_low, ¤t_high, cu)) { best_low = min (best_low, current_low); best_high = max (best_high, current_high); } break; case DW_TAG_namespace: /* FIXME: carlton/2004-01-16: Should we do this for DW_TAG_class_type/DW_TAG_structure_type, too? I think that current GCC's always emit the DIEs corresponding to definitions of methods of classes as children of a DW_TAG_compile_unit or DW_TAG_namespace (as opposed to the DIEs giving the declarations, which could be anywhere). But I don't see any reason why the standards says that they have to be there. */ get_scope_pc_bounds (child, ¤t_low, ¤t_high, cu); if (current_low != ((CORE_ADDR) -1)) { best_low = min (best_low, current_low); best_high = max (best_high, current_high); } break; default: /* Ignore. */ break; } child = sibling_die (child); } } *lowpc = best_low; *highpc = best_high; } /* Add an aggregate field to the field list. */ static void dwarf2_add_field (struct field_info *fip, struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct nextfield *new_field; struct attribute *attr; struct field *fp; char *fieldname = ""; /* Allocate a new field list entry and link it in. */ new_field = (struct nextfield *) xmalloc (sizeof (struct nextfield)); make_cleanup (xfree, new_field); memset (new_field, 0, sizeof (struct nextfield)); new_field->next = fip->fields; fip->fields = new_field; fip->nfields++; /* Handle accessibility and virtuality of field. The default accessibility for members is public, the default accessibility for inheritance is private. */ if (die->tag != DW_TAG_inheritance) new_field->accessibility = DW_ACCESS_public; else new_field->accessibility = DW_ACCESS_private; new_field->virtuality = DW_VIRTUALITY_none; attr = dwarf2_attr (die, DW_AT_accessibility, cu); if (attr) new_field->accessibility = DW_UNSND (attr); if (new_field->accessibility != DW_ACCESS_public) fip->non_public_fields = 1; attr = dwarf2_attr (die, DW_AT_virtuality, cu); if (attr) new_field->virtuality = DW_UNSND (attr); fp = &new_field->field; if (die->tag == DW_TAG_member && ! die_is_declaration (die, cu)) { /* Data member other than a C++ static data member. */ /* Get type of field. */ fp->type = die_type (die, cu); FIELD_STATIC_KIND (*fp) = 0; /* Get bit size of field (zero if none). */ attr = dwarf2_attr (die, DW_AT_bit_size, cu); if (attr) { FIELD_BITSIZE (*fp) = DW_UNSND (attr); } else { FIELD_BITSIZE (*fp) = 0; } /* Get bit offset of field. */ attr = dwarf2_attr (die, DW_AT_data_member_location, cu); if (attr) { FIELD_BITPOS (*fp) = decode_locdesc (DW_BLOCK (attr), cu) * bits_per_byte; } else FIELD_BITPOS (*fp) = 0; attr = dwarf2_attr (die, DW_AT_bit_offset, cu); if (attr) { if (BITS_BIG_ENDIAN) { /* For big endian bits, the DW_AT_bit_offset gives the additional bit offset from the MSB of the containing anonymous object to the MSB of the field. We don't have to do anything special since we don't need to know the size of the anonymous object. */ FIELD_BITPOS (*fp) += DW_UNSND (attr); } else { /* For little endian bits, compute the bit offset to the MSB of the anonymous object, subtract off the number of bits from the MSB of the field to the MSB of the object, and then subtract off the number of bits of the field itself. The result is the bit offset of the LSB of the field. */ int anonymous_size; int bit_offset = DW_UNSND (attr); attr = dwarf2_attr (die, DW_AT_byte_size, cu); if (attr) { /* The size of the anonymous object containing the bit field is explicit, so use the indicated size (in bytes). */ anonymous_size = DW_UNSND (attr); } else { /* The size of the anonymous object containing the bit field must be inferred from the type attribute of the data member containing the bit field. */ anonymous_size = TYPE_LENGTH (fp->type); } FIELD_BITPOS (*fp) += anonymous_size * bits_per_byte - bit_offset - FIELD_BITSIZE (*fp); } } /* Get name of field. */ attr = dwarf2_attr (die, DW_AT_name, cu); if (attr && DW_STRING (attr)) fieldname = DW_STRING (attr); fp->name = obsavestring (fieldname, strlen (fieldname), &objfile->objfile_obstack); /* Change accessibility for artificial fields (e.g. virtual table pointer or virtual base class pointer) to private. */ if (dwarf2_attr (die, DW_AT_artificial, cu)) { new_field->accessibility = DW_ACCESS_private; fip->non_public_fields = 1; } } else if (die->tag == DW_TAG_member || die->tag == DW_TAG_variable) { /* C++ static member. */ /* NOTE: carlton/2002-11-05: It should be a DW_TAG_member that is a declaration, but all versions of G++ as of this writing (so through at least 3.2.1) incorrectly generate DW_TAG_variable tags. */ char *physname; /* Get name of field. */ attr = dwarf2_attr (die, DW_AT_name, cu); if (attr && DW_STRING (attr)) fieldname = DW_STRING (attr); else return; /* Get physical name. */ physname = dwarf2_linkage_name (die, cu); SET_FIELD_PHYSNAME (*fp, obsavestring (physname, strlen (physname), &objfile->objfile_obstack)); FIELD_TYPE (*fp) = die_type (die, cu); FIELD_NAME (*fp) = obsavestring (fieldname, strlen (fieldname), &objfile->objfile_obstack); } else if (die->tag == DW_TAG_inheritance) { /* C++ base class field. */ attr = dwarf2_attr (die, DW_AT_data_member_location, cu); if (attr) FIELD_BITPOS (*fp) = (decode_locdesc (DW_BLOCK (attr), cu) * bits_per_byte); FIELD_BITSIZE (*fp) = 0; FIELD_STATIC_KIND (*fp) = 0; FIELD_TYPE (*fp) = die_type (die, cu); FIELD_NAME (*fp) = type_name_no_tag (fp->type); fip->nbaseclasses++; } } /* Create the vector of fields, and attach it to the type. */ static void dwarf2_attach_fields_to_type (struct field_info *fip, struct type *type, struct dwarf2_cu *cu) { int nfields = fip->nfields; /* Record the field count, allocate space for the array of fields, and create blank accessibility bitfields if necessary. */ TYPE_NFIELDS (type) = nfields; TYPE_FIELDS (type) = (struct field *) TYPE_ALLOC (type, sizeof (struct field) * nfields); memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields); if (fip->non_public_fields) { ALLOCATE_CPLUS_STRUCT_TYPE (type); TYPE_FIELD_PRIVATE_BITS (type) = (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields)); B_CLRALL (TYPE_FIELD_PRIVATE_BITS (type), nfields); TYPE_FIELD_PROTECTED_BITS (type) = (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields)); B_CLRALL (TYPE_FIELD_PROTECTED_BITS (type), nfields); TYPE_FIELD_IGNORE_BITS (type) = (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields)); B_CLRALL (TYPE_FIELD_IGNORE_BITS (type), nfields); } /* If the type has baseclasses, allocate and clear a bit vector for TYPE_FIELD_VIRTUAL_BITS. */ if (fip->nbaseclasses) { int num_bytes = B_BYTES (fip->nbaseclasses); char *pointer; ALLOCATE_CPLUS_STRUCT_TYPE (type); pointer = (char *) TYPE_ALLOC (type, num_bytes); TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *) pointer; B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), fip->nbaseclasses); TYPE_N_BASECLASSES (type) = fip->nbaseclasses; } /* Copy the saved-up fields into the field vector. Start from the head of the list, adding to the tail of the field array, so that they end up in the same order in the array in which they were added to the list. */ while (nfields-- > 0) { TYPE_FIELD (type, nfields) = fip->fields->field; switch (fip->fields->accessibility) { case DW_ACCESS_private: SET_TYPE_FIELD_PRIVATE (type, nfields); break; case DW_ACCESS_protected: SET_TYPE_FIELD_PROTECTED (type, nfields); break; case DW_ACCESS_public: break; default: /* Unknown accessibility. Complain and treat it as public. */ { complaint (&symfile_complaints, "unsupported accessibility %d", fip->fields->accessibility); } break; } if (nfields < fip->nbaseclasses) { switch (fip->fields->virtuality) { case DW_VIRTUALITY_virtual: case DW_VIRTUALITY_pure_virtual: SET_TYPE_FIELD_VIRTUAL (type, nfields); break; } } fip->fields = fip->fields->next; } } /* Add a member function to the proper fieldlist. */ static void dwarf2_add_member_fn (struct field_info *fip, struct die_info *die, struct type *type, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct attribute *attr; struct fnfieldlist *flp; int i; struct fn_field *fnp; char *fieldname; char *physname; struct nextfnfield *new_fnfield; /* Get name of member function. */ attr = dwarf2_attr (die, DW_AT_name, cu); if (attr && DW_STRING (attr)) fieldname = DW_STRING (attr); else return; /* Get the mangled name. */ physname = dwarf2_linkage_name (die, cu); /* Look up member function name in fieldlist. */ for (i = 0; i < fip->nfnfields; i++) { if (strcmp (fip->fnfieldlists[i].name, fieldname) == 0) break; } /* Create new list element if necessary. */ if (i < fip->nfnfields) flp = &fip->fnfieldlists[i]; else { if ((fip->nfnfields % DW_FIELD_ALLOC_CHUNK) == 0) { fip->fnfieldlists = (struct fnfieldlist *) xrealloc (fip->fnfieldlists, (fip->nfnfields + DW_FIELD_ALLOC_CHUNK) * sizeof (struct fnfieldlist)); if (fip->nfnfields == 0) make_cleanup (free_current_contents, &fip->fnfieldlists); } flp = &fip->fnfieldlists[fip->nfnfields]; flp->name = fieldname; flp->length = 0; flp->head = NULL; fip->nfnfields++; } /* Create a new member function field and chain it to the field list entry. */ new_fnfield = (struct nextfnfield *) xmalloc (sizeof (struct nextfnfield)); make_cleanup (xfree, new_fnfield); memset (new_fnfield, 0, sizeof (struct nextfnfield)); new_fnfield->next = flp->head; flp->head = new_fnfield; flp->length++; /* Fill in the member function field info. */ fnp = &new_fnfield->fnfield; fnp->physname = obsavestring (physname, strlen (physname), &objfile->objfile_obstack); fnp->type = alloc_type (objfile); if (die->type && TYPE_CODE (die->type) == TYPE_CODE_FUNC) { int nparams = TYPE_NFIELDS (die->type); /* TYPE is the domain of this method, and DIE->TYPE is the type of the method itself (TYPE_CODE_METHOD). */ smash_to_method_type (fnp->type, type, TYPE_TARGET_TYPE (die->type), TYPE_FIELDS (die->type), TYPE_NFIELDS (die->type), TYPE_VARARGS (die->type)); /* Handle static member functions. Dwarf2 has no clean way to discern C++ static and non-static member functions. G++ helps GDB by marking the first parameter for non-static member functions (which is the this pointer) as artificial. We obtain this information from read_subroutine_type via TYPE_FIELD_ARTIFICIAL. */ if (nparams == 0 || TYPE_FIELD_ARTIFICIAL (die->type, 0) == 0) fnp->voffset = VOFFSET_STATIC; } else complaint (&symfile_complaints, "member function type missing for '%s'", physname); /* Get fcontext from DW_AT_containing_type if present. */ if (dwarf2_attr (die, DW_AT_containing_type, cu) != NULL) fnp->fcontext = die_containing_type (die, cu); /* dwarf2 doesn't have stubbed physical names, so the setting of is_const and is_volatile is irrelevant, as it is needed by gdb_mangle_name only. */ /* Get accessibility. */ attr = dwarf2_attr (die, DW_AT_accessibility, cu); if (attr) { switch (DW_UNSND (attr)) { case DW_ACCESS_private: fnp->is_private = 1; break; case DW_ACCESS_protected: fnp->is_protected = 1; break; } } /* Check for artificial methods. */ attr = dwarf2_attr (die, DW_AT_artificial, cu); if (attr && DW_UNSND (attr) != 0) fnp->is_artificial = 1; /* Get index in virtual function table if it is a virtual member function. */ attr = dwarf2_attr (die, DW_AT_vtable_elem_location, cu); if (attr) { /* Support the .debug_loc offsets */ if (attr_form_is_block (attr)) { fnp->voffset = decode_locdesc (DW_BLOCK (attr), cu) + 2; } else if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8) { dwarf2_complex_location_expr_complaint (); } else { dwarf2_invalid_attrib_class_complaint ("DW_AT_vtable_elem_location", fieldname); } } } /* Create the vector of member function fields, and attach it to the type. */ static void dwarf2_attach_fn_fields_to_type (struct field_info *fip, struct type *type, struct dwarf2_cu *cu) { struct fnfieldlist *flp; int total_length = 0; int i; ALLOCATE_CPLUS_STRUCT_TYPE (type); TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *) TYPE_ALLOC (type, sizeof (struct fn_fieldlist) * fip->nfnfields); for (i = 0, flp = fip->fnfieldlists; i < fip->nfnfields; i++, flp++) { struct nextfnfield *nfp = flp->head; struct fn_fieldlist *fn_flp = &TYPE_FN_FIELDLIST (type, i); int k; TYPE_FN_FIELDLIST_NAME (type, i) = flp->name; TYPE_FN_FIELDLIST_LENGTH (type, i) = flp->length; fn_flp->fn_fields = (struct fn_field *) TYPE_ALLOC (type, sizeof (struct fn_field) * flp->length); for (k = flp->length; (k--, nfp); nfp = nfp->next) fn_flp->fn_fields[k] = nfp->fnfield; total_length += flp->length; } TYPE_NFN_FIELDS (type) = fip->nfnfields; TYPE_NFN_FIELDS_TOTAL (type) = total_length; } /* Called when we find the DIE that starts a structure or union scope (definition) to process all dies that define the members of the structure or union. NOTE: we need to call struct_type regardless of whether or not the DIE has an at_name attribute, since it might be an anonymous structure or union. This gets the type entered into our set of user defined types. However, if the structure is incomplete (an opaque struct/union) then suppress creating a symbol table entry for it since gdb only wants to find the one with the complete definition. Note that if it is complete, we just call new_symbol, which does it's own checking about whether the struct/union is anonymous or not (and suppresses creating a symbol table entry itself). */ static void read_structure_type (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct type *type; struct attribute *attr; const char *previous_prefix = processing_current_prefix; struct cleanup *back_to = NULL; if (die->type) return; type = alloc_type (objfile); INIT_CPLUS_SPECIFIC (type); attr = dwarf2_attr (die, DW_AT_name, cu); if (attr && DW_STRING (attr)) { if (cu->language == language_cplus) { char *new_prefix = determine_class_name (die, cu); TYPE_TAG_NAME (type) = obsavestring (new_prefix, strlen (new_prefix), &objfile->objfile_obstack); back_to = make_cleanup (xfree, new_prefix); processing_current_prefix = new_prefix; } else { TYPE_TAG_NAME (type) = DW_STRING (attr); } } if (die->tag == DW_TAG_structure_type) { TYPE_CODE (type) = TYPE_CODE_STRUCT; } else if (die->tag == DW_TAG_union_type) { TYPE_CODE (type) = TYPE_CODE_UNION; } else { /* FIXME: TYPE_CODE_CLASS is currently defined to TYPE_CODE_STRUCT in gdbtypes.h. */ TYPE_CODE (type) = TYPE_CODE_CLASS; } attr = dwarf2_attr (die, DW_AT_byte_size, cu); if (attr) { TYPE_LENGTH (type) = DW_UNSND (attr); } else { TYPE_LENGTH (type) = 0; } /* We need to add the type field to the die immediately so we don't infinitely recurse when dealing with pointers to the structure type within the structure itself. */ die->type = type; if (die->child != NULL && ! die_is_declaration (die, cu)) { struct field_info fi; struct die_info *child_die; struct cleanup *back_to = make_cleanup (null_cleanup, NULL); memset (&fi, 0, sizeof (struct field_info)); child_die = die->child; while (child_die && child_die->tag) { if (child_die->tag == DW_TAG_member || child_die->tag == DW_TAG_variable) { /* NOTE: carlton/2002-11-05: A C++ static data member should be a DW_TAG_member that is a declaration, but all versions of G++ as of this writing (so through at least 3.2.1) incorrectly generate DW_TAG_variable tags for them instead. */ dwarf2_add_field (&fi, child_die, cu); } else if (child_die->tag == DW_TAG_subprogram) { /* C++ member function. */ read_type_die (child_die, cu); dwarf2_add_member_fn (&fi, child_die, type, cu); } else if (child_die->tag == DW_TAG_inheritance) { /* C++ base class field. */ dwarf2_add_field (&fi, child_die, cu); } child_die = sibling_die (child_die); } /* Attach fields and member functions to the type. */ if (fi.nfields) dwarf2_attach_fields_to_type (&fi, type, cu); if (fi.nfnfields) { dwarf2_attach_fn_fields_to_type (&fi, type, cu); /* Get the type which refers to the base class (possibly this class itself) which contains the vtable pointer for the current class from the DW_AT_containing_type attribute. */ if (dwarf2_attr (die, DW_AT_containing_type, cu) != NULL) { struct type *t = die_containing_type (die, cu); TYPE_VPTR_BASETYPE (type) = t; if (type == t) { static const char vptr_name[] = {'_', 'v', 'p', 't', 'r', '\0'}; int i; /* Our own class provides vtbl ptr. */ for (i = TYPE_NFIELDS (t) - 1; i >= TYPE_N_BASECLASSES (t); --i) { char *fieldname = TYPE_FIELD_NAME (t, i); if ((strncmp (fieldname, vptr_name, strlen (vptr_name) - 1) == 0) && is_cplus_marker (fieldname[strlen (vptr_name)])) { TYPE_VPTR_FIELDNO (type) = i; break; } } /* Complain if virtual function table field not found. */ if (i < TYPE_N_BASECLASSES (t)) complaint (&symfile_complaints, "virtual function table pointer not found when defining class '%s'", TYPE_TAG_NAME (type) ? TYPE_TAG_NAME (type) : ""); } else { TYPE_VPTR_FIELDNO (type) = TYPE_VPTR_FIELDNO (t); } } } do_cleanups (back_to); } else { /* No children, must be stub. */ TYPE_FLAGS (type) |= TYPE_FLAG_STUB; } processing_current_prefix = previous_prefix; if (back_to != NULL) do_cleanups (back_to); } static void process_structure_scope (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; const char *previous_prefix = processing_current_prefix; struct die_info *child_die = die->child; if (TYPE_TAG_NAME (die->type) != NULL) processing_current_prefix = TYPE_TAG_NAME (die->type); /* NOTE: carlton/2004-03-16: GCC 3.4 (or at least one of its snapshots) has been known to create a die giving a declaration for a class that has, as a child, a die giving a definition for a nested class. So we have to process our children even if the current die is a declaration. Normally, of course, a declaration won't have any children at all. */ while (child_die != NULL && child_die->tag) { if (child_die->tag == DW_TAG_member || child_die->tag == DW_TAG_variable || child_die->tag == DW_TAG_inheritance) { /* Do nothing. */ } else process_die (child_die, cu); child_die = sibling_die (child_die); } if (die->child != NULL && ! die_is_declaration (die, cu)) new_symbol (die, die->type, cu); processing_current_prefix = previous_prefix; } /* Given a DW_AT_enumeration_type die, set its type. We do not complete the type's fields yet, or create any symbols. */ static void read_enumeration_type (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct type *type; struct attribute *attr; if (die->type) return; type = alloc_type (objfile); TYPE_CODE (type) = TYPE_CODE_ENUM; attr = dwarf2_attr (die, DW_AT_name, cu); if (attr && DW_STRING (attr)) { const char *name = DW_STRING (attr); if (processing_has_namespace_info) { TYPE_TAG_NAME (type) = obconcat (&objfile->objfile_obstack, processing_current_prefix, processing_current_prefix[0] == '\0' ? "" : "::", name); } else { TYPE_TAG_NAME (type) = obsavestring (name, strlen (name), &objfile->objfile_obstack); } } attr = dwarf2_attr (die, DW_AT_byte_size, cu); if (attr) { TYPE_LENGTH (type) = DW_UNSND (attr); } else { TYPE_LENGTH (type) = 0; } die->type = type; } /* Determine the name of the type represented by DIE, which should be a named C++ compound type. Return the name in question; the caller is responsible for xfree()'ing it. */ static char * determine_class_name (struct die_info *die, struct dwarf2_cu *cu) { struct cleanup *back_to = NULL; struct die_info *spec_die = die_specification (die, cu); char *new_prefix = NULL; /* If this is the definition of a class that is declared by another die, then processing_current_prefix may not be accurate; see read_func_scope for a similar example. */ if (spec_die != NULL) { char *specification_prefix = determine_prefix (spec_die, cu); processing_current_prefix = specification_prefix; back_to = make_cleanup (xfree, specification_prefix); } /* If we don't have namespace debug info, guess the name by trying to demangle the names of members, just like we did in add_partial_structure. */ if (!processing_has_namespace_info) { struct die_info *child; for (child = die->child; child != NULL && child->tag != 0; child = sibling_die (child)) { if (child->tag == DW_TAG_subprogram) { new_prefix = class_name_from_physname (dwarf2_linkage_name (child, cu)); if (new_prefix != NULL) break; } } } if (new_prefix == NULL) { const char *name = dwarf2_name (die, cu); new_prefix = typename_concat (processing_current_prefix, name ? name : "<>"); } if (back_to != NULL) do_cleanups (back_to); return new_prefix; } /* Given a pointer to a die which begins an enumeration, process all the dies that define the members of the enumeration, and create the symbol for the enumeration type. NOTE: We reverse the order of the element list. */ static void process_enumeration_scope (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct die_info *child_die; struct field *fields; struct attribute *attr; struct symbol *sym; int num_fields; int unsigned_enum = 1; num_fields = 0; fields = NULL; if (die->child != NULL) { child_die = die->child; while (child_die && child_die->tag) { if (child_die->tag != DW_TAG_enumerator) { process_die (child_die, cu); } else { attr = dwarf2_attr (child_die, DW_AT_name, cu); if (attr) { sym = new_symbol (child_die, die->type, cu); if (SYMBOL_VALUE (sym) < 0) unsigned_enum = 0; if ((num_fields % DW_FIELD_ALLOC_CHUNK) == 0) { fields = (struct field *) xrealloc (fields, (num_fields + DW_FIELD_ALLOC_CHUNK) * sizeof (struct field)); } FIELD_NAME (fields[num_fields]) = DEPRECATED_SYMBOL_NAME (sym); FIELD_TYPE (fields[num_fields]) = NULL; FIELD_BITPOS (fields[num_fields]) = SYMBOL_VALUE (sym); FIELD_BITSIZE (fields[num_fields]) = 0; FIELD_STATIC_KIND (fields[num_fields]) = 0; num_fields++; } } child_die = sibling_die (child_die); } if (num_fields) { TYPE_NFIELDS (die->type) = num_fields; TYPE_FIELDS (die->type) = (struct field *) TYPE_ALLOC (die->type, sizeof (struct field) * num_fields); memcpy (TYPE_FIELDS (die->type), fields, sizeof (struct field) * num_fields); xfree (fields); } if (unsigned_enum) TYPE_FLAGS (die->type) |= TYPE_FLAG_UNSIGNED; } new_symbol (die, die->type, cu); } /* Extract all information from a DW_TAG_array_type DIE and put it in the DIE's type field. For now, this only handles one dimensional arrays. */ static void read_array_type (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct die_info *child_die; struct type *type = NULL; struct type *element_type, *range_type, *index_type; struct type **range_types = NULL; struct attribute *attr; int ndim = 0; struct cleanup *back_to; /* Return if we've already decoded this type. */ if (die->type) { return; } element_type = die_type (die, cu); /* Irix 6.2 native cc creates array types without children for arrays with unspecified length. */ if (die->child == NULL) { index_type = dwarf2_fundamental_type (objfile, FT_INTEGER, cu); range_type = create_range_type (NULL, index_type, 0, -1); die->type = create_array_type (NULL, element_type, range_type); return; } back_to = make_cleanup (null_cleanup, NULL); child_die = die->child; while (child_die && child_die->tag) { if (child_die->tag == DW_TAG_subrange_type) { read_subrange_type (child_die, cu); if (child_die->type != NULL) { /* The range type was succesfully read. Save it for the array type creation. */ if ((ndim % DW_FIELD_ALLOC_CHUNK) == 0) { range_types = (struct type **) xrealloc (range_types, (ndim + DW_FIELD_ALLOC_CHUNK) * sizeof (struct type *)); if (ndim == 0) make_cleanup (free_current_contents, &range_types); } range_types[ndim++] = child_die->type; } } child_die = sibling_die (child_die); } /* Dwarf2 dimensions are output from left to right, create the necessary array types in backwards order. */ type = element_type; while (ndim-- > 0) type = create_array_type (NULL, type, range_types[ndim]); /* Understand Dwarf2 support for vector types (like they occur on the PowerPC w/ AltiVec). Gcc just adds another attribute to the array type. This is not part of the Dwarf2/3 standard yet, but a custom vendor extension. The main difference between a regular array and the vector variant is that vectors are passed by value to functions. */ attr = dwarf2_attr (die, DW_AT_GNU_vector, cu); if (attr) TYPE_FLAGS (type) |= TYPE_FLAG_VECTOR; do_cleanups (back_to); /* Install the type in the die. */ die->type = type; } /* First cut: install each common block member as a global variable. */ static void read_common_block (struct die_info *die, struct dwarf2_cu *cu) { struct die_info *child_die; struct attribute *attr; struct symbol *sym; CORE_ADDR base = (CORE_ADDR) 0; attr = dwarf2_attr (die, DW_AT_location, cu); if (attr) { /* Support the .debug_loc offsets */ if (attr_form_is_block (attr)) { base = decode_locdesc (DW_BLOCK (attr), cu); } else if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8) { dwarf2_complex_location_expr_complaint (); } else { dwarf2_invalid_attrib_class_complaint ("DW_AT_location", "common block member"); } } if (die->child != NULL) { child_die = die->child; while (child_die && child_die->tag) { sym = new_symbol (child_die, NULL, cu); attr = dwarf2_attr (child_die, DW_AT_data_member_location, cu); if (attr) { SYMBOL_VALUE_ADDRESS (sym) = base + decode_locdesc (DW_BLOCK (attr), cu); add_symbol_to_list (sym, &global_symbols); } child_die = sibling_die (child_die); } } } /* Read a C++ namespace. */ static void read_namespace (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; const char *previous_prefix = processing_current_prefix; const char *name; int is_anonymous; struct die_info *current_die; name = namespace_name (die, &is_anonymous, cu); /* Now build the name of the current namespace. */ if (previous_prefix[0] == '\0') { processing_current_prefix = name; } else { /* We need temp_name around because processing_current_prefix is a const char *. */ char *temp_name = alloca (strlen (previous_prefix) + 2 + strlen(name) + 1); strcpy (temp_name, previous_prefix); strcat (temp_name, "::"); strcat (temp_name, name); processing_current_prefix = temp_name; } /* Add a symbol associated to this if we haven't seen the namespace before. Also, add a using directive if it's an anonymous namespace. */ if (dwarf2_extension (die, cu) == NULL) { struct type *type; /* FIXME: carlton/2003-06-27: Once GDB is more const-correct, this cast will hopefully become unnecessary. */ type = init_type (TYPE_CODE_NAMESPACE, 0, 0, (char *) processing_current_prefix, objfile); TYPE_TAG_NAME (type) = TYPE_NAME (type); new_symbol (die, type, cu); die->type = type; if (is_anonymous) cp_add_using_directive (processing_current_prefix, strlen (previous_prefix), strlen (processing_current_prefix)); } if (die->child != NULL) { struct die_info *child_die = die->child; while (child_die && child_die->tag) { process_die (child_die, cu); child_die = sibling_die (child_die); } } processing_current_prefix = previous_prefix; } /* Return the name of the namespace represented by DIE. Set *IS_ANONYMOUS to tell whether or not the namespace is an anonymous namespace. */ static const char * namespace_name (struct die_info *die, int *is_anonymous, struct dwarf2_cu *cu) { struct die_info *current_die; const char *name = NULL; /* Loop through the extensions until we find a name. */ for (current_die = die; current_die != NULL; current_die = dwarf2_extension (die, cu)) { name = dwarf2_name (current_die, cu); if (name != NULL) break; } /* Is it an anonymous namespace? */ *is_anonymous = (name == NULL); if (*is_anonymous) name = "(anonymous namespace)"; return name; } /* Extract all information from a DW_TAG_pointer_type DIE and add to the user defined type vector. */ static void read_tag_pointer_type (struct die_info *die, struct dwarf2_cu *cu) { struct comp_unit_head *cu_header = &cu->header; struct type *type; struct attribute *attr_byte_size; struct attribute *attr_address_class; int byte_size, addr_class; if (die->type) { return; } type = lookup_pointer_type (die_type (die, cu)); attr_byte_size = dwarf2_attr (die, DW_AT_byte_size, cu); if (attr_byte_size) byte_size = DW_UNSND (attr_byte_size); else byte_size = cu_header->addr_size; attr_address_class = dwarf2_attr (die, DW_AT_address_class, cu); if (attr_address_class) addr_class = DW_UNSND (attr_address_class); else addr_class = DW_ADDR_none; /* If the pointer size or address class is different than the default, create a type variant marked as such and set the length accordingly. */ if (TYPE_LENGTH (type) != byte_size || addr_class != DW_ADDR_none) { if (ADDRESS_CLASS_TYPE_FLAGS_P ()) { int type_flags; type_flags = ADDRESS_CLASS_TYPE_FLAGS (byte_size, addr_class); gdb_assert ((type_flags & ~TYPE_FLAG_ADDRESS_CLASS_ALL) == 0); type = make_type_with_address_space (type, type_flags); } else if (TYPE_LENGTH (type) != byte_size) { complaint (&symfile_complaints, "invalid pointer size %d", byte_size); } else { /* Should we also complain about unhandled address classes? */ } } TYPE_LENGTH (type) = byte_size; die->type = type; } /* Extract all information from a DW_TAG_ptr_to_member_type DIE and add to the user defined type vector. */ static void read_tag_ptr_to_member_type (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct type *type; struct type *to_type; struct type *domain; if (die->type) { return; } type = alloc_type (objfile); to_type = die_type (die, cu); domain = die_containing_type (die, cu); smash_to_member_type (type, domain, to_type); die->type = type; } /* Extract all information from a DW_TAG_reference_type DIE and add to the user defined type vector. */ static void read_tag_reference_type (struct die_info *die, struct dwarf2_cu *cu) { struct comp_unit_head *cu_header = &cu->header; struct type *type; struct attribute *attr; if (die->type) { return; } type = lookup_reference_type (die_type (die, cu)); attr = dwarf2_attr (die, DW_AT_byte_size, cu); if (attr) { TYPE_LENGTH (type) = DW_UNSND (attr); } else { TYPE_LENGTH (type) = cu_header->addr_size; } die->type = type; } static void read_tag_unspecified_type (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct type *type; struct attribute *attr; if (die->type) { return; } type = alloc_type (objfile); TYPE_LENGTH (type) = 0; attr = dwarf2_attr (die, DW_AT_name, cu); if (attr && DW_STRING (attr)) TYPE_NAME (type) = DW_STRING (attr); die->type = type; } static void read_tag_const_type (struct die_info *die, struct dwarf2_cu *cu) { struct type *base_type; if (die->type) { return; } base_type = die_type (die, cu); die->type = make_cvr_type (1, TYPE_VOLATILE (base_type), TYPE_RESTRICT (base_type), base_type, 0); } static void read_tag_volatile_type (struct die_info *die, struct dwarf2_cu *cu) { struct type *base_type; if (die->type) { return; } base_type = die_type (die, cu); die->type = make_cvr_type (TYPE_CONST (base_type), 1, TYPE_RESTRICT (base_type), base_type, 0); } static void read_tag_restrict_type (struct die_info *die, struct dwarf2_cu *cu) { struct type *base_type; if (die->type) { return; } base_type = die_type (die, cu); die->type = make_cvr_type (TYPE_CONST (base_type), TYPE_VOLATILE (base_type), 1, base_type, 0); } /* Extract all information from a DW_TAG_string_type DIE and add to the user defined type vector. It isn't really a user defined type, but it behaves like one, with other DIE's using an AT_user_def_type attribute to reference it. */ static void read_tag_string_type (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct type *type, *range_type, *index_type, *char_type; struct attribute *attr; unsigned int length; if (die->type) { return; } attr = dwarf2_attr (die, DW_AT_string_length, cu); if (attr) { length = DW_UNSND (attr); } else { /* check for the DW_AT_byte_size attribute */ attr = dwarf2_attr (die, DW_AT_byte_size, cu); if (attr) { length = DW_UNSND (attr); } else { length = 1; } } index_type = dwarf2_fundamental_type (objfile, FT_INTEGER, cu); range_type = create_range_type (NULL, index_type, 1, length); if (cu->language == language_fortran) { /* Need to create a unique string type for bounds information */ type = create_string_type (0, range_type); } else { char_type = dwarf2_fundamental_type (objfile, FT_CHAR, cu); type = create_string_type (char_type, range_type); } die->type = type; } /* Handle DIES due to C code like: struct foo { int (*funcp)(int a, long l); int b; }; ('funcp' generates a DW_TAG_subroutine_type DIE) */ static void read_subroutine_type (struct die_info *die, struct dwarf2_cu *cu) { struct type *type; /* Type that this function returns */ struct type *ftype; /* Function that returns above type */ struct attribute *attr; /* Decode the type that this subroutine returns */ if (die->type) { return; } type = die_type (die, cu); ftype = lookup_function_type (type); /* All functions in C++ have prototypes. */ attr = dwarf2_attr (die, DW_AT_prototyped, cu); if ((attr && (DW_UNSND (attr) != 0)) || cu->language == language_cplus) TYPE_FLAGS (ftype) |= TYPE_FLAG_PROTOTYPED; if (die->child != NULL) { struct die_info *child_die; int nparams = 0; int iparams = 0; /* Count the number of parameters. FIXME: GDB currently ignores vararg functions, but knows about vararg member functions. */ child_die = die->child; while (child_die && child_die->tag) { if (child_die->tag == DW_TAG_formal_parameter) nparams++; else if (child_die->tag == DW_TAG_unspecified_parameters) TYPE_FLAGS (ftype) |= TYPE_FLAG_VARARGS; child_die = sibling_die (child_die); } /* Allocate storage for parameters and fill them in. */ TYPE_NFIELDS (ftype) = nparams; TYPE_FIELDS (ftype) = (struct field *) TYPE_ALLOC (ftype, nparams * sizeof (struct field)); child_die = die->child; while (child_die && child_die->tag) { if (child_die->tag == DW_TAG_formal_parameter) { /* Dwarf2 has no clean way to discern C++ static and non-static member functions. G++ helps GDB by marking the first parameter for non-static member functions (which is the this pointer) as artificial. We pass this information to dwarf2_add_member_fn via TYPE_FIELD_ARTIFICIAL. */ attr = dwarf2_attr (child_die, DW_AT_artificial, cu); if (attr) TYPE_FIELD_ARTIFICIAL (ftype, iparams) = DW_UNSND (attr); else TYPE_FIELD_ARTIFICIAL (ftype, iparams) = 0; TYPE_FIELD_TYPE (ftype, iparams) = die_type (child_die, cu); iparams++; } child_die = sibling_die (child_die); } } die->type = ftype; } static void read_typedef (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct attribute *attr; char *name = NULL; if (!die->type) { attr = dwarf2_attr (die, DW_AT_name, cu); if (attr && DW_STRING (attr)) { name = DW_STRING (attr); } die->type = init_type (TYPE_CODE_TYPEDEF, 0, TYPE_FLAG_TARGET_STUB, name, objfile); TYPE_TARGET_TYPE (die->type) = die_type (die, cu); } } /* Find a representation of a given base type and install it in the TYPE field of the die. */ static void read_base_type (struct die_info *die, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct type *type; struct attribute *attr; int encoding = 0, size = 0; /* If we've already decoded this die, this is a no-op. */ if (die->type) { return; } attr = dwarf2_attr (die, DW_AT_encoding, cu); if (attr) { encoding = DW_UNSND (attr); } attr = dwarf2_attr (die, DW_AT_byte_size, cu); if (attr) { size = DW_UNSND (attr); } attr = dwarf2_attr (die, DW_AT_name, cu); if (attr && DW_STRING (attr)) { enum type_code code = TYPE_CODE_INT; int type_flags = 0; switch (encoding) { case DW_ATE_address: /* Turn DW_ATE_address into a void * pointer. */ code = TYPE_CODE_PTR; type_flags |= TYPE_FLAG_UNSIGNED; break; case DW_ATE_boolean: code = TYPE_CODE_BOOL; type_flags |= TYPE_FLAG_UNSIGNED; break; case DW_ATE_complex_float: code = TYPE_CODE_COMPLEX; break; case DW_ATE_float: code = TYPE_CODE_FLT; break; case DW_ATE_signed: case DW_ATE_signed_char: break; case DW_ATE_unsigned: case DW_ATE_unsigned_char: type_flags |= TYPE_FLAG_UNSIGNED; break; default: complaint (&symfile_complaints, "unsupported DW_AT_encoding: '%s'", dwarf_type_encoding_name (encoding)); break; } type = init_type (code, size, type_flags, DW_STRING (attr), objfile); if (encoding == DW_ATE_address) TYPE_TARGET_TYPE (type) = dwarf2_fundamental_type (objfile, FT_VOID, cu); else if (encoding == DW_ATE_complex_float) { if (size == 32) TYPE_TARGET_TYPE (type) = dwarf2_fundamental_type (objfile, FT_EXT_PREC_FLOAT, cu); else if (size == 16) TYPE_TARGET_TYPE (type) = dwarf2_fundamental_type (objfile, FT_DBL_PREC_FLOAT, cu); else if (size == 8) TYPE_TARGET_TYPE (type) = dwarf2_fundamental_type (objfile, FT_FLOAT, cu); } } else { type = dwarf_base_type (encoding, size, cu); } die->type = type; } /* Read the given DW_AT_subrange DIE. */ static void read_subrange_type (struct die_info *die, struct dwarf2_cu *cu) { struct type *base_type; struct type *range_type; struct attribute *attr; int low = 0; int high = -1; /* If we have already decoded this die, then nothing more to do. */ if (die->type) return; base_type = die_type (die, cu); if (base_type == NULL) { complaint (&symfile_complaints, "DW_AT_type missing from DW_TAG_subrange_type"); return; } if (TYPE_CODE (base_type) == TYPE_CODE_VOID) base_type = alloc_type (NULL); if (cu->language == language_fortran) { /* FORTRAN implies a lower bound of 1, if not given. */ low = 1; } attr = dwarf2_attr (die, DW_AT_lower_bound, cu); if (attr) low = dwarf2_get_attr_constant_value (attr, 0); attr = dwarf2_attr (die, DW_AT_upper_bound, cu); if (attr) { if (attr->form == DW_FORM_block1) { /* GCC encodes arrays with unspecified or dynamic length with a DW_FORM_block1 attribute. FIXME: GDB does not yet know how to handle dynamic arrays properly, treat them as arrays with unspecified length for now. FIXME: jimb/2003-09-22: GDB does not really know how to handle arrays of unspecified length either; we just represent them as zero-length arrays. Choose an appropriate upper bound given the lower bound we've computed above. */ high = low - 1; } else high = dwarf2_get_attr_constant_value (attr, 1); } range_type = create_range_type (NULL, base_type, low, high); attr = dwarf2_attr (die, DW_AT_name, cu); if (attr && DW_STRING (attr)) TYPE_NAME (range_type) = DW_STRING (attr); attr = dwarf2_attr (die, DW_AT_byte_size, cu); if (attr) TYPE_LENGTH (range_type) = DW_UNSND (attr); die->type = range_type; } /* Read a whole compilation unit into a linked list of dies. */ static struct die_info * read_comp_unit (char *info_ptr, bfd *abfd, struct dwarf2_cu *cu) { /* Reset die reference table; we are building new ones now. */ dwarf2_empty_hash_tables (); return read_die_and_children (info_ptr, abfd, cu, &info_ptr, NULL); } /* Read a single die and all its descendents. Set the die's sibling field to NULL; set other fields in the die correctly, and set all of the descendents' fields correctly. Set *NEW_INFO_PTR to the location of the info_ptr after reading all of those dies. PARENT is the parent of the die in question. */ static struct die_info * read_die_and_children (char *info_ptr, bfd *abfd, struct dwarf2_cu *cu, char **new_info_ptr, struct die_info *parent) { struct die_info *die; char *cur_ptr; int has_children; cur_ptr = read_full_die (&die, abfd, info_ptr, cu, &has_children); store_in_ref_table (die->offset, die); if (has_children) { die->child = read_die_and_siblings (cur_ptr, abfd, cu, new_info_ptr, die); } else { die->child = NULL; *new_info_ptr = cur_ptr; } die->sibling = NULL; die->parent = parent; return die; } /* Read a die, all of its descendents, and all of its siblings; set all of the fields of all of the dies correctly. Arguments are as in read_die_and_children. */ static struct die_info * read_die_and_siblings (char *info_ptr, bfd *abfd, struct dwarf2_cu *cu, char **new_info_ptr, struct die_info *parent) { struct die_info *first_die, *last_sibling; char *cur_ptr; cur_ptr = info_ptr; first_die = last_sibling = NULL; while (1) { struct die_info *die = read_die_and_children (cur_ptr, abfd, cu, &cur_ptr, parent); if (!first_die) { first_die = die; } else { last_sibling->sibling = die; } if (die->tag == 0) { *new_info_ptr = cur_ptr; return first_die; } else { last_sibling = die; } } } /* Free a linked list of dies. */ static void free_die_list (struct die_info *dies) { struct die_info *die, *next; die = dies; while (die) { if (die->child != NULL) free_die_list (die->child); next = die->sibling; xfree (die->attrs); xfree (die); die = next; } } static void do_free_die_list_cleanup (void *dies) { free_die_list (dies); } static struct cleanup * make_cleanup_free_die_list (struct die_info *dies) { return make_cleanup (do_free_die_list_cleanup, dies); } /* Read the contents of the section at OFFSET and of size SIZE from the object file specified by OBJFILE into the objfile_obstack and return it. */ char * dwarf2_read_section (struct objfile *objfile, asection *sectp) { bfd *abfd = objfile->obfd; char *buf, *retbuf; bfd_size_type size = bfd_get_section_size (sectp); if (size == 0) return NULL; buf = (char *) obstack_alloc (&objfile->objfile_obstack, size); retbuf = (char *) symfile_relocate_debug_section (abfd, sectp, (bfd_byte *) buf); if (retbuf != NULL) return retbuf; if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0 || bfd_bread (buf, size, abfd) != size) error ("Dwarf Error: Can't read DWARF data from '%s'", bfd_get_filename (abfd)); return buf; } /* In DWARF version 2, the description of the debugging information is stored in a separate .debug_abbrev section. Before we read any dies from a section we read in all abbreviations and install them in a hash table. */ static void dwarf2_read_abbrevs (bfd *abfd, struct dwarf2_cu *cu) { struct comp_unit_head *cu_header = &cu->header; char *abbrev_ptr; struct abbrev_info *cur_abbrev; unsigned int abbrev_number, bytes_read, abbrev_name; unsigned int abbrev_form, hash_number; /* Initialize dwarf2 abbrevs */ memset (cu_header->dwarf2_abbrevs, 0, ABBREV_HASH_SIZE*sizeof (struct abbrev_info *)); abbrev_ptr = dwarf_abbrev_buffer + cu_header->abbrev_offset; abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; /* loop until we reach an abbrev number of 0 */ while (abbrev_number) { cur_abbrev = dwarf_alloc_abbrev (); /* read in abbrev header */ cur_abbrev->number = abbrev_number; cur_abbrev->tag = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr); abbrev_ptr += 1; /* now read in declarations */ abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; while (abbrev_name) { if ((cur_abbrev->num_attrs % ATTR_ALLOC_CHUNK) == 0) { cur_abbrev->attrs = (struct attr_abbrev *) xrealloc (cur_abbrev->attrs, (cur_abbrev->num_attrs + ATTR_ALLOC_CHUNK) * sizeof (struct attr_abbrev)); } cur_abbrev->attrs[cur_abbrev->num_attrs].name = abbrev_name; cur_abbrev->attrs[cur_abbrev->num_attrs++].form = abbrev_form; abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; } hash_number = abbrev_number % ABBREV_HASH_SIZE; cur_abbrev->next = cu_header->dwarf2_abbrevs[hash_number]; cu_header->dwarf2_abbrevs[hash_number] = cur_abbrev; /* Get next abbreviation. Under Irix6 the abbreviations for a compilation unit are not always properly terminated with an abbrev number of 0. Exit loop if we encounter an abbreviation which we have already read (which means we are about to read the abbreviations for the next compile unit) or if the end of the abbreviation table is reached. */ if ((unsigned int) (abbrev_ptr - dwarf_abbrev_buffer) >= dwarf_abbrev_size) break; abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); abbrev_ptr += bytes_read; if (dwarf2_lookup_abbrev (abbrev_number, cu) != NULL) break; } } /* Empty the abbrev table for a new compilation unit. */ static void dwarf2_empty_abbrev_table (void *ptr_to_abbrevs_table) { int i; struct abbrev_info *abbrev, *next; struct abbrev_info **abbrevs; abbrevs = (struct abbrev_info **)ptr_to_abbrevs_table; for (i = 0; i < ABBREV_HASH_SIZE; ++i) { next = NULL; abbrev = abbrevs[i]; while (abbrev) { next = abbrev->next; xfree (abbrev->attrs); xfree (abbrev); abbrev = next; } abbrevs[i] = NULL; } } /* Lookup an abbrev_info structure in the abbrev hash table. */ static struct abbrev_info * dwarf2_lookup_abbrev (unsigned int number, struct dwarf2_cu *cu) { struct comp_unit_head *cu_header = &cu->header; unsigned int hash_number; struct abbrev_info *abbrev; hash_number = number % ABBREV_HASH_SIZE; abbrev = cu_header->dwarf2_abbrevs[hash_number]; while (abbrev) { if (abbrev->number == number) return abbrev; else abbrev = abbrev->next; } return NULL; } /* Read a minimal amount of information into the minimal die structure. */ static char * read_partial_die (struct partial_die_info *part_die, bfd *abfd, char *info_ptr, struct dwarf2_cu *cu) { unsigned int abbrev_number, bytes_read, i; struct abbrev_info *abbrev; struct attribute attr; struct attribute spec_attr; int found_spec_attr = 0; int has_low_pc_attr = 0; int has_high_pc_attr = 0; *part_die = zeroed_partial_die; abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; if (!abbrev_number) return info_ptr; abbrev = dwarf2_lookup_abbrev (abbrev_number, cu); if (!abbrev) { error ("Dwarf Error: Could not find abbrev number %d [in module %s]", abbrev_number, bfd_get_filename (abfd)); } part_die->offset = info_ptr - dwarf_info_buffer; part_die->tag = abbrev->tag; part_die->has_children = abbrev->has_children; part_die->abbrev = abbrev_number; for (i = 0; i < abbrev->num_attrs; ++i) { info_ptr = read_attribute (&attr, &abbrev->attrs[i], abfd, info_ptr, cu); /* Store the data if it is of an attribute we want to keep in a partial symbol table. */ switch (attr.name) { case DW_AT_name: /* Prefer DW_AT_MIPS_linkage_name over DW_AT_name. */ if (part_die->name == NULL) part_die->name = DW_STRING (&attr); break; case DW_AT_MIPS_linkage_name: part_die->name = DW_STRING (&attr); break; case DW_AT_low_pc: has_low_pc_attr = 1; part_die->lowpc = DW_ADDR (&attr); break; case DW_AT_high_pc: has_high_pc_attr = 1; part_die->highpc = DW_ADDR (&attr); break; case DW_AT_location: /* Support the .debug_loc offsets */ if (attr_form_is_block (&attr)) { part_die->locdesc = DW_BLOCK (&attr); } else if (attr.form == DW_FORM_data4 || attr.form == DW_FORM_data8) { dwarf2_complex_location_expr_complaint (); } else { dwarf2_invalid_attrib_class_complaint ("DW_AT_location", "partial symbol information"); } break; case DW_AT_language: part_die->language = DW_UNSND (&attr); break; case DW_AT_external: part_die->is_external = DW_UNSND (&attr); break; case DW_AT_declaration: part_die->is_declaration = DW_UNSND (&attr); break; case DW_AT_type: part_die->has_type = 1; break; case DW_AT_abstract_origin: case DW_AT_specification: found_spec_attr = 1; spec_attr = attr; break; case DW_AT_sibling: /* Ignore absolute siblings, they might point outside of the current compile unit. */ if (attr.form == DW_FORM_ref_addr) complaint (&symfile_complaints, "ignoring absolute DW_AT_sibling"); else part_die->sibling = dwarf_info_buffer + dwarf2_get_ref_die_offset (&attr, cu); break; default: break; } } /* If we found a reference attribute and the die has no name, try to find a name in the referred to die. */ if (found_spec_attr && part_die->name == NULL) { struct partial_die_info spec_die; char *spec_ptr; spec_ptr = dwarf_info_buffer + dwarf2_get_ref_die_offset (&spec_attr, cu); read_partial_die (&spec_die, abfd, spec_ptr, cu); if (spec_die.name) { part_die->name = spec_die.name; /* Copy DW_AT_external attribute if it is set. */ if (spec_die.is_external) part_die->is_external = spec_die.is_external; } } /* When using the GNU linker, .gnu.linkonce. sections are used to eliminate duplicate copies of functions and vtables and such. The linker will arbitrarily choose one and discard the others. The AT_*_pc values for such functions refer to local labels in these sections. If the section from that file was discarded, the labels are not in the output, so the relocs get a value of 0. If this is a discarded function, mark the pc bounds as invalid, so that GDB will ignore it. */ if (has_low_pc_attr && has_high_pc_attr && part_die->lowpc < part_die->highpc && (part_die->lowpc != 0 || (bfd_get_file_flags (abfd) & HAS_RELOC))) part_die->has_pc_info = 1; return info_ptr; } /* Read the die from the .debug_info section buffer. Set DIEP to point to a newly allocated die with its information, except for its child, sibling, and parent fields. Set HAS_CHILDREN to tell whether the die has children or not. */ static char * read_full_die (struct die_info **diep, bfd *abfd, char *info_ptr, struct dwarf2_cu *cu, int *has_children) { unsigned int abbrev_number, bytes_read, i, offset; struct abbrev_info *abbrev; struct die_info *die; offset = info_ptr - dwarf_info_buffer; abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; if (!abbrev_number) { die = dwarf_alloc_die (); die->tag = 0; die->abbrev = abbrev_number; die->type = NULL; *diep = die; *has_children = 0; return info_ptr; } abbrev = dwarf2_lookup_abbrev (abbrev_number, cu); if (!abbrev) { error ("Dwarf Error: could not find abbrev number %d [in module %s]", abbrev_number, bfd_get_filename (abfd)); } die = dwarf_alloc_die (); die->offset = offset; die->tag = abbrev->tag; die->abbrev = abbrev_number; die->type = NULL; die->num_attrs = abbrev->num_attrs; die->attrs = (struct attribute *) xmalloc (die->num_attrs * sizeof (struct attribute)); for (i = 0; i < abbrev->num_attrs; ++i) { info_ptr = read_attribute (&die->attrs[i], &abbrev->attrs[i], abfd, info_ptr, cu); } *diep = die; *has_children = abbrev->has_children; return info_ptr; } /* Read an attribute value described by an attribute form. */ static char * read_attribute_value (struct attribute *attr, unsigned form, bfd *abfd, char *info_ptr, struct dwarf2_cu *cu) { struct comp_unit_head *cu_header = &cu->header; unsigned int bytes_read; struct dwarf_block *blk; attr->form = form; switch (form) { case DW_FORM_addr: case DW_FORM_ref_addr: DW_ADDR (attr) = read_address (abfd, info_ptr, cu, &bytes_read); info_ptr += bytes_read; break; case DW_FORM_block2: blk = dwarf_alloc_block (); blk->size = read_2_bytes (abfd, info_ptr); info_ptr += 2; blk->data = read_n_bytes (abfd, info_ptr, blk->size); info_ptr += blk->size; DW_BLOCK (attr) = blk; break; case DW_FORM_block4: blk = dwarf_alloc_block (); blk->size = read_4_bytes (abfd, info_ptr); info_ptr += 4; blk->data = read_n_bytes (abfd, info_ptr, blk->size); info_ptr += blk->size; DW_BLOCK (attr) = blk; break; case DW_FORM_data2: DW_UNSND (attr) = read_2_bytes (abfd, info_ptr); info_ptr += 2; break; case DW_FORM_data4: DW_UNSND (attr) = read_4_bytes (abfd, info_ptr); info_ptr += 4; break; case DW_FORM_data8: DW_UNSND (attr) = read_8_bytes (abfd, info_ptr); info_ptr += 8; break; case DW_FORM_string: DW_STRING (attr) = read_string (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; break; case DW_FORM_strp: DW_STRING (attr) = read_indirect_string (abfd, info_ptr, cu_header, &bytes_read); info_ptr += bytes_read; break; case DW_FORM_block: blk = dwarf_alloc_block (); blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; blk->data = read_n_bytes (abfd, info_ptr, blk->size); info_ptr += blk->size; DW_BLOCK (attr) = blk; break; case DW_FORM_block1: blk = dwarf_alloc_block (); blk->size = read_1_byte (abfd, info_ptr); info_ptr += 1; blk->data = read_n_bytes (abfd, info_ptr, blk->size); info_ptr += blk->size; DW_BLOCK (attr) = blk; break; case DW_FORM_data1: DW_UNSND (attr) = read_1_byte (abfd, info_ptr); info_ptr += 1; break; case DW_FORM_flag: DW_UNSND (attr) = read_1_byte (abfd, info_ptr); info_ptr += 1; break; case DW_FORM_flag_present: DW_UNSND (attr) = 1; break; case DW_FORM_sdata: DW_SND (attr) = read_signed_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; break; case DW_FORM_udata: DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; break; case DW_FORM_ref1: DW_UNSND (attr) = read_1_byte (abfd, info_ptr); info_ptr += 1; break; case DW_FORM_ref2: DW_UNSND (attr) = read_2_bytes (abfd, info_ptr); info_ptr += 2; break; case DW_FORM_ref4: DW_UNSND (attr) = read_4_bytes (abfd, info_ptr); info_ptr += 4; break; case DW_FORM_ref8: DW_UNSND (attr) = read_8_bytes (abfd, info_ptr); info_ptr += 8; break; case DW_FORM_ref_udata: DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; break; case DW_FORM_indirect: form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); info_ptr += bytes_read; info_ptr = read_attribute_value (attr, form, abfd, info_ptr, cu); break; default: error ("Dwarf Error: Cannot handle %s in DWARF reader [in module %s]", dwarf_form_name (form), bfd_get_filename (abfd)); } return info_ptr; } /* Read an attribute described by an abbreviated attribute. */ static char * read_attribute (struct attribute *attr, struct attr_abbrev *abbrev, bfd *abfd, char *info_ptr, struct dwarf2_cu *cu) { attr->name = abbrev->name; return read_attribute_value (attr, abbrev->form, abfd, info_ptr, cu); } /* read dwarf information from a buffer */ static unsigned int read_1_byte (bfd *abfd, char *buf) { return bfd_get_8 (abfd, (bfd_byte *) buf); } static int read_1_signed_byte (bfd *abfd, char *buf) { return bfd_get_signed_8 (abfd, (bfd_byte *) buf); } static unsigned int read_2_bytes (bfd *abfd, char *buf) { return bfd_get_16 (abfd, (bfd_byte *) buf); } static int read_2_signed_bytes (bfd *abfd, char *buf) { return bfd_get_signed_16 (abfd, (bfd_byte *) buf); } static unsigned int read_4_bytes (bfd *abfd, char *buf) { return bfd_get_32 (abfd, (bfd_byte *) buf); } static int read_4_signed_bytes (bfd *abfd, char *buf) { return bfd_get_signed_32 (abfd, (bfd_byte *) buf); } static unsigned long read_8_bytes (bfd *abfd, char *buf) { return bfd_get_64 (abfd, (bfd_byte *) buf); } static CORE_ADDR read_address (bfd *abfd, char *buf, struct dwarf2_cu *cu, int *bytes_read) { struct comp_unit_head *cu_header = &cu->header; CORE_ADDR retval = 0; if (cu_header->signed_addr_p) { switch (cu_header->addr_size) { case 2: retval = bfd_get_signed_16 (abfd, (bfd_byte *) buf); break; case 4: retval = bfd_get_signed_32 (abfd, (bfd_byte *) buf); break; case 8: retval = bfd_get_signed_64 (abfd, (bfd_byte *) buf); break; default: internal_error (__FILE__, __LINE__, "read_address: bad switch, signed [in module %s]", bfd_get_filename (abfd)); } } else { switch (cu_header->addr_size) { case 2: retval = bfd_get_16 (abfd, (bfd_byte *) buf); break; case 4: retval = bfd_get_32 (abfd, (bfd_byte *) buf); break; case 8: retval = bfd_get_64 (abfd, (bfd_byte *) buf); break; default: internal_error (__FILE__, __LINE__, "read_address: bad switch, unsigned [in module %s]", bfd_get_filename (abfd)); } } *bytes_read = cu_header->addr_size; return retval; } /* Read the initial length from a section. The (draft) DWARF 3 specification allows the initial length to take up either 4 bytes or 12 bytes. If the first 4 bytes are 0xffffffff, then the next 8 bytes describe the length and all offsets will be 8 bytes in length instead of 4. An older, non-standard 64-bit format is also handled by this function. The older format in question stores the initial length as an 8-byte quantity without an escape value. Lengths greater than 2^32 aren't very common which means that the initial 4 bytes is almost always zero. Since a length value of zero doesn't make sense for the 32-bit format, this initial zero can be considered to be an escape value which indicates the presence of the older 64-bit format. As written, the code can't detect (old format) lengths greater than 4GB. If it becomes necessary to handle lengths somewhat larger than 4GB, we could allow other small values (such as the non-sensical values of 1, 2, and 3) to also be used as escape values indicating the presence of the old format. The value returned via bytes_read should be used to increment the relevant pointer after calling read_initial_length(). As a side effect, this function sets the fields initial_length_size and offset_size in cu_header to the values appropriate for the length field. (The format of the initial length field determines the width of file offsets to be fetched later with fetch_offset().) [ Note: read_initial_length() and read_offset() are based on the document entitled "DWARF Debugging Information Format", revision 3, draft 8, dated November 19, 2001. This document was obtained from: http://reality.sgiweb.org/davea/dwarf3-draft8-011125.pdf This document is only a draft and is subject to change. (So beware.) Details regarding the older, non-standard 64-bit format were determined empirically by examining 64-bit ELF files produced by the SGI toolchain on an IRIX 6.5 machine. - Kevin, July 16, 2002 ] */ static LONGEST read_initial_length (bfd *abfd, char *buf, struct comp_unit_head *cu_header, int *bytes_read) { LONGEST retval = 0; retval = bfd_get_32 (abfd, (bfd_byte *) buf); if (retval == 0xffffffff) { retval = bfd_get_64 (abfd, (bfd_byte *) buf + 4); *bytes_read = 12; if (cu_header != NULL) { cu_header->initial_length_size = 12; cu_header->offset_size = 8; } } else if (retval == 0) { /* Handle (non-standard) 64-bit DWARF2 formats such as that used by IRIX. */ retval = bfd_get_64 (abfd, (bfd_byte *) buf); *bytes_read = 8; if (cu_header != NULL) { cu_header->initial_length_size = 8; cu_header->offset_size = 8; } } else { *bytes_read = 4; if (cu_header != NULL) { cu_header->initial_length_size = 4; cu_header->offset_size = 4; } } return retval; } /* Read an offset from the data stream. The size of the offset is given by cu_header->offset_size. */ static LONGEST read_offset (bfd *abfd, char *buf, const struct comp_unit_head *cu_header, int *bytes_read) { LONGEST retval = 0; switch (cu_header->offset_size) { case 4: retval = bfd_get_32 (abfd, (bfd_byte *) buf); *bytes_read = 4; break; case 8: retval = bfd_get_64 (abfd, (bfd_byte *) buf); *bytes_read = 8; break; default: internal_error (__FILE__, __LINE__, "read_offset: bad switch [in module %s]", bfd_get_filename (abfd)); } return retval; } static char * read_n_bytes (bfd *abfd, char *buf, unsigned int size) { /* If the size of a host char is 8 bits, we can return a pointer to the buffer, otherwise we have to copy the data to a buffer allocated on the temporary obstack. */ gdb_assert (HOST_CHAR_BIT == 8); return buf; } static char * read_string (bfd *abfd, char *buf, unsigned int *bytes_read_ptr) { /* If the size of a host char is 8 bits, we can return a pointer to the string, otherwise we have to copy the string to a buffer allocated on the temporary obstack. */ gdb_assert (HOST_CHAR_BIT == 8); if (*buf == '\0') { *bytes_read_ptr = 1; return NULL; } *bytes_read_ptr = strlen (buf) + 1; return buf; } static char * read_indirect_string (bfd *abfd, char *buf, const struct comp_unit_head *cu_header, unsigned int *bytes_read_ptr) { LONGEST str_offset = read_offset (abfd, buf, cu_header, (int *) bytes_read_ptr); if (dwarf_str_buffer == NULL) { error ("DW_FORM_strp used without .debug_str section [in module %s]", bfd_get_filename (abfd)); return NULL; } if (str_offset >= dwarf_str_size) { error ("DW_FORM_strp pointing outside of .debug_str section [in module %s]", bfd_get_filename (abfd)); return NULL; } gdb_assert (HOST_CHAR_BIT == 8); if (dwarf_str_buffer[str_offset] == '\0') return NULL; return dwarf_str_buffer + str_offset; } static unsigned long read_unsigned_leb128 (bfd *abfd, char *buf, unsigned int *bytes_read_ptr) { unsigned long result; unsigned int num_read; int i, shift; unsigned char byte; result = 0; shift = 0; num_read = 0; i = 0; while (1) { byte = bfd_get_8 (abfd, (bfd_byte *) buf); buf++; num_read++; result |= ((unsigned long)(byte & 127) << shift); if ((byte & 128) == 0) { break; } shift += 7; } *bytes_read_ptr = num_read; return result; } static long read_signed_leb128 (bfd *abfd, char *buf, unsigned int *bytes_read_ptr) { long result; int i, shift, size, num_read; unsigned char byte; result = 0; shift = 0; size = 32; num_read = 0; i = 0; while (1) { byte = bfd_get_8 (abfd, (bfd_byte *) buf); buf++; num_read++; result |= ((long)(byte & 127) << shift); shift += 7; if ((byte & 128) == 0) { break; } } if ((shift < size) && (byte & 0x40)) { result |= -(1 << shift); } *bytes_read_ptr = num_read; return result; } static void set_cu_language (unsigned int lang, struct dwarf2_cu *cu) { switch (lang) { case DW_LANG_C89: case DW_LANG_C: cu->language = language_c; break; case DW_LANG_C_plus_plus: cu->language = language_cplus; break; case DW_LANG_Fortran77: case DW_LANG_Fortran90: case DW_LANG_Fortran95: cu->language = language_fortran; break; case DW_LANG_Mips_Assembler: cu->language = language_asm; break; case DW_LANG_Java: cu->language = language_java; break; case DW_LANG_Ada83: case DW_LANG_Ada95: case DW_LANG_Cobol74: case DW_LANG_Cobol85: case DW_LANG_Pascal83: case DW_LANG_Modula2: default: cu->language = language_minimal; break; } cu->language_defn = language_def (cu->language); } /* Return the named attribute or NULL if not there. */ static struct attribute * dwarf2_attr (struct die_info *die, unsigned int name, struct dwarf2_cu *cu) { unsigned int i; struct attribute *spec = NULL; for (i = 0; i < die->num_attrs; ++i) { if (die->attrs[i].name == name) { return &die->attrs[i]; } if (die->attrs[i].name == DW_AT_specification || die->attrs[i].name == DW_AT_abstract_origin) spec = &die->attrs[i]; } if (spec) { struct die_info *ref_die = follow_die_ref (dwarf2_get_ref_die_offset (spec, cu)); if (ref_die) return dwarf2_attr (ref_die, name, cu); } return NULL; } static int die_is_declaration (struct die_info *die, struct dwarf2_cu *cu) { return (dwarf2_attr (die, DW_AT_declaration, cu) && ! dwarf2_attr (die, DW_AT_specification, cu)); } /* Return the die giving the specification for DIE, if there is one. */ static struct die_info * die_specification (struct die_info *die, struct dwarf2_cu *cu) { struct attribute *spec_attr = dwarf2_attr (die, DW_AT_specification, cu); if (spec_attr == NULL) return NULL; else return follow_die_ref (dwarf2_get_ref_die_offset (spec_attr, cu)); } /* Free the line_header structure *LH, and any arrays and strings it refers to. */ static void free_line_header (struct line_header *lh) { if (lh->standard_opcode_lengths) xfree (lh->standard_opcode_lengths); /* Remember that all the lh->file_names[i].name pointers are pointers into debug_line_buffer, and don't need to be freed. */ if (lh->file_names) xfree (lh->file_names); /* Similarly for the include directory names. */ if (lh->include_dirs) xfree (lh->include_dirs); xfree (lh); } /* Add an entry to LH's include directory table. */ static void add_include_dir (struct line_header *lh, char *include_dir) { /* Grow the array if necessary. */ if (lh->include_dirs_size == 0) { lh->include_dirs_size = 1; /* for testing */ lh->include_dirs = xmalloc (lh->include_dirs_size * sizeof (*lh->include_dirs)); } else if (lh->num_include_dirs >= lh->include_dirs_size) { lh->include_dirs_size *= 2; lh->include_dirs = xrealloc (lh->include_dirs, (lh->include_dirs_size * sizeof (*lh->include_dirs))); } lh->include_dirs[lh->num_include_dirs++] = include_dir; } /* Add an entry to LH's file name table. */ static void add_file_name (struct line_header *lh, char *name, unsigned int dir_index, unsigned int mod_time, unsigned int length) { struct file_entry *fe; /* Grow the array if necessary. */ if (lh->file_names_size == 0) { lh->file_names_size = 1; /* for testing */ lh->file_names = xmalloc (lh->file_names_size * sizeof (*lh->file_names)); } else if (lh->num_file_names >= lh->file_names_size) { lh->file_names_size *= 2; lh->file_names = xrealloc (lh->file_names, (lh->file_names_size * sizeof (*lh->file_names))); } fe = &lh->file_names[lh->num_file_names++]; fe->name = name; fe->dir_index = dir_index; fe->mod_time = mod_time; fe->length = length; } /* Read the statement program header starting at OFFSET in dwarf_line_buffer, according to the endianness of ABFD. Return a pointer to a struct line_header, allocated using xmalloc. NOTE: the strings in the include directory and file name tables of the returned object point into debug_line_buffer, and must not be freed. */ static struct line_header * dwarf_decode_line_header (unsigned int offset, bfd *abfd, struct dwarf2_cu *cu) { struct cleanup *back_to; struct line_header *lh; char *line_ptr; int bytes_read; int i; char *cur_dir, *cur_file; if (dwarf_line_buffer == NULL) { complaint (&symfile_complaints, "missing .debug_line section"); return 0; } /* Make sure that at least there's room for the total_length field. That could be 12 bytes long, but we're just going to fudge that. */ if (offset + 4 >= dwarf_line_size) { dwarf2_statement_list_fits_in_line_number_section_complaint (); return 0; } lh = xmalloc (sizeof (*lh)); memset (lh, 0, sizeof (*lh)); back_to = make_cleanup ((make_cleanup_ftype *) free_line_header, (void *) lh); line_ptr = dwarf_line_buffer + offset; /* read in the header */ lh->total_length = read_initial_length (abfd, line_ptr, &cu->header, &bytes_read); line_ptr += bytes_read; if (line_ptr + lh->total_length > dwarf_line_buffer + dwarf_line_size) { dwarf2_statement_list_fits_in_line_number_section_complaint (); return 0; } lh->statement_program_end = line_ptr + lh->total_length; lh->version = read_2_bytes (abfd, line_ptr); line_ptr += 2; lh->header_length = read_offset (abfd, line_ptr, &cu->header, &bytes_read); line_ptr += bytes_read; lh->minimum_instruction_length = read_1_byte (abfd, line_ptr); line_ptr += 1; lh->default_is_stmt = read_1_byte (abfd, line_ptr); line_ptr += 1; lh->line_base = read_1_signed_byte (abfd, line_ptr); line_ptr += 1; lh->line_range = read_1_byte (abfd, line_ptr); line_ptr += 1; lh->opcode_base = read_1_byte (abfd, line_ptr); line_ptr += 1; lh->standard_opcode_lengths = (unsigned char *) xmalloc (lh->opcode_base * sizeof (unsigned char)); lh->standard_opcode_lengths[0] = 1; /* This should never be used anyway. */ for (i = 1; i < lh->opcode_base; ++i) { lh->standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr); line_ptr += 1; } /* Read directory table */ while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL) { line_ptr += bytes_read; add_include_dir (lh, cur_dir); } line_ptr += bytes_read; /* Read file name table */ while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL) { unsigned int dir_index, mod_time, length; line_ptr += bytes_read; dir_index = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; mod_time = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; length = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; add_file_name (lh, cur_file, dir_index, mod_time, length); } line_ptr += bytes_read; lh->statement_program_start = line_ptr; if (line_ptr > dwarf_line_buffer + dwarf_line_size) complaint (&symfile_complaints, "line number info header doesn't fit in `.debug_line' section"); discard_cleanups (back_to); return lh; } /* This function exists to work around a bug in certain compilers (particularly GCC 2.95), in which the first line number marker of a function does not show up until after the prologue, right before the second line number marker. This function shifts ADDRESS down to the beginning of the function if necessary, and is called on addresses passed to record_line. */ static CORE_ADDR check_cu_functions (CORE_ADDR address, struct dwarf2_cu *cu) { struct function_range *fn; /* Find the function_range containing address. */ if (!cu->first_fn) return address; if (!cu->cached_fn) cu->cached_fn = cu->first_fn; fn = cu->cached_fn; while (fn) if (fn->lowpc <= address && fn->highpc > address) goto found; else fn = fn->next; fn = cu->first_fn; while (fn && fn != cu->cached_fn) if (fn->lowpc <= address && fn->highpc > address) goto found; else fn = fn->next; return address; found: if (fn->seen_line) return address; if (address != fn->lowpc) complaint (&symfile_complaints, "misplaced first line number at 0x%lx for '%s'", (unsigned long) address, fn->name); fn->seen_line = 1; return fn->lowpc; } /* Decode the line number information for the compilation unit whose line number info is at OFFSET in the .debug_line section. The compilation directory of the file is passed in COMP_DIR. */ static void dwarf_decode_lines (struct line_header *lh, char *comp_dir, bfd *abfd, struct dwarf2_cu *cu) { char *line_ptr; char *line_end; unsigned int bytes_read; unsigned char op_code, extended_op, adj_opcode; CORE_ADDR baseaddr; struct objfile *objfile = cu->objfile; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); line_ptr = lh->statement_program_start; line_end = lh->statement_program_end; /* Read the statement sequences until there's nothing left. */ while (line_ptr < line_end) { /* state machine registers */ CORE_ADDR address = 0; unsigned int file = 1; unsigned int line = 1; unsigned int column = 0; int is_stmt = lh->default_is_stmt; int basic_block = 0; int end_sequence = 0; /* Start a subfile for the current file of the state machine. */ if (lh->num_file_names >= file) { /* lh->include_dirs and lh->file_names are 0-based, but the directory and file name numbers in the statement program are 1-based. */ struct file_entry *fe = &lh->file_names[file - 1]; char *dir; if (fe->dir_index) dir = lh->include_dirs[fe->dir_index - 1]; else dir = comp_dir; dwarf2_start_subfile (fe->name, dir); } /* Decode the table. */ while (!end_sequence) { op_code = read_1_byte (abfd, line_ptr); line_ptr += 1; if (op_code >= lh->opcode_base) { /* Special operand. */ adj_opcode = op_code - lh->opcode_base; address += (adj_opcode / lh->line_range) * lh->minimum_instruction_length; line += lh->line_base + (adj_opcode % lh->line_range); /* append row to matrix using current values */ record_line (current_subfile, line, check_cu_functions (address, cu)); basic_block = 1; } else switch (op_code) { case DW_LNS_extended_op: line_ptr += 1; /* ignore length */ extended_op = read_1_byte (abfd, line_ptr); line_ptr += 1; switch (extended_op) { case DW_LNE_end_sequence: end_sequence = 1; record_line (current_subfile, 0, address); break; case DW_LNE_set_address: address = read_address (abfd, line_ptr, cu, &bytes_read); line_ptr += bytes_read; address += baseaddr; break; case DW_LNE_define_file: { char *cur_file; unsigned int dir_index, mod_time, length; cur_file = read_string (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; dir_index = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; mod_time = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; length = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; add_file_name (lh, cur_file, dir_index, mod_time, length); } break; default: complaint (&symfile_complaints, "mangled .debug_line section"); return; } break; case DW_LNS_copy: record_line (current_subfile, line, check_cu_functions (address, cu)); basic_block = 0; break; case DW_LNS_advance_pc: address += lh->minimum_instruction_length * read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; break; case DW_LNS_advance_line: line += read_signed_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; break; case DW_LNS_set_file: { /* lh->include_dirs and lh->file_names are 0-based, but the directory and file name numbers in the statement program are 1-based. */ struct file_entry *fe; char *dir; file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; fe = &lh->file_names[file - 1]; if (fe->dir_index) dir = lh->include_dirs[fe->dir_index - 1]; else dir = comp_dir; dwarf2_start_subfile (fe->name, dir); } break; case DW_LNS_set_column: column = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; break; case DW_LNS_negate_stmt: is_stmt = (!is_stmt); break; case DW_LNS_set_basic_block: basic_block = 1; break; /* Add to the address register of the state machine the address increment value corresponding to special opcode 255. Ie, this value is scaled by the minimum instruction length since special opcode 255 would have scaled the the increment. */ case DW_LNS_const_add_pc: address += (lh->minimum_instruction_length * ((255 - lh->opcode_base) / lh->line_range)); break; case DW_LNS_fixed_advance_pc: address += read_2_bytes (abfd, line_ptr); line_ptr += 2; break; default: { /* Unknown standard opcode, ignore it. */ int i; for (i = 0; i < lh->standard_opcode_lengths[op_code]; i++) { (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read); line_ptr += bytes_read; } } } } } } /* Start a subfile for DWARF. FILENAME is the name of the file and DIRNAME the name of the source directory which contains FILENAME or NULL if not known. This routine tries to keep line numbers from identical absolute and relative file names in a common subfile. Using the `list' example from the GDB testsuite, which resides in /srcdir and compiling it with Irix6.2 cc in /compdir using a filename of /srcdir/list0.c yields the following debugging information for list0.c: DW_AT_name: /srcdir/list0.c DW_AT_comp_dir: /compdir files.files[0].name: list0.h files.files[0].dir: /srcdir files.files[1].name: list0.c files.files[1].dir: /srcdir The line number information for list0.c has to end up in a single subfile, so that `break /srcdir/list0.c:1' works as expected. */ static void dwarf2_start_subfile (char *filename, char *dirname) { /* If the filename isn't absolute, try to match an existing subfile with the full pathname. */ if (!IS_ABSOLUTE_PATH (filename) && dirname != NULL) { struct subfile *subfile; char *fullname = concat (dirname, "/", filename, NULL); for (subfile = subfiles; subfile; subfile = subfile->next) { if (FILENAME_CMP (subfile->name, fullname) == 0) { current_subfile = subfile; xfree (fullname); return; } } xfree (fullname); } start_subfile (filename, dirname); } static void var_decode_location (struct attribute *attr, struct symbol *sym, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct comp_unit_head *cu_header = &cu->header; /* NOTE drow/2003-01-30: There used to be a comment and some special code here to turn a symbol with DW_AT_external and a SYMBOL_VALUE_ADDRESS of 0 into a LOC_UNRESOLVED symbol. This was necessary for platforms (maybe Alpha, certainly PowerPC GNU/Linux with some versions of binutils) where shared libraries could have relocations against symbols in their debug information - the minimal symbol would have the right address, but the debug info would not. It's no longer necessary, because we will explicitly apply relocations when we read in the debug information now. */ /* A DW_AT_location attribute with no contents indicates that a variable has been optimized away. */ if (attr_form_is_block (attr) && DW_BLOCK (attr)->size == 0) { SYMBOL_CLASS (sym) = LOC_OPTIMIZED_OUT; return; } /* Handle one degenerate form of location expression specially, to preserve GDB's previous behavior when section offsets are specified. If this is just a DW_OP_addr then mark this symbol as LOC_STATIC. */ if (attr_form_is_block (attr) && DW_BLOCK (attr)->size == 1 + cu_header->addr_size && DW_BLOCK (attr)->data[0] == DW_OP_addr) { int dummy; SYMBOL_VALUE_ADDRESS (sym) = read_address (objfile->obfd, DW_BLOCK (attr)->data + 1, cu, &dummy); fixup_symbol_section (sym, objfile); SYMBOL_VALUE_ADDRESS (sym) += ANOFFSET (objfile->section_offsets, SYMBOL_SECTION (sym)); SYMBOL_CLASS (sym) = LOC_STATIC; return; } /* NOTE drow/2002-01-30: It might be worthwhile to have a static expression evaluator, and use LOC_COMPUTED only when necessary (i.e. when the value of a register or memory location is referenced, or a thread-local block, etc.). Then again, it might not be worthwhile. I'm assuming that it isn't unless performance or memory numbers show me otherwise. */ dwarf2_symbol_mark_computed (attr, sym, cu); SYMBOL_CLASS (sym) = LOC_COMPUTED; } /* Given a pointer to a DWARF information entry, figure out if we need to make a symbol table entry for it, and if so, create a new entry and return a pointer to it. If TYPE is NULL, determine symbol type from the die, otherwise used the passed type. */ static struct symbol * new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct symbol *sym = NULL; char *name; struct attribute *attr = NULL; struct attribute *attr2 = NULL; CORE_ADDR baseaddr; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); if (die->tag != DW_TAG_namespace) name = dwarf2_linkage_name (die, cu); else name = TYPE_NAME (type); if (name) { sym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack, sizeof (struct symbol)); OBJSTAT (objfile, n_syms++); memset (sym, 0, sizeof (struct symbol)); /* Cache this symbol's name and the name's demangled form (if any). */ SYMBOL_LANGUAGE (sym) = cu->language; SYMBOL_SET_NAMES (sym, name, strlen (name), objfile); /* Default assumptions. Use the passed type or decode it from the die. */ SYMBOL_DOMAIN (sym) = VAR_DOMAIN; SYMBOL_CLASS (sym) = LOC_STATIC; if (type != NULL) SYMBOL_TYPE (sym) = type; else SYMBOL_TYPE (sym) = die_type (die, cu); attr = dwarf2_attr (die, DW_AT_decl_line, cu); if (attr) { SYMBOL_LINE (sym) = DW_UNSND (attr); } switch (die->tag) { case DW_TAG_label: attr = dwarf2_attr (die, DW_AT_low_pc, cu); if (attr) { SYMBOL_VALUE_ADDRESS (sym) = DW_ADDR (attr) + baseaddr; } SYMBOL_CLASS (sym) = LOC_LABEL; break; case DW_TAG_subprogram: /* SYMBOL_BLOCK_VALUE (sym) will be filled in later by finish_block. */ SYMBOL_CLASS (sym) = LOC_BLOCK; attr2 = dwarf2_attr (die, DW_AT_external, cu); if (attr2 && (DW_UNSND (attr2) != 0)) { add_symbol_to_list (sym, &global_symbols); } else { add_symbol_to_list (sym, cu->list_in_scope); } break; case DW_TAG_variable: /* Compilation with minimal debug info may result in variables with missing type entries. Change the misleading `void' type to something sensible. */ if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_VOID) SYMBOL_TYPE (sym) = init_type (TYPE_CODE_INT, TARGET_INT_BIT / HOST_CHAR_BIT, 0, "", objfile); attr = dwarf2_attr (die, DW_AT_const_value, cu); if (attr) { dwarf2_const_value (attr, sym, cu); attr2 = dwarf2_attr (die, DW_AT_external, cu); if (attr2 && (DW_UNSND (attr2) != 0)) add_symbol_to_list (sym, &global_symbols); else add_symbol_to_list (sym, cu->list_in_scope); break; } attr = dwarf2_attr (die, DW_AT_location, cu); if (attr) { var_decode_location (attr, sym, cu); attr2 = dwarf2_attr (die, DW_AT_external, cu); if (attr2 && (DW_UNSND (attr2) != 0)) add_symbol_to_list (sym, &global_symbols); else add_symbol_to_list (sym, cu->list_in_scope); } else { /* We do not know the address of this symbol. If it is an external symbol and we have type information for it, enter the symbol as a LOC_UNRESOLVED symbol. The address of the variable will then be determined from the minimal symbol table whenever the variable is referenced. */ attr2 = dwarf2_attr (die, DW_AT_external, cu); if (attr2 && (DW_UNSND (attr2) != 0) && dwarf2_attr (die, DW_AT_type, cu) != NULL) { SYMBOL_CLASS (sym) = LOC_UNRESOLVED; add_symbol_to_list (sym, &global_symbols); } } break; case DW_TAG_formal_parameter: attr = dwarf2_attr (die, DW_AT_location, cu); if (attr) { var_decode_location (attr, sym, cu); /* FIXME drow/2003-07-31: Is LOC_COMPUTED_ARG necessary? */ if (SYMBOL_CLASS (sym) == LOC_COMPUTED) SYMBOL_CLASS (sym) = LOC_COMPUTED_ARG; } attr = dwarf2_attr (die, DW_AT_const_value, cu); if (attr) { dwarf2_const_value (attr, sym, cu); } add_symbol_to_list (sym, cu->list_in_scope); break; case DW_TAG_unspecified_parameters: /* From varargs functions; gdb doesn't seem to have any interest in this information, so just ignore it for now. (FIXME?) */ break; case DW_TAG_class_type: case DW_TAG_structure_type: case DW_TAG_union_type: case DW_TAG_enumeration_type: SYMBOL_CLASS (sym) = LOC_TYPEDEF; SYMBOL_DOMAIN (sym) = STRUCT_DOMAIN; /* Make sure that the symbol includes appropriate enclosing classes/namespaces in its name. These are calculated in read_structure_type, and the correct name is saved in the type. */ if (cu->language == language_cplus) { struct type *type = SYMBOL_TYPE (sym); if (TYPE_TAG_NAME (type) != NULL) { /* FIXME: carlton/2003-11-10: Should this use SYMBOL_SET_NAMES instead? (The same problem also arises a further down in the function.) */ SYMBOL_LINKAGE_NAME (sym) = obsavestring (TYPE_TAG_NAME (type), strlen (TYPE_TAG_NAME (type)), &objfile->objfile_obstack); } } { /* NOTE: carlton/2003-11-10: C++ class symbols shouldn't really ever be static objects: otherwise, if you try to, say, break of a class's method and you're in a file which doesn't mention that class, it won't work unless the check for all static symbols in lookup_symbol_aux saves you. See the OtherFileClass tests in gdb.c++/namespace.exp. */ struct pending **list_to_add; list_to_add = (cu->list_in_scope == &file_symbols && cu->language == language_cplus ? &global_symbols : cu->list_in_scope); add_symbol_to_list (sym, list_to_add); /* The semantics of C++ state that "struct foo { ... }" also defines a typedef for "foo". Synthesize a typedef symbol so that "ptype foo" works as expected. */ if (cu->language == language_cplus) { struct symbol *typedef_sym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack, sizeof (struct symbol)); *typedef_sym = *sym; SYMBOL_DOMAIN (typedef_sym) = VAR_DOMAIN; if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0) TYPE_NAME (SYMBOL_TYPE (sym)) = obsavestring (SYMBOL_NATURAL_NAME (sym), strlen (SYMBOL_NATURAL_NAME (sym)), &objfile->objfile_obstack); add_symbol_to_list (typedef_sym, list_to_add); } } break; case DW_TAG_typedef: if (processing_has_namespace_info && processing_current_prefix[0] != '\0') { SYMBOL_LINKAGE_NAME (sym) = obconcat (&objfile->objfile_obstack, processing_current_prefix, "::", name); } SYMBOL_CLASS (sym) = LOC_TYPEDEF; SYMBOL_DOMAIN (sym) = VAR_DOMAIN; add_symbol_to_list (sym, cu->list_in_scope); break; case DW_TAG_base_type: case DW_TAG_subrange_type: SYMBOL_CLASS (sym) = LOC_TYPEDEF; SYMBOL_DOMAIN (sym) = VAR_DOMAIN; add_symbol_to_list (sym, cu->list_in_scope); break; case DW_TAG_enumerator: if (processing_has_namespace_info && processing_current_prefix[0] != '\0') { SYMBOL_LINKAGE_NAME (sym) = obconcat (&objfile->objfile_obstack, processing_current_prefix, "::", name); } attr = dwarf2_attr (die, DW_AT_const_value, cu); if (attr) { dwarf2_const_value (attr, sym, cu); } { /* NOTE: carlton/2003-11-10: See comment above in the DW_TAG_class_type, etc. block. */ struct pending **list_to_add; list_to_add = (cu->list_in_scope == &file_symbols && cu->language == language_cplus ? &global_symbols : cu->list_in_scope); add_symbol_to_list (sym, list_to_add); } break; case DW_TAG_namespace: SYMBOL_CLASS (sym) = LOC_TYPEDEF; add_symbol_to_list (sym, &global_symbols); break; default: /* Not a tag we recognize. Hopefully we aren't processing trash data, but since we must specifically ignore things we don't recognize, there is nothing else we should do at this point. */ complaint (&symfile_complaints, "unsupported tag: '%s'", dwarf_tag_name (die->tag)); break; } } return (sym); } /* Copy constant value from an attribute to a symbol. */ static void dwarf2_const_value (struct attribute *attr, struct symbol *sym, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct comp_unit_head *cu_header = &cu->header; struct dwarf_block *blk; switch (attr->form) { case DW_FORM_addr: if (TYPE_LENGTH (SYMBOL_TYPE (sym)) != cu_header->addr_size) dwarf2_const_value_length_mismatch_complaint (DEPRECATED_SYMBOL_NAME (sym), cu_header->addr_size, TYPE_LENGTH (SYMBOL_TYPE (sym))); SYMBOL_VALUE_BYTES (sym) = (char *) obstack_alloc (&objfile->objfile_obstack, cu_header->addr_size); /* NOTE: cagney/2003-05-09: In-lined store_address call with it's body - store_unsigned_integer. */ store_unsigned_integer (SYMBOL_VALUE_BYTES (sym), cu_header->addr_size, DW_ADDR (attr)); SYMBOL_CLASS (sym) = LOC_CONST_BYTES; break; case DW_FORM_block1: case DW_FORM_block2: case DW_FORM_block4: case DW_FORM_block: blk = DW_BLOCK (attr); if (TYPE_LENGTH (SYMBOL_TYPE (sym)) != blk->size) dwarf2_const_value_length_mismatch_complaint (DEPRECATED_SYMBOL_NAME (sym), blk->size, TYPE_LENGTH (SYMBOL_TYPE (sym))); SYMBOL_VALUE_BYTES (sym) = (char *) obstack_alloc (&objfile->objfile_obstack, blk->size); memcpy (SYMBOL_VALUE_BYTES (sym), blk->data, blk->size); SYMBOL_CLASS (sym) = LOC_CONST_BYTES; break; /* The DW_AT_const_value attributes are supposed to carry the symbol's value "represented as it would be on the target architecture." By the time we get here, it's already been converted to host endianness, so we just need to sign- or zero-extend it as appropriate. */ case DW_FORM_data1: dwarf2_const_value_data (attr, sym, 8); break; case DW_FORM_data2: dwarf2_const_value_data (attr, sym, 16); break; case DW_FORM_data4: dwarf2_const_value_data (attr, sym, 32); break; case DW_FORM_data8: dwarf2_const_value_data (attr, sym, 64); break; case DW_FORM_sdata: SYMBOL_VALUE (sym) = DW_SND (attr); SYMBOL_CLASS (sym) = LOC_CONST; break; case DW_FORM_udata: SYMBOL_VALUE (sym) = DW_UNSND (attr); SYMBOL_CLASS (sym) = LOC_CONST; break; default: complaint (&symfile_complaints, "unsupported const value attribute form: '%s'", dwarf_form_name (attr->form)); SYMBOL_VALUE (sym) = 0; SYMBOL_CLASS (sym) = LOC_CONST; break; } } /* Given an attr with a DW_FORM_dataN value in host byte order, sign- or zero-extend it as appropriate for the symbol's type. */ static void dwarf2_const_value_data (struct attribute *attr, struct symbol *sym, int bits) { LONGEST l = DW_UNSND (attr); if (bits < sizeof (l) * 8) { if (TYPE_UNSIGNED (SYMBOL_TYPE (sym))) l &= ((LONGEST) 1 << bits) - 1; else l = (l << (sizeof (l) * 8 - bits)) >> (sizeof (l) * 8 - bits); } SYMBOL_VALUE (sym) = l; SYMBOL_CLASS (sym) = LOC_CONST; } /* Return the type of the die in question using its DW_AT_type attribute. */ static struct type * die_type (struct die_info *die, struct dwarf2_cu *cu) { struct type *type; struct attribute *type_attr; struct die_info *type_die; unsigned int ref; type_attr = dwarf2_attr (die, DW_AT_type, cu); if (!type_attr) { /* A missing DW_AT_type represents a void type. */ return dwarf2_fundamental_type (cu->objfile, FT_VOID, cu); } else { ref = dwarf2_get_ref_die_offset (type_attr, cu); type_die = follow_die_ref (ref); if (!type_die) { error ("Dwarf Error: Cannot find referent at offset %d [in module %s]", ref, cu->objfile->name); return NULL; } } type = tag_type_to_type (type_die, cu); if (!type) { dump_die (type_die); error ("Dwarf Error: Problem turning type die at offset into gdb type [in module %s]", cu->objfile->name); } return type; } /* Return the containing type of the die in question using its DW_AT_containing_type attribute. */ static struct type * die_containing_type (struct die_info *die, struct dwarf2_cu *cu) { struct type *type = NULL; struct attribute *type_attr; struct die_info *type_die = NULL; unsigned int ref; type_attr = dwarf2_attr (die, DW_AT_containing_type, cu); if (type_attr) { ref = dwarf2_get_ref_die_offset (type_attr, cu); type_die = follow_die_ref (ref); if (!type_die) { error ("Dwarf Error: Cannot find referent at offset %d [in module %s]", ref, cu->objfile->name); return NULL; } type = tag_type_to_type (type_die, cu); } if (!type) { if (type_die) dump_die (type_die); error ("Dwarf Error: Problem turning containing type into gdb type [in module %s]", cu->objfile->name); } return type; } #if 0 static struct type * type_at_offset (unsigned int offset, struct dwarf2_cu *cu) { struct die_info *die; struct type *type; die = follow_die_ref (offset); if (!die) { error ("Dwarf Error: Cannot find type referent at offset %d.", offset); return NULL; } type = tag_type_to_type (die, cu); return type; } #endif static struct type * tag_type_to_type (struct die_info *die, struct dwarf2_cu *cu) { if (die->type) { return die->type; } else { read_type_die (die, cu); if (!die->type) { dump_die (die); error ("Dwarf Error: Cannot find type of die 0x%x [in module %s]", die->tag, cu->objfile->name); } return die->type; } } static void read_type_die (struct die_info *die, struct dwarf2_cu *cu) { char *prefix = determine_prefix (die, cu); const char *old_prefix = processing_current_prefix; struct cleanup *back_to = make_cleanup (xfree, prefix); processing_current_prefix = prefix; switch (die->tag) { case DW_TAG_class_type: case DW_TAG_structure_type: case DW_TAG_union_type: read_structure_type (die, cu); break; case DW_TAG_enumeration_type: read_enumeration_type (die, cu); break; case DW_TAG_subprogram: case DW_TAG_subroutine_type: read_subroutine_type (die, cu); break; case DW_TAG_array_type: read_array_type (die, cu); break; case DW_TAG_pointer_type: read_tag_pointer_type (die, cu); break; case DW_TAG_unspecified_type: read_tag_unspecified_type (die, cu); break; case DW_TAG_ptr_to_member_type: read_tag_ptr_to_member_type (die, cu); break; case DW_TAG_reference_type: case DW_TAG_rvalue_reference_type: read_tag_reference_type (die, cu); break; case DW_TAG_const_type: read_tag_const_type (die, cu); break; case DW_TAG_volatile_type: read_tag_volatile_type (die, cu); break; case DW_TAG_restrict_type: read_tag_restrict_type (die, cu); break; case DW_TAG_string_type: read_tag_string_type (die, cu); break; case DW_TAG_typedef: read_typedef (die, cu); break; case DW_TAG_subrange_type: read_subrange_type (die, cu); break; case DW_TAG_base_type: read_base_type (die, cu); break; default: complaint (&symfile_complaints, "unexepected tag in read_type_die: '%s'", dwarf_tag_name (die->tag)); break; } processing_current_prefix = old_prefix; do_cleanups (back_to); } /* Return the name of the namespace/class that DIE is defined within, or "" if we can't tell. The caller should xfree the result. */ /* NOTE: carlton/2004-01-23: See read_func_scope (and the comment therein) for an example of how to use this function to deal with DW_AT_specification. */ static char * determine_prefix (struct die_info *die, struct dwarf2_cu *cu) { struct die_info *parent; if (cu->language != language_cplus) return NULL; parent = die->parent; if (parent == NULL) { return xstrdup (""); } else { switch (parent->tag) { case DW_TAG_namespace: { /* FIXME: carlton/2004-03-05: Should I follow extension dies before doing this check? */ if (parent->type != NULL && TYPE_TAG_NAME (parent->type) != NULL) { return xstrdup (TYPE_TAG_NAME (parent->type)); } else { int dummy; char *parent_prefix = determine_prefix (parent, cu); char *retval = typename_concat (parent_prefix, namespace_name (parent, &dummy, cu)); xfree (parent_prefix); return retval; } } break; case DW_TAG_class_type: case DW_TAG_structure_type: { if (parent->type != NULL && TYPE_TAG_NAME (parent->type) != NULL) { return xstrdup (TYPE_TAG_NAME (parent->type)); } else { const char *old_prefix = processing_current_prefix; char *new_prefix = determine_prefix (parent, cu); char *retval; processing_current_prefix = new_prefix; retval = determine_class_name (parent, cu); processing_current_prefix = old_prefix; xfree (new_prefix); return retval; } } default: return determine_prefix (parent, cu); } } } /* Return a newly-allocated string formed by concatenating PREFIX, "::", and SUFFIX, except that if PREFIX is NULL or the empty string, just return a copy of SUFFIX. */ static char * typename_concat (const char *prefix, const char *suffix) { if (prefix == NULL || prefix[0] == '\0') return xstrdup (suffix); else { char *retval = xmalloc (strlen (prefix) + 2 + strlen (suffix) + 1); strcpy (retval, prefix); strcat (retval, "::"); strcat (retval, suffix); return retval; } } static struct type * dwarf_base_type (int encoding, int size, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; /* FIXME - this should not produce a new (struct type *) every time. It should cache base types. */ struct type *type; switch (encoding) { case DW_ATE_address: type = dwarf2_fundamental_type (objfile, FT_VOID, cu); return type; case DW_ATE_boolean: type = dwarf2_fundamental_type (objfile, FT_BOOLEAN, cu); return type; case DW_ATE_complex_float: if (size == 16) { type = dwarf2_fundamental_type (objfile, FT_DBL_PREC_COMPLEX, cu); } else { type = dwarf2_fundamental_type (objfile, FT_COMPLEX, cu); } return type; case DW_ATE_float: if (size == 8) { type = dwarf2_fundamental_type (objfile, FT_DBL_PREC_FLOAT, cu); } else { type = dwarf2_fundamental_type (objfile, FT_FLOAT, cu); } return type; case DW_ATE_signed: switch (size) { case 1: type = dwarf2_fundamental_type (objfile, FT_SIGNED_CHAR, cu); break; case 2: type = dwarf2_fundamental_type (objfile, FT_SIGNED_SHORT, cu); break; default: case 4: type = dwarf2_fundamental_type (objfile, FT_SIGNED_INTEGER, cu); break; } return type; case DW_ATE_signed_char: type = dwarf2_fundamental_type (objfile, FT_SIGNED_CHAR, cu); return type; case DW_ATE_unsigned: switch (size) { case 1: type = dwarf2_fundamental_type (objfile, FT_UNSIGNED_CHAR, cu); break; case 2: type = dwarf2_fundamental_type (objfile, FT_UNSIGNED_SHORT, cu); break; default: case 4: type = dwarf2_fundamental_type (objfile, FT_UNSIGNED_INTEGER, cu); break; } return type; case DW_ATE_unsigned_char: type = dwarf2_fundamental_type (objfile, FT_UNSIGNED_CHAR, cu); return type; default: type = dwarf2_fundamental_type (objfile, FT_SIGNED_INTEGER, cu); return type; } } #if 0 struct die_info * copy_die (struct die_info *old_die) { struct die_info *new_die; int i, num_attrs; new_die = (struct die_info *) xmalloc (sizeof (struct die_info)); memset (new_die, 0, sizeof (struct die_info)); new_die->tag = old_die->tag; new_die->has_children = old_die->has_children; new_die->abbrev = old_die->abbrev; new_die->offset = old_die->offset; new_die->type = NULL; num_attrs = old_die->num_attrs; new_die->num_attrs = num_attrs; new_die->attrs = (struct attribute *) xmalloc (num_attrs * sizeof (struct attribute)); for (i = 0; i < old_die->num_attrs; ++i) { new_die->attrs[i].name = old_die->attrs[i].name; new_die->attrs[i].form = old_die->attrs[i].form; new_die->attrs[i].u.addr = old_die->attrs[i].u.addr; } new_die->next = NULL; return new_die; } #endif /* Return sibling of die, NULL if no sibling. */ static struct die_info * sibling_die (struct die_info *die) { return die->sibling; } /* Get linkage name of a die, return NULL if not found. */ static char * dwarf2_linkage_name (struct die_info *die, struct dwarf2_cu *cu) { struct attribute *attr; attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu); if (attr && DW_STRING (attr)) return DW_STRING (attr); attr = dwarf2_attr (die, DW_AT_name, cu); if (attr && DW_STRING (attr)) return DW_STRING (attr); return NULL; } /* Get name of a die, return NULL if not found. */ static char * dwarf2_name (struct die_info *die, struct dwarf2_cu *cu) { struct attribute *attr; attr = dwarf2_attr (die, DW_AT_name, cu); if (attr && DW_STRING (attr)) return DW_STRING (attr); return NULL; } /* Return the die that this die in an extension of, or NULL if there is none. */ static struct die_info * dwarf2_extension (struct die_info *die, struct dwarf2_cu *cu) { struct attribute *attr; struct die_info *extension_die; unsigned int ref; attr = dwarf2_attr (die, DW_AT_extension, cu); if (attr == NULL) return NULL; ref = dwarf2_get_ref_die_offset (attr, cu); extension_die = follow_die_ref (ref); if (!extension_die) { error ("Dwarf Error: Cannot find referent at offset %d.", ref); } return extension_die; } /* Convert a DIE tag into its string name. */ static char * dwarf_tag_name (unsigned tag) { switch (tag) { case DW_TAG_padding: return "DW_TAG_padding"; case DW_TAG_array_type: return "DW_TAG_array_type"; case DW_TAG_class_type: return "DW_TAG_class_type"; case DW_TAG_entry_point: return "DW_TAG_entry_point"; case DW_TAG_enumeration_type: return "DW_TAG_enumeration_type"; case DW_TAG_formal_parameter: return "DW_TAG_formal_parameter"; case DW_TAG_imported_declaration: return "DW_TAG_imported_declaration"; case DW_TAG_label: return "DW_TAG_label"; case DW_TAG_lexical_block: return "DW_TAG_lexical_block"; case DW_TAG_member: return "DW_TAG_member"; case DW_TAG_pointer_type: return "DW_TAG_pointer_type"; case DW_TAG_reference_type: return "DW_TAG_reference_type"; case DW_TAG_rvalue_reference_type: return "DW_TAG_rvalue_reference_type"; case DW_TAG_compile_unit: return "DW_TAG_compile_unit"; case DW_TAG_string_type: return "DW_TAG_string_type"; case DW_TAG_structure_type: return "DW_TAG_structure_type"; case DW_TAG_subroutine_type: return "DW_TAG_subroutine_type"; case DW_TAG_typedef: return "DW_TAG_typedef"; case DW_TAG_union_type: return "DW_TAG_union_type"; case DW_TAG_unspecified_parameters: return "DW_TAG_unspecified_parameters"; case DW_TAG_variant: return "DW_TAG_variant"; case DW_TAG_common_block: return "DW_TAG_common_block"; case DW_TAG_common_inclusion: return "DW_TAG_common_inclusion"; case DW_TAG_inheritance: return "DW_TAG_inheritance"; case DW_TAG_inlined_subroutine: return "DW_TAG_inlined_subroutine"; case DW_TAG_module: return "DW_TAG_module"; case DW_TAG_ptr_to_member_type: return "DW_TAG_ptr_to_member_type"; case DW_TAG_set_type: return "DW_TAG_set_type"; case DW_TAG_subrange_type: return "DW_TAG_subrange_type"; case DW_TAG_with_stmt: return "DW_TAG_with_stmt"; case DW_TAG_access_declaration: return "DW_TAG_access_declaration"; case DW_TAG_base_type: return "DW_TAG_base_type"; case DW_TAG_catch_block: return "DW_TAG_catch_block"; case DW_TAG_const_type: return "DW_TAG_const_type"; case DW_TAG_constant: return "DW_TAG_constant"; case DW_TAG_enumerator: return "DW_TAG_enumerator"; case DW_TAG_file_type: return "DW_TAG_file_type"; case DW_TAG_friend: return "DW_TAG_friend"; case DW_TAG_namelist: return "DW_TAG_namelist"; case DW_TAG_namelist_item: return "DW_TAG_namelist_item"; case DW_TAG_packed_type: return "DW_TAG_packed_type"; case DW_TAG_subprogram: return "DW_TAG_subprogram"; case DW_TAG_template_type_param: return "DW_TAG_template_type_param"; case DW_TAG_template_value_param: return "DW_TAG_template_value_param"; case DW_TAG_thrown_type: return "DW_TAG_thrown_type"; case DW_TAG_try_block: return "DW_TAG_try_block"; case DW_TAG_variant_part: return "DW_TAG_variant_part"; case DW_TAG_variable: return "DW_TAG_variable"; case DW_TAG_volatile_type: return "DW_TAG_volatile_type"; case DW_TAG_dwarf_procedure: return "DW_TAG_dwarf_procedure"; case DW_TAG_restrict_type: return "DW_TAG_restrict_type"; case DW_TAG_interface_type: return "DW_TAG_interface_type"; case DW_TAG_namespace: return "DW_TAG_namespace"; case DW_TAG_imported_module: return "DW_TAG_imported_module"; case DW_TAG_unspecified_type: return "DW_TAG_unspecified_type"; case DW_TAG_partial_unit: return "DW_TAG_partial_unit"; case DW_TAG_imported_unit: return "DW_TAG_imported_unit"; case DW_TAG_MIPS_loop: return "DW_TAG_MIPS_loop"; case DW_TAG_format_label: return "DW_TAG_format_label"; case DW_TAG_function_template: return "DW_TAG_function_template"; case DW_TAG_class_template: return "DW_TAG_class_template"; default: return "DW_TAG_"; } } /* Convert a DWARF attribute code into its string name. */ static char * dwarf_attr_name (unsigned attr) { switch (attr) { case DW_AT_sibling: return "DW_AT_sibling"; case DW_AT_location: return "DW_AT_location"; case DW_AT_name: return "DW_AT_name"; case DW_AT_ordering: return "DW_AT_ordering"; case DW_AT_subscr_data: return "DW_AT_subscr_data"; case DW_AT_byte_size: return "DW_AT_byte_size"; case DW_AT_bit_offset: return "DW_AT_bit_offset"; case DW_AT_bit_size: return "DW_AT_bit_size"; case DW_AT_element_list: return "DW_AT_element_list"; case DW_AT_stmt_list: return "DW_AT_stmt_list"; case DW_AT_low_pc: return "DW_AT_low_pc"; case DW_AT_high_pc: return "DW_AT_high_pc"; case DW_AT_language: return "DW_AT_language"; case DW_AT_member: return "DW_AT_member"; case DW_AT_discr: return "DW_AT_discr"; case DW_AT_discr_value: return "DW_AT_discr_value"; case DW_AT_visibility: return "DW_AT_visibility"; case DW_AT_import: return "DW_AT_import"; case DW_AT_string_length: return "DW_AT_string_length"; case DW_AT_common_reference: return "DW_AT_common_reference"; case DW_AT_comp_dir: return "DW_AT_comp_dir"; case DW_AT_const_value: return "DW_AT_const_value"; case DW_AT_containing_type: return "DW_AT_containing_type"; case DW_AT_default_value: return "DW_AT_default_value"; case DW_AT_inline: return "DW_AT_inline"; case DW_AT_is_optional: return "DW_AT_is_optional"; case DW_AT_lower_bound: return "DW_AT_lower_bound"; case DW_AT_producer: return "DW_AT_producer"; case DW_AT_prototyped: return "DW_AT_prototyped"; case DW_AT_return_addr: return "DW_AT_return_addr"; case DW_AT_start_scope: return "DW_AT_start_scope"; case DW_AT_stride_size: return "DW_AT_stride_size"; case DW_AT_upper_bound: return "DW_AT_upper_bound"; case DW_AT_abstract_origin: return "DW_AT_abstract_origin"; case DW_AT_accessibility: return "DW_AT_accessibility"; case DW_AT_address_class: return "DW_AT_address_class"; case DW_AT_artificial: return "DW_AT_artificial"; case DW_AT_base_types: return "DW_AT_base_types"; case DW_AT_calling_convention: return "DW_AT_calling_convention"; case DW_AT_count: return "DW_AT_count"; case DW_AT_data_member_location: return "DW_AT_data_member_location"; case DW_AT_decl_column: return "DW_AT_decl_column"; case DW_AT_decl_file: return "DW_AT_decl_file"; case DW_AT_decl_line: return "DW_AT_decl_line"; case DW_AT_declaration: return "DW_AT_declaration"; case DW_AT_discr_list: return "DW_AT_discr_list"; case DW_AT_encoding: return "DW_AT_encoding"; case DW_AT_external: return "DW_AT_external"; case DW_AT_frame_base: return "DW_AT_frame_base"; case DW_AT_friend: return "DW_AT_friend"; case DW_AT_identifier_case: return "DW_AT_identifier_case"; case DW_AT_macro_info: return "DW_AT_macro_info"; case DW_AT_namelist_items: return "DW_AT_namelist_items"; case DW_AT_priority: return "DW_AT_priority"; case DW_AT_segment: return "DW_AT_segment"; case DW_AT_specification: return "DW_AT_specification"; case DW_AT_static_link: return "DW_AT_static_link"; case DW_AT_type: return "DW_AT_type"; case DW_AT_use_location: return "DW_AT_use_location"; case DW_AT_variable_parameter: return "DW_AT_variable_parameter"; case DW_AT_virtuality: return "DW_AT_virtuality"; case DW_AT_vtable_elem_location: return "DW_AT_vtable_elem_location"; case DW_AT_allocated: return "DW_AT_allocated"; case DW_AT_associated: return "DW_AT_associated"; case DW_AT_data_location: return "DW_AT_data_location"; case DW_AT_stride: return "DW_AT_stride"; case DW_AT_entry_pc: return "DW_AT_entry_pc"; case DW_AT_use_UTF8: return "DW_AT_use_UTF8"; case DW_AT_extension: return "DW_AT_extension"; case DW_AT_ranges: return "DW_AT_ranges"; case DW_AT_trampoline: return "DW_AT_trampoline"; case DW_AT_call_column: return "DW_AT_call_column"; case DW_AT_call_file: return "DW_AT_call_file"; case DW_AT_call_line: return "DW_AT_call_line"; #ifdef MIPS case DW_AT_MIPS_fde: return "DW_AT_MIPS_fde"; case DW_AT_MIPS_loop_begin: return "DW_AT_MIPS_loop_begin"; case DW_AT_MIPS_tail_loop_begin: return "DW_AT_MIPS_tail_loop_begin"; case DW_AT_MIPS_epilog_begin: return "DW_AT_MIPS_epilog_begin"; case DW_AT_MIPS_loop_unroll_factor: return "DW_AT_MIPS_loop_unroll_factor"; case DW_AT_MIPS_software_pipeline_depth: return "DW_AT_MIPS_software_pipeline_depth"; #endif case DW_AT_MIPS_linkage_name: return "DW_AT_MIPS_linkage_name"; case DW_AT_sf_names: return "DW_AT_sf_names"; case DW_AT_src_info: return "DW_AT_src_info"; case DW_AT_mac_info: return "DW_AT_mac_info"; case DW_AT_src_coords: return "DW_AT_src_coords"; case DW_AT_body_begin: return "DW_AT_body_begin"; case DW_AT_body_end: return "DW_AT_body_end"; case DW_AT_GNU_vector: return "DW_AT_GNU_vector"; default: return "DW_AT_"; } } /* Convert a DWARF value form code into its string name. */ static char * dwarf_form_name (unsigned form) { switch (form) { case DW_FORM_addr: return "DW_FORM_addr"; case DW_FORM_block2: return "DW_FORM_block2"; case DW_FORM_block4: return "DW_FORM_block4"; case DW_FORM_data2: return "DW_FORM_data2"; case DW_FORM_data4: return "DW_FORM_data4"; case DW_FORM_data8: return "DW_FORM_data8"; case DW_FORM_string: return "DW_FORM_string"; case DW_FORM_block: return "DW_FORM_block"; case DW_FORM_block1: return "DW_FORM_block1"; case DW_FORM_data1: return "DW_FORM_data1"; case DW_FORM_flag: return "DW_FORM_flag"; case DW_FORM_sdata: return "DW_FORM_sdata"; case DW_FORM_strp: return "DW_FORM_strp"; case DW_FORM_udata: return "DW_FORM_udata"; case DW_FORM_ref_addr: return "DW_FORM_ref_addr"; case DW_FORM_ref1: return "DW_FORM_ref1"; case DW_FORM_ref2: return "DW_FORM_ref2"; case DW_FORM_ref4: return "DW_FORM_ref4"; case DW_FORM_ref8: return "DW_FORM_ref8"; case DW_FORM_ref_udata: return "DW_FORM_ref_udata"; case DW_FORM_indirect: return "DW_FORM_indirect"; default: return "DW_FORM_"; } } /* Convert a DWARF stack opcode into its string name. */ static char * dwarf_stack_op_name (unsigned op) { switch (op) { case DW_OP_addr: return "DW_OP_addr"; case DW_OP_deref: return "DW_OP_deref"; case DW_OP_const1u: return "DW_OP_const1u"; case DW_OP_const1s: return "DW_OP_const1s"; case DW_OP_const2u: return "DW_OP_const2u"; case DW_OP_const2s: return "DW_OP_const2s"; case DW_OP_const4u: return "DW_OP_const4u"; case DW_OP_const4s: return "DW_OP_const4s"; case DW_OP_const8u: return "DW_OP_const8u"; case DW_OP_const8s: return "DW_OP_const8s"; case DW_OP_constu: return "DW_OP_constu"; case DW_OP_consts: return "DW_OP_consts"; case DW_OP_dup: return "DW_OP_dup"; case DW_OP_drop: return "DW_OP_drop"; case DW_OP_over: return "DW_OP_over"; case DW_OP_pick: return "DW_OP_pick"; case DW_OP_swap: return "DW_OP_swap"; case DW_OP_rot: return "DW_OP_rot"; case DW_OP_xderef: return "DW_OP_xderef"; case DW_OP_abs: return "DW_OP_abs"; case DW_OP_and: return "DW_OP_and"; case DW_OP_div: return "DW_OP_div"; case DW_OP_minus: return "DW_OP_minus"; case DW_OP_mod: return "DW_OP_mod"; case DW_OP_mul: return "DW_OP_mul"; case DW_OP_neg: return "DW_OP_neg"; case DW_OP_not: return "DW_OP_not"; case DW_OP_or: return "DW_OP_or"; case DW_OP_plus: return "DW_OP_plus"; case DW_OP_plus_uconst: return "DW_OP_plus_uconst"; case DW_OP_shl: return "DW_OP_shl"; case DW_OP_shr: return "DW_OP_shr"; case DW_OP_shra: return "DW_OP_shra"; case DW_OP_xor: return "DW_OP_xor"; case DW_OP_bra: return "DW_OP_bra"; case DW_OP_eq: return "DW_OP_eq"; case DW_OP_ge: return "DW_OP_ge"; case DW_OP_gt: return "DW_OP_gt"; case DW_OP_le: return "DW_OP_le"; case DW_OP_lt: return "DW_OP_lt"; case DW_OP_ne: return "DW_OP_ne"; case DW_OP_skip: return "DW_OP_skip"; case DW_OP_lit0: return "DW_OP_lit0"; case DW_OP_lit1: return "DW_OP_lit1"; case DW_OP_lit2: return "DW_OP_lit2"; case DW_OP_lit3: return "DW_OP_lit3"; case DW_OP_lit4: return "DW_OP_lit4"; case DW_OP_lit5: return "DW_OP_lit5"; case DW_OP_lit6: return "DW_OP_lit6"; case DW_OP_lit7: return "DW_OP_lit7"; case DW_OP_lit8: return "DW_OP_lit8"; case DW_OP_lit9: return "DW_OP_lit9"; case DW_OP_lit10: return "DW_OP_lit10"; case DW_OP_lit11: return "DW_OP_lit11"; case DW_OP_lit12: return "DW_OP_lit12"; case DW_OP_lit13: return "DW_OP_lit13"; case DW_OP_lit14: return "DW_OP_lit14"; case DW_OP_lit15: return "DW_OP_lit15"; case DW_OP_lit16: return "DW_OP_lit16"; case DW_OP_lit17: return "DW_OP_lit17"; case DW_OP_lit18: return "DW_OP_lit18"; case DW_OP_lit19: return "DW_OP_lit19"; case DW_OP_lit20: return "DW_OP_lit20"; case DW_OP_lit21: return "DW_OP_lit21"; case DW_OP_lit22: return "DW_OP_lit22"; case DW_OP_lit23: return "DW_OP_lit23"; case DW_OP_lit24: return "DW_OP_lit24"; case DW_OP_lit25: return "DW_OP_lit25"; case DW_OP_lit26: return "DW_OP_lit26"; case DW_OP_lit27: return "DW_OP_lit27"; case DW_OP_lit28: return "DW_OP_lit28"; case DW_OP_lit29: return "DW_OP_lit29"; case DW_OP_lit30: return "DW_OP_lit30"; case DW_OP_lit31: return "DW_OP_lit31"; case DW_OP_reg0: return "DW_OP_reg0"; case DW_OP_reg1: return "DW_OP_reg1"; case DW_OP_reg2: return "DW_OP_reg2"; case DW_OP_reg3: return "DW_OP_reg3"; case DW_OP_reg4: return "DW_OP_reg4"; case DW_OP_reg5: return "DW_OP_reg5"; case DW_OP_reg6: return "DW_OP_reg6"; case DW_OP_reg7: return "DW_OP_reg7"; case DW_OP_reg8: return "DW_OP_reg8"; case DW_OP_reg9: return "DW_OP_reg9"; case DW_OP_reg10: return "DW_OP_reg10"; case DW_OP_reg11: return "DW_OP_reg11"; case DW_OP_reg12: return "DW_OP_reg12"; case DW_OP_reg13: return "DW_OP_reg13"; case DW_OP_reg14: return "DW_OP_reg14"; case DW_OP_reg15: return "DW_OP_reg15"; case DW_OP_reg16: return "DW_OP_reg16"; case DW_OP_reg17: return "DW_OP_reg17"; case DW_OP_reg18: return "DW_OP_reg18"; case DW_OP_reg19: return "DW_OP_reg19"; case DW_OP_reg20: return "DW_OP_reg20"; case DW_OP_reg21: return "DW_OP_reg21"; case DW_OP_reg22: return "DW_OP_reg22"; case DW_OP_reg23: return "DW_OP_reg23"; case DW_OP_reg24: return "DW_OP_reg24"; case DW_OP_reg25: return "DW_OP_reg25"; case DW_OP_reg26: return "DW_OP_reg26"; case DW_OP_reg27: return "DW_OP_reg27"; case DW_OP_reg28: return "DW_OP_reg28"; case DW_OP_reg29: return "DW_OP_reg29"; case DW_OP_reg30: return "DW_OP_reg30"; case DW_OP_reg31: return "DW_OP_reg31"; case DW_OP_breg0: return "DW_OP_breg0"; case DW_OP_breg1: return "DW_OP_breg1"; case DW_OP_breg2: return "DW_OP_breg2"; case DW_OP_breg3: return "DW_OP_breg3"; case DW_OP_breg4: return "DW_OP_breg4"; case DW_OP_breg5: return "DW_OP_breg5"; case DW_OP_breg6: return "DW_OP_breg6"; case DW_OP_breg7: return "DW_OP_breg7"; case DW_OP_breg8: return "DW_OP_breg8"; case DW_OP_breg9: return "DW_OP_breg9"; case DW_OP_breg10: return "DW_OP_breg10"; case DW_OP_breg11: return "DW_OP_breg11"; case DW_OP_breg12: return "DW_OP_breg12"; case DW_OP_breg13: return "DW_OP_breg13"; case DW_OP_breg14: return "DW_OP_breg14"; case DW_OP_breg15: return "DW_OP_breg15"; case DW_OP_breg16: return "DW_OP_breg16"; case DW_OP_breg17: return "DW_OP_breg17"; case DW_OP_breg18: return "DW_OP_breg18"; case DW_OP_breg19: return "DW_OP_breg19"; case DW_OP_breg20: return "DW_OP_breg20"; case DW_OP_breg21: return "DW_OP_breg21"; case DW_OP_breg22: return "DW_OP_breg22"; case DW_OP_breg23: return "DW_OP_breg23"; case DW_OP_breg24: return "DW_OP_breg24"; case DW_OP_breg25: return "DW_OP_breg25"; case DW_OP_breg26: return "DW_OP_breg26"; case DW_OP_breg27: return "DW_OP_breg27"; case DW_OP_breg28: return "DW_OP_breg28"; case DW_OP_breg29: return "DW_OP_breg29"; case DW_OP_breg30: return "DW_OP_breg30"; case DW_OP_breg31: return "DW_OP_breg31"; case DW_OP_regx: return "DW_OP_regx"; case DW_OP_fbreg: return "DW_OP_fbreg"; case DW_OP_bregx: return "DW_OP_bregx"; case DW_OP_piece: return "DW_OP_piece"; case DW_OP_deref_size: return "DW_OP_deref_size"; case DW_OP_xderef_size: return "DW_OP_xderef_size"; case DW_OP_nop: return "DW_OP_nop"; /* DWARF 3 extensions. */ case DW_OP_push_object_address: return "DW_OP_push_object_address"; case DW_OP_call2: return "DW_OP_call2"; case DW_OP_call4: return "DW_OP_call4"; case DW_OP_call_ref: return "DW_OP_call_ref"; /* GNU extensions. */ case DW_OP_GNU_push_tls_address: return "DW_OP_GNU_push_tls_address"; + case DW_OP_GNU_uninit: + return "DW_OP_GNU_uninit"; default: return "OP_"; } } static char * dwarf_bool_name (unsigned mybool) { if (mybool) return "TRUE"; else return "FALSE"; } /* Convert a DWARF type code into its string name. */ static char * dwarf_type_encoding_name (unsigned enc) { switch (enc) { case DW_ATE_address: return "DW_ATE_address"; case DW_ATE_boolean: return "DW_ATE_boolean"; case DW_ATE_complex_float: return "DW_ATE_complex_float"; case DW_ATE_float: return "DW_ATE_float"; case DW_ATE_signed: return "DW_ATE_signed"; case DW_ATE_signed_char: return "DW_ATE_signed_char"; case DW_ATE_unsigned: return "DW_ATE_unsigned"; case DW_ATE_unsigned_char: return "DW_ATE_unsigned_char"; case DW_ATE_imaginary_float: return "DW_ATE_imaginary_float"; default: return "DW_ATE_"; } } /* Convert a DWARF call frame info operation to its string name. */ #if 0 static char * dwarf_cfi_name (unsigned cfi_opc) { switch (cfi_opc) { case DW_CFA_advance_loc: return "DW_CFA_advance_loc"; case DW_CFA_offset: return "DW_CFA_offset"; case DW_CFA_restore: return "DW_CFA_restore"; case DW_CFA_nop: return "DW_CFA_nop"; case DW_CFA_set_loc: return "DW_CFA_set_loc"; case DW_CFA_advance_loc1: return "DW_CFA_advance_loc1"; case DW_CFA_advance_loc2: return "DW_CFA_advance_loc2"; case DW_CFA_advance_loc4: return "DW_CFA_advance_loc4"; case DW_CFA_offset_extended: return "DW_CFA_offset_extended"; case DW_CFA_restore_extended: return "DW_CFA_restore_extended"; case DW_CFA_undefined: return "DW_CFA_undefined"; case DW_CFA_same_value: return "DW_CFA_same_value"; case DW_CFA_register: return "DW_CFA_register"; case DW_CFA_remember_state: return "DW_CFA_remember_state"; case DW_CFA_restore_state: return "DW_CFA_restore_state"; case DW_CFA_def_cfa: return "DW_CFA_def_cfa"; case DW_CFA_def_cfa_register: return "DW_CFA_def_cfa_register"; case DW_CFA_def_cfa_offset: return "DW_CFA_def_cfa_offset"; /* DWARF 3 */ case DW_CFA_def_cfa_expression: return "DW_CFA_def_cfa_expression"; case DW_CFA_expression: return "DW_CFA_expression"; case DW_CFA_offset_extended_sf: return "DW_CFA_offset_extended_sf"; case DW_CFA_def_cfa_sf: return "DW_CFA_def_cfa_sf"; case DW_CFA_def_cfa_offset_sf: return "DW_CFA_def_cfa_offset_sf"; /* SGI/MIPS specific */ case DW_CFA_MIPS_advance_loc8: return "DW_CFA_MIPS_advance_loc8"; /* GNU extensions */ case DW_CFA_GNU_window_save: return "DW_CFA_GNU_window_save"; case DW_CFA_GNU_args_size: return "DW_CFA_GNU_args_size"; case DW_CFA_GNU_negative_offset_extended: return "DW_CFA_GNU_negative_offset_extended"; default: return "DW_CFA_"; } } #endif static void dump_die (struct die_info *die) { unsigned int i; fprintf_unfiltered (gdb_stderr, "Die: %s (abbrev = %d, offset = %d)\n", dwarf_tag_name (die->tag), die->abbrev, die->offset); fprintf_unfiltered (gdb_stderr, "\thas children: %s\n", dwarf_bool_name (die->child != NULL)); fprintf_unfiltered (gdb_stderr, "\tattributes:\n"); for (i = 0; i < die->num_attrs; ++i) { fprintf_unfiltered (gdb_stderr, "\t\t%s (%s) ", dwarf_attr_name (die->attrs[i].name), dwarf_form_name (die->attrs[i].form)); switch (die->attrs[i].form) { case DW_FORM_ref_addr: case DW_FORM_addr: fprintf_unfiltered (gdb_stderr, "address: "); print_address_numeric (DW_ADDR (&die->attrs[i]), 1, gdb_stderr); break; case DW_FORM_block2: case DW_FORM_block4: case DW_FORM_block: case DW_FORM_block1: fprintf_unfiltered (gdb_stderr, "block: size %d", DW_BLOCK (&die->attrs[i])->size); break; case DW_FORM_data1: case DW_FORM_data2: case DW_FORM_data4: case DW_FORM_data8: case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_udata: case DW_FORM_sdata: fprintf_unfiltered (gdb_stderr, "constant: %ld", DW_UNSND (&die->attrs[i])); break; case DW_FORM_string: case DW_FORM_strp: fprintf_unfiltered (gdb_stderr, "string: \"%s\"", DW_STRING (&die->attrs[i]) ? DW_STRING (&die->attrs[i]) : ""); break; case DW_FORM_flag: if (DW_UNSND (&die->attrs[i])) fprintf_unfiltered (gdb_stderr, "flag: TRUE"); else fprintf_unfiltered (gdb_stderr, "flag: FALSE"); break; case DW_FORM_flag_present: fprintf_unfiltered (gdb_stderr, "flag: TRUE"); break; case DW_FORM_indirect: /* the reader will have reduced the indirect form to the "base form" so this form should not occur */ fprintf_unfiltered (gdb_stderr, "unexpected attribute form: DW_FORM_indirect"); break; default: fprintf_unfiltered (gdb_stderr, "unsupported attribute form: %d.", die->attrs[i].form); } fprintf_unfiltered (gdb_stderr, "\n"); } } static void dump_die_list (struct die_info *die) { while (die) { dump_die (die); if (die->child != NULL) dump_die_list (die->child); if (die->sibling != NULL) dump_die_list (die->sibling); } } static void store_in_ref_table (unsigned int offset, struct die_info *die) { int h; struct die_info *old; h = (offset % REF_HASH_SIZE); old = die_ref_table[h]; die->next_ref = old; die_ref_table[h] = die; } static void dwarf2_empty_hash_tables (void) { memset (die_ref_table, 0, sizeof (die_ref_table)); } static unsigned int dwarf2_get_ref_die_offset (struct attribute *attr, struct dwarf2_cu *cu) { unsigned int result = 0; switch (attr->form) { case DW_FORM_ref_addr: result = DW_ADDR (attr); break; case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: result = cu->header.offset + DW_UNSND (attr); break; default: complaint (&symfile_complaints, "unsupported die ref attribute form: '%s'", dwarf_form_name (attr->form)); } return result; } /* Return the constant value held by the given attribute. Return -1 if the value held by the attribute is not constant. */ static int dwarf2_get_attr_constant_value (struct attribute *attr, int default_value) { if (attr->form == DW_FORM_sdata) return DW_SND (attr); else if (attr->form == DW_FORM_udata || attr->form == DW_FORM_data1 || attr->form == DW_FORM_data2 || attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8) return DW_UNSND (attr); else { complaint (&symfile_complaints, "Attribute value is not a constant (%s)", dwarf_form_name (attr->form)); return default_value; } } static struct die_info * follow_die_ref (unsigned int offset) { struct die_info *die; int h; h = (offset % REF_HASH_SIZE); die = die_ref_table[h]; while (die) { if (die->offset == offset) { return die; } die = die->next_ref; } return NULL; } static struct type * dwarf2_fundamental_type (struct objfile *objfile, int typeid, struct dwarf2_cu *cu) { if (typeid < 0 || typeid >= FT_NUM_MEMBERS) { error ("Dwarf Error: internal error - invalid fundamental type id %d [in module %s]", typeid, objfile->name); } /* Look for this particular type in the fundamental type vector. If one is not found, create and install one appropriate for the current language and the current target machine. */ if (cu->ftypes[typeid] == NULL) { cu->ftypes[typeid] = cu->language_defn->la_fund_type (objfile, typeid); } return (cu->ftypes[typeid]); } /* Decode simple location descriptions. Given a pointer to a dwarf block that defines a location, compute the location and return the value. NOTE drow/2003-11-18: This function is called in two situations now: for the address of static or global variables (partial symbols only) and for offsets into structures which are expected to be (more or less) constant. The partial symbol case should go away, and only the constant case should remain. That will let this function complain more accurately. A few special modes are allowed without complaint for global variables (for instance, global register values and thread-local values). A location description containing no operations indicates that the object is optimized out. The return value is 0 for that case. FIXME drow/2003-11-16: No callers check for this case any more; soon all callers will only want a very basic result and this can become a complaint. When the result is a register number, the global isreg flag is set, otherwise it is cleared. Note that stack[0] is unused except as a default error return. Note that stack overflow is not yet handled. */ static CORE_ADDR decode_locdesc (struct dwarf_block *blk, struct dwarf2_cu *cu) { struct objfile *objfile = cu->objfile; struct comp_unit_head *cu_header = &cu->header; int i; int size = blk->size; char *data = blk->data; CORE_ADDR stack[64]; int stacki; unsigned int bytes_read, unsnd; unsigned char op; i = 0; stacki = 0; stack[stacki] = 0; isreg = 0; while (i < size) { op = data[i++]; switch (op) { case DW_OP_lit0: case DW_OP_lit1: case DW_OP_lit2: case DW_OP_lit3: case DW_OP_lit4: case DW_OP_lit5: case DW_OP_lit6: case DW_OP_lit7: case DW_OP_lit8: case DW_OP_lit9: case DW_OP_lit10: case DW_OP_lit11: case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14: case DW_OP_lit15: case DW_OP_lit16: case DW_OP_lit17: case DW_OP_lit18: case DW_OP_lit19: case DW_OP_lit20: case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23: case DW_OP_lit24: case DW_OP_lit25: case DW_OP_lit26: case DW_OP_lit27: case DW_OP_lit28: case DW_OP_lit29: case DW_OP_lit30: case DW_OP_lit31: stack[++stacki] = op - DW_OP_lit0; break; case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2: case DW_OP_reg3: case DW_OP_reg4: case DW_OP_reg5: case DW_OP_reg6: case DW_OP_reg7: case DW_OP_reg8: case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11: case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14: case DW_OP_reg15: case DW_OP_reg16: case DW_OP_reg17: case DW_OP_reg18: case DW_OP_reg19: case DW_OP_reg20: case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23: case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26: case DW_OP_reg27: case DW_OP_reg28: case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31: isreg = 1; stack[++stacki] = op - DW_OP_reg0; if (i < size) dwarf2_complex_location_expr_complaint (); break; case DW_OP_regx: isreg = 1; unsnd = read_unsigned_leb128 (NULL, (data + i), &bytes_read); i += bytes_read; stack[++stacki] = unsnd; if (i < size) dwarf2_complex_location_expr_complaint (); break; case DW_OP_addr: stack[++stacki] = read_address (objfile->obfd, &data[i], cu, &bytes_read); i += bytes_read; break; case DW_OP_const1u: stack[++stacki] = read_1_byte (objfile->obfd, &data[i]); i += 1; break; case DW_OP_const1s: stack[++stacki] = read_1_signed_byte (objfile->obfd, &data[i]); i += 1; break; case DW_OP_const2u: stack[++stacki] = read_2_bytes (objfile->obfd, &data[i]); i += 2; break; case DW_OP_const2s: stack[++stacki] = read_2_signed_bytes (objfile->obfd, &data[i]); i += 2; break; case DW_OP_const4u: stack[++stacki] = read_4_bytes (objfile->obfd, &data[i]); i += 4; break; case DW_OP_const4s: stack[++stacki] = read_4_signed_bytes (objfile->obfd, &data[i]); i += 4; break; case DW_OP_constu: stack[++stacki] = read_unsigned_leb128 (NULL, (data + i), &bytes_read); i += bytes_read; break; case DW_OP_consts: stack[++stacki] = read_signed_leb128 (NULL, (data + i), &bytes_read); i += bytes_read; break; case DW_OP_dup: stack[stacki + 1] = stack[stacki]; stacki++; break; case DW_OP_plus: stack[stacki - 1] += stack[stacki]; stacki--; break; case DW_OP_plus_uconst: stack[stacki] += read_unsigned_leb128 (NULL, (data + i), &bytes_read); i += bytes_read; break; case DW_OP_minus: stack[stacki - 1] -= stack[stacki]; stacki--; break; case DW_OP_deref: /* If we're not the last op, then we definitely can't encode this using GDB's address_class enum. This is valid for partial global symbols, although the variable's address will be bogus in the psymtab. */ if (i < size) dwarf2_complex_location_expr_complaint (); break; case DW_OP_GNU_push_tls_address: /* The top of the stack has the offset from the beginning of the thread control block at which the variable is located. */ /* Nothing should follow this operator, so the top of stack would be returned. */ /* This is valid for partial global symbols, but the variable's address will be bogus in the psymtab. */ if (i < size) dwarf2_complex_location_expr_complaint (); break; + + case DW_OP_GNU_uninit: + break; default: complaint (&symfile_complaints, "unsupported stack op: '%s'", dwarf_stack_op_name (op)); return (stack[stacki]); } } return (stack[stacki]); } /* memory allocation interface */ static void dwarf2_free_tmp_obstack (void *ignore) { obstack_free (&dwarf2_tmp_obstack, NULL); } static struct dwarf_block * dwarf_alloc_block (void) { struct dwarf_block *blk; blk = (struct dwarf_block *) obstack_alloc (&dwarf2_tmp_obstack, sizeof (struct dwarf_block)); return (blk); } static struct abbrev_info * dwarf_alloc_abbrev (void) { struct abbrev_info *abbrev; abbrev = (struct abbrev_info *) xmalloc (sizeof (struct abbrev_info)); memset (abbrev, 0, sizeof (struct abbrev_info)); return (abbrev); } static struct die_info * dwarf_alloc_die (void) { struct die_info *die; die = (struct die_info *) xmalloc (sizeof (struct die_info)); memset (die, 0, sizeof (struct die_info)); return (die); } /* Macro support. */ /* Return the full name of file number I in *LH's file name table. Use COMP_DIR as the name of the current directory of the compilation. The result is allocated using xmalloc; the caller is responsible for freeing it. */ static char * file_full_name (int file, struct line_header *lh, const char *comp_dir) { struct file_entry *fe = &lh->file_names[file - 1]; if (IS_ABSOLUTE_PATH (fe->name)) return xstrdup (fe->name); else { const char *dir; int dir_len; char *full_name; if (fe->dir_index) dir = lh->include_dirs[fe->dir_index - 1]; else dir = comp_dir; if (dir) { dir_len = strlen (dir); full_name = xmalloc (dir_len + 1 + strlen (fe->name) + 1); strcpy (full_name, dir); full_name[dir_len] = '/'; strcpy (full_name + dir_len + 1, fe->name); return full_name; } else return xstrdup (fe->name); } } static struct macro_source_file * macro_start_file (int file, int line, struct macro_source_file *current_file, const char *comp_dir, struct line_header *lh, struct objfile *objfile) { /* The full name of this source file. */ char *full_name = file_full_name (file, lh, comp_dir); /* We don't create a macro table for this compilation unit at all until we actually get a filename. */ if (! pending_macros) pending_macros = new_macro_table (&objfile->objfile_obstack, objfile->macro_cache); if (! current_file) /* If we have no current file, then this must be the start_file directive for the compilation unit's main source file. */ current_file = macro_set_main (pending_macros, full_name); else current_file = macro_include (current_file, line, full_name); xfree (full_name); return current_file; } /* Copy the LEN characters at BUF to a xmalloc'ed block of memory, followed by a null byte. */ static char * copy_string (const char *buf, int len) { char *s = xmalloc (len + 1); memcpy (s, buf, len); s[len] = '\0'; return s; } static const char * consume_improper_spaces (const char *p, const char *body) { if (*p == ' ') { complaint (&symfile_complaints, "macro definition contains spaces in formal argument list:\n`%s'", body); while (*p == ' ') p++; } return p; } static void parse_macro_definition (struct macro_source_file *file, int line, const char *body) { const char *p; /* The body string takes one of two forms. For object-like macro definitions, it should be: " " For function-like macro definitions, it should be: "() " or "(" ( "," ) * ") " Spaces may appear only where explicitly indicated, and in the . The Dwarf 2 spec says that an object-like macro's name is always followed by a space, but versions of GCC around March 2002 omit the space when the macro's definition is the empty string. The Dwarf 2 spec says that there should be no spaces between the formal arguments in a function-like macro's formal argument list, but versions of GCC around March 2002 include spaces after the commas. */ /* Find the extent of the macro name. The macro name is terminated by either a space or null character (for an object-like macro) or an opening paren (for a function-like macro). */ for (p = body; *p; p++) if (*p == ' ' || *p == '(') break; if (*p == ' ' || *p == '\0') { /* It's an object-like macro. */ int name_len = p - body; char *name = copy_string (body, name_len); const char *replacement; if (*p == ' ') replacement = body + name_len + 1; else { dwarf2_macro_malformed_definition_complaint (body); replacement = body + name_len; } macro_define_object (file, line, name, replacement); xfree (name); } else if (*p == '(') { /* It's a function-like macro. */ char *name = copy_string (body, p - body); int argc = 0; int argv_size = 1; char **argv = xmalloc (argv_size * sizeof (*argv)); p++; p = consume_improper_spaces (p, body); /* Parse the formal argument list. */ while (*p && *p != ')') { /* Find the extent of the current argument name. */ const char *arg_start = p; while (*p && *p != ',' && *p != ')' && *p != ' ') p++; if (! *p || p == arg_start) dwarf2_macro_malformed_definition_complaint (body); else { /* Make sure argv has room for the new argument. */ if (argc >= argv_size) { argv_size *= 2; argv = xrealloc (argv, argv_size * sizeof (*argv)); } argv[argc++] = copy_string (arg_start, p - arg_start); } p = consume_improper_spaces (p, body); /* Consume the comma, if present. */ if (*p == ',') { p++; p = consume_improper_spaces (p, body); } } if (*p == ')') { p++; if (*p == ' ') /* Perfectly formed definition, no complaints. */ macro_define_function (file, line, name, argc, (const char **) argv, p + 1); else if (*p == '\0') { /* Complain, but do define it. */ dwarf2_macro_malformed_definition_complaint (body); macro_define_function (file, line, name, argc, (const char **) argv, p); } else /* Just complain. */ dwarf2_macro_malformed_definition_complaint (body); } else /* Just complain. */ dwarf2_macro_malformed_definition_complaint (body); xfree (name); { int i; for (i = 0; i < argc; i++) xfree (argv[i]); } xfree (argv); } else dwarf2_macro_malformed_definition_complaint (body); } static void dwarf_decode_macros (struct line_header *lh, unsigned int offset, char *comp_dir, bfd *abfd, struct dwarf2_cu *cu) { char *mac_ptr, *mac_end; struct macro_source_file *current_file = 0; if (dwarf_macinfo_buffer == NULL) { complaint (&symfile_complaints, "missing .debug_macinfo section"); return; } mac_ptr = dwarf_macinfo_buffer + offset; mac_end = dwarf_macinfo_buffer + dwarf_macinfo_size; for (;;) { enum dwarf_macinfo_record_type macinfo_type; /* Do we at least have room for a macinfo type byte? */ if (mac_ptr >= mac_end) { dwarf2_macros_too_long_complaint (); return; } macinfo_type = read_1_byte (abfd, mac_ptr); mac_ptr++; switch (macinfo_type) { /* A zero macinfo type indicates the end of the macro information. */ case 0: return; case DW_MACINFO_define: case DW_MACINFO_undef: { int bytes_read; int line; char *body; line = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); mac_ptr += bytes_read; body = read_string (abfd, mac_ptr, &bytes_read); mac_ptr += bytes_read; if (! current_file) complaint (&symfile_complaints, "debug info gives macro %s outside of any file: %s", macinfo_type == DW_MACINFO_define ? "definition" : macinfo_type == DW_MACINFO_undef ? "undefinition" : "something-or-other", body); else { if (macinfo_type == DW_MACINFO_define) parse_macro_definition (current_file, line, body); else if (macinfo_type == DW_MACINFO_undef) macro_undef (current_file, line, body); } } break; case DW_MACINFO_start_file: { int bytes_read; int line, file; line = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); mac_ptr += bytes_read; file = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); mac_ptr += bytes_read; current_file = macro_start_file (file, line, current_file, comp_dir, lh, cu->objfile); } break; case DW_MACINFO_end_file: if (! current_file) complaint (&symfile_complaints, "macro debug info has an unmatched `close_file' directive"); else { current_file = current_file->included_by; if (! current_file) { enum dwarf_macinfo_record_type next_type; /* GCC circa March 2002 doesn't produce the zero type byte marking the end of the compilation unit. Complain if it's not there, but exit no matter what. */ /* Do we at least have room for a macinfo type byte? */ if (mac_ptr >= mac_end) { dwarf2_macros_too_long_complaint (); return; } /* We don't increment mac_ptr here, so this is just a look-ahead. */ next_type = read_1_byte (abfd, mac_ptr); if (next_type != 0) complaint (&symfile_complaints, "no terminating 0-type entry for macros in `.debug_macinfo' section"); return; } } break; case DW_MACINFO_vendor_ext: { int bytes_read; int constant; char *string; constant = read_unsigned_leb128 (abfd, mac_ptr, &bytes_read); mac_ptr += bytes_read; string = read_string (abfd, mac_ptr, &bytes_read); mac_ptr += bytes_read; /* We don't recognize any vendor extensions. */ } break; } } } /* Check if the attribute's form is a DW_FORM_block* if so return true else false. */ static int attr_form_is_block (struct attribute *attr) { return (attr == NULL ? 0 : attr->form == DW_FORM_block1 || attr->form == DW_FORM_block2 || attr->form == DW_FORM_block4 || attr->form == DW_FORM_block); } static void dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym, struct dwarf2_cu *cu) { if (attr->form == DW_FORM_data4 || attr->form == DW_FORM_data8) { struct dwarf2_loclist_baton *baton; baton = obstack_alloc (&cu->objfile->objfile_obstack, sizeof (struct dwarf2_loclist_baton)); baton->objfile = cu->objfile; /* We don't know how long the location list is, but make sure we don't run off the edge of the section. */ baton->size = dwarf_loc_size - DW_UNSND (attr); baton->data = dwarf_loc_buffer + DW_UNSND (attr); baton->base_address = cu->header.base_address; if (cu->header.base_known == 0) complaint (&symfile_complaints, "Location list used without specifying the CU base address."); SYMBOL_OPS (sym) = &dwarf2_loclist_funcs; SYMBOL_LOCATION_BATON (sym) = baton; } else { struct dwarf2_locexpr_baton *baton; baton = obstack_alloc (&cu->objfile->objfile_obstack, sizeof (struct dwarf2_locexpr_baton)); baton->objfile = cu->objfile; if (attr_form_is_block (attr)) { /* Note that we're just copying the block's data pointer here, not the actual data. We're still pointing into the dwarf_info_buffer for SYM's objfile; right now we never release that buffer, but when we do clean up properly this may need to change. */ baton->size = DW_BLOCK (attr)->size; baton->data = DW_BLOCK (attr)->data; } else { dwarf2_invalid_attrib_class_complaint ("location description", SYMBOL_NATURAL_NAME (sym)); baton->size = 0; baton->data = NULL; } SYMBOL_OPS (sym) = &dwarf2_locexpr_funcs; SYMBOL_LOCATION_BATON (sym) = baton; } } Index: projects/ci20_mips/contrib/gdb/gdb/value.h =================================================================== --- projects/ci20_mips/contrib/gdb/gdb/value.h (revision 283030) +++ projects/ci20_mips/contrib/gdb/gdb/value.h (revision 283031) @@ -1,574 +1,577 @@ /* Definitions for values of C expressions, for GDB. Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if !defined (VALUE_H) #define VALUE_H 1 #include "doublest.h" #include "frame.h" /* For struct frame_id. */ struct block; struct expression; struct regcache; struct symbol; struct type; struct ui_file; /* The structure which defines the type of a value. It should never be possible for a program lval value to survive over a call to the inferior (i.e. to be put into the history list or an internal variable). */ struct value { /* Type of value; either not an lval, or one of the various different possible kinds of lval. */ enum lval_type lval; /* Is it modifiable? Only relevant if lval != not_lval. */ int modifiable; /* Location of value (if lval). */ union { /* If lval == lval_memory, this is the address in the inferior. If lval == lval_register, this is the byte offset into the registers structure. */ CORE_ADDR address; /* Pointer to internal variable. */ struct internalvar *internalvar; /* Number of register. Only used with lval_reg_frame_relative. */ int regnum; } location; /* Describes offset of a value within lval of a structure in bytes. If lval == lval_memory, this is an offset to the address. If lval == lval_register, this is a further offset from location.address within the registers structure. Note also the member embedded_offset below. */ int offset; /* Only used for bitfields; number of bits contained in them. */ int bitsize; /* Only used for bitfields; position of start of field. For BITS_BIG_ENDIAN=0 targets, it is the position of the LSB. For BITS_BIG_ENDIAN=1 targets, it is the position of the MSB. */ int bitpos; /* Frame value is relative to. In practice, this ID is only used if the value is stored in several registers in other than the current frame, and these registers have not all been saved at the same place in memory. This will be described in the lval enum above as "lval_reg_frame_relative". */ struct frame_id frame_id; /* Type of the value. */ struct type *type; /* If a value represents a C++ object, then the `type' field gives the object's compile-time type. If the object actually belongs to some class derived from `type', perhaps with other base classes and additional members, then `type' is just a subobject of the real thing, and the full object is probably larger than `type' would suggest. If `type' is a dynamic class (i.e. one with a vtable), then GDB can actually determine the object's run-time type by looking at the run-time type information in the vtable. When this information is available, we may elect to read in the entire object, for several reasons: - When printing the value, the user would probably rather see the full object, not just the limited portion apparent from the compile-time type. - If `type' has virtual base classes, then even printing `type' alone may require reaching outside the `type' portion of the object to wherever the virtual base class has been stored. When we store the entire object, `enclosing_type' is the run-time type -- the complete object -- and `embedded_offset' is the offset of `type' within that larger type, in bytes. The VALUE_CONTENTS macro takes `embedded_offset' into account, so most GDB code continues to see the `type' portion of the value, just as the inferior would. If `type' is a pointer to an object, then `enclosing_type' is a pointer to the object's run-time type, and `pointed_to_offset' is the offset in bytes from the full object to the pointed-to object -- that is, the value `embedded_offset' would have if we followed the pointer and fetched the complete object. (I don't really see the point. Why not just determine the run-time type when you indirect, and avoid the special case? The contents don't matter until you indirect anyway.) If we're not doing anything fancy, `enclosing_type' is equal to `type', and `embedded_offset' is zero, so everything works normally. */ struct type *enclosing_type; int embedded_offset; int pointed_to_offset; /* Values are stored in a chain, so that they can be deleted easily over calls to the inferior. Values assigned to internal variables or put into the value history are taken off this list. */ struct value *next; /* Register number if the value is from a register. */ short regno; /* If zero, contents of this value are in the contents field. If nonzero, contents are in inferior memory at address in the location.address field plus the offset field (and the lval field should be lval_memory). WARNING: This field is used by the code which handles watchpoints (see breakpoint.c) to decide whether a particular value can be watched by hardware watchpoints. If the lazy flag is set for some member of a value chain, it is assumed that this member of the chain doesn't need to be watched as part of watching the value itself. This is how GDB avoids watching the entire struct or array when the user wants to watch a single struct member or array element. If you ever change the way lazy flag is set and reset, be sure to consider this use as well! */ char lazy; /* If nonzero, this is the value of a variable which does not actually exist in the program. */ char optimized_out; /* The BFD section associated with this value. */ asection *bfd_section; + /* If value is a variable, is it initialized or not. */ + int initialized; + /* Actual contents of the value. For use of this value; setting it uses the stuff above. Not valid if lazy is nonzero. Target byte-order. We force it to be aligned properly for any possible value. Note that a value therefore extends beyond what is declared here. */ union { long contents[1]; DOUBLEST force_doublest_align; LONGEST force_longest_align; CORE_ADDR force_core_addr_align; void *force_pointer_align; } aligner; /* Do not add any new members here -- contents above will trash them. */ }; #define VALUE_TYPE(val) (val)->type #define VALUE_ENCLOSING_TYPE(val) (val)->enclosing_type #define VALUE_LAZY(val) (val)->lazy /* VALUE_CONTENTS and VALUE_CONTENTS_RAW both return the address of the gdb buffer used to hold a copy of the contents of the lval. VALUE_CONTENTS is used when the contents of the buffer are needed -- it uses value_fetch_lazy() to load the buffer from the process being debugged if it hasn't already been loaded. VALUE_CONTENTS_RAW is used when data is being stored into the buffer, or when it is certain that the contents of the buffer are valid. Note: The contents pointer is adjusted by the offset required to get to the real subobject, if the value happens to represent something embedded in a larger run-time object. */ #define VALUE_CONTENTS_RAW(val) \ ((char *) (val)->aligner.contents + (val)->embedded_offset) #define VALUE_CONTENTS(val) \ ((void)(VALUE_LAZY(val) && value_fetch_lazy(val)), VALUE_CONTENTS_RAW(val)) /* The ALL variants of the above two macros do not adjust the returned pointer by the embedded_offset value. */ #define VALUE_CONTENTS_ALL_RAW(val) ((char *) (val)->aligner.contents) #define VALUE_CONTENTS_ALL(val) \ ((void) (VALUE_LAZY(val) && value_fetch_lazy(val)), \ VALUE_CONTENTS_ALL_RAW(val)) extern int value_fetch_lazy (struct value *val); #define VALUE_LVAL(val) (val)->lval #define VALUE_ADDRESS(val) (val)->location.address #define VALUE_INTERNALVAR(val) (val)->location.internalvar #define VALUE_FRAME_REGNUM(val) ((val)->location.regnum) #define VALUE_FRAME_ID(val) ((val)->frame_id) #define VALUE_OFFSET(val) (val)->offset #define VALUE_BITSIZE(val) (val)->bitsize #define VALUE_BITPOS(val) (val)->bitpos #define VALUE_NEXT(val) (val)->next #define VALUE_REGNO(val) (val)->regno #define VALUE_OPTIMIZED_OUT(val) ((val)->optimized_out) #define VALUE_EMBEDDED_OFFSET(val) ((val)->embedded_offset) #define VALUE_POINTED_TO_OFFSET(val) ((val)->pointed_to_offset) #define VALUE_BFD_SECTION(val) ((val)->bfd_section) /* Convert a REF to the object referenced. */ #define COERCE_REF(arg) \ do { \ struct type *value_type_arg_tmp = check_typedef (VALUE_TYPE (arg)); \ if (TYPE_CODE (value_type_arg_tmp) == TYPE_CODE_REF) \ arg = value_at_lazy (TYPE_TARGET_TYPE (value_type_arg_tmp), \ unpack_pointer (VALUE_TYPE (arg), \ VALUE_CONTENTS (arg)), \ VALUE_BFD_SECTION (arg)); \ } while (0) /* If ARG is an array, convert it to a pointer. If ARG is an enum, convert it to an integer. If ARG is a function, convert it to a function pointer. References are dereferenced. */ #define COERCE_ARRAY(arg) \ do { \ COERCE_REF(arg); \ if (current_language->c_style_arrays \ && TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ARRAY) \ arg = value_coerce_array (arg); \ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_FUNC) \ arg = value_coerce_function (arg); \ } while (0) #define COERCE_NUMBER(arg) \ do { COERCE_ARRAY(arg); COERCE_ENUM(arg); } while (0) /* NOTE: cagney/2002-12-17: This macro was handling a chill language problem but that language has gone away. */ #define COERCE_VARYING_ARRAY(arg, real_arg_type) /* If ARG is an enum, convert it to an integer. */ #define COERCE_ENUM(arg) \ do { \ if (TYPE_CODE (check_typedef (VALUE_TYPE (arg))) == TYPE_CODE_ENUM) \ arg = value_cast (builtin_type_unsigned_int, arg); \ } while (0) /* Internal variables (variables for convenience of use of debugger) are recorded as a chain of these structures. */ struct internalvar { struct internalvar *next; char *name; struct value *value; }; /* Pointer to member function. Depends on compiler implementation. */ #define METHOD_PTR_IS_VIRTUAL(ADDR) ((ADDR) & 0x80000000) #define METHOD_PTR_FROM_VOFFSET(OFFSET) (0x80000000 + (OFFSET)) #define METHOD_PTR_TO_VOFFSET(ADDR) (~0x80000000 & (ADDR)) #include "symtab.h" #include "gdbtypes.h" #include "expression.h" struct frame_info; struct fn_field; extern void print_address_demangle (CORE_ADDR, struct ui_file *, int); extern LONGEST value_as_long (struct value *val); extern DOUBLEST value_as_double (struct value *val); extern CORE_ADDR value_as_address (struct value *val); extern LONGEST unpack_long (struct type *type, const char *valaddr); extern DOUBLEST unpack_double (struct type *type, const char *valaddr, int *invp); extern CORE_ADDR unpack_pointer (struct type *type, const char *valaddr); extern LONGEST unpack_field_as_long (struct type *type, const char *valaddr, int fieldno); extern struct value *value_from_longest (struct type *type, LONGEST num); extern struct value *value_from_pointer (struct type *type, CORE_ADDR addr); extern struct value *value_from_double (struct type *type, DOUBLEST num); extern struct value *value_from_string (char *string); extern struct value *value_at (struct type *type, CORE_ADDR addr, asection * sect); extern struct value *value_at_lazy (struct type *type, CORE_ADDR addr, asection * sect); extern struct value *value_from_register (struct type *type, int regnum, struct frame_info *frame); extern struct value *value_of_variable (struct symbol *var, struct block *b); extern struct value *value_of_register (int regnum, struct frame_info *frame); extern int symbol_read_needs_frame (struct symbol *); extern struct value *read_var_value (struct symbol *var, struct frame_info *frame); extern struct value *locate_var_value (struct symbol *var, struct frame_info *frame); extern struct value *allocate_value (struct type *type); extern struct value *allocate_repeat_value (struct type *type, int count); extern struct value *value_change_enclosing_type (struct value *val, struct type *new_type); extern struct value *value_mark (void); extern void value_free_to_mark (struct value *mark); extern struct value *value_string (char *ptr, int len); extern struct value *value_bitstring (char *ptr, int len); extern struct value *value_array (int lowbound, int highbound, struct value ** elemvec); extern struct value *value_concat (struct value *arg1, struct value *arg2); extern struct value *value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op); extern struct value *value_add (struct value *arg1, struct value *arg2); extern struct value *value_sub (struct value *arg1, struct value *arg2); extern struct value *value_coerce_array (struct value *arg1); extern struct value *value_coerce_function (struct value *arg1); extern struct value *value_ind (struct value *arg1); extern struct value *value_addr (struct value *arg1); extern struct value *value_assign (struct value *toval, struct value *fromval); extern struct value *value_neg (struct value *arg1); extern struct value *value_complement (struct value *arg1); extern struct value *value_struct_elt (struct value **argp, struct value **args, char *name, int *static_memfuncp, char *err); extern struct value *value_aggregate_elt (struct type *curtype, char *name, enum noside noside); extern struct value *value_static_field (struct type *type, int fieldno); extern struct fn_field *value_find_oload_method_list (struct value **, char *, int, int *, struct type **, int *); extern int find_overload_match (struct type **arg_types, int nargs, char *name, int method, int lax, struct value **objp, struct symbol *fsym, struct value **valp, struct symbol **symp, int *staticp); extern struct value *value_field (struct value *arg1, int fieldno); extern struct value *value_primitive_field (struct value *arg1, int offset, int fieldno, struct type *arg_type); extern struct type *value_rtti_target_type (struct value *, int *, int *, int *); extern struct value *value_full_object (struct value *, struct type *, int, int, int); extern struct value *value_cast (struct type *type, struct value *arg2); extern struct value *value_zero (struct type *type, enum lval_type lv); extern struct value *value_repeat (struct value *arg1, int count); extern struct value *value_subscript (struct value *array, struct value *idx); extern struct value *register_value_being_returned (struct type *valtype, struct regcache *retbuf); extern struct value *value_in (struct value *element, struct value *set); extern int value_bit_index (struct type *type, char *addr, int index); extern int using_struct_return (struct type *value_type, int gcc_p); extern struct value *evaluate_expression (struct expression *exp); extern struct value *evaluate_type (struct expression *exp); extern struct value *evaluate_subexp_with_coercion (struct expression *, int *, enum noside); extern struct value *parse_and_eval (char *exp); extern struct value *parse_to_comma_and_eval (char **expp); extern struct type *parse_and_eval_type (char *p, int length); extern CORE_ADDR parse_and_eval_address (char *exp); extern CORE_ADDR parse_and_eval_address_1 (char **expptr); extern LONGEST parse_and_eval_long (char *exp); extern struct value *access_value_history (int num); extern struct value *value_of_internalvar (struct internalvar *var); extern void set_internalvar (struct internalvar *var, struct value *val); extern void set_internalvar_component (struct internalvar *var, int offset, int bitpos, int bitsize, struct value *newvalue); extern struct internalvar *lookup_internalvar (char *name); extern int value_equal (struct value *arg1, struct value *arg2); extern int value_less (struct value *arg1, struct value *arg2); extern int value_logical_not (struct value *arg1); /* C++ */ extern struct value *value_of_this (int complain); extern struct value *value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op, enum exp_opcode otherop, enum noside noside); extern struct value *value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside); extern struct value *value_fn_field (struct value ** arg1p, struct fn_field *f, int j, struct type *type, int offset); extern int binop_user_defined_p (enum exp_opcode op, struct value *arg1, struct value *arg2); extern int unop_user_defined_p (enum exp_opcode op, struct value *arg1); extern int destructor_name_p (const char *name, const struct type *type); #define value_free(val) xfree (val) extern void free_all_values (void); extern void release_value (struct value *val); extern int record_latest_value (struct value *val); extern void modify_field (char *addr, LONGEST fieldval, int bitpos, int bitsize); extern void type_print (struct type * type, char *varstring, struct ui_file * stream, int show); extern char *baseclass_addr (struct type *type, int index, char *valaddr, struct value **valuep, int *errp); extern void print_longest (struct ui_file * stream, int format, int use_local, LONGEST val); extern void print_floating (char *valaddr, struct type * type, struct ui_file * stream); extern int value_print (struct value *val, struct ui_file *stream, int format, enum val_prettyprint pretty); extern void value_print_array_elements (struct value *val, struct ui_file *stream, int format, enum val_prettyprint pretty); extern struct value *value_release_to_mark (struct value *mark); extern int val_print (struct type * type, char *valaddr, int embedded_offset, CORE_ADDR address, struct ui_file * stream, int format, int deref_ref, int recurse, enum val_prettyprint pretty); extern int common_val_print (struct value *val, struct ui_file *stream, int format, int deref_ref, int recurse, enum val_prettyprint pretty); extern int val_print_string (CORE_ADDR addr, int len, int width, struct ui_file *stream); extern void print_variable_value (struct symbol * var, struct frame_info * frame, struct ui_file *stream); extern int check_field (struct value *, const char *); extern void typedef_print (struct type * type, struct symbol * news, struct ui_file * stream); extern char *internalvar_name (struct internalvar *var); extern void clear_value_history (void); extern void clear_internalvars (void); /* From values.c */ extern struct value *value_copy (struct value *); /* From valops.c */ extern struct value *varying_to_slice (struct value *); extern struct value *value_slice (struct value *, int, int); extern struct value *value_literal_complex (struct value *, struct value *, struct type *); extern void find_rt_vbase_offset (struct type *, struct type *, char *, int, int *, int *); extern struct value *find_function_in_inferior (const char *); extern struct value *value_allocate_space_in_inferior (int); extern CORE_ADDR legacy_push_arguments (int nargs, struct value ** args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr); extern struct value *value_of_local (const char *name, int complain); #endif /* !defined (VALUE_H) */ Index: projects/ci20_mips/contrib/gdb/gdb/values.c =================================================================== --- projects/ci20_mips/contrib/gdb/gdb/values.c (revision 283030) +++ projects/ci20_mips/contrib/gdb/gdb/values.c (revision 283031) @@ -1,1329 +1,1346 @@ /* Low level packing and unpacking of values for GDB, the GNU Debugger. Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "defs.h" #include "gdb_string.h" #include "symtab.h" #include "gdbtypes.h" #include "value.h" #include "gdbcore.h" #include "command.h" #include "gdbcmd.h" #include "target.h" #include "language.h" #include "scm-lang.h" #include "demangle.h" #include "doublest.h" #include "gdb_assert.h" #include "regcache.h" #include "block.h" /* Prototypes for exported functions. */ void _initialize_values (void); /* Prototypes for local functions. */ static void show_values (char *, int); static void show_convenience (char *, int); /* The value-history records all the values printed by print commands during this session. Each chunk records 60 consecutive values. The first chunk on the chain records the most recent values. The total number of values is in value_history_count. */ #define VALUE_HISTORY_CHUNK 60 struct value_history_chunk { struct value_history_chunk *next; struct value *values[VALUE_HISTORY_CHUNK]; }; /* Chain of chunks now in use. */ static struct value_history_chunk *value_history_chain; static int value_history_count; /* Abs number of last entry stored */ /* List of all value objects currently allocated (except for those released by calls to release_value) This is so they can be freed after each command. */ static struct value *all_values; /* Allocate a value that has the correct length for type TYPE. */ struct value * allocate_value (struct type *type) { struct value *val; struct type *atype = check_typedef (type); val = (struct value *) xmalloc (sizeof (struct value) + TYPE_LENGTH (atype)); VALUE_NEXT (val) = all_values; all_values = val; VALUE_TYPE (val) = type; VALUE_ENCLOSING_TYPE (val) = type; VALUE_LVAL (val) = not_lval; VALUE_ADDRESS (val) = 0; VALUE_FRAME_ID (val) = null_frame_id; VALUE_OFFSET (val) = 0; VALUE_BITPOS (val) = 0; VALUE_BITSIZE (val) = 0; VALUE_REGNO (val) = -1; VALUE_LAZY (val) = 0; VALUE_OPTIMIZED_OUT (val) = 0; VALUE_BFD_SECTION (val) = NULL; VALUE_EMBEDDED_OFFSET (val) = 0; VALUE_POINTED_TO_OFFSET (val) = 0; val->modifiable = 1; + val->initialized = 1; /* Default to initialized. */ return val; } /* Allocate a value that has the correct length for COUNT repetitions type TYPE. */ struct value * allocate_repeat_value (struct type *type, int count) { int low_bound = current_language->string_lower_bound; /* ??? */ /* FIXME-type-allocation: need a way to free this type when we are done with it. */ struct type *range_type = create_range_type ((struct type *) NULL, builtin_type_int, low_bound, count + low_bound - 1); /* FIXME-type-allocation: need a way to free this type when we are done with it. */ return allocate_value (create_array_type ((struct type *) NULL, type, range_type)); } /* Return a mark in the value chain. All values allocated after the mark is obtained (except for those released) are subject to being freed if a subsequent value_free_to_mark is passed the mark. */ struct value * value_mark (void) { return all_values; } /* Free all values allocated since MARK was obtained by value_mark (except for those released). */ void value_free_to_mark (struct value *mark) { struct value *val; struct value *next; for (val = all_values; val && val != mark; val = next) { next = VALUE_NEXT (val); value_free (val); } all_values = val; } /* Free all the values that have been allocated (except for those released). Called after each command, successful or not. */ void free_all_values (void) { struct value *val; struct value *next; for (val = all_values; val; val = next) { next = VALUE_NEXT (val); value_free (val); } all_values = 0; } /* Remove VAL from the chain all_values so it will not be freed automatically. */ void release_value (struct value *val) { struct value *v; if (all_values == val) { all_values = val->next; return; } for (v = all_values; v; v = v->next) { if (v->next == val) { v->next = val->next; break; } } } /* Release all values up to mark */ struct value * value_release_to_mark (struct value *mark) { struct value *val; struct value *next; for (val = next = all_values; next; next = VALUE_NEXT (next)) if (VALUE_NEXT (next) == mark) { all_values = VALUE_NEXT (next); VALUE_NEXT (next) = 0; return val; } all_values = 0; return val; } /* Return a copy of the value ARG. It contains the same contents, for same memory address, but it's a different block of storage. */ struct value * value_copy (struct value *arg) { struct type *encl_type = VALUE_ENCLOSING_TYPE (arg); struct value *val = allocate_value (encl_type); VALUE_TYPE (val) = VALUE_TYPE (arg); VALUE_LVAL (val) = VALUE_LVAL (arg); VALUE_ADDRESS (val) = VALUE_ADDRESS (arg); VALUE_OFFSET (val) = VALUE_OFFSET (arg); VALUE_BITPOS (val) = VALUE_BITPOS (arg); VALUE_BITSIZE (val) = VALUE_BITSIZE (arg); VALUE_FRAME_ID (val) = VALUE_FRAME_ID (arg); VALUE_REGNO (val) = VALUE_REGNO (arg); VALUE_LAZY (val) = VALUE_LAZY (arg); VALUE_OPTIMIZED_OUT (val) = VALUE_OPTIMIZED_OUT (arg); VALUE_EMBEDDED_OFFSET (val) = VALUE_EMBEDDED_OFFSET (arg); VALUE_POINTED_TO_OFFSET (val) = VALUE_POINTED_TO_OFFSET (arg); VALUE_BFD_SECTION (val) = VALUE_BFD_SECTION (arg); val->modifiable = arg->modifiable; if (!VALUE_LAZY (val)) { memcpy (VALUE_CONTENTS_ALL_RAW (val), VALUE_CONTENTS_ALL_RAW (arg), TYPE_LENGTH (VALUE_ENCLOSING_TYPE (arg))); } return val; } /* Access to the value history. */ /* Record a new value in the value history. Returns the absolute history index of the entry. Result of -1 indicates the value was not saved; otherwise it is the value history index of this new item. */ int record_latest_value (struct value *val) { int i; /* We don't want this value to have anything to do with the inferior anymore. In particular, "set $1 = 50" should not affect the variable from which the value was taken, and fast watchpoints should be able to assume that a value on the value history never changes. */ if (VALUE_LAZY (val)) value_fetch_lazy (val); /* We preserve VALUE_LVAL so that the user can find out where it was fetched from. This is a bit dubious, because then *&$1 does not just return $1 but the current contents of that location. c'est la vie... */ val->modifiable = 0; release_value (val); /* Here we treat value_history_count as origin-zero and applying to the value being stored now. */ i = value_history_count % VALUE_HISTORY_CHUNK; if (i == 0) { struct value_history_chunk *new = (struct value_history_chunk *) xmalloc (sizeof (struct value_history_chunk)); memset (new->values, 0, sizeof new->values); new->next = value_history_chain; value_history_chain = new; } value_history_chain->values[i] = val; /* Now we regard value_history_count as origin-one and applying to the value just stored. */ return ++value_history_count; } /* Return a copy of the value in the history with sequence number NUM. */ struct value * access_value_history (int num) { struct value_history_chunk *chunk; int i; int absnum = num; if (absnum <= 0) absnum += value_history_count; if (absnum <= 0) { if (num == 0) error ("The history is empty."); else if (num == 1) error ("There is only one value in the history."); else error ("History does not go back to $$%d.", -num); } if (absnum > value_history_count) error ("History has not yet reached $%d.", absnum); absnum--; /* Now absnum is always absolute and origin zero. */ chunk = value_history_chain; for (i = (value_history_count - 1) / VALUE_HISTORY_CHUNK - absnum / VALUE_HISTORY_CHUNK; i > 0; i--) chunk = chunk->next; return value_copy (chunk->values[absnum % VALUE_HISTORY_CHUNK]); } /* Clear the value history entirely. Must be done when new symbol tables are loaded, because the type pointers become invalid. */ void clear_value_history (void) { struct value_history_chunk *next; int i; struct value *val; while (value_history_chain) { for (i = 0; i < VALUE_HISTORY_CHUNK; i++) if ((val = value_history_chain->values[i]) != NULL) xfree (val); next = value_history_chain->next; xfree (value_history_chain); value_history_chain = next; } value_history_count = 0; } static void show_values (char *num_exp, int from_tty) { int i; struct value *val; static int num = 1; if (num_exp) { /* "info history +" should print from the stored position. "info history " should print around value number . */ if (num_exp[0] != '+' || num_exp[1] != '\0') num = parse_and_eval_long (num_exp) - 5; } else { /* "info history" means print the last 10 values. */ num = value_history_count - 9; } if (num <= 0) num = 1; for (i = num; i < num + 10 && i <= value_history_count; i++) { val = access_value_history (i); printf_filtered ("$%d = ", i); value_print (val, gdb_stdout, 0, Val_pretty_default); printf_filtered ("\n"); } /* The next "info history +" should start after what we just printed. */ num += 10; /* Hitting just return after this command should do the same thing as "info history +". If num_exp is null, this is unnecessary, since "info history +" is not useful after "info history". */ if (from_tty && num_exp) { num_exp[0] = '+'; num_exp[1] = '\0'; } } /* Internal variables. These are variables within the debugger that hold values assigned by debugger commands. The user refers to them with a '$' prefix that does not appear in the variable names stored internally. */ static struct internalvar *internalvars; /* Look up an internal variable with name NAME. NAME should not normally include a dollar sign. If the specified internal variable does not exist, one is created, with a void value. */ struct internalvar * lookup_internalvar (char *name) { struct internalvar *var; for (var = internalvars; var; var = var->next) if (strcmp (var->name, name) == 0) return var; var = (struct internalvar *) xmalloc (sizeof (struct internalvar)); var->name = concat (name, NULL); var->value = allocate_value (builtin_type_void); release_value (var->value); var->next = internalvars; internalvars = var; return var; } struct value * value_of_internalvar (struct internalvar *var) { struct value *val; val = value_copy (var->value); if (VALUE_LAZY (val)) value_fetch_lazy (val); VALUE_LVAL (val) = lval_internalvar; VALUE_INTERNALVAR (val) = var; return val; } void set_internalvar_component (struct internalvar *var, int offset, int bitpos, int bitsize, struct value *newval) { char *addr = VALUE_CONTENTS (var->value) + offset; if (bitsize) modify_field (addr, value_as_long (newval), bitpos, bitsize); else memcpy (addr, VALUE_CONTENTS (newval), TYPE_LENGTH (VALUE_TYPE (newval))); } void set_internalvar (struct internalvar *var, struct value *val) { struct value *newval; newval = value_copy (val); newval->modifiable = 1; /* Force the value to be fetched from the target now, to avoid problems later when this internalvar is referenced and the target is gone or has changed. */ if (VALUE_LAZY (newval)) value_fetch_lazy (newval); /* Begin code which must not call error(). If var->value points to something free'd, an error() obviously leaves a dangling pointer. But we also get a danling pointer if var->value points to something in the value chain (i.e., before release_value is called), because after the error free_all_values will get called before long. */ xfree (var->value); var->value = newval; release_value (newval); /* End code which must not call error(). */ } char * internalvar_name (struct internalvar *var) { return var->name; } /* Free all internalvars. Done when new symtabs are loaded, because that makes the values invalid. */ void clear_internalvars (void) { struct internalvar *var; while (internalvars) { var = internalvars; internalvars = var->next; xfree (var->name); xfree (var->value); xfree (var); } } static void show_convenience (char *ignore, int from_tty) { struct internalvar *var; int varseen = 0; for (var = internalvars; var; var = var->next) { if (!varseen) { varseen = 1; } printf_filtered ("$%s = ", var->name); value_print (var->value, gdb_stdout, 0, Val_pretty_default); printf_filtered ("\n"); } if (!varseen) printf_unfiltered ("No debugger convenience variables now defined.\n\ Convenience variables have names starting with \"$\";\n\ use \"set\" as in \"set $foo = 5\" to define them.\n"); } /* Extract a value as a C number (either long or double). Knows how to convert fixed values to double, or floating values to long. Does not deallocate the value. */ LONGEST value_as_long (struct value *val) { /* This coerces arrays and functions, which is necessary (e.g. in disassemble_command). It also dereferences references, which I suspect is the most logical thing to do. */ COERCE_ARRAY (val); return unpack_long (VALUE_TYPE (val), VALUE_CONTENTS (val)); } DOUBLEST value_as_double (struct value *val) { DOUBLEST foo; int inv; foo = unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val), &inv); if (inv) error ("Invalid floating value found in program."); return foo; } /* Extract a value as a C pointer. Does not deallocate the value. Note that val's type may not actually be a pointer; value_as_long handles all the cases. */ CORE_ADDR value_as_address (struct value *val) { /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure whether we want this to be true eventually. */ #if 0 /* ADDR_BITS_REMOVE is wrong if we are being called for a non-address (e.g. argument to "signal", "info break", etc.), or for pointers to char, in which the low bits *are* significant. */ return ADDR_BITS_REMOVE (value_as_long (val)); #else /* There are several targets (IA-64, PowerPC, and others) which don't represent pointers to functions as simply the address of the function's entry point. For example, on the IA-64, a function pointer points to a two-word descriptor, generated by the linker, which contains the function's entry point, and the value the IA-64 "global pointer" register should have --- to support position-independent code. The linker generates descriptors only for those functions whose addresses are taken. On such targets, it's difficult for GDB to convert an arbitrary function address into a function pointer; it has to either find an existing descriptor for that function, or call malloc and build its own. On some targets, it is impossible for GDB to build a descriptor at all: the descriptor must contain a jump instruction; data memory cannot be executed; and code memory cannot be modified. Upon entry to this function, if VAL is a value of type `function' (that is, TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FUNC), then VALUE_ADDRESS (val) is the address of the function. This is what you'll get if you evaluate an expression like `main'. The call to COERCE_ARRAY below actually does all the usual unary conversions, which includes converting values of type `function' to `pointer to function'. This is the challenging conversion discussed above. Then, `unpack_long' will convert that pointer back into an address. So, suppose the user types `disassemble foo' on an architecture with a strange function pointer representation, on which GDB cannot build its own descriptors, and suppose further that `foo' has no linker-built descriptor. The address->pointer conversion will signal an error and prevent the command from running, even though the next step would have been to convert the pointer directly back into the same address. The following shortcut avoids this whole mess. If VAL is a function, just return its address directly. */ if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FUNC || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_METHOD) return VALUE_ADDRESS (val); COERCE_ARRAY (val); /* Some architectures (e.g. Harvard), map instruction and data addresses onto a single large unified address space. For instance: An architecture may consider a large integer in the range 0x10000000 .. 0x1000ffff to already represent a data addresses (hence not need a pointer to address conversion) while a small integer would still need to be converted integer to pointer to address. Just assume such architectures handle all integer conversions in a single function. */ /* JimB writes: I think INTEGER_TO_ADDRESS is a good idea as proposed --- but we must admonish GDB hackers to make sure its behavior matches the compiler's, whenever possible. In general, I think GDB should evaluate expressions the same way the compiler does. When the user copies an expression out of their source code and hands it to a `print' command, they should get the same value the compiler would have computed. Any deviation from this rule can cause major confusion and annoyance, and needs to be justified carefully. In other words, GDB doesn't really have the freedom to do these conversions in clever and useful ways. AndrewC pointed out that users aren't complaining about how GDB casts integers to pointers; they are complaining that they can't take an address from a disassembly listing and give it to `x/i'. This is certainly important. Adding an architecture method like INTEGER_TO_ADDRESS certainly makes it possible for GDB to "get it right" in all circumstances --- the target has complete control over how things get done, so people can Do The Right Thing for their target without breaking anyone else. The standard doesn't specify how integers get converted to pointers; usually, the ABI doesn't either, but ABI-specific code is a more reasonable place to handle it. */ if (TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_PTR && TYPE_CODE (VALUE_TYPE (val)) != TYPE_CODE_REF && INTEGER_TO_ADDRESS_P ()) return INTEGER_TO_ADDRESS (VALUE_TYPE (val), VALUE_CONTENTS (val)); return unpack_long (VALUE_TYPE (val), VALUE_CONTENTS (val)); #endif } /* Unpack raw data (copied from debugee, target byte order) at VALADDR as a long, or as a double, assuming the raw data is described by type TYPE. Knows how to convert different sizes of values and can convert between fixed and floating point. We don't assume any alignment for the raw data. Return value is in host byte order. If you want functions and arrays to be coerced to pointers, and references to be dereferenced, call value_as_long() instead. C++: It is assumed that the front-end has taken care of all matters concerning pointers to members. A pointer to member which reaches here is considered to be equivalent to an INT (or some size). After all, it is only an offset. */ LONGEST unpack_long (struct type *type, const char *valaddr) { enum type_code code = TYPE_CODE (type); int len = TYPE_LENGTH (type); int nosign = TYPE_UNSIGNED (type); if (current_language->la_language == language_scm && is_scmvalue_type (type)) return scm_unpack (type, valaddr, TYPE_CODE_INT); switch (code) { case TYPE_CODE_TYPEDEF: return unpack_long (check_typedef (type), valaddr); case TYPE_CODE_ENUM: case TYPE_CODE_BOOL: case TYPE_CODE_INT: case TYPE_CODE_CHAR: case TYPE_CODE_RANGE: if (nosign) return extract_unsigned_integer (valaddr, len); else return extract_signed_integer (valaddr, len); case TYPE_CODE_FLT: return extract_typed_floating (valaddr, type); case TYPE_CODE_PTR: case TYPE_CODE_REF: /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure whether we want this to be true eventually. */ return extract_typed_address (valaddr, type); case TYPE_CODE_MEMBER: error ("not implemented: member types in unpack_long"); default: error ("Value can't be converted to integer."); } return 0; /* Placate lint. */ } /* Return a double value from the specified type and address. INVP points to an int which is set to 0 for valid value, 1 for invalid value (bad float format). In either case, the returned double is OK to use. Argument is in target format, result is in host format. */ DOUBLEST unpack_double (struct type *type, const char *valaddr, int *invp) { enum type_code code; int len; int nosign; *invp = 0; /* Assume valid. */ CHECK_TYPEDEF (type); code = TYPE_CODE (type); len = TYPE_LENGTH (type); nosign = TYPE_UNSIGNED (type); if (code == TYPE_CODE_FLT) { /* NOTE: cagney/2002-02-19: There was a test here to see if the floating-point value was valid (using the macro INVALID_FLOAT). That test/macro have been removed. It turns out that only the VAX defined this macro and then only in a non-portable way. Fixing the portability problem wouldn't help since the VAX floating-point code is also badly bit-rotten. The target needs to add definitions for the methods TARGET_FLOAT_FORMAT and TARGET_DOUBLE_FORMAT - these exactly describe the target floating-point format. The problem here is that the corresponding floatformat_vax_f and floatformat_vax_d values these methods should be set to are also not defined either. Oops! Hopefully someone will add both the missing floatformat definitions and the new cases for floatformat_is_valid (). */ if (!floatformat_is_valid (floatformat_from_type (type), valaddr)) { *invp = 1; return 0.0; } return extract_typed_floating (valaddr, type); } else if (nosign) { /* Unsigned -- be sure we compensate for signed LONGEST. */ return (ULONGEST) unpack_long (type, valaddr); } else { /* Signed -- we are OK with unpack_long. */ return unpack_long (type, valaddr); } } /* Unpack raw data (copied from debugee, target byte order) at VALADDR as a CORE_ADDR, assuming the raw data is described by type TYPE. We don't assume any alignment for the raw data. Return value is in host byte order. If you want functions and arrays to be coerced to pointers, and references to be dereferenced, call value_as_address() instead. C++: It is assumed that the front-end has taken care of all matters concerning pointers to members. A pointer to member which reaches here is considered to be equivalent to an INT (or some size). After all, it is only an offset. */ CORE_ADDR unpack_pointer (struct type *type, const char *valaddr) { /* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure whether we want this to be true eventually. */ return unpack_long (type, valaddr); } /* Get the value of the FIELDN'th field (which must be static) of TYPE. Return NULL if the field doesn't exist or has been optimized out. */ struct value * value_static_field (struct type *type, int fieldno) { struct value *retval; if (TYPE_FIELD_STATIC_HAS_ADDR (type, fieldno)) { retval = value_at (TYPE_FIELD_TYPE (type, fieldno), TYPE_FIELD_STATIC_PHYSADDR (type, fieldno), NULL); } else { char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, fieldno); struct symbol *sym = lookup_symbol (phys_name, 0, VAR_DOMAIN, 0, NULL); if (sym == NULL) { /* With some compilers, e.g. HP aCC, static data members are reported as non-debuggable symbols */ struct minimal_symbol *msym = lookup_minimal_symbol (phys_name, NULL, NULL); if (!msym) return NULL; else { retval = value_at (TYPE_FIELD_TYPE (type, fieldno), SYMBOL_VALUE_ADDRESS (msym), SYMBOL_BFD_SECTION (msym)); } } else { /* SYM should never have a SYMBOL_CLASS which will require read_var_value to use the FRAME parameter. */ if (symbol_read_needs_frame (sym)) warning ("static field's value depends on the current " "frame - bad debug info?"); retval = read_var_value (sym, NULL); } if (retval && VALUE_LVAL (retval) == lval_memory) SET_FIELD_PHYSADDR (TYPE_FIELD (type, fieldno), VALUE_ADDRESS (retval)); } return retval; } /* Change the enclosing type of a value object VAL to NEW_ENCL_TYPE. You have to be careful here, since the size of the data area for the value is set by the length of the enclosing type. So if NEW_ENCL_TYPE is bigger than the old enclosing type, you have to allocate more space for the data. The return value is a pointer to the new version of this value structure. */ struct value * value_change_enclosing_type (struct value *val, struct type *new_encl_type) { if (TYPE_LENGTH (new_encl_type) <= TYPE_LENGTH (VALUE_ENCLOSING_TYPE (val))) { VALUE_ENCLOSING_TYPE (val) = new_encl_type; return val; } else { struct value *new_val; struct value *prev; new_val = (struct value *) xrealloc (val, sizeof (struct value) + TYPE_LENGTH (new_encl_type)); VALUE_ENCLOSING_TYPE (new_val) = new_encl_type; /* We have to make sure this ends up in the same place in the value chain as the original copy, so it's clean-up behavior is the same. If the value has been released, this is a waste of time, but there is no way to tell that in advance, so... */ if (val != all_values) { for (prev = all_values; prev != NULL; prev = prev->next) { if (prev->next == val) { prev->next = new_val; break; } } } return new_val; } } /* Given a value ARG1 (offset by OFFSET bytes) of a struct or union type ARG_TYPE, extract and return the value of one of its (non-static) fields. FIELDNO says which field. */ struct value * value_primitive_field (struct value *arg1, int offset, int fieldno, struct type *arg_type) { struct value *v; struct type *type; CHECK_TYPEDEF (arg_type); type = TYPE_FIELD_TYPE (arg_type, fieldno); /* Handle packed fields */ if (TYPE_FIELD_BITSIZE (arg_type, fieldno)) { v = value_from_longest (type, unpack_field_as_long (arg_type, VALUE_CONTENTS (arg1) + offset, fieldno)); VALUE_BITPOS (v) = TYPE_FIELD_BITPOS (arg_type, fieldno) % 8; VALUE_BITSIZE (v) = TYPE_FIELD_BITSIZE (arg_type, fieldno); VALUE_OFFSET (v) = VALUE_OFFSET (arg1) + offset + TYPE_FIELD_BITPOS (arg_type, fieldno) / 8; } else if (fieldno < TYPE_N_BASECLASSES (arg_type)) { /* This field is actually a base subobject, so preserve the entire object's contents for later references to virtual bases, etc. */ v = allocate_value (VALUE_ENCLOSING_TYPE (arg1)); VALUE_TYPE (v) = type; if (VALUE_LAZY (arg1)) VALUE_LAZY (v) = 1; else memcpy (VALUE_CONTENTS_ALL_RAW (v), VALUE_CONTENTS_ALL_RAW (arg1), TYPE_LENGTH (VALUE_ENCLOSING_TYPE (arg1))); VALUE_OFFSET (v) = VALUE_OFFSET (arg1); VALUE_EMBEDDED_OFFSET (v) = offset + VALUE_EMBEDDED_OFFSET (arg1) + TYPE_FIELD_BITPOS (arg_type, fieldno) / 8; } else { /* Plain old data member */ offset += TYPE_FIELD_BITPOS (arg_type, fieldno) / 8; v = allocate_value (type); if (VALUE_LAZY (arg1)) VALUE_LAZY (v) = 1; else memcpy (VALUE_CONTENTS_RAW (v), VALUE_CONTENTS_RAW (arg1) + offset, TYPE_LENGTH (type)); VALUE_OFFSET (v) = VALUE_OFFSET (arg1) + offset + VALUE_EMBEDDED_OFFSET (arg1); } VALUE_LVAL (v) = VALUE_LVAL (arg1); if (VALUE_LVAL (arg1) == lval_internalvar) VALUE_LVAL (v) = lval_internalvar_component; VALUE_ADDRESS (v) = VALUE_ADDRESS (arg1); VALUE_REGNO (v) = VALUE_REGNO (arg1); /* VALUE_OFFSET (v) = VALUE_OFFSET (arg1) + offset + TYPE_FIELD_BITPOS (arg_type, fieldno) / 8; */ return v; } /* Given a value ARG1 of a struct or union type, extract and return the value of one of its (non-static) fields. FIELDNO says which field. */ struct value * value_field (struct value *arg1, int fieldno) { return value_primitive_field (arg1, 0, fieldno, VALUE_TYPE (arg1)); } /* Return a non-virtual function as a value. F is the list of member functions which contains the desired method. J is an index into F which provides the desired method. We only use the symbol for its address, so be happy with either a full symbol or a minimal symbol. */ struct value * value_fn_field (struct value **arg1p, struct fn_field *f, int j, struct type *type, int offset) { struct value *v; struct type *ftype = TYPE_FN_FIELD_TYPE (f, j); char *physname = TYPE_FN_FIELD_PHYSNAME (f, j); struct symbol *sym; struct minimal_symbol *msym; sym = lookup_symbol (physname, 0, VAR_DOMAIN, 0, NULL); if (sym != NULL) { msym = NULL; } else { gdb_assert (sym == NULL); msym = lookup_minimal_symbol (physname, NULL, NULL); if (msym == NULL) return NULL; } v = allocate_value (ftype); if (sym) { VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); } else { VALUE_ADDRESS (v) = SYMBOL_VALUE_ADDRESS (msym); } if (arg1p) { if (type != VALUE_TYPE (*arg1p)) *arg1p = value_ind (value_cast (lookup_pointer_type (type), value_addr (*arg1p))); /* Move the `this' pointer according to the offset. VALUE_OFFSET (*arg1p) += offset; */ } return v; } /* Unpack a field FIELDNO of the specified TYPE, from the anonymous object at VALADDR. Extracting bits depends on endianness of the machine. Compute the number of least significant bits to discard. For big endian machines, we compute the total number of bits in the anonymous object, subtract off the bit count from the MSB of the object to the MSB of the bitfield, then the size of the bitfield, which leaves the LSB discard count. For little endian machines, the discard count is simply the number of bits from the LSB of the anonymous object to the LSB of the bitfield. If the field is signed, we also do sign extension. */ LONGEST unpack_field_as_long (struct type *type, const char *valaddr, int fieldno) { ULONGEST val; ULONGEST valmask; int bitpos = TYPE_FIELD_BITPOS (type, fieldno); int bitsize = TYPE_FIELD_BITSIZE (type, fieldno); int lsbcount; struct type *field_type; val = extract_unsigned_integer (valaddr + bitpos / 8, sizeof (val)); field_type = TYPE_FIELD_TYPE (type, fieldno); CHECK_TYPEDEF (field_type); /* Extract bits. See comment above. */ if (BITS_BIG_ENDIAN) lsbcount = (sizeof val * 8 - bitpos % 8 - bitsize); else lsbcount = (bitpos % 8); val >>= lsbcount; /* If the field does not entirely fill a LONGEST, then zero the sign bits. If the field is signed, and is negative, then sign extend. */ if ((bitsize > 0) && (bitsize < 8 * (int) sizeof (val))) { valmask = (((ULONGEST) 1) << bitsize) - 1; val &= valmask; if (!TYPE_UNSIGNED (field_type)) { if (val & (valmask ^ (valmask >> 1))) { val |= ~valmask; } } } return (val); } /* Modify the value of a bitfield. ADDR points to a block of memory in target byte order; the bitfield starts in the byte pointed to. FIELDVAL is the desired value of the field, in host byte order. BITPOS and BITSIZE indicate which bits (in target bit order) comprise the bitfield. */ void modify_field (char *addr, LONGEST fieldval, int bitpos, int bitsize) { LONGEST oword; /* If a negative fieldval fits in the field in question, chop off the sign extension bits. */ if (bitsize < (8 * (int) sizeof (fieldval)) && (~fieldval & ~((1 << (bitsize - 1)) - 1)) == 0) fieldval = fieldval & ((1 << bitsize) - 1); /* Warn if value is too big to fit in the field in question. */ if (bitsize < (8 * (int) sizeof (fieldval)) && 0 != (fieldval & ~((1 << bitsize) - 1))) { /* FIXME: would like to include fieldval in the message, but we don't have a sprintf_longest. */ warning ("Value does not fit in %d bits.", bitsize); /* Truncate it, otherwise adjoining fields may be corrupted. */ fieldval = fieldval & ((1 << bitsize) - 1); } oword = extract_signed_integer (addr, sizeof oword); /* Shifting for bit field depends on endianness of the target machine. */ if (BITS_BIG_ENDIAN) bitpos = sizeof (oword) * 8 - bitpos - bitsize; /* Mask out old value, while avoiding shifts >= size of oword */ if (bitsize < 8 * (int) sizeof (oword)) oword &= ~(((((ULONGEST) 1) << bitsize) - 1) << bitpos); else oword &= ~((~(ULONGEST) 0) << bitpos); oword |= fieldval << bitpos; store_signed_integer (addr, sizeof oword, oword); } /* Convert C numbers into newly allocated values */ struct value * value_from_longest (struct type *type, LONGEST num) { struct value *val = allocate_value (type); enum type_code code; int len; retry: code = TYPE_CODE (type); len = TYPE_LENGTH (type); switch (code) { case TYPE_CODE_TYPEDEF: type = check_typedef (type); goto retry; case TYPE_CODE_INT: case TYPE_CODE_CHAR: case TYPE_CODE_ENUM: case TYPE_CODE_BOOL: case TYPE_CODE_RANGE: store_signed_integer (VALUE_CONTENTS_RAW (val), len, num); break; case TYPE_CODE_REF: case TYPE_CODE_PTR: store_typed_address (VALUE_CONTENTS_RAW (val), type, (CORE_ADDR) num); break; default: error ("Unexpected type (%d) encountered for integer constant.", code); } return val; } /* Create a value representing a pointer of type TYPE to the address ADDR. */ struct value * value_from_pointer (struct type *type, CORE_ADDR addr) { struct value *val = allocate_value (type); store_typed_address (VALUE_CONTENTS_RAW (val), type, addr); return val; } /* Create a value for a string constant to be stored locally (not in the inferior's memory space, but in GDB memory). This is analogous to value_from_longest, which also does not use inferior memory. String shall NOT contain embedded nulls. */ struct value * value_from_string (char *ptr) { struct value *val; int len = strlen (ptr); int lowbound = current_language->string_lower_bound; struct type *rangetype = create_range_type ((struct type *) NULL, builtin_type_int, lowbound, len + lowbound - 1); struct type *stringtype = create_array_type ((struct type *) NULL, *current_language->string_char_type, rangetype); val = allocate_value (stringtype); memcpy (VALUE_CONTENTS_RAW (val), ptr, len); return val; } struct value * value_from_double (struct type *type, DOUBLEST num) { struct value *val = allocate_value (type); struct type *base_type = check_typedef (type); enum type_code code = TYPE_CODE (base_type); int len = TYPE_LENGTH (base_type); if (code == TYPE_CODE_FLT) { store_typed_floating (VALUE_CONTENTS_RAW (val), base_type, num); } else error ("Unexpected type encountered for floating constant."); return val; } /* Deal with the return-value of a function that has "just returned". Extract the return-value (as a "struct value") that a function, using register convention, has just returned to its caller. Assume that the type of the function is VALTYPE, and that the "just returned" register state is found in RETBUF. The function has "just returned" because GDB halts a returning function by setting a breakpoint at the return address (in the caller), and not the return instruction (in the callee). Because, in the case of a return from an inferior function call, GDB needs to restore the inferiors registers, RETBUF is normally a copy of the inferior's registers. */ struct value * register_value_being_returned (struct type *valtype, struct regcache *retbuf) { struct value *val = allocate_value (valtype); /* If the function returns void, don't bother fetching the return value. See also "using_struct_return". */ if (TYPE_CODE (valtype) == TYPE_CODE_VOID) return val; if (!gdbarch_return_value_p (current_gdbarch)) { /* NOTE: cagney/2003-10-20: Unlike "gdbarch_return_value", the EXTRACT_RETURN_VALUE and USE_STRUCT_CONVENTION methods do not handle the edge case of a function returning a small structure / union in registers. */ CHECK_TYPEDEF (valtype); EXTRACT_RETURN_VALUE (valtype, retbuf, VALUE_CONTENTS_RAW (val)); return val; } /* This function only handles "register convention". */ gdb_assert (gdbarch_return_value (current_gdbarch, valtype, NULL, NULL, NULL) == RETURN_VALUE_REGISTER_CONVENTION); gdbarch_return_value (current_gdbarch, valtype, retbuf, VALUE_CONTENTS_RAW (val) /*read*/, NULL /*write*/); return val; } /* Should we use DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS instead of EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc and TYPE is the type (which is known to be struct, union or array). On most machines, the struct convention is used unless we are using gcc and the type is of a special size. */ /* As of about 31 Mar 93, GCC was changed to be compatible with the native compiler. GCC 2.3.3 was the last release that did it the old way. Since gcc2_compiled was not changed, we have no way to correctly win in all cases, so we just do the right thing for gcc1 and for gcc2 after this change. Thus it loses for gcc 2.0-2.3.3. This is somewhat unfortunate, but changing gcc2_compiled would cause more chaos than dealing with some struct returns being handled wrong. */ int generic_use_struct_convention (int gcc_p, struct type *value_type) { return !((gcc_p == 1) && (TYPE_LENGTH (value_type) == 1 || TYPE_LENGTH (value_type) == 2 || TYPE_LENGTH (value_type) == 4 || TYPE_LENGTH (value_type) == 8)); } /* Return true if the function returning the specified type is using the convention of returning structures in memory (passing in the address as a hidden first parameter). GCC_P is nonzero if compiled with GCC. */ int using_struct_return (struct type *value_type, int gcc_p) { enum type_code code = TYPE_CODE (value_type); if (code == TYPE_CODE_ERROR) error ("Function return type unknown."); if (code == TYPE_CODE_VOID) /* A void return value is never in memory. See also corresponding code in "register_value_being_returned". */ return 0; if (!gdbarch_return_value_p (current_gdbarch)) { /* FIXME: cagney/2003-10-01: The below is dead. Instead an architecture should implement "gdbarch_return_value". Using that new function it is possible to exactly specify the ABIs "struct return" vs "register return" conventions. */ if (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION || code == TYPE_CODE_ARRAY || RETURN_VALUE_ON_STACK (value_type)) return USE_STRUCT_CONVENTION (gcc_p, value_type); else return 0; } /* Probe the architecture for the return-value convention. */ return (gdbarch_return_value (current_gdbarch, value_type, NULL, NULL, NULL) == RETURN_VALUE_STRUCT_CONVENTION); +} + +/* Set the initialized field in a value struct. */ + +void +set_value_initialized (struct value *val, int status) +{ + val->initialized = status; +} + +/* Return the initialized field in a value struct. */ + +int +value_initialized (struct value *val) +{ + return val->initialized; } void _initialize_values (void) { add_cmd ("convenience", no_class, show_convenience, "Debugger convenience (\"$foo\") variables.\n\ These variables are created when you assign them values;\n\ thus, \"print $foo=1\" gives \"$foo\" the value 1. Values may be any type.\n\n\ A few convenience variables are given values automatically:\n\ \"$_\"holds the last address examined with \"x\" or \"info lines\",\n\ \"$__\" holds the contents of the last address examined with \"x\".", &showlist); add_cmd ("values", no_class, show_values, "Elements of value history around item number IDX (or last ten).", &showlist); } Index: projects/ci20_mips/contrib/gdb =================================================================== --- projects/ci20_mips/contrib/gdb (revision 283030) +++ projects/ci20_mips/contrib/gdb (revision 283031) Property changes on: projects/ci20_mips/contrib/gdb ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/contrib/gdb:r282737-283030 Index: projects/ci20_mips/contrib/libarchive/libarchive/archive_read.c =================================================================== --- projects/ci20_mips/contrib/libarchive/libarchive/archive_read.c (revision 283030) +++ projects/ci20_mips/contrib/libarchive/libarchive/archive_read.c (revision 283031) @@ -1,1641 +1,1643 @@ /*- * Copyright (c) 2003-2011 Tim Kientzle * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This file contains the "essential" portions of the read API, that * is, stuff that will probably always be used by any client that * actually needs to read an archive. Optional pieces have been, as * far as possible, separated out into separate files to avoid * needlessly bloating statically-linked clients. */ #include "archive_platform.h" __FBSDID("$FreeBSD$"); #ifdef HAVE_ERRNO_H #include #endif #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #include "archive.h" #include "archive_entry.h" #include "archive_private.h" #include "archive_read_private.h" #define minimum(a, b) (a < b ? a : b) static int choose_filters(struct archive_read *); static int choose_format(struct archive_read *); static struct archive_vtable *archive_read_vtable(void); static int64_t _archive_filter_bytes(struct archive *, int); static int _archive_filter_code(struct archive *, int); static const char *_archive_filter_name(struct archive *, int); static int _archive_filter_count(struct archive *); static int _archive_read_close(struct archive *); static int _archive_read_data_block(struct archive *, const void **, size_t *, int64_t *); static int _archive_read_free(struct archive *); static int _archive_read_next_header(struct archive *, struct archive_entry **); static int _archive_read_next_header2(struct archive *, struct archive_entry *); static int64_t advance_file_pointer(struct archive_read_filter *, int64_t); static struct archive_vtable * archive_read_vtable(void) { static struct archive_vtable av; static int inited = 0; if (!inited) { av.archive_filter_bytes = _archive_filter_bytes; av.archive_filter_code = _archive_filter_code; av.archive_filter_name = _archive_filter_name; av.archive_filter_count = _archive_filter_count; av.archive_read_data_block = _archive_read_data_block; av.archive_read_next_header = _archive_read_next_header; av.archive_read_next_header2 = _archive_read_next_header2; av.archive_free = _archive_read_free; av.archive_close = _archive_read_close; inited = 1; } return (&av); } /* * Allocate, initialize and return a struct archive object. */ struct archive * archive_read_new(void) { struct archive_read *a; a = (struct archive_read *)malloc(sizeof(*a)); if (a == NULL) return (NULL); memset(a, 0, sizeof(*a)); a->archive.magic = ARCHIVE_READ_MAGIC; a->archive.state = ARCHIVE_STATE_NEW; a->entry = archive_entry_new2(&a->archive); a->archive.vtable = archive_read_vtable(); return (&a->archive); } /* * Record the do-not-extract-to file. This belongs in archive_read_extract.c. */ void archive_read_extract_set_skip_file(struct archive *_a, int64_t d, int64_t i) { struct archive_read *a = (struct archive_read *)_a; if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_extract_set_skip_file")) return; a->skip_file_set = 1; a->skip_file_dev = d; a->skip_file_ino = i; } /* * Open the archive */ int archive_read_open(struct archive *a, void *client_data, archive_open_callback *client_opener, archive_read_callback *client_reader, archive_close_callback *client_closer) { /* Old archive_read_open() is just a thin shell around * archive_read_open1. */ archive_read_set_open_callback(a, client_opener); archive_read_set_read_callback(a, client_reader); archive_read_set_close_callback(a, client_closer); archive_read_set_callback_data(a, client_data); return archive_read_open1(a); } int archive_read_open2(struct archive *a, void *client_data, archive_open_callback *client_opener, archive_read_callback *client_reader, archive_skip_callback *client_skipper, archive_close_callback *client_closer) { /* Old archive_read_open2() is just a thin shell around * archive_read_open1. */ archive_read_set_callback_data(a, client_data); archive_read_set_open_callback(a, client_opener); archive_read_set_read_callback(a, client_reader); archive_read_set_skip_callback(a, client_skipper); archive_read_set_close_callback(a, client_closer); return archive_read_open1(a); } static ssize_t client_read_proxy(struct archive_read_filter *self, const void **buff) { ssize_t r; r = (self->archive->client.reader)(&self->archive->archive, self->data, buff); return (r); } static int64_t client_skip_proxy(struct archive_read_filter *self, int64_t request) { if (request < 0) __archive_errx(1, "Negative skip requested."); if (request == 0) return 0; if (self->archive->client.skipper != NULL) { /* Seek requests over 1GiB are broken down into * multiple seeks. This avoids overflows when the * requests get passed through 32-bit arguments. */ int64_t skip_limit = (int64_t)1 << 30; int64_t total = 0; for (;;) { int64_t get, ask = request; if (ask > skip_limit) ask = skip_limit; get = (self->archive->client.skipper) (&self->archive->archive, self->data, ask); if (get == 0) return (total); request -= get; total += get; } } else if (self->archive->client.seeker != NULL && request > 64 * 1024) { /* If the client provided a seeker but not a skipper, * we can use the seeker to skip forward. * * Note: This isn't always a good idea. The client * skipper is allowed to skip by less than requested * if it needs to maintain block alignment. The * seeker is not allowed to play such games, so using * the seeker here may be a performance loss compared * to just reading and discarding. That's why we * only do this for skips of over 64k. */ int64_t before = self->position; int64_t after = (self->archive->client.seeker) (&self->archive->archive, self->data, request, SEEK_CUR); if (after != before + request) return ARCHIVE_FATAL; return after - before; } return 0; } static int64_t client_seek_proxy(struct archive_read_filter *self, int64_t offset, int whence) { /* DO NOT use the skipper here! If we transparently handled * forward seek here by using the skipper, that will break * other libarchive code that assumes a successful forward * seek means it can also seek backwards. */ if (self->archive->client.seeker == NULL) return (ARCHIVE_FAILED); return (self->archive->client.seeker)(&self->archive->archive, self->data, offset, whence); } static int client_close_proxy(struct archive_read_filter *self) { int r = ARCHIVE_OK, r2; unsigned int i; if (self->archive->client.closer == NULL) return (r); for (i = 0; i < self->archive->client.nodes; i++) { r2 = (self->archive->client.closer) ((struct archive *)self->archive, self->archive->client.dataset[i].data); if (r > r2) r = r2; } return (r); } static int client_open_proxy(struct archive_read_filter *self) { int r = ARCHIVE_OK; if (self->archive->client.opener != NULL) r = (self->archive->client.opener)( (struct archive *)self->archive, self->data); return (r); } static int client_switch_proxy(struct archive_read_filter *self, unsigned int iindex) { int r1 = ARCHIVE_OK, r2 = ARCHIVE_OK; void *data2 = NULL; /* Don't do anything if already in the specified data node */ if (self->archive->client.cursor == iindex) return (ARCHIVE_OK); self->archive->client.cursor = iindex; data2 = self->archive->client.dataset[self->archive->client.cursor].data; if (self->archive->client.switcher != NULL) { r1 = r2 = (self->archive->client.switcher) ((struct archive *)self->archive, self->data, data2); self->data = data2; } else { /* Attempt to call close and open instead */ if (self->archive->client.closer != NULL) r1 = (self->archive->client.closer) ((struct archive *)self->archive, self->data); self->data = data2; if (self->archive->client.opener != NULL) r2 = (self->archive->client.opener) ((struct archive *)self->archive, self->data); } return (r1 < r2) ? r1 : r2; } int archive_read_set_open_callback(struct archive *_a, archive_open_callback *client_opener) { struct archive_read *a = (struct archive_read *)_a; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_set_open_callback"); a->client.opener = client_opener; return ARCHIVE_OK; } int archive_read_set_read_callback(struct archive *_a, archive_read_callback *client_reader) { struct archive_read *a = (struct archive_read *)_a; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_set_read_callback"); a->client.reader = client_reader; return ARCHIVE_OK; } int archive_read_set_skip_callback(struct archive *_a, archive_skip_callback *client_skipper) { struct archive_read *a = (struct archive_read *)_a; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_set_skip_callback"); a->client.skipper = client_skipper; return ARCHIVE_OK; } int archive_read_set_seek_callback(struct archive *_a, archive_seek_callback *client_seeker) { struct archive_read *a = (struct archive_read *)_a; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_set_seek_callback"); a->client.seeker = client_seeker; return ARCHIVE_OK; } int archive_read_set_close_callback(struct archive *_a, archive_close_callback *client_closer) { struct archive_read *a = (struct archive_read *)_a; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_set_close_callback"); a->client.closer = client_closer; return ARCHIVE_OK; } int archive_read_set_switch_callback(struct archive *_a, archive_switch_callback *client_switcher) { struct archive_read *a = (struct archive_read *)_a; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_set_switch_callback"); a->client.switcher = client_switcher; return ARCHIVE_OK; } int archive_read_set_callback_data(struct archive *_a, void *client_data) { return archive_read_set_callback_data2(_a, client_data, 0); } int archive_read_set_callback_data2(struct archive *_a, void *client_data, unsigned int iindex) { struct archive_read *a = (struct archive_read *)_a; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_set_callback_data2"); if (a->client.nodes == 0) { a->client.dataset = (struct archive_read_data_node *) calloc(1, sizeof(*a->client.dataset)); if (a->client.dataset == NULL) { archive_set_error(&a->archive, ENOMEM, "No memory."); return ARCHIVE_FATAL; } a->client.nodes = 1; } if (iindex > a->client.nodes - 1) { archive_set_error(&a->archive, EINVAL, "Invalid index specified."); return ARCHIVE_FATAL; } a->client.dataset[iindex].data = client_data; a->client.dataset[iindex].begin_position = -1; a->client.dataset[iindex].total_size = -1; return ARCHIVE_OK; } int archive_read_add_callback_data(struct archive *_a, void *client_data, unsigned int iindex) { struct archive_read *a = (struct archive_read *)_a; void *p; unsigned int i; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_add_callback_data"); if (iindex > a->client.nodes) { archive_set_error(&a->archive, EINVAL, "Invalid index specified."); return ARCHIVE_FATAL; } p = realloc(a->client.dataset, sizeof(*a->client.dataset) * (++(a->client.nodes))); if (p == NULL) { archive_set_error(&a->archive, ENOMEM, "No memory."); return ARCHIVE_FATAL; } a->client.dataset = (struct archive_read_data_node *)p; for (i = a->client.nodes - 1; i > iindex && i > 0; i--) { a->client.dataset[i].data = a->client.dataset[i-1].data; a->client.dataset[i].begin_position = -1; a->client.dataset[i].total_size = -1; } a->client.dataset[iindex].data = client_data; a->client.dataset[iindex].begin_position = -1; a->client.dataset[iindex].total_size = -1; return ARCHIVE_OK; } int archive_read_append_callback_data(struct archive *_a, void *client_data) { struct archive_read *a = (struct archive_read *)_a; return archive_read_add_callback_data(_a, client_data, a->client.nodes); } int archive_read_prepend_callback_data(struct archive *_a, void *client_data) { return archive_read_add_callback_data(_a, client_data, 0); } int archive_read_open1(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; struct archive_read_filter *filter, *tmp; int slot; int e = 0; unsigned int i; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_open"); archive_clear_error(&a->archive); if (a->client.reader == NULL) { archive_set_error(&a->archive, EINVAL, "No reader function provided to archive_read_open"); a->archive.state = ARCHIVE_STATE_FATAL; return (ARCHIVE_FATAL); } /* Open data source. */ if (a->client.opener != NULL) { e = (a->client.opener)(&a->archive, a->client.dataset[0].data); if (e != 0) { /* If the open failed, call the closer to clean up. */ if (a->client.closer) { for (i = 0; i < a->client.nodes; i++) (a->client.closer)(&a->archive, a->client.dataset[i].data); } return (e); } } filter = calloc(1, sizeof(*filter)); if (filter == NULL) return (ARCHIVE_FATAL); filter->bidder = NULL; filter->upstream = NULL; filter->archive = a; filter->data = a->client.dataset[0].data; filter->open = client_open_proxy; filter->read = client_read_proxy; filter->skip = client_skip_proxy; filter->seek = client_seek_proxy; filter->close = client_close_proxy; filter->sswitch = client_switch_proxy; filter->name = "none"; filter->code = ARCHIVE_FILTER_NONE; a->client.dataset[0].begin_position = 0; if (!a->filter || !a->bypass_filter_bidding) { a->filter = filter; /* Build out the input pipeline. */ e = choose_filters(a); if (e < ARCHIVE_WARN) { a->archive.state = ARCHIVE_STATE_FATAL; return (ARCHIVE_FATAL); } } else { /* Need to add "NONE" type filter at the end of the filter chain */ tmp = a->filter; while (tmp->upstream) tmp = tmp->upstream; tmp->upstream = filter; } if (!a->format) { slot = choose_format(a); if (slot < 0) { __archive_read_close_filters(a); a->archive.state = ARCHIVE_STATE_FATAL; return (ARCHIVE_FATAL); } a->format = &(a->formats[slot]); } a->archive.state = ARCHIVE_STATE_HEADER; /* Ensure libarchive starts from the first node in a multivolume set */ client_switch_proxy(a->filter, 0); return (e); } /* * Allow each registered stream transform to bid on whether * it wants to handle this stream. Repeat until we've finished * building the pipeline. */ static int choose_filters(struct archive_read *a) { int number_bidders, i, bid, best_bid; struct archive_read_filter_bidder *bidder, *best_bidder; struct archive_read_filter *filter; ssize_t avail; int r; for (;;) { number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); best_bid = 0; best_bidder = NULL; bidder = a->bidders; for (i = 0; i < number_bidders; i++, bidder++) { if (bidder->bid != NULL) { bid = (bidder->bid)(bidder, a->filter); if (bid > best_bid) { best_bid = bid; best_bidder = bidder; } } } /* If no bidder, we're done. */ if (best_bidder == NULL) { /* Verify the filter by asking it for some data. */ __archive_read_filter_ahead(a->filter, 1, &avail); if (avail < 0) { __archive_read_close_filters(a); __archive_read_free_filters(a); return (ARCHIVE_FATAL); } a->archive.compression_name = a->filter->name; a->archive.compression_code = a->filter->code; return (ARCHIVE_OK); } filter = (struct archive_read_filter *)calloc(1, sizeof(*filter)); if (filter == NULL) return (ARCHIVE_FATAL); filter->bidder = best_bidder; filter->archive = a; filter->upstream = a->filter; a->filter = filter; r = (best_bidder->init)(a->filter); if (r != ARCHIVE_OK) { __archive_read_close_filters(a); __archive_read_free_filters(a); return (ARCHIVE_FATAL); } } } /* * Read header of next entry. */ static int _archive_read_next_header2(struct archive *_a, struct archive_entry *entry) { struct archive_read *a = (struct archive_read *)_a; int r1 = ARCHIVE_OK, r2; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, "archive_read_next_header"); archive_entry_clear(entry); archive_clear_error(&a->archive); /* * If client didn't consume entire data, skip any remainder * (This is especially important for GNU incremental directories.) */ if (a->archive.state == ARCHIVE_STATE_DATA) { r1 = archive_read_data_skip(&a->archive); if (r1 == ARCHIVE_EOF) archive_set_error(&a->archive, EIO, "Premature end-of-file."); if (r1 == ARCHIVE_EOF || r1 == ARCHIVE_FATAL) { a->archive.state = ARCHIVE_STATE_FATAL; return (ARCHIVE_FATAL); } } /* Record start-of-header offset in uncompressed stream. */ a->header_position = a->filter->position; ++_a->file_count; r2 = (a->format->read_header)(a, entry); /* * EOF and FATAL are persistent at this layer. By * modifying the state, we guarantee that future calls to * read a header or read data will fail. */ switch (r2) { case ARCHIVE_EOF: a->archive.state = ARCHIVE_STATE_EOF; --_a->file_count;/* Revert a file counter. */ break; case ARCHIVE_OK: a->archive.state = ARCHIVE_STATE_DATA; break; case ARCHIVE_WARN: a->archive.state = ARCHIVE_STATE_DATA; break; case ARCHIVE_RETRY: break; case ARCHIVE_FATAL: a->archive.state = ARCHIVE_STATE_FATAL; break; } a->read_data_output_offset = 0; a->read_data_remaining = 0; a->read_data_is_posix_read = 0; a->read_data_requested = 0; a->data_start_node = a->client.cursor; /* EOF always wins; otherwise return the worst error. */ return (r2 < r1 || r2 == ARCHIVE_EOF) ? r2 : r1; } int _archive_read_next_header(struct archive *_a, struct archive_entry **entryp) { int ret; struct archive_read *a = (struct archive_read *)_a; *entryp = NULL; ret = _archive_read_next_header2(_a, a->entry); *entryp = a->entry; return ret; } /* * Allow each registered format to bid on whether it wants to handle * the next entry. Return index of winning bidder. */ static int choose_format(struct archive_read *a) { int slots; int i; int bid, best_bid; int best_bid_slot; slots = sizeof(a->formats) / sizeof(a->formats[0]); best_bid = -1; best_bid_slot = -1; /* Set up a->format for convenience of bidders. */ a->format = &(a->formats[0]); for (i = 0; i < slots; i++, a->format++) { if (a->format->bid) { bid = (a->format->bid)(a, best_bid); if (bid == ARCHIVE_FATAL) return (ARCHIVE_FATAL); if (a->filter->position != 0) __archive_read_seek(a, 0, SEEK_SET); if ((bid > best_bid) || (best_bid_slot < 0)) { best_bid = bid; best_bid_slot = i; } } } /* * There were no bidders; this is a serious programmer error * and demands a quick and definitive abort. */ if (best_bid_slot < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "No formats registered"); return (ARCHIVE_FATAL); } /* * There were bidders, but no non-zero bids; this means we * can't support this stream. */ if (best_bid < 1) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Unrecognized archive format"); return (ARCHIVE_FATAL); } return (best_bid_slot); } /* * Return the file offset (within the uncompressed data stream) where * the last header started. */ int64_t archive_read_header_position(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_header_position"); return (a->header_position); } /* * Read data from an archive entry, using a read(2)-style interface. * This is a convenience routine that just calls * archive_read_data_block and copies the results into the client * buffer, filling any gaps with zero bytes. Clients using this * API can be completely ignorant of sparse-file issues; sparse files * will simply be padded with nulls. * * DO NOT intermingle calls to this function and archive_read_data_block * to read a single entry body. */ ssize_t archive_read_data(struct archive *_a, void *buff, size_t s) { struct archive_read *a = (struct archive_read *)_a; char *dest; const void *read_buf; size_t bytes_read; size_t len; int r; bytes_read = 0; dest = (char *)buff; while (s > 0) { if (a->read_data_remaining == 0) { read_buf = a->read_data_block; a->read_data_is_posix_read = 1; a->read_data_requested = s; r = _archive_read_data_block(&a->archive, &read_buf, &a->read_data_remaining, &a->read_data_offset); a->read_data_block = read_buf; if (r == ARCHIVE_EOF) return (bytes_read); /* * Error codes are all negative, so the status * return here cannot be confused with a valid * byte count. (ARCHIVE_OK is zero.) */ if (r < ARCHIVE_OK) return (r); } if (a->read_data_offset < a->read_data_output_offset) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Encountered out-of-order sparse blocks"); return (ARCHIVE_RETRY); } /* Compute the amount of zero padding needed. */ if (a->read_data_output_offset + (int64_t)s < a->read_data_offset) { len = s; } else if (a->read_data_output_offset < a->read_data_offset) { len = (size_t)(a->read_data_offset - a->read_data_output_offset); } else len = 0; /* Add zeroes. */ memset(dest, 0, len); s -= len; a->read_data_output_offset += len; dest += len; bytes_read += len; /* Copy data if there is any space left. */ if (s > 0) { len = a->read_data_remaining; if (len > s) len = s; memcpy(dest, a->read_data_block, len); s -= len; a->read_data_block += len; a->read_data_remaining -= len; a->read_data_output_offset += len; a->read_data_offset += len; dest += len; bytes_read += len; } } a->read_data_is_posix_read = 0; a->read_data_requested = 0; return (bytes_read); } /* * Skip over all remaining data in this entry. */ int archive_read_data_skip(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; int r; const void *buff; size_t size; int64_t offset; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_read_data_skip"); if (a->format->read_data_skip != NULL) r = (a->format->read_data_skip)(a); else { while ((r = archive_read_data_block(&a->archive, &buff, &size, &offset)) == ARCHIVE_OK) ; } if (r == ARCHIVE_EOF) r = ARCHIVE_OK; a->archive.state = ARCHIVE_STATE_HEADER; return (r); } int64_t archive_seek_data(struct archive *_a, int64_t offset, int whence) { struct archive_read *a = (struct archive_read *)_a; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_seek_data_block"); if (a->format->seek_data == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, "Internal error: " "No format_seek_data_block function registered"); return (ARCHIVE_FATAL); } return (a->format->seek_data)(a, offset, whence); } /* * Read the next block of entry data from the archive. * This is a zero-copy interface; the client receives a pointer, * size, and file offset of the next available block of data. * * Returns ARCHIVE_OK if the operation is successful, ARCHIVE_EOF if * the end of entry is encountered. */ static int _archive_read_data_block(struct archive *_a, const void **buff, size_t *size, int64_t *offset) { struct archive_read *a = (struct archive_read *)_a; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_read_data_block"); if (a->format->read_data == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, "Internal error: " "No format_read_data_block function registered"); return (ARCHIVE_FATAL); } return (a->format->read_data)(a, buff, size, offset); } int __archive_read_close_filters(struct archive_read *a) { struct archive_read_filter *f = a->filter; int r = ARCHIVE_OK; /* Close each filter in the pipeline. */ while (f != NULL) { struct archive_read_filter *t = f->upstream; if (!f->closed && f->close != NULL) { int r1 = (f->close)(f); f->closed = 1; if (r1 < r) r = r1; } free(f->buffer); f->buffer = NULL; f = t; } return r; } void __archive_read_free_filters(struct archive_read *a) { while (a->filter != NULL) { struct archive_read_filter *t = a->filter->upstream; free(a->filter); a->filter = t; } } /* * return the count of # of filters in use */ static int _archive_filter_count(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; struct archive_read_filter *p = a->filter; int count = 0; while(p) { count++; p = p->upstream; } return count; } /* * Close the file and all I/O. */ static int _archive_read_close(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; int r = ARCHIVE_OK, r1 = ARCHIVE_OK; archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_close"); if (a->archive.state == ARCHIVE_STATE_CLOSED) return (ARCHIVE_OK); archive_clear_error(&a->archive); a->archive.state = ARCHIVE_STATE_CLOSED; /* TODO: Clean up the formatters. */ /* Release the filter objects. */ r1 = __archive_read_close_filters(a); if (r1 < r) r = r1; return (r); } /* * Release memory and other resources. */ static int _archive_read_free(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; int i, n; int slots; int r = ARCHIVE_OK; if (_a == NULL) return (ARCHIVE_OK); archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_read_free"); if (a->archive.state != ARCHIVE_STATE_CLOSED && a->archive.state != ARCHIVE_STATE_FATAL) r = archive_read_close(&a->archive); /* Call cleanup functions registered by optional components. */ if (a->cleanup_archive_extract != NULL) r = (a->cleanup_archive_extract)(a); /* Cleanup format-specific data. */ slots = sizeof(a->formats) / sizeof(a->formats[0]); for (i = 0; i < slots; i++) { a->format = &(a->formats[i]); if (a->formats[i].cleanup) (a->formats[i].cleanup)(a); } /* Free the filters */ __archive_read_free_filters(a); /* Release the bidder objects. */ n = sizeof(a->bidders)/sizeof(a->bidders[0]); for (i = 0; i < n; i++) { if (a->bidders[i].free != NULL) { int r1 = (a->bidders[i].free)(&a->bidders[i]); if (r1 < r) r = r1; } } archive_string_free(&a->archive.error_string); if (a->entry) archive_entry_free(a->entry); a->archive.magic = 0; __archive_clean(&a->archive); free(a->client.dataset); free(a); return (r); } static struct archive_read_filter * get_filter(struct archive *_a, int n) { struct archive_read *a = (struct archive_read *)_a; struct archive_read_filter *f = a->filter; /* We use n == -1 for 'the last filter', which is always the * client proxy. */ if (n == -1 && f != NULL) { struct archive_read_filter *last = f; f = f->upstream; while (f != NULL) { last = f; f = f->upstream; } return (last); } if (n < 0) return NULL; while (n > 0 && f != NULL) { f = f->upstream; --n; } return (f); } static int _archive_filter_code(struct archive *_a, int n) { struct archive_read_filter *f = get_filter(_a, n); return f == NULL ? -1 : f->code; } static const char * _archive_filter_name(struct archive *_a, int n) { struct archive_read_filter *f = get_filter(_a, n); return f == NULL ? NULL : f->name; } static int64_t _archive_filter_bytes(struct archive *_a, int n) { struct archive_read_filter *f = get_filter(_a, n); return f == NULL ? -1 : f->position; } /* * Used internally by read format handlers to register their bid and * initialization functions. */ int __archive_read_register_format(struct archive_read *a, void *format_data, const char *name, int (*bid)(struct archive_read *, int), int (*options)(struct archive_read *, const char *, const char *), int (*read_header)(struct archive_read *, struct archive_entry *), int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *), int (*read_data_skip)(struct archive_read *), int64_t (*seek_data)(struct archive_read *, int64_t, int), int (*cleanup)(struct archive_read *)) { int i, number_slots; archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "__archive_read_register_format"); number_slots = sizeof(a->formats) / sizeof(a->formats[0]); for (i = 0; i < number_slots; i++) { if (a->formats[i].bid == bid) return (ARCHIVE_WARN); /* We've already installed */ if (a->formats[i].bid == NULL) { a->formats[i].bid = bid; a->formats[i].options = options; a->formats[i].read_header = read_header; a->formats[i].read_data = read_data; a->formats[i].read_data_skip = read_data_skip; a->formats[i].seek_data = seek_data; a->formats[i].cleanup = cleanup; a->formats[i].data = format_data; a->formats[i].name = name; return (ARCHIVE_OK); } } archive_set_error(&a->archive, ENOMEM, "Not enough slots for format registration"); return (ARCHIVE_FATAL); } /* * Used internally by decompression routines to register their bid and * initialization functions. */ int __archive_read_get_bidder(struct archive_read *a, struct archive_read_filter_bidder **bidder) { int i, number_slots; number_slots = sizeof(a->bidders) / sizeof(a->bidders[0]); for (i = 0; i < number_slots; i++) { if (a->bidders[i].bid == NULL) { memset(a->bidders + i, 0, sizeof(a->bidders[0])); *bidder = (a->bidders + i); return (ARCHIVE_OK); } } archive_set_error(&a->archive, ENOMEM, "Not enough slots for filter registration"); return (ARCHIVE_FATAL); } /* * The next section implements the peek/consume internal I/O * system used by archive readers. This system allows simple * read-ahead for consumers while preserving zero-copy operation * most of the time. * * The two key operations: * * The read-ahead function returns a pointer to a block of data * that satisfies a minimum request. * * The consume function advances the file pointer. * * In the ideal case, filters generate blocks of data * and __archive_read_ahead() just returns pointers directly into * those blocks. Then __archive_read_consume() just bumps those * pointers. Only if your request would span blocks does the I/O * layer use a copy buffer to provide you with a contiguous block of * data. * * A couple of useful idioms: * * "I just want some data." Ask for 1 byte and pay attention to * the "number of bytes available" from __archive_read_ahead(). * Consume whatever you actually use. * * "I want to output a large block of data." As above, ask for 1 byte, * emit all that's available (up to whatever limit you have), consume * it all, then repeat until you're done. This effectively means that * you're passing along the blocks that came from your provider. * * "I want to peek ahead by a large amount." Ask for 4k or so, then * double and repeat until you get an error or have enough. Note * that the I/O layer will likely end up expanding its copy buffer * to fit your request, so use this technique cautiously. This * technique is used, for example, by some of the format tasting * code that has uncertain look-ahead needs. */ /* * Looks ahead in the input stream: * * If 'avail' pointer is provided, that returns number of bytes available * in the current buffer, which may be much larger than requested. * * If end-of-file, *avail gets set to zero. * * If error, *avail gets error code. * * If request can be met, returns pointer to data. * * If minimum request cannot be met, returns NULL. * * Note: If you just want "some data", ask for 1 byte and pay attention * to *avail, which will have the actual amount available. If you * know exactly how many bytes you need, just ask for that and treat * a NULL return as an error. * * Important: This does NOT move the file pointer. See * __archive_read_consume() below. */ const void * __archive_read_ahead(struct archive_read *a, size_t min, ssize_t *avail) { return (__archive_read_filter_ahead(a->filter, min, avail)); } const void * __archive_read_filter_ahead(struct archive_read_filter *filter, size_t min, ssize_t *avail) { ssize_t bytes_read; size_t tocopy; if (filter->fatal) { if (avail) *avail = ARCHIVE_FATAL; return (NULL); } /* * Keep pulling more data until we can satisfy the request. */ for (;;) { /* * If we can satisfy from the copy buffer (and the * copy buffer isn't empty), we're done. In particular, * note that min == 0 is a perfectly well-defined * request. */ if (filter->avail >= min && filter->avail > 0) { if (avail != NULL) *avail = filter->avail; return (filter->next); } /* * We can satisfy directly from client buffer if everything * currently in the copy buffer is still in the client buffer. */ if (filter->client_total >= filter->client_avail + filter->avail && filter->client_avail + filter->avail >= min) { /* "Roll back" to client buffer. */ filter->client_avail += filter->avail; filter->client_next -= filter->avail; /* Copy buffer is now empty. */ filter->avail = 0; filter->next = filter->buffer; /* Return data from client buffer. */ if (avail != NULL) *avail = filter->client_avail; return (filter->client_next); } /* Move data forward in copy buffer if necessary. */ if (filter->next > filter->buffer && filter->next + min > filter->buffer + filter->buffer_size) { if (filter->avail > 0) memmove(filter->buffer, filter->next, filter->avail); filter->next = filter->buffer; } /* If we've used up the client data, get more. */ if (filter->client_avail <= 0) { if (filter->end_of_file) { if (avail != NULL) *avail = 0; return (NULL); } bytes_read = (filter->read)(filter, &filter->client_buff); if (bytes_read < 0) { /* Read error. */ filter->client_total = filter->client_avail = 0; filter->client_next = filter->client_buff = NULL; filter->fatal = 1; if (avail != NULL) *avail = ARCHIVE_FATAL; return (NULL); } if (bytes_read == 0) { /* Check for another client object first */ if (filter->archive->client.cursor != filter->archive->client.nodes - 1) { if (client_switch_proxy(filter, filter->archive->client.cursor + 1) == ARCHIVE_OK) continue; } /* Premature end-of-file. */ filter->client_total = filter->client_avail = 0; filter->client_next = filter->client_buff = NULL; filter->end_of_file = 1; /* Return whatever we do have. */ if (avail != NULL) *avail = filter->avail; return (NULL); } filter->client_total = bytes_read; filter->client_avail = filter->client_total; filter->client_next = filter->client_buff; } else { /* * We can't satisfy the request from the copy * buffer or the existing client data, so we * need to copy more client data over to the * copy buffer. */ /* Ensure the buffer is big enough. */ if (min > filter->buffer_size) { size_t s, t; char *p; /* Double the buffer; watch for overflow. */ s = t = filter->buffer_size; if (s == 0) s = min; while (s < min) { t *= 2; if (t <= s) { /* Integer overflow! */ archive_set_error( &filter->archive->archive, ENOMEM, "Unable to allocate copy" " buffer"); filter->fatal = 1; if (avail != NULL) *avail = ARCHIVE_FATAL; return (NULL); } s = t; } /* Now s >= min, so allocate a new buffer. */ p = (char *)malloc(s); if (p == NULL) { archive_set_error( &filter->archive->archive, ENOMEM, "Unable to allocate copy buffer"); filter->fatal = 1; if (avail != NULL) *avail = ARCHIVE_FATAL; return (NULL); } /* Move data into newly-enlarged buffer. */ if (filter->avail > 0) memmove(p, filter->next, filter->avail); free(filter->buffer); filter->next = filter->buffer = p; filter->buffer_size = s; } /* We can add client data to copy buffer. */ /* First estimate: copy to fill rest of buffer. */ tocopy = (filter->buffer + filter->buffer_size) - (filter->next + filter->avail); /* Don't waste time buffering more than we need to. */ if (tocopy + filter->avail > min) tocopy = min - filter->avail; /* Don't copy more than is available. */ if (tocopy > filter->client_avail) tocopy = filter->client_avail; memcpy(filter->next + filter->avail, filter->client_next, tocopy); /* Remove this data from client buffer. */ filter->client_next += tocopy; filter->client_avail -= tocopy; /* add it to copy buffer. */ filter->avail += tocopy; } } } /* * Move the file pointer forward. */ int64_t __archive_read_consume(struct archive_read *a, int64_t request) { return (__archive_read_filter_consume(a->filter, request)); } int64_t __archive_read_filter_consume(struct archive_read_filter * filter, int64_t request) { int64_t skipped; + if (request < 0) + return ARCHIVE_FATAL; if (request == 0) return 0; skipped = advance_file_pointer(filter, request); if (skipped == request) return (skipped); /* We hit EOF before we satisfied the skip request. */ if (skipped < 0) /* Map error code to 0 for error message below. */ skipped = 0; archive_set_error(&filter->archive->archive, ARCHIVE_ERRNO_MISC, "Truncated input file (needed %jd bytes, only %jd available)", (intmax_t)request, (intmax_t)skipped); return (ARCHIVE_FATAL); } /* * Advance the file pointer by the amount requested. * Returns the amount actually advanced, which may be less than the * request if EOF is encountered first. * Returns a negative value if there's an I/O error. */ static int64_t advance_file_pointer(struct archive_read_filter *filter, int64_t request) { int64_t bytes_skipped, total_bytes_skipped = 0; ssize_t bytes_read; size_t min; if (filter->fatal) return (-1); /* Use up the copy buffer first. */ if (filter->avail > 0) { min = (size_t)minimum(request, (int64_t)filter->avail); filter->next += min; filter->avail -= min; request -= min; filter->position += min; total_bytes_skipped += min; } /* Then use up the client buffer. */ if (filter->client_avail > 0) { min = (size_t)minimum(request, (int64_t)filter->client_avail); filter->client_next += min; filter->client_avail -= min; request -= min; filter->position += min; total_bytes_skipped += min; } if (request == 0) return (total_bytes_skipped); /* If there's an optimized skip function, use it. */ if (filter->skip != NULL) { bytes_skipped = (filter->skip)(filter, request); if (bytes_skipped < 0) { /* error */ filter->fatal = 1; return (bytes_skipped); } filter->position += bytes_skipped; total_bytes_skipped += bytes_skipped; request -= bytes_skipped; if (request == 0) return (total_bytes_skipped); } /* Use ordinary reads as necessary to complete the request. */ for (;;) { bytes_read = (filter->read)(filter, &filter->client_buff); if (bytes_read < 0) { filter->client_buff = NULL; filter->fatal = 1; return (bytes_read); } if (bytes_read == 0) { if (filter->archive->client.cursor != filter->archive->client.nodes - 1) { if (client_switch_proxy(filter, filter->archive->client.cursor + 1) == ARCHIVE_OK) continue; } filter->client_buff = NULL; filter->end_of_file = 1; return (total_bytes_skipped); } if (bytes_read >= request) { filter->client_next = ((const char *)filter->client_buff) + request; filter->client_avail = (size_t)(bytes_read - request); filter->client_total = bytes_read; total_bytes_skipped += request; filter->position += request; return (total_bytes_skipped); } filter->position += bytes_read; total_bytes_skipped += bytes_read; request -= bytes_read; } } /** * Returns ARCHIVE_FAILED if seeking isn't supported. */ int64_t __archive_read_seek(struct archive_read *a, int64_t offset, int whence) { return __archive_read_filter_seek(a->filter, offset, whence); } int64_t __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset, int whence) { struct archive_read_client *client; int64_t r; unsigned int cursor; if (filter->closed || filter->fatal) return (ARCHIVE_FATAL); if (filter->seek == NULL) return (ARCHIVE_FAILED); client = &(filter->archive->client); switch (whence) { case SEEK_CUR: /* Adjust the offset and use SEEK_SET instead */ offset += filter->position; case SEEK_SET: cursor = 0; while (1) { if (client->dataset[cursor].begin_position < 0 || client->dataset[cursor].total_size < 0 || client->dataset[cursor].begin_position + client->dataset[cursor].total_size - 1 > offset || cursor + 1 >= client->nodes) break; r = client->dataset[cursor].begin_position + client->dataset[cursor].total_size; client->dataset[++cursor].begin_position = r; } while (1) { r = client_switch_proxy(filter, cursor); if (r != ARCHIVE_OK) return r; if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0) return r; client->dataset[cursor].total_size = r; if (client->dataset[cursor].begin_position + client->dataset[cursor].total_size - 1 > offset || cursor + 1 >= client->nodes) break; r = client->dataset[cursor].begin_position + client->dataset[cursor].total_size; client->dataset[++cursor].begin_position = r; } offset -= client->dataset[cursor].begin_position; if (offset < 0) offset = 0; else if (offset > client->dataset[cursor].total_size - 1) offset = client->dataset[cursor].total_size - 1; if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < 0) return r; break; case SEEK_END: cursor = 0; while (1) { if (client->dataset[cursor].begin_position < 0 || client->dataset[cursor].total_size < 0 || cursor + 1 >= client->nodes) break; r = client->dataset[cursor].begin_position + client->dataset[cursor].total_size; client->dataset[++cursor].begin_position = r; } while (1) { r = client_switch_proxy(filter, cursor); if (r != ARCHIVE_OK) return r; if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0) return r; client->dataset[cursor].total_size = r; r = client->dataset[cursor].begin_position + client->dataset[cursor].total_size; if (cursor + 1 >= client->nodes) break; client->dataset[++cursor].begin_position = r; } while (1) { if (r + offset >= client->dataset[cursor].begin_position) break; offset += client->dataset[cursor].total_size; if (cursor == 0) break; cursor--; r = client->dataset[cursor].begin_position + client->dataset[cursor].total_size; } offset = (r + offset) - client->dataset[cursor].begin_position; if ((r = client_switch_proxy(filter, cursor)) != ARCHIVE_OK) return r; r = client_seek_proxy(filter, offset, SEEK_SET); if (r < ARCHIVE_OK) return r; break; default: return (ARCHIVE_FATAL); } r += client->dataset[cursor].begin_position; if (r >= 0) { /* * Ouch. Clearing the buffer like this hurts, especially * at bid time. A lot of our efficiency at bid time comes * from having bidders reuse the data we've already read. * * TODO: If the seek request is in data we already * have, then don't call the seek callback. * * TODO: Zip seeks to end-of-file at bid time. If * other formats also start doing this, we may need to * find a way for clients to fudge the seek offset to * a block boundary. * * Hmmm... If whence was SEEK_END, we know the file * size is (r - offset). Can we use that to simplify * the TODO items above? */ filter->avail = filter->client_avail = 0; filter->next = filter->buffer; filter->position = r; filter->end_of_file = 0; } return r; } Index: projects/ci20_mips/contrib/libarchive/libarchive/archive_read_support_format_cpio.c =================================================================== --- projects/ci20_mips/contrib/libarchive/libarchive/archive_read_support_format_cpio.c (revision 283030) +++ projects/ci20_mips/contrib/libarchive/libarchive/archive_read_support_format_cpio.c (revision 283031) @@ -1,1066 +1,1072 @@ /*- * Copyright (c) 2003-2007 Tim Kientzle * Copyright (c) 2010-2012 Michihiro NAKAJIMA * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "archive_platform.h" __FBSDID("$FreeBSD$"); #ifdef HAVE_ERRNO_H #include #endif /* #include */ /* See archive_platform.h */ #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #include "archive.h" #include "archive_entry.h" #include "archive_entry_locale.h" #include "archive_private.h" #include "archive_read_private.h" #define bin_magic_offset 0 #define bin_magic_size 2 #define bin_dev_offset 2 #define bin_dev_size 2 #define bin_ino_offset 4 #define bin_ino_size 2 #define bin_mode_offset 6 #define bin_mode_size 2 #define bin_uid_offset 8 #define bin_uid_size 2 #define bin_gid_offset 10 #define bin_gid_size 2 #define bin_nlink_offset 12 #define bin_nlink_size 2 #define bin_rdev_offset 14 #define bin_rdev_size 2 #define bin_mtime_offset 16 #define bin_mtime_size 4 #define bin_namesize_offset 20 #define bin_namesize_size 2 #define bin_filesize_offset 22 #define bin_filesize_size 4 #define bin_header_size 26 #define odc_magic_offset 0 #define odc_magic_size 6 #define odc_dev_offset 6 #define odc_dev_size 6 #define odc_ino_offset 12 #define odc_ino_size 6 #define odc_mode_offset 18 #define odc_mode_size 6 #define odc_uid_offset 24 #define odc_uid_size 6 #define odc_gid_offset 30 #define odc_gid_size 6 #define odc_nlink_offset 36 #define odc_nlink_size 6 #define odc_rdev_offset 42 #define odc_rdev_size 6 #define odc_mtime_offset 48 #define odc_mtime_size 11 #define odc_namesize_offset 59 #define odc_namesize_size 6 #define odc_filesize_offset 65 #define odc_filesize_size 11 #define odc_header_size 76 #define newc_magic_offset 0 #define newc_magic_size 6 #define newc_ino_offset 6 #define newc_ino_size 8 #define newc_mode_offset 14 #define newc_mode_size 8 #define newc_uid_offset 22 #define newc_uid_size 8 #define newc_gid_offset 30 #define newc_gid_size 8 #define newc_nlink_offset 38 #define newc_nlink_size 8 #define newc_mtime_offset 46 #define newc_mtime_size 8 #define newc_filesize_offset 54 #define newc_filesize_size 8 #define newc_devmajor_offset 62 #define newc_devmajor_size 8 #define newc_devminor_offset 70 #define newc_devminor_size 8 #define newc_rdevmajor_offset 78 #define newc_rdevmajor_size 8 #define newc_rdevminor_offset 86 #define newc_rdevminor_size 8 #define newc_namesize_offset 94 #define newc_namesize_size 8 #define newc_checksum_offset 102 #define newc_checksum_size 8 #define newc_header_size 110 /* * An afio large ASCII header, which they named itself. * afio utility uses this header, if a file size is larger than 2G bytes * or inode/uid/gid is bigger than 65535(0xFFFF) or mtime is bigger than * 0x7fffffff, which we cannot record to odc header because of its limit. * If not, uses odc header. */ #define afiol_magic_offset 0 #define afiol_magic_size 6 #define afiol_dev_offset 6 #define afiol_dev_size 8 /* hex */ #define afiol_ino_offset 14 #define afiol_ino_size 16 /* hex */ #define afiol_ino_m_offset 30 /* 'm' */ #define afiol_mode_offset 31 #define afiol_mode_size 6 /* oct */ #define afiol_uid_offset 37 #define afiol_uid_size 8 /* hex */ #define afiol_gid_offset 45 #define afiol_gid_size 8 /* hex */ #define afiol_nlink_offset 53 #define afiol_nlink_size 8 /* hex */ #define afiol_rdev_offset 61 #define afiol_rdev_size 8 /* hex */ #define afiol_mtime_offset 69 #define afiol_mtime_size 16 /* hex */ #define afiol_mtime_n_offset 85 /* 'n' */ #define afiol_namesize_offset 86 #define afiol_namesize_size 4 /* hex */ #define afiol_flag_offset 90 #define afiol_flag_size 4 /* hex */ #define afiol_xsize_offset 94 #define afiol_xsize_size 4 /* hex */ #define afiol_xsize_s_offset 98 /* 's' */ #define afiol_filesize_offset 99 #define afiol_filesize_size 16 /* hex */ #define afiol_filesize_c_offset 115 /* ':' */ #define afiol_header_size 116 struct links_entry { struct links_entry *next; struct links_entry *previous; int links; dev_t dev; int64_t ino; char *name; }; #define CPIO_MAGIC 0x13141516 struct cpio { int magic; int (*read_header)(struct archive_read *, struct cpio *, struct archive_entry *, size_t *, size_t *); struct links_entry *links_head; int64_t entry_bytes_remaining; int64_t entry_bytes_unconsumed; int64_t entry_offset; int64_t entry_padding; struct archive_string_conv *opt_sconv; struct archive_string_conv *sconv_default; int init_default_conversion; }; static int64_t atol16(const char *, unsigned); static int64_t atol8(const char *, unsigned); static int archive_read_format_cpio_bid(struct archive_read *, int); static int archive_read_format_cpio_options(struct archive_read *, const char *, const char *); static int archive_read_format_cpio_cleanup(struct archive_read *); static int archive_read_format_cpio_read_data(struct archive_read *, const void **, size_t *, int64_t *); static int archive_read_format_cpio_read_header(struct archive_read *, struct archive_entry *); static int archive_read_format_cpio_skip(struct archive_read *); -static int be4(const unsigned char *); +static int64_t be4(const unsigned char *); static int find_odc_header(struct archive_read *); static int find_newc_header(struct archive_read *); static int header_bin_be(struct archive_read *, struct cpio *, struct archive_entry *, size_t *, size_t *); static int header_bin_le(struct archive_read *, struct cpio *, struct archive_entry *, size_t *, size_t *); static int header_newc(struct archive_read *, struct cpio *, struct archive_entry *, size_t *, size_t *); static int header_odc(struct archive_read *, struct cpio *, struct archive_entry *, size_t *, size_t *); static int header_afiol(struct archive_read *, struct cpio *, struct archive_entry *, size_t *, size_t *); static int is_octal(const char *, size_t); static int is_hex(const char *, size_t); -static int le4(const unsigned char *); +static int64_t le4(const unsigned char *); static int record_hardlink(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry); int archive_read_support_format_cpio(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; struct cpio *cpio; int r; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_support_format_cpio"); cpio = (struct cpio *)calloc(1, sizeof(*cpio)); if (cpio == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data"); return (ARCHIVE_FATAL); } cpio->magic = CPIO_MAGIC; r = __archive_read_register_format(a, cpio, "cpio", archive_read_format_cpio_bid, archive_read_format_cpio_options, archive_read_format_cpio_read_header, archive_read_format_cpio_read_data, archive_read_format_cpio_skip, NULL, archive_read_format_cpio_cleanup); if (r != ARCHIVE_OK) free(cpio); return (ARCHIVE_OK); } static int archive_read_format_cpio_bid(struct archive_read *a, int best_bid) { const unsigned char *p; struct cpio *cpio; int bid; (void)best_bid; /* UNUSED */ cpio = (struct cpio *)(a->format->data); if ((p = __archive_read_ahead(a, 6, NULL)) == NULL) return (-1); bid = 0; if (memcmp(p, "070707", 6) == 0) { /* ASCII cpio archive (odc, POSIX.1) */ cpio->read_header = header_odc; bid += 48; /* * XXX TODO: More verification; Could check that only octal * digits appear in appropriate header locations. XXX */ } else if (memcmp(p, "070727", 6) == 0) { /* afio large ASCII cpio archive */ cpio->read_header = header_odc; bid += 48; /* * XXX TODO: More verification; Could check that almost hex * digits appear in appropriate header locations. XXX */ } else if (memcmp(p, "070701", 6) == 0) { /* ASCII cpio archive (SVR4 without CRC) */ cpio->read_header = header_newc; bid += 48; /* * XXX TODO: More verification; Could check that only hex * digits appear in appropriate header locations. XXX */ } else if (memcmp(p, "070702", 6) == 0) { /* ASCII cpio archive (SVR4 with CRC) */ /* XXX TODO: Flag that we should check the CRC. XXX */ cpio->read_header = header_newc; bid += 48; /* * XXX TODO: More verification; Could check that only hex * digits appear in appropriate header locations. XXX */ } else if (p[0] * 256 + p[1] == 070707) { /* big-endian binary cpio archives */ cpio->read_header = header_bin_be; bid += 16; /* Is more verification possible here? */ } else if (p[0] + p[1] * 256 == 070707) { /* little-endian binary cpio archives */ cpio->read_header = header_bin_le; bid += 16; /* Is more verification possible here? */ } else return (ARCHIVE_WARN); return (bid); } static int archive_read_format_cpio_options(struct archive_read *a, const char *key, const char *val) { struct cpio *cpio; int ret = ARCHIVE_FAILED; cpio = (struct cpio *)(a->format->data); if (strcmp(key, "compat-2x") == 0) { /* Handle filnames as libarchive 2.x */ cpio->init_default_conversion = (val != NULL)?1:0; return (ARCHIVE_OK); } else if (strcmp(key, "hdrcharset") == 0) { if (val == NULL || val[0] == 0) archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "cpio: hdrcharset option needs a character-set name"); else { cpio->opt_sconv = archive_string_conversion_from_charset( &a->archive, val, 0); if (cpio->opt_sconv != NULL) ret = ARCHIVE_OK; else ret = ARCHIVE_FATAL; } return (ret); } /* Note: The "warn" return is just to inform the options * supervisor that we didn't handle it. It will generate * a suitable error if no one used this option. */ return (ARCHIVE_WARN); } static int archive_read_format_cpio_read_header(struct archive_read *a, struct archive_entry *entry) { struct cpio *cpio; const void *h; struct archive_string_conv *sconv; size_t namelength; size_t name_pad; int r; cpio = (struct cpio *)(a->format->data); sconv = cpio->opt_sconv; if (sconv == NULL) { if (!cpio->init_default_conversion) { cpio->sconv_default = archive_string_default_conversion_for_read( &(a->archive)); cpio->init_default_conversion = 1; } sconv = cpio->sconv_default; } r = (cpio->read_header(a, cpio, entry, &namelength, &name_pad)); if (r < ARCHIVE_WARN) return (r); /* Read name from buffer. */ h = __archive_read_ahead(a, namelength + name_pad, NULL); if (h == NULL) return (ARCHIVE_FATAL); if (archive_entry_copy_pathname_l(entry, (const char *)h, namelength, sconv) != 0) { if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Pathname"); return (ARCHIVE_FATAL); } archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Pathname can't be converted from %s to current locale.", archive_string_conversion_charset_name(sconv)); r = ARCHIVE_WARN; } cpio->entry_offset = 0; __archive_read_consume(a, namelength + name_pad); /* If this is a symlink, read the link contents. */ if (archive_entry_filetype(entry) == AE_IFLNK) { h = __archive_read_ahead(a, (size_t)cpio->entry_bytes_remaining, NULL); if (h == NULL) return (ARCHIVE_FATAL); if (archive_entry_copy_symlink_l(entry, (const char *)h, (size_t)cpio->entry_bytes_remaining, sconv) != 0) { if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, "Can't allocate memory for Linkname"); return (ARCHIVE_FATAL); } archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Linkname can't be converted from %s to " "current locale.", archive_string_conversion_charset_name(sconv)); r = ARCHIVE_WARN; } __archive_read_consume(a, cpio->entry_bytes_remaining); cpio->entry_bytes_remaining = 0; } /* XXX TODO: If the full mode is 0160200, then this is a Solaris * ACL description for the following entry. Read this body * and parse it as a Solaris-style ACL, then read the next * header. XXX */ /* Compare name to "TRAILER!!!" to test for end-of-archive. */ if (namelength == 11 && strcmp((const char *)h, "TRAILER!!!") == 0) { /* TODO: Store file location of start of block. */ archive_clear_error(&a->archive); return (ARCHIVE_EOF); } /* Detect and record hardlinks to previously-extracted entries. */ if (record_hardlink(a, cpio, entry) != ARCHIVE_OK) { return (ARCHIVE_FATAL); } return (r); } static int archive_read_format_cpio_read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset) { ssize_t bytes_read; struct cpio *cpio; cpio = (struct cpio *)(a->format->data); if (cpio->entry_bytes_unconsumed) { __archive_read_consume(a, cpio->entry_bytes_unconsumed); cpio->entry_bytes_unconsumed = 0; } if (cpio->entry_bytes_remaining > 0) { *buff = __archive_read_ahead(a, 1, &bytes_read); if (bytes_read <= 0) return (ARCHIVE_FATAL); if (bytes_read > cpio->entry_bytes_remaining) bytes_read = (ssize_t)cpio->entry_bytes_remaining; *size = bytes_read; cpio->entry_bytes_unconsumed = bytes_read; *offset = cpio->entry_offset; cpio->entry_offset += bytes_read; cpio->entry_bytes_remaining -= bytes_read; return (ARCHIVE_OK); } else { if (cpio->entry_padding != __archive_read_consume(a, cpio->entry_padding)) { return (ARCHIVE_FATAL); } cpio->entry_padding = 0; *buff = NULL; *size = 0; *offset = cpio->entry_offset; return (ARCHIVE_EOF); } } static int archive_read_format_cpio_skip(struct archive_read *a) { struct cpio *cpio = (struct cpio *)(a->format->data); int64_t to_skip = cpio->entry_bytes_remaining + cpio->entry_padding + cpio->entry_bytes_unconsumed; if (to_skip != __archive_read_consume(a, to_skip)) { return (ARCHIVE_FATAL); } cpio->entry_bytes_remaining = 0; cpio->entry_padding = 0; cpio->entry_bytes_unconsumed = 0; return (ARCHIVE_OK); } /* * Skip forward to the next cpio newc header by searching for the * 07070[12] string. This should be generalized and merged with * find_odc_header below. */ static int is_hex(const char *p, size_t len) { while (len-- > 0) { if ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')) ++p; else return (0); } return (1); } static int find_newc_header(struct archive_read *a) { const void *h; const char *p, *q; size_t skip, skipped = 0; ssize_t bytes; for (;;) { h = __archive_read_ahead(a, newc_header_size, &bytes); if (h == NULL) return (ARCHIVE_FATAL); p = h; q = p + bytes; /* Try the typical case first, then go into the slow search.*/ if (memcmp("07070", p, 5) == 0 && (p[5] == '1' || p[5] == '2') && is_hex(p, newc_header_size)) return (ARCHIVE_OK); /* * Scan ahead until we find something that looks * like a newc header. */ while (p + newc_header_size <= q) { switch (p[5]) { case '1': case '2': if (memcmp("07070", p, 5) == 0 && is_hex(p, newc_header_size)) { skip = p - (const char *)h; __archive_read_consume(a, skip); skipped += skip; if (skipped > 0) { archive_set_error(&a->archive, 0, "Skipped %d bytes before " "finding valid header", (int)skipped); return (ARCHIVE_WARN); } return (ARCHIVE_OK); } p += 2; break; case '0': p++; break; default: p += 6; break; } } skip = p - (const char *)h; __archive_read_consume(a, skip); skipped += skip; } } static int header_newc(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry, size_t *namelength, size_t *name_pad) { const void *h; const char *header; int r; r = find_newc_header(a); if (r < ARCHIVE_WARN) return (r); /* Read fixed-size portion of header. */ h = __archive_read_ahead(a, newc_header_size, NULL); if (h == NULL) return (ARCHIVE_FATAL); /* Parse out hex fields. */ header = (const char *)h; if (memcmp(header + newc_magic_offset, "070701", 6) == 0) { a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC; a->archive.archive_format_name = "ASCII cpio (SVR4 with no CRC)"; } else if (memcmp(header + newc_magic_offset, "070702", 6) == 0) { a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_CRC; a->archive.archive_format_name = "ASCII cpio (SVR4 with CRC)"; } else { /* TODO: Abort here? */ } archive_entry_set_devmajor(entry, (dev_t)atol16(header + newc_devmajor_offset, newc_devmajor_size)); archive_entry_set_devminor(entry, (dev_t)atol16(header + newc_devminor_offset, newc_devminor_size)); archive_entry_set_ino(entry, atol16(header + newc_ino_offset, newc_ino_size)); archive_entry_set_mode(entry, (mode_t)atol16(header + newc_mode_offset, newc_mode_size)); archive_entry_set_uid(entry, atol16(header + newc_uid_offset, newc_uid_size)); archive_entry_set_gid(entry, atol16(header + newc_gid_offset, newc_gid_size)); archive_entry_set_nlink(entry, (unsigned int)atol16(header + newc_nlink_offset, newc_nlink_size)); archive_entry_set_rdevmajor(entry, (dev_t)atol16(header + newc_rdevmajor_offset, newc_rdevmajor_size)); archive_entry_set_rdevminor(entry, (dev_t)atol16(header + newc_rdevminor_offset, newc_rdevminor_size)); archive_entry_set_mtime(entry, atol16(header + newc_mtime_offset, newc_mtime_size), 0); *namelength = (size_t)atol16(header + newc_namesize_offset, newc_namesize_size); /* Pad name to 2 more than a multiple of 4. */ *name_pad = (2 - *namelength) & 3; /* * Note: entry_bytes_remaining is at least 64 bits and * therefore guaranteed to be big enough for a 33-bit file * size. */ cpio->entry_bytes_remaining = atol16(header + newc_filesize_offset, newc_filesize_size); archive_entry_set_size(entry, cpio->entry_bytes_remaining); /* Pad file contents to a multiple of 4. */ cpio->entry_padding = 3 & -cpio->entry_bytes_remaining; __archive_read_consume(a, newc_header_size); return (r); } /* * Skip forward to the next cpio odc header by searching for the * 070707 string. This is a hand-optimized search that could * probably be easily generalized to handle all character-based * cpio variants. */ static int is_octal(const char *p, size_t len) { while (len-- > 0) { if (*p < '0' || *p > '7') return (0); ++p; } return (1); } static int is_afio_large(const char *h, size_t len) { if (len < afiol_header_size) return (0); if (h[afiol_ino_m_offset] != 'm' || h[afiol_mtime_n_offset] != 'n' || h[afiol_xsize_s_offset] != 's' || h[afiol_filesize_c_offset] != ':') return (0); if (!is_hex(h + afiol_dev_offset, afiol_ino_m_offset - afiol_dev_offset)) return (0); if (!is_hex(h + afiol_mode_offset, afiol_mtime_n_offset - afiol_mode_offset)) return (0); if (!is_hex(h + afiol_namesize_offset, afiol_xsize_s_offset - afiol_namesize_offset)) return (0); if (!is_hex(h + afiol_filesize_offset, afiol_filesize_size)) return (0); return (1); } static int find_odc_header(struct archive_read *a) { const void *h; const char *p, *q; size_t skip, skipped = 0; ssize_t bytes; for (;;) { h = __archive_read_ahead(a, odc_header_size, &bytes); if (h == NULL) return (ARCHIVE_FATAL); p = h; q = p + bytes; /* Try the typical case first, then go into the slow search.*/ if (memcmp("070707", p, 6) == 0 && is_octal(p, odc_header_size)) return (ARCHIVE_OK); if (memcmp("070727", p, 6) == 0 && is_afio_large(p, bytes)) { a->archive.archive_format = ARCHIVE_FORMAT_CPIO_AFIO_LARGE; return (ARCHIVE_OK); } /* * Scan ahead until we find something that looks * like an odc header. */ while (p + odc_header_size <= q) { switch (p[5]) { case '7': if ((memcmp("070707", p, 6) == 0 && is_octal(p, odc_header_size)) || (memcmp("070727", p, 6) == 0 && is_afio_large(p, q - p))) { skip = p - (const char *)h; __archive_read_consume(a, skip); skipped += skip; if (p[4] == '2') a->archive.archive_format = ARCHIVE_FORMAT_CPIO_AFIO_LARGE; if (skipped > 0) { archive_set_error(&a->archive, 0, "Skipped %d bytes before " "finding valid header", (int)skipped); return (ARCHIVE_WARN); } return (ARCHIVE_OK); } p += 2; break; case '0': p++; break; default: p += 6; break; } } skip = p - (const char *)h; __archive_read_consume(a, skip); skipped += skip; } } static int header_odc(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry, size_t *namelength, size_t *name_pad) { const void *h; int r; const char *header; a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX; a->archive.archive_format_name = "POSIX octet-oriented cpio"; /* Find the start of the next header. */ r = find_odc_header(a); if (r < ARCHIVE_WARN) return (r); if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_AFIO_LARGE) { int r2 = (header_afiol(a, cpio, entry, namelength, name_pad)); if (r2 == ARCHIVE_OK) return (r); else return (r2); } /* Read fixed-size portion of header. */ h = __archive_read_ahead(a, odc_header_size, NULL); if (h == NULL) return (ARCHIVE_FATAL); /* Parse out octal fields. */ header = (const char *)h; archive_entry_set_dev(entry, (dev_t)atol8(header + odc_dev_offset, odc_dev_size)); archive_entry_set_ino(entry, atol8(header + odc_ino_offset, odc_ino_size)); archive_entry_set_mode(entry, (mode_t)atol8(header + odc_mode_offset, odc_mode_size)); archive_entry_set_uid(entry, atol8(header + odc_uid_offset, odc_uid_size)); archive_entry_set_gid(entry, atol8(header + odc_gid_offset, odc_gid_size)); archive_entry_set_nlink(entry, (unsigned int)atol8(header + odc_nlink_offset, odc_nlink_size)); archive_entry_set_rdev(entry, (dev_t)atol8(header + odc_rdev_offset, odc_rdev_size)); archive_entry_set_mtime(entry, atol8(header + odc_mtime_offset, odc_mtime_size), 0); *namelength = (size_t)atol8(header + odc_namesize_offset, odc_namesize_size); *name_pad = 0; /* No padding of filename. */ /* * Note: entry_bytes_remaining is at least 64 bits and * therefore guaranteed to be big enough for a 33-bit file * size. */ cpio->entry_bytes_remaining = atol8(header + odc_filesize_offset, odc_filesize_size); archive_entry_set_size(entry, cpio->entry_bytes_remaining); cpio->entry_padding = 0; __archive_read_consume(a, odc_header_size); return (r); } /* * NOTE: if a filename suffix is ".z", it is the file gziped by afio. * it would be nice that we can show uncompressed file size and we can * uncompressed file contents automatically, unfortunately we have nothing * to get a uncompressed file size while reading each header. it means * we also cannot uncompressed file contens under the our framework. */ static int header_afiol(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry, size_t *namelength, size_t *name_pad) { const void *h; const char *header; a->archive.archive_format = ARCHIVE_FORMAT_CPIO_AFIO_LARGE; a->archive.archive_format_name = "afio large ASCII"; /* Read fixed-size portion of header. */ h = __archive_read_ahead(a, afiol_header_size, NULL); if (h == NULL) return (ARCHIVE_FATAL); /* Parse out octal fields. */ header = (const char *)h; archive_entry_set_dev(entry, (dev_t)atol16(header + afiol_dev_offset, afiol_dev_size)); archive_entry_set_ino(entry, atol16(header + afiol_ino_offset, afiol_ino_size)); archive_entry_set_mode(entry, (mode_t)atol8(header + afiol_mode_offset, afiol_mode_size)); archive_entry_set_uid(entry, atol16(header + afiol_uid_offset, afiol_uid_size)); archive_entry_set_gid(entry, atol16(header + afiol_gid_offset, afiol_gid_size)); archive_entry_set_nlink(entry, (unsigned int)atol16(header + afiol_nlink_offset, afiol_nlink_size)); archive_entry_set_rdev(entry, (dev_t)atol16(header + afiol_rdev_offset, afiol_rdev_size)); archive_entry_set_mtime(entry, atol16(header + afiol_mtime_offset, afiol_mtime_size), 0); *namelength = (size_t)atol16(header + afiol_namesize_offset, afiol_namesize_size); *name_pad = 0; /* No padding of filename. */ cpio->entry_bytes_remaining = atol16(header + afiol_filesize_offset, afiol_filesize_size); archive_entry_set_size(entry, cpio->entry_bytes_remaining); cpio->entry_padding = 0; __archive_read_consume(a, afiol_header_size); return (ARCHIVE_OK); } static int header_bin_le(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry, size_t *namelength, size_t *name_pad) { const void *h; const unsigned char *header; a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_LE; a->archive.archive_format_name = "cpio (little-endian binary)"; /* Read fixed-size portion of header. */ h = __archive_read_ahead(a, bin_header_size, NULL); - if (h == NULL) + if (h == NULL) { + archive_set_error(&a->archive, 0, + "End of file trying to read next cpio header"); return (ARCHIVE_FATAL); + } /* Parse out binary fields. */ header = (const unsigned char *)h; archive_entry_set_dev(entry, header[bin_dev_offset] + header[bin_dev_offset + 1] * 256); archive_entry_set_ino(entry, header[bin_ino_offset] + header[bin_ino_offset + 1] * 256); archive_entry_set_mode(entry, header[bin_mode_offset] + header[bin_mode_offset + 1] * 256); archive_entry_set_uid(entry, header[bin_uid_offset] + header[bin_uid_offset + 1] * 256); archive_entry_set_gid(entry, header[bin_gid_offset] + header[bin_gid_offset + 1] * 256); archive_entry_set_nlink(entry, header[bin_nlink_offset] + header[bin_nlink_offset + 1] * 256); archive_entry_set_rdev(entry, header[bin_rdev_offset] + header[bin_rdev_offset + 1] * 256); archive_entry_set_mtime(entry, le4(header + bin_mtime_offset), 0); *namelength = header[bin_namesize_offset] + header[bin_namesize_offset + 1] * 256; *name_pad = *namelength & 1; /* Pad to even. */ cpio->entry_bytes_remaining = le4(header + bin_filesize_offset); archive_entry_set_size(entry, cpio->entry_bytes_remaining); cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */ __archive_read_consume(a, bin_header_size); return (ARCHIVE_OK); } static int header_bin_be(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry, size_t *namelength, size_t *name_pad) { const void *h; const unsigned char *header; a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE; a->archive.archive_format_name = "cpio (big-endian binary)"; /* Read fixed-size portion of header. */ h = __archive_read_ahead(a, bin_header_size, NULL); - if (h == NULL) + if (h == NULL) { + archive_set_error(&a->archive, 0, + "End of file trying to read next cpio header"); return (ARCHIVE_FATAL); + } /* Parse out binary fields. */ header = (const unsigned char *)h; archive_entry_set_dev(entry, header[bin_dev_offset] * 256 + header[bin_dev_offset + 1]); archive_entry_set_ino(entry, header[bin_ino_offset] * 256 + header[bin_ino_offset + 1]); archive_entry_set_mode(entry, header[bin_mode_offset] * 256 + header[bin_mode_offset + 1]); archive_entry_set_uid(entry, header[bin_uid_offset] * 256 + header[bin_uid_offset + 1]); archive_entry_set_gid(entry, header[bin_gid_offset] * 256 + header[bin_gid_offset + 1]); archive_entry_set_nlink(entry, header[bin_nlink_offset] * 256 + header[bin_nlink_offset + 1]); archive_entry_set_rdev(entry, header[bin_rdev_offset] * 256 + header[bin_rdev_offset + 1]); archive_entry_set_mtime(entry, be4(header + bin_mtime_offset), 0); *namelength = header[bin_namesize_offset] * 256 + header[bin_namesize_offset + 1]; *name_pad = *namelength & 1; /* Pad to even. */ cpio->entry_bytes_remaining = be4(header + bin_filesize_offset); archive_entry_set_size(entry, cpio->entry_bytes_remaining); cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */ __archive_read_consume(a, bin_header_size); return (ARCHIVE_OK); } static int archive_read_format_cpio_cleanup(struct archive_read *a) { struct cpio *cpio; cpio = (struct cpio *)(a->format->data); /* Free inode->name map */ while (cpio->links_head != NULL) { struct links_entry *lp = cpio->links_head->next; if (cpio->links_head->name) free(cpio->links_head->name); free(cpio->links_head); cpio->links_head = lp; } free(cpio); (a->format->data) = NULL; return (ARCHIVE_OK); } -static int +static int64_t le4(const unsigned char *p) { - return ((p[0]<<16) + (p[1]<<24) + (p[2]<<0) + (p[3]<<8)); + return ((p[0] << 16) + (((int64_t)p[1]) << 24) + (p[2] << 0) + (p[3] << 8)); } -static int +static int64_t be4(const unsigned char *p) { - return ((p[0]<<24) + (p[1]<<16) + (p[2]<<8) + (p[3])); + return ((((int64_t)p[0]) << 24) + (p[1] << 16) + (p[2] << 8) + (p[3])); } /* * Note that this implementation does not (and should not!) obey * locale settings; you cannot simply substitute strtol here, since * it does obey locale. */ static int64_t atol8(const char *p, unsigned char_cnt) { int64_t l; int digit; l = 0; while (char_cnt-- > 0) { if (*p >= '0' && *p <= '7') digit = *p - '0'; else return (l); p++; l <<= 3; l |= digit; } return (l); } static int64_t atol16(const char *p, unsigned char_cnt) { int64_t l; int digit; l = 0; while (char_cnt-- > 0) { if (*p >= 'a' && *p <= 'f') digit = *p - 'a' + 10; else if (*p >= 'A' && *p <= 'F') digit = *p - 'A' + 10; else if (*p >= '0' && *p <= '9') digit = *p - '0'; else return (l); p++; l <<= 4; l |= digit; } return (l); } static int record_hardlink(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry) { struct links_entry *le; dev_t dev; int64_t ino; if (archive_entry_nlink(entry) <= 1) return (ARCHIVE_OK); dev = archive_entry_dev(entry); ino = archive_entry_ino64(entry); /* * First look in the list of multiply-linked files. If we've * already dumped it, convert this entry to a hard link entry. */ for (le = cpio->links_head; le; le = le->next) { if (le->dev == dev && le->ino == ino) { archive_entry_copy_hardlink(entry, le->name); if (--le->links <= 0) { if (le->previous != NULL) le->previous->next = le->next; if (le->next != NULL) le->next->previous = le->previous; if (cpio->links_head == le) cpio->links_head = le->next; free(le->name); free(le); } return (ARCHIVE_OK); } } le = (struct links_entry *)malloc(sizeof(struct links_entry)); if (le == NULL) { archive_set_error(&a->archive, ENOMEM, "Out of memory adding file to list"); return (ARCHIVE_FATAL); } if (cpio->links_head != NULL) cpio->links_head->previous = le; le->next = cpio->links_head; le->previous = NULL; cpio->links_head = le; le->dev = dev; le->ino = ino; le->links = archive_entry_nlink(entry) - 1; le->name = strdup(archive_entry_pathname(entry)); if (le->name == NULL) { archive_set_error(&a->archive, ENOMEM, "Out of memory adding file to list"); return (ARCHIVE_FATAL); } return (ARCHIVE_OK); } Index: projects/ci20_mips/contrib/libarchive/libarchive =================================================================== --- projects/ci20_mips/contrib/libarchive/libarchive (revision 283030) +++ projects/ci20_mips/contrib/libarchive/libarchive (revision 283031) Property changes on: projects/ci20_mips/contrib/libarchive/libarchive ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,2 ## Merged /head/contrib/libarchive/libarchive:r282737-283030 Merged /vendor/libarchive/dist/libarchive:r232134-238824,238826-248589,248591-248593,248595-282930 Index: projects/ci20_mips/contrib/libarchive =================================================================== --- projects/ci20_mips/contrib/libarchive (revision 283030) +++ projects/ci20_mips/contrib/libarchive (revision 283031) Property changes on: projects/ci20_mips/contrib/libarchive ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,2 ## Merged /head/contrib/libarchive:r282737-283030 Merged /vendor/libarchive/dist:r232134-238824,238826-248589,248591-248593,248595-282930 Index: projects/ci20_mips/gnu/lib/Makefile =================================================================== --- projects/ci20_mips/gnu/lib/Makefile (revision 283030) +++ projects/ci20_mips/gnu/lib/Makefile (revision 283031) @@ -1,21 +1,25 @@ # $FreeBSD$ .include -SUBDIR= csu libgcc libgcov libdialog libgomp libregex libreadline +SUBDIR= csu libgcc libgcov libdialog libregex libreadline + +.if ${MK_GCC} != "no" +SUBDIR+= libgomp +.endif .if ${MK_SSP} != "no" SUBDIR+= libssp .endif .if ${MK_TESTS} != "no" SUBDIR+= tests .endif # libsupc++ uses libstdc++ headers, although 'make includes' should # have taken care of that already. .if ${MK_GNUCXX} != "no" SUBDIR+= libstdc++ libsupc++ .endif .include Index: projects/ci20_mips/gnu/lib =================================================================== --- projects/ci20_mips/gnu/lib (revision 283030) +++ projects/ci20_mips/gnu/lib (revision 283031) Property changes on: projects/ci20_mips/gnu/lib ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/gnu/lib:r282737-283030 Index: projects/ci20_mips/include/stdlib.h =================================================================== --- projects/ci20_mips/include/stdlib.h (revision 283030) +++ projects/ci20_mips/include/stdlib.h (revision 283031) @@ -1,328 +1,329 @@ /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)stdlib.h 8.5 (Berkeley) 5/19/95 * $FreeBSD$ */ #ifndef _STDLIB_H_ #define _STDLIB_H_ #include #include #include #if __BSD_VISIBLE #ifndef _RUNE_T_DECLARED typedef __rune_t rune_t; #define _RUNE_T_DECLARED #endif #endif #ifndef _SIZE_T_DECLARED typedef __size_t size_t; #define _SIZE_T_DECLARED #endif #ifndef __cplusplus #ifndef _WCHAR_T_DECLARED typedef ___wchar_t wchar_t; #define _WCHAR_T_DECLARED #endif #endif typedef struct { int quot; /* quotient */ int rem; /* remainder */ } div_t; typedef struct { long quot; long rem; } ldiv_t; #define EXIT_FAILURE 1 #define EXIT_SUCCESS 0 #define RAND_MAX 0x7ffffffd __BEGIN_DECLS #ifdef _XLOCALE_H_ #include #endif extern int __mb_cur_max; extern int ___mb_cur_max(void); #define MB_CUR_MAX (___mb_cur_max()) _Noreturn void abort(void); int abs(int) __pure2; int atexit(void (*)(void)); double atof(const char *); int atoi(const char *); long atol(const char *); void *bsearch(const void *, const void *, size_t, size_t, int (*)(const void *, const void *)); void *calloc(size_t, size_t) __malloc_like __result_use_check __alloc_size(1) __alloc_size(2); div_t div(int, int) __pure2; _Noreturn void exit(int); void free(void *); char *getenv(const char *); long labs(long) __pure2; ldiv_t ldiv(long, long) __pure2; void *malloc(size_t) __malloc_like __result_use_check __alloc_size(1); int mblen(const char *, size_t); size_t mbstowcs(wchar_t * __restrict , const char * __restrict, size_t); int mbtowc(wchar_t * __restrict, const char * __restrict, size_t); void qsort(void *, size_t, size_t, int (*)(const void *, const void *)); int rand(void); void *realloc(void *, size_t) __result_use_check __alloc_size(2); void srand(unsigned); double strtod(const char * __restrict, char ** __restrict); float strtof(const char * __restrict, char ** __restrict); long strtol(const char * __restrict, char ** __restrict, int); long double strtold(const char * __restrict, char ** __restrict); unsigned long strtoul(const char * __restrict, char ** __restrict, int); int system(const char *); int wctomb(char *, wchar_t); size_t wcstombs(char * __restrict, const wchar_t * __restrict, size_t); /* * Functions added in C99 which we make conditionally available in the * BSD^C89 namespace if the compiler supports `long long'. * The #if test is more complicated than it ought to be because * __BSD_VISIBLE implies __ISO_C_VISIBLE == 1999 *even if* `long long' * is not supported in the compilation environment (which therefore means * that it can't really be ISO C99). * * (The only other extension made by C99 in thie header is _Exit().) */ #if __ISO_C_VISIBLE >= 1999 #ifdef __LONG_LONG_SUPPORTED /* LONGLONG */ typedef struct { long long quot; long long rem; } lldiv_t; /* LONGLONG */ long long atoll(const char *); /* LONGLONG */ long long llabs(long long) __pure2; /* LONGLONG */ lldiv_t lldiv(long long, long long) __pure2; /* LONGLONG */ long long strtoll(const char * __restrict, char ** __restrict, int); /* LONGLONG */ unsigned long long strtoull(const char * __restrict, char ** __restrict, int); #endif /* __LONG_LONG_SUPPORTED */ _Noreturn void _Exit(int); #endif /* __ISO_C_VISIBLE >= 1999 */ /* * If we're in a mode greater than C99, expose C11 functions. */ #if __ISO_C_VISIBLE >= 2011 || __cplusplus >= 201103L -void * aligned_alloc(size_t, size_t) __malloc_like __alloc_size(2); +void * aligned_alloc(size_t, size_t) __malloc_like __alloc_align(1) + __alloc_size(2); int at_quick_exit(void (*)(void)); _Noreturn void quick_exit(int); #endif /* __ISO_C_VISIBLE >= 2011 */ /* * Extensions made by POSIX relative to C. */ #if __POSIX_VISIBLE >= 199506 || __XSI_VISIBLE char *realpath(const char * __restrict, char * __restrict); #endif #if __POSIX_VISIBLE >= 199506 int rand_r(unsigned *); /* (TSF) */ #endif #if __POSIX_VISIBLE >= 200112 -int posix_memalign(void **, size_t, size_t) __nonnull(1) +int posix_memalign(void **, size_t, size_t) __nonnull(1) __alloc_align(2) __alloc_size(3); /* (ADV) */ int setenv(const char *, const char *, int); int unsetenv(const char *); #endif #if __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE int getsubopt(char **, char *const *, char **); #ifndef _MKDTEMP_DECLARED char *mkdtemp(char *); #define _MKDTEMP_DECLARED #endif #ifndef _MKSTEMP_DECLARED int mkstemp(char *); #define _MKSTEMP_DECLARED #endif #endif /* __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE */ /* * The only changes to the XSI namespace in revision 6 were the deletion * of the ttyslot() and valloc() functions, which FreeBSD never declared * in this header. For revision 7, ecvt(), fcvt(), and gcvt(), which * FreeBSD also does not have, and mktemp(), are to be deleted. */ #if __XSI_VISIBLE /* XXX XSI requires pollution from here. We'd rather not. */ long a64l(const char *); double drand48(void); /* char *ecvt(double, int, int * __restrict, int * __restrict); */ double erand48(unsigned short[3]); /* char *fcvt(double, int, int * __restrict, int * __restrict); */ /* char *gcvt(double, int, int * __restrict, int * __restrict); */ int grantpt(int); char *initstate(unsigned long /* XSI requires u_int */, char *, long); long jrand48(unsigned short[3]); char *l64a(long); void lcong48(unsigned short[7]); long lrand48(void); #if !defined(_MKTEMP_DECLARED) && (__BSD_VISIBLE || __XSI_VISIBLE <= 600) char *mktemp(char *); #define _MKTEMP_DECLARED #endif long mrand48(void); long nrand48(unsigned short[3]); int posix_openpt(int); char *ptsname(int); int putenv(char *); long random(void); unsigned short *seed48(unsigned short[3]); #ifndef _SETKEY_DECLARED int setkey(const char *); #define _SETKEY_DECLARED #endif char *setstate(/* const */ char *); void srand48(long); void srandom(unsigned long); int unlockpt(int); #endif /* __XSI_VISIBLE */ #if __BSD_VISIBLE extern const char *malloc_conf; extern void (*malloc_message)(void *, const char *); /* * The alloca() function can't be implemented in C, and on some * platforms it can't be implemented at all as a callable function. * The GNU C compiler provides a built-in alloca() which we can use; * in all other cases, provide a prototype, mainly to pacify various * incarnations of lint. On platforms where alloca() is not in libc, * programs which use it will fail to link when compiled with non-GNU * compilers. */ #if __GNUC__ >= 2 || defined(__INTEL_COMPILER) #undef alloca /* some GNU bits try to get cute and define this on their own */ #define alloca(sz) __builtin_alloca(sz) #elif defined(lint) void *alloca(size_t); #endif void abort2(const char *, int, void **) __dead2; __uint32_t arc4random(void); void arc4random_addrandom(unsigned char *, int); void arc4random_buf(void *, size_t); void arc4random_stir(void); __uint32_t arc4random_uniform(__uint32_t); #ifdef __BLOCKS__ int atexit_b(void (^)(void)); void *bsearch_b(const void *, const void *, size_t, size_t, int (^)(const void *, const void *)); #endif char *getbsize(int *, long *); /* getcap(3) functions */ char *cgetcap(char *, const char *, int); int cgetclose(void); int cgetent(char **, char **, const char *); int cgetfirst(char **, char **); int cgetmatch(const char *, const char *); int cgetnext(char **, char **); int cgetnum(char *, const char *, long *); int cgetset(const char *); int cgetstr(char *, const char *, char **); int cgetustr(char *, const char *, char **); int daemon(int, int); char *devname(__dev_t, __mode_t); char *devname_r(__dev_t, __mode_t, char *, int); char *fdevname(int); char *fdevname_r(int, char *, int); int getloadavg(double [], int); const char * getprogname(void); int heapsort(void *, size_t, size_t, int (*)(const void *, const void *)); #ifdef __BLOCKS__ int heapsort_b(void *, size_t, size_t, int (^)(const void *, const void *)); void qsort_b(void *, size_t, size_t, int (^)(const void *, const void *)); #endif int l64a_r(long, char *, int); int mergesort(void *, size_t, size_t, int (*)(const void *, const void *)); #ifdef __BLOCKS__ int mergesort_b(void *, size_t, size_t, int (^)(const void *, const void *)); #endif int mkostemp(char *, int); int mkostemps(char *, int, int); void qsort_r(void *, size_t, size_t, void *, int (*)(void *, const void *, const void *)); int radixsort(const unsigned char **, int, const unsigned char *, unsigned); void *reallocarray(void *, size_t, size_t) __result_use_check __alloc_size(2) __alloc_size(3); void *reallocf(void *, size_t) __alloc_size(2); int rpmatch(const char *); void setprogname(const char *); int sradixsort(const unsigned char **, int, const unsigned char *, unsigned); void sranddev(void); void srandomdev(void); long long strtonum(const char *, long long, long long, const char **); /* Deprecated interfaces, to be removed in FreeBSD 6.0. */ __int64_t strtoq(const char *, char **, int); __uint64_t strtouq(const char *, char **, int); extern char *suboptarg; /* getsubopt(3) external variable */ #endif /* __BSD_VISIBLE */ __END_DECLS #endif /* !_STDLIB_H_ */ Index: projects/ci20_mips/include =================================================================== --- projects/ci20_mips/include (revision 283030) +++ projects/ci20_mips/include (revision 283031) Property changes on: projects/ci20_mips/include ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/include:r282737-283030 Index: projects/ci20_mips/lib/libthr/thread/thr_spec.c =================================================================== --- projects/ci20_mips/lib/libthr/thread/thr_spec.c (revision 283030) +++ projects/ci20_mips/lib/libthr/thread/thr_spec.c (revision 283031) @@ -1,261 +1,242 @@ /* * Copyright (c) 1995 John Birrell . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include "namespace.h" +#include #include #include #include #include #include #include "un-namespace.h" #include "libc_private.h" #include "thr_private.h" -/* Static variables: */ struct pthread_key _thread_keytable[PTHREAD_KEYS_MAX]; __weak_reference(_pthread_key_create, pthread_key_create); __weak_reference(_pthread_key_delete, pthread_key_delete); __weak_reference(_pthread_getspecific, pthread_getspecific); __weak_reference(_pthread_setspecific, pthread_setspecific); int -_pthread_key_create(pthread_key_t *key, void (*destructor) (void *)) +_pthread_key_create(pthread_key_t *key, void (*destructor)(void *)) { struct pthread *curthread; int i; _thr_check_init(); curthread = _get_curthread(); - /* Lock the key table: */ THR_LOCK_ACQUIRE(curthread, &_keytable_lock); for (i = 0; i < PTHREAD_KEYS_MAX; i++) { if (_thread_keytable[i].allocated == 0) { _thread_keytable[i].allocated = 1; _thread_keytable[i].destructor = destructor; _thread_keytable[i].seqno++; - /* Unlock the key table: */ THR_LOCK_RELEASE(curthread, &_keytable_lock); *key = i + 1; return (0); } } - /* Unlock the key table: */ THR_LOCK_RELEASE(curthread, &_keytable_lock); return (EAGAIN); } int _pthread_key_delete(pthread_key_t userkey) { - struct pthread *curthread = _get_curthread(); - int key = userkey - 1; - int ret = 0; + struct pthread *curthread; + int key, ret; - if ((unsigned int)key < PTHREAD_KEYS_MAX) { - /* Lock the key table: */ - THR_LOCK_ACQUIRE(curthread, &_keytable_lock); - - if (_thread_keytable[key].allocated) - _thread_keytable[key].allocated = 0; - else - ret = EINVAL; - - /* Unlock the key table: */ - THR_LOCK_RELEASE(curthread, &_keytable_lock); - } else + key = userkey - 1; + if ((unsigned int)key >= PTHREAD_KEYS_MAX) + return (EINVAL); + curthread = _get_curthread(); + THR_LOCK_ACQUIRE(curthread, &_keytable_lock); + if (_thread_keytable[key].allocated) { + _thread_keytable[key].allocated = 0; + ret = 0; + } else { ret = EINVAL; + } + THR_LOCK_RELEASE(curthread, &_keytable_lock); return (ret); } void _thread_cleanupspecific(void) { - struct pthread *curthread = _get_curthread(); - void (*destructor)( void *); - const void *data = NULL; - int key; - int i; + struct pthread *curthread; + void (*destructor)(void *); + const void *data; + int i, key; + curthread = _get_curthread(); if (curthread->specific == NULL) return; - - /* Lock the key table: */ THR_LOCK_ACQUIRE(curthread, &_keytable_lock); - for (i = 0; (i < PTHREAD_DESTRUCTOR_ITERATIONS) && - (curthread->specific_data_count > 0); i++) { - for (key = 0; (key < PTHREAD_KEYS_MAX) && - (curthread->specific_data_count > 0); key++) { + for (i = 0; i < PTHREAD_DESTRUCTOR_ITERATIONS && + curthread->specific_data_count > 0; i++) { + for (key = 0; key < PTHREAD_KEYS_MAX && + curthread->specific_data_count > 0; key++) { destructor = NULL; if (_thread_keytable[key].allocated && (curthread->specific[key].data != NULL)) { if (curthread->specific[key].seqno == _thread_keytable[key].seqno) { data = curthread->specific[key].data; - destructor = _thread_keytable[key].destructor; + destructor = _thread_keytable[key]. + destructor; } curthread->specific[key].data = NULL; curthread->specific_data_count--; - } - else if (curthread->specific[key].data != NULL) { + } else if (curthread->specific[key].data != NULL) { /* - * This can happen if the key is deleted via - * pthread_key_delete without first setting the value - * to NULL in all threads. POSIX says that the - * destructor is not invoked in this case. + * This can happen if the key is + * deleted via pthread_key_delete + * without first setting the value to + * NULL in all threads. POSIX says + * that the destructor is not invoked + * in this case. */ curthread->specific[key].data = NULL; curthread->specific_data_count--; } /* - * If there is a destructor, call it - * with the key table entry unlocked: + * If there is a destructor, call it with the + * key table entry unlocked. */ if (destructor != NULL) { - /* - * Don't hold the lock while calling the - * destructor: - */ THR_LOCK_RELEASE(curthread, &_keytable_lock); destructor(__DECONST(void *, data)); THR_LOCK_ACQUIRE(curthread, &_keytable_lock); } } } THR_LOCK_RELEASE(curthread, &_keytable_lock); - free(curthread->specific); + munmap(curthread->specific, PTHREAD_KEYS_MAX * sizeof(struct + pthread_specific_elem)); curthread->specific = NULL; - if (curthread->specific_data_count > 0) + if (curthread->specific_data_count > 0) { stderr_debug("Thread %p has exited with leftover " "thread-specific data after %d destructor iterations\n", curthread, PTHREAD_DESTRUCTOR_ITERATIONS); + } } -static inline struct pthread_specific_elem * -pthread_key_allocate_data(void) -{ - struct pthread_specific_elem *new_data; - - new_data = (struct pthread_specific_elem *) - calloc(1, sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX); - return (new_data); -} - int _pthread_setspecific(pthread_key_t userkey, const void *value) { - struct pthread *pthread; - pthread_key_t key = userkey - 1; - int ret = 0; + struct pthread *pthread; + void *tmp; + pthread_key_t key; - /* Point to the running thread: */ - pthread = _get_curthread(); + key = userkey - 1; + if ((unsigned int)key >= PTHREAD_KEYS_MAX || + !_thread_keytable[key].allocated) + return (EINVAL); - if ((pthread->specific) || - (pthread->specific = pthread_key_allocate_data())) { - if ((unsigned int)key < PTHREAD_KEYS_MAX) { - if (_thread_keytable[key].allocated) { - if (pthread->specific[key].data == NULL) { - if (value != NULL) - pthread->specific_data_count++; - } else if (value == NULL) - pthread->specific_data_count--; - pthread->specific[key].data = value; - pthread->specific[key].seqno = - _thread_keytable[key].seqno; - ret = 0; - } else - ret = EINVAL; - } else - ret = EINVAL; - } else - ret = ENOMEM; - return (ret); + pthread = _get_curthread(); + if (pthread->specific == NULL) { + tmp = mmap(NULL, PTHREAD_KEYS_MAX * + sizeof(struct pthread_specific_elem), + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + if (tmp == MAP_FAILED) + return (ENOMEM); + pthread->specific = tmp; + } + if (pthread->specific[key].data == NULL) { + if (value != NULL) + pthread->specific_data_count++; + } else if (value == NULL) + pthread->specific_data_count--; + pthread->specific[key].data = value; + pthread->specific[key].seqno = _thread_keytable[key].seqno; + return (0); } void * _pthread_getspecific(pthread_key_t userkey) { - struct pthread *pthread; - pthread_key_t key = userkey - 1; - const void *data; + struct pthread *pthread; + const void *data; + pthread_key_t key; - /* Point to the running thread: */ - pthread = _get_curthread(); + /* Check if there is specific data. */ + key = userkey - 1; + if ((unsigned int)key >= PTHREAD_KEYS_MAX) + return (NULL); - /* Check if there is specific data: */ - if (pthread->specific != NULL && (unsigned int)key < PTHREAD_KEYS_MAX) { - /* Check if this key has been used before: */ - if (_thread_keytable[key].allocated && - (pthread->specific[key].seqno == _thread_keytable[key].seqno)) { - /* Return the value: */ - data = pthread->specific[key].data; - } else { - /* - * This key has not been used before, so return NULL - * instead: - */ - data = NULL; - } - } else - /* No specific data has been created, so just return NULL: */ + pthread = _get_curthread(); + /* Check if this key has been used before. */ + if (_thread_keytable[key].allocated && pthread->specific != NULL && + pthread->specific[key].seqno == _thread_keytable[key].seqno) { + /* Return the value: */ + data = pthread->specific[key].data; + } else { + /* + * This key has not been used before, so return NULL + * instead. + */ data = NULL; + } return (__DECONST(void *, data)); } void _thr_tsd_unload(struct dl_phdr_info *phdr_info) { - struct pthread *curthread = _get_curthread(); + struct pthread *curthread; void (*destructor)(void *); int key; + curthread = _get_curthread(); THR_LOCK_ACQUIRE(curthread, &_keytable_lock); for (key = 0; key < PTHREAD_KEYS_MAX; key++) { - if (_thread_keytable[key].allocated) { - destructor = _thread_keytable[key].destructor; - if (destructor != NULL) { - if (__elf_phdr_match_addr(phdr_info, destructor)) - _thread_keytable[key].destructor = NULL; - } - } + if (!_thread_keytable[key].allocated) + continue; + destructor = _thread_keytable[key].destructor; + if (destructor == NULL) + continue; + if (__elf_phdr_match_addr(phdr_info, destructor)) + _thread_keytable[key].destructor = NULL; } THR_LOCK_RELEASE(curthread, &_keytable_lock); } Index: projects/ci20_mips/sbin/ifconfig/ifconfig.8 =================================================================== --- projects/ci20_mips/sbin/ifconfig/ifconfig.8 (revision 283030) +++ projects/ci20_mips/sbin/ifconfig/ifconfig.8 (revision 283031) @@ -1,2857 +1,2865 @@ .\" Copyright (c) 1983, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94 .\" $FreeBSD$ .\" -.Dd May 12, 2015 +.Dd May 15, 2015 .Dt IFCONFIG 8 .Os .Sh NAME .Nm ifconfig .Nd configure network interface parameters .Sh SYNOPSIS .Nm .Op Fl L .Op Fl k .Op Fl m .Op Fl n .Ar interface .Op Cm create .Ar address_family .Oo .Ar address .Op Ar dest_address .Oc .Op Ar parameters .Nm .Ar interface .Cm destroy .Nm .Fl a .Op Fl L .Op Fl d .Op Fl m .Op Fl u .Op Fl v .Op Ar address_family .Nm .Fl l .Op Fl d .Op Fl u .Op Ar address_family .Nm .Op Fl L .Op Fl d .Op Fl k .Op Fl m .Op Fl u .Op Fl v .Op Fl C .Nm .Op Fl g Ar groupname .Sh DESCRIPTION The .Nm utility is used to assign an address to a network interface and/or configure network interface parameters. The .Nm utility must be used at boot time to define the network address of each interface present on a machine; it may also be used at a later time to redefine an interface's address or other operating parameters. .Pp The following options are available: .Bl -tag -width indent .It Ar address For the .Tn DARPA Ns -Internet family, the address is either a host name present in the host name data base, .Xr hosts 5 , or a .Tn DARPA Internet address expressed in the Internet standard .Dq dot notation . .Pp It is also possible to use the CIDR notation (also known as the slash notation) to include the netmask. That is, one can specify an address like .Li 192.168.0.1/16 . .Pp For the .Dq inet6 family, it is also possible to specify the prefix length using the slash notation, like .Li ::1/128 . See the .Cm prefixlen parameter below for more information. .\" For the Xerox Network Systems(tm) family, .\" addresses are .\" .Ar net:a.b.c.d.e.f , .\" where .\" .Ar net .\" is the assigned network number (in decimal), .\" and each of the six bytes of the host number, .\" .Ar a .\" through .\" .Ar f , .\" are specified in hexadecimal. .\" The host number may be omitted on IEEE 802 protocol .\" (Ethernet, FDDI, and Token Ring) interfaces, .\" which use the hardware physical address, .\" and on interfaces other than the first. .\" For the .\" .Tn ISO .\" family, addresses are specified as a long hexadecimal string, .\" as in the Xerox family. .\" However, two consecutive dots imply a zero .\" byte, and the dots are optional, if the user wishes to (carefully) .\" count out long strings of digits in network byte order. .Pp The link-level .Pq Dq link address is specified as a series of colon-separated hex digits. This can be used to, for example, set a new MAC address on an Ethernet interface, though the mechanism used is not Ethernet specific. If the interface is already up when this option is used, it will be briefly brought down and then brought back up again in order to ensure that the receive filter in the underlying Ethernet hardware is properly reprogrammed. .It Ar address_family Specify the address family which affects interpretation of the remaining parameters. Since an interface can receive transmissions in differing protocols with different naming schemes, specifying the address family is recommended. The address or protocol families currently supported are .Dq inet , .Dq inet6 , and .Dq link . The default if available is .Dq inet or otherwise .Dq link . .Dq ether and .Dq lladdr are synonyms for .Dq link . When using the .Fl l flag, the .Dq ether address family has special meaning and is no longer synonymous with .Dq link or .Dq lladdr . Specifying .Fl l Dq ether will list only Ethernet interfaces, excluding all other interface types, including the loopback interface. .It Ar dest_address Specify the address of the correspondent on the other end of a point to point link. .It Ar interface This parameter is a string of the form .Dq name unit , for example, .Dq Li ed0 . .It Ar groupname List the interfaces in the given group. .El .Pp The following parameters may be set with .Nm : .Bl -tag -width indent .It Cm add Another name for the .Cm alias parameter. Introduced for compatibility with .Bsx . .It Cm alias Establish an additional network address for this interface. This is sometimes useful when changing network numbers, and one wishes to accept packets addressed to the old interface. If the address is on the same subnet as the first network address for this interface, a non-conflicting netmask must be given. Usually .Li 0xffffffff is most appropriate. .It Fl alias Remove the network address specified. This would be used if you incorrectly specified an alias, or it was no longer needed. If you have incorrectly set an NS address having the side effect of specifying the host portion, removing all NS addresses will allow you to respecify the host portion. .It Cm anycast (Inet6 only.) Specify that the address configured is an anycast address. Based on the current specification, only routers may configure anycast addresses. Anycast address will not be used as source address of any of outgoing IPv6 packets. .It Cm arp Enable the use of the Address Resolution Protocol .Pq Xr arp 4 in mapping between network level addresses and link level addresses (default). This is currently implemented for mapping between .Tn DARPA Internet addresses and .Tn IEEE 802 48-bit MAC addresses (Ethernet, FDDI, and Token Ring addresses). .It Fl arp Disable the use of the Address Resolution Protocol .Pq Xr arp 4 . .It Cm staticarp If the Address Resolution Protocol is enabled, the host will only reply to requests for its addresses, and will never send any requests. .It Fl staticarp If the Address Resolution Protocol is enabled, the host will perform normally, sending out requests and listening for replies. .It Cm broadcast (Inet only.) Specify the address to use to represent broadcasts to the network. The default broadcast address is the address with a host part of all 1's. .It Cm debug Enable driver dependent debugging code; usually, this turns on extra console error logging. .It Fl debug Disable driver dependent debugging code. .It Cm promisc Put interface into permanently promiscuous mode. .It Fl promisc Disable permanently promiscuous mode. .It Cm delete Another name for the .Fl alias parameter. .It Cm description Ar value , Cm descr Ar value Specify a description of the interface. This can be used to label interfaces in situations where they may otherwise be difficult to distinguish. .It Cm -description , Cm -descr Clear the interface description. .It Cm down Mark an interface .Dq down . When an interface is marked .Dq down , the system will not attempt to transmit messages through that interface. If possible, the interface will be reset to disable reception as well. This action does not automatically disable routes using the interface. .It Cm group Ar group-name Assign the interface to a .Dq group . Any interface can be in multiple groups. .Pp Cloned interfaces are members of their interface family group by default. For example, a PPP interface such as .Em ppp0 is a member of the PPP interface family group, .Em ppp . .\" The interface(s) the default route(s) point to are members of the .\" .Em egress .\" interface group. .It Cm -group Ar group-name Remove the interface from the given .Dq group . .It Cm eui64 (Inet6 only.) Fill interface index (lowermost 64bit of an IPv6 address) automatically. .It Cm fib Ar fib_number Specify interface FIB. A FIB .Ar fib_number is assigned to all frames or packets received on that interface. The FIB is not inherited, e.g., vlans or other sub-interfaces will use the default FIB (0) irrespective of the parent interface's FIB. The kernel needs to be tuned to support more than the default FIB using the .Va ROUTETABLES kernel configuration option, or the .Va net.fibs tunable. .It Cm tunnelfib Ar fib_number Specify tunnel FIB. A FIB .Ar fib_number is assigned to all packets encapsulated by tunnel interface, e.g., .Xr gif 4 and .Xr gre 4 . .It Cm maclabel Ar label If Mandatory Access Control support is enabled in the kernel, set the MAC label to .Ar label . .\" (see .\" .Xr maclabel 7 ) . .It Cm media Ar type If the driver supports the media selection system, set the media type of the interface to .Ar type . Some interfaces support the mutually exclusive use of one of several different physical media connectors. For example, a 10Mbit/s Ethernet interface might support the use of either .Tn AUI or twisted pair connectors. Setting the media type to .Cm 10base5/AUI would change the currently active connector to the AUI port. Setting it to .Cm 10baseT/UTP would activate twisted pair. Refer to the interfaces' driver specific documentation or man page for a complete list of the available types. .It Cm mediaopt Ar opts If the driver supports the media selection system, set the specified media options on the interface. The .Ar opts argument is a comma delimited list of options to apply to the interface. Refer to the interfaces' driver specific man page for a complete list of available options. .It Fl mediaopt Ar opts If the driver supports the media selection system, disable the specified media options on the interface. .It Cm mode Ar mode If the driver supports the media selection system, set the specified operating mode on the interface to .Ar mode . For IEEE 802.11 wireless interfaces that support multiple operating modes this directive is used to select between 802.11a .Pq Cm 11a , 802.11b .Pq Cm 11b , and 802.11g .Pq Cm 11g operating modes. .It Cm inst Ar minst , Cm instance Ar minst Set the media instance to .Ar minst . This is useful for devices which have multiple physical layer interfaces .Pq PHYs . .It Cm name Ar name Set the interface name to .Ar name . .It Cm rxcsum , txcsum , rxcsum6 , txcsum6 If the driver supports user-configurable checksum offloading, enable receive (or transmit) checksum offloading on the interface. The feature can be turned on selectively per protocol family. Use .Cm rxcsum6 , txcsum6 for .Xr ip6 4 or .Cm rxcsum , txcsum otherwise. Some drivers may not be able to enable these flags independently of each other, so setting one may also set the other. The driver will offload as much checksum work as it can reliably support, the exact level of offloading varies between drivers. .It Fl rxcsum , txcsum , rxcsum6 , txcsum6 If the driver supports user-configurable checksum offloading, disable receive (or transmit) checksum offloading on the interface. The feature can be turned off selectively per protocol family. Use .Fl rxcsum6 , txcsum6 for .Xr ip6 4 or .Fl rxcsum , txcsum otherwise. These settings may not always be independent of each other. .It Cm tso If the driver supports .Xr tcp 4 segmentation offloading, enable TSO on the interface. Some drivers may not be able to support TSO for .Xr ip 4 and .Xr ip6 4 packets, so they may enable only one of them. .It Fl tso If the driver supports .Xr tcp 4 segmentation offloading, disable TSO on the interface. It will always disable TSO for .Xr ip 4 and .Xr ip6 4 . .It Cm tso6 , tso4 If the driver supports .Xr tcp 4 segmentation offloading for .Xr ip6 4 or .Xr ip 4 use one of these to selectively enabled it only for one protocol family. .It Fl tso6 , tso4 If the driver supports .Xr tcp 4 segmentation offloading for .Xr ip6 4 or .Xr ip 4 use one of these to selectively disable it only for one protocol family. .It Cm lro If the driver supports .Xr tcp 4 large receive offloading, enable LRO on the interface. .It Fl lro If the driver supports .Xr tcp 4 large receive offloading, disable LRO on the interface. .It Cm wol , wol_ucast , wol_mcast , wol_magic Enable Wake On Lan (WOL) support, if available. WOL is a facility whereby a machine in a low power state may be woken in response to a received packet. There are three types of packets that may wake a system: ucast (directed solely to the machine's mac address), mcast (directed to a broadcast or multicast address), or magic (unicast or multicast frames with a ``magic contents''). Not all devices support WOL, those that do indicate the mechanisms they support in their capabilities. .Cm wol is a synonym for enabling all available WOL mechanisms. To disable WOL use .Fl wol . .It Cm vlanmtu , vlanhwtag, vlanhwfilter, vlanhwcsum, vlanhwtso If the driver offers user-configurable VLAN support, enable reception of extended frames, tag processing in hardware, frame filtering in hardware, checksum offloading, or TSO on VLAN, respectively. Note that this must be issued on a physical interface associated with .Xr vlan 4 , not on a .Xr vlan 4 interface itself. .It Fl vlanmtu , vlanhwtag, vlanhwfilter, vlanhwtso If the driver offers user-configurable VLAN support, disable reception of extended frames, tag processing in hardware, frame filtering in hardware, or TSO on VLAN, respectively. .It Cm vnet Ar jail Move the interface to the .Xr jail 8 , specified by name or JID. If the jail has a virtual network stack, the interface will disappear from the current environment and become visible to the jail. .It Fl vnet Ar jail Reclaim the interface from the .Xr jail 8 , specified by name or JID. If the jail has a virtual network stack, the interface will disappear from the jail, and become visible to the current network environment. .It Cm polling Turn on .Xr polling 4 feature and disable interrupts on the interface, if driver supports this mode. .It Fl polling Turn off .Xr polling 4 feature and enable interrupt mode on the interface. .It Cm create Create the specified network pseudo-device. If the interface is given without a unit number, try to create a new device with an arbitrary unit number. If creation of an arbitrary device is successful, the new device name is printed to standard output unless the interface is renamed or destroyed in the same .Nm invocation. .It Cm destroy Destroy the specified network pseudo-device. .It Cm plumb Another name for the .Cm create parameter. Included for .Tn Solaris compatibility. .It Cm unplumb Another name for the .Cm destroy parameter. Included for .Tn Solaris compatibility. .It Cm metric Ar n Set the routing metric of the interface to .Ar n , default 0. The routing metric is used by the routing protocol .Pq Xr routed 8 . Higher metrics have the effect of making a route less favorable; metrics are counted as additional hops to the destination network or host. .It Cm mtu Ar n Set the maximum transmission unit of the interface to .Ar n , default is interface specific. The MTU is used to limit the size of packets that are transmitted on an interface. Not all interfaces support setting the MTU, and some interfaces have range restrictions. .It Cm netmask Ar mask .\" (Inet and ISO.) (Inet only.) Specify how much of the address to reserve for subdividing networks into sub-networks. The mask includes the network part of the local address and the subnet part, which is taken from the host field of the address. The mask can be specified as a single hexadecimal number with a leading .Ql 0x , with a dot-notation Internet address, or with a pseudo-network name listed in the network table .Xr networks 5 . The mask contains 1's for the bit positions in the 32-bit address which are to be used for the network and subnet parts, and 0's for the host part. The mask should contain at least the standard network portion, and the subnet field should be contiguous with the network portion. .Pp The netmask can also be specified in CIDR notation after the address. See the .Ar address option above for more information. .It Cm prefixlen Ar len (Inet6 only.) Specify that .Ar len bits are reserved for subdividing networks into sub-networks. The .Ar len must be integer, and for syntactical reason it must be between 0 to 128. It is almost always 64 under the current IPv6 assignment rule. If the parameter is omitted, 64 is used. .Pp The prefix can also be specified using the slash notation after the address. See the .Ar address option above for more information. .It Cm remove Another name for the .Fl alias parameter. Introduced for compatibility with .Bsx . .Sm off .It Cm link Op Cm 0 No - Cm 2 .Sm on Enable special processing of the link level of the interface. These three options are interface specific in actual effect, however, they are in general used to select special modes of operation. An example of this is to enable SLIP compression, or to select the connector type for some Ethernet cards. Refer to the man page for the specific driver for more information. .Sm off .It Fl link Op Cm 0 No - Cm 2 .Sm on Disable special processing at the link level with the specified interface. .It Cm monitor Put the interface in monitor mode. No packets are transmitted, and received packets are discarded after .Xr bpf 4 processing. .It Fl monitor Take the interface out of monitor mode. .It Cm up Mark an interface .Dq up . This may be used to enable an interface after an .Dq Nm Cm down . It happens automatically when setting the first address on an interface. If the interface was reset when previously marked down, the hardware will be re-initialized. .El .Pp The following parameters are for ICMPv6 Neighbor Discovery Protocol. Note that the address family keyword .Dq Li inet6 is needed for them: .Bl -tag -width indent .It Cm accept_rtadv Set a flag to enable accepting ICMPv6 Router Advertisement messages. The .Xr sysctl 8 variable .Va net.inet6.ip6.accept_rtadv controls whether this flag is set by default or not. .It Cm -accept_rtadv Clear a flag .Cm accept_rtadv . .It Cm no_radr Set a flag to control whether routers from which the system accepts Router Advertisement messages will be added to the Default Router List or not. When the .Cm accept_rtadv flag is disabled, this flag has no effect. The .Xr sysctl 8 variable .Va net.inet6.ip6.no_radr controls whether this flag is set by default or not. .It Cm -no_radr Clear a flag .Cm no_radr . .It Cm auto_linklocal Set a flag to perform automatic link-local address configuration when the interface becomes available. The .Xr sysctl 8 variable .Va net.inet6.ip6.auto_linklocal controls whether this flag is set by default or not. .It Cm -auto_linklocal Clear a flag .Cm auto_linklocal . .It Cm defaultif Set the specified interface as the default route when there is no default router. .It Cm -defaultif Clear a flag .Cm defaultif . .It Cm ifdisabled Set a flag to disable all of IPv6 network communications on the specified interface. Note that if there are already configured IPv6 addresses on that interface, all of them are marked as .Dq tentative and DAD will be performed when this flag is cleared. .It Cm -ifdisabled Clear a flag .Cm ifdisabled . When this flag is cleared and .Cm auto_linklocal flag is enabled, automatic configuration of a link-local address is performed. .It Cm nud Set a flag to enable Neighbor Unreachability Detection. .It Cm -nud Clear a flag .Cm nud . .It Cm no_prefer_iface Set a flag to not honor rule 5 of source address selection in RFC 3484. In practice this means the address on the outgoing interface will not be preferred, effectively yielding the decision to the address selection policy table, configurable with .Xr ip6addrctl 8 . .It Cm -no_prefer_iface Clear a flag .Cm no_prefer_iface . .It Cm no_dad Set a flag to disable Duplicate Address Detection. .It Cm -no_dad Clear a flag .Cm no_dad . .El .Pp The following parameters are specific for IPv6 addresses. Note that the address family keyword .Dq Li inet6 is needed for them: .Bl -tag -width indent .It Cm prefer_source Set a flag to prefer address as a candidate of the source address for outgoing packets. .It Cm -prefer_source Clear a flag .Cm prefer_source . .El .Pp The following parameters are specific to cloning IEEE 802.11 wireless interfaces with the .Cm create request: .Bl -tag -width indent .It Cm wlandev Ar device Use .Ar device as the parent for the cloned device. .It Cm wlanmode Ar mode Specify the operating mode for this cloned device. .Ar mode is one of .Cm sta , .Cm ahdemo (or .Cm adhoc-demo ), .Cm ibss , (or .Cm adhoc ), .Cm ap , (or .Cm hostap ), .Cm wds , .Cm tdma , .Cm mesh , and .Cm monitor . The operating mode of a cloned interface cannot be changed. The .Cm tdma mode is actually implemented as an .Cm adhoc-demo interface with special properties. .It Cm wlanbssid Ar bssid The 802.11 mac address to use for the bssid. This must be specified at create time for a legacy .Cm wds device. .It Cm wlanaddr Ar address The local mac address. If this is not specified then a mac address will automatically be assigned to the cloned device. Typically this address is the same as the address of the parent device but if the .Cm bssid parameter is specified then the driver will craft a unique address for the device (if supported). .It Cm wdslegacy Mark a .Cm wds device as operating in ``legacy mode''. Legacy .Cm wds devices have a fixed peer relationship and do not, for example, roam if their peer stops communicating. For completeness a Dynamic WDS (DWDS) interface may marked as .Fl wdslegacy . .It Cm bssid Request a unique local mac address for the cloned device. This is only possible if the device supports multiple mac addresses. To force use of the parent's mac address use .Fl bssid . .It Cm beacons Mark the cloned interface as depending on hardware support to track received beacons. To have beacons tracked in software use .Fl beacons . For .Cm hostap mode .Fl beacons can also be used to indicate no beacons should be transmitted; this can be useful when creating a WDS configuration but .Cm wds interfaces can only be created as companions to an access point. .El .Pp The following parameters are specific to IEEE 802.11 wireless interfaces cloned with a .Cm create operation: .Bl -tag -width indent .It Cm ampdu Enable sending and receiving AMPDU frames when using 802.11n (default). The 802.11n specification states a compliant station must be capable of receiving AMPDU frames but transmission is optional. Use .Fl ampdu to disable all use of AMPDU with 802.11n. For testing and/or to work around interoperability problems one can use .Cm ampdutx and .Cm ampdurx to control use of AMPDU in one direction. .It Cm ampdudensity Ar density Set the AMPDU density parameter used when operating with 802.11n. This parameter controls the inter-packet gap for AMPDU frames. The sending device normally controls this setting but a receiving station may request wider gaps. Legal values for .Ar density are 0, .25, .5, 1, 2, 4, 8, and 16 (microseconds). A value of .Cm - is treated the same as 0. .It Cm ampdulimit Ar limit Set the limit on packet size for receiving AMPDU frames when operating with 802.11n. Legal values for .Ar limit are 8192, 16384, 32768, and 65536 but one can also specify just the unique prefix: 8, 16, 32, 64. Note the sender may limit the size of AMPDU frames to be less than the maximum specified by the receiving station. .It Cm amsdu Enable sending and receiving AMSDU frames when using 802.11n. By default AMSDU is received but not transmitted. Use .Fl amsdu to disable all use of AMSDU with 802.11n. For testing and/or to work around interoperability problems one can use .Cm amsdutx and .Cm amsdurx to control use of AMSDU in one direction. .It Cm amsdulimit Ar limit Set the limit on packet size for sending and receiving AMSDU frames when operating with 802.11n. Legal values for .Ar limit are 7935 and 3839 (bytes). Note the sender may limit the size of AMSDU frames to be less than the maximum specified by the receiving station. Note also that devices are not required to support the 7935 limit, only 3839 is required by the specification and the larger value may require more memory to be dedicated to support functionality that is rarely used. .It Cm apbridge When operating as an access point, pass packets between wireless clients directly (default). To instead let them pass up through the system and be forwarded using some other mechanism, use .Fl apbridge . Disabling the internal bridging is useful when traffic is to be processed with packet filtering. .It Cm authmode Ar mode Set the desired authentication mode in infrastructure mode. Not all adapters support all modes. The set of valid modes is .Cm none , open , shared (shared key), .Cm 8021x (IEEE 802.1x), and .Cm wpa (IEEE WPA/WPA2/802.11i). The .Cm 8021x and .Cm wpa modes are only useful when using an authentication service (a supplicant for client operation or an authenticator when operating as an access point). Modes are case insensitive. .It Cm bgscan Enable background scanning when operating as a station. Background scanning is a technique whereby a station associated to an access point will temporarily leave the channel to scan for neighboring stations. This allows a station to maintain a cache of nearby access points so that roaming between access points can be done without a lengthy scan operation. Background scanning is done only when a station is not busy and any outbound traffic will cancel a scan operation. Background scanning should never cause packets to be lost though there may be some small latency if outbound traffic interrupts a scan operation. By default background scanning is enabled if the device is capable. To disable background scanning, use .Fl bgscan . Background scanning is controlled by the .Cm bgscanidle and .Cm bgscanintvl parameters. Background scanning must be enabled for roaming; this is an artifact of the current implementation and may not be required in the future. .It Cm bgscanidle Ar idletime Set the minimum time a station must be idle (not transmitting or receiving frames) before a background scan is initiated. The .Ar idletime parameter is specified in milliseconds. By default a station must be idle at least 250 milliseconds before a background scan is initiated. The idle time may not be set to less than 100 milliseconds. .It Cm bgscanintvl Ar interval Set the interval at which background scanning is attempted. The .Ar interval parameter is specified in seconds. By default a background scan is considered every 300 seconds (5 minutes). The .Ar interval may not be set to less than 15 seconds. .It Cm bintval Ar interval Set the interval at which beacon frames are sent when operating in ad-hoc or ap mode. The .Ar interval parameter is specified in TU's (1024 usecs). By default beacon frames are transmitted every 100 TU's. .It Cm bmissthreshold Ar count Set the number of consecutive missed beacons at which the station will attempt to roam (i.e., search for a new access point). The .Ar count parameter must be in the range 1 to 255; though the upper bound may be reduced according to device capabilities. The default threshold is 7 consecutive missed beacons; but this may be overridden by the device driver. Another name for the .Cm bmissthreshold parameter is .Cm bmiss . .It Cm bssid Ar address Specify the MAC address of the access point to use when operating as a station in a BSS network. This overrides any automatic selection done by the system. To disable a previously selected access point, supply .Cm any , none , or .Cm - for the address. This option is useful when more than one access point uses the same SSID. Another name for the .Cm bssid parameter is .Cm ap . .It Cm burst Enable packet bursting. Packet bursting is a transmission technique whereby the wireless medium is acquired once to send multiple frames and the interframe spacing is reduced. This technique can significantly increase throughput by reducing transmission overhead. Packet bursting is supported by the 802.11e QoS specification and some devices that do not support QoS may still be capable. By default packet bursting is enabled if a device is capable of doing it. To disable packet bursting, use .Fl burst . .It Cm chanlist Ar channels Set the desired channels to use when scanning for access points, neighbors in an IBSS network, or looking for unoccupied channels when operating as an access point. The set of channels is specified as a comma-separated list with each element in the list representing either a single channel number or a range of the form .Dq Li a-b . Channel numbers must be in the range 1 to 255 and be permissible according to the operating characteristics of the device. .It Cm channel Ar number Set a single desired channel. Channels range from 1 to 255, but the exact selection available depends on the region your adaptor was manufactured for. Setting the channel to .Li any , or .Cm - will clear any desired channel and, if the device is marked up, force a scan for a channel to operate on. Alternatively the frequency, in megahertz, may be specified instead of the channel number. .Pp When there are several ways to use a channel the channel number/frequency may be appended with attributes to clarify. For example, if a device is capable of operating on channel 6 with 802.11n and 802.11g then one can specify that g-only use should be used by specifying ``6:g''. Similarly the channel width can be specified by appending it with ``/''; e.g., ``6/40'' specifies a 40MHz wide channel, These attributes can be combined as in: ``6:ht/40''. The full set of flags specified following a ``:'' are: .Cm a (802.11a), .Cm b (802.11b), .Cm d (Atheros Dynamic Turbo mode), .Cm g (802.11g), .Cm h or .Cm n (802.11n aka HT), .Cm s (Atheros Static Turbo mode), and .Cm t (Atheros Dynamic Turbo mode, or appended to ``st'' and ``dt''). The full set of channel widths following a '/' are: .Cm 5 (5MHz aka quarter-rate channel), .Cm 10 (10MHz aka half-rate channel), .Cm 20 (20MHz mostly for use in specifying ht20), and .Cm 40 (40MHz mostly for use in specifying ht40). In addition, a 40MHz HT channel specification may include the location of the extension channel by appending ``+'' or ``-'' for above and below, respectively; e.g., ``2437:ht/40+'' specifies 40MHz wide HT operation with the center channel at frequency 2437 and the extension channel above. .It Cm country Ar name Set the country code to use in calculating the regulatory constraints for operation. In particular the set of available channels, how the wireless device will operation on the channels, and the maximum transmit power that can be used on a channel are defined by this setting. Country/Region codes are specified as a 2-character abbreviation defined by ISO 3166 or using a longer, but possibly ambiguous, spelling; e.g., "ES" and "Spain". The set of country codes are taken from .Pa /etc/regdomain.xml and can also be viewed with the ``list countries'' request. Note that not all devices support changing the country code from a default setting; typically stored in EEPROM. See also .Cm regdomain , .Cm indoor , .Cm outdoor , and .Cm anywhere . .It Cm dfs Enable Dynamic Frequency Selection (DFS) as specified in 802.11h. DFS embodies several facilities including detection of overlapping radar signals, dynamic transmit power control, and channel selection according to a least-congested criteria. DFS support is mandatory for some 5GHz frequencies in certain locales (e.g., ETSI). By default DFS is enabled according to the regulatory definitions specified in .Pa /etc/regdomain.xml and the current country code, regdomain, and channel. Note the underlying device (and driver) must support radar detection for full DFS support to work. To be fully compliant with the local regulatory agency frequencies that require DFS should not be used unless it is fully supported. Use .Fl dfs to disable this functionality for testing. .It Cm dotd Enable support for the 802.11d specification (default). When this support is enabled in station mode, beacon frames that advertise a country code different than the currently configured country code will cause an event to be dispatched to user applications. This event can be used by the station to adopt that country code and operate according to the associated regulatory constraints. When operating as an access point with 802.11d enabled the beacon and probe response frames transmitted will advertise the current regulatory domain settings. To disable 802.11d use .Fl dotd . .It Cm doth Enable 802.11h support including spectrum management. When 802.11h is enabled beacon and probe response frames will have the SpectrumMgt bit set in the capabilities field and country and power constraint information elements will be present. 802.11h support also includes handling Channel Switch Announcements (CSA) which are a mechanism to coordinate channel changes by an access point. By default 802.11h is enabled if the device is capable. To disable 802.11h use .Fl doth . .It Cm deftxkey Ar index Set the default key to use for transmission. Typically this is only set when using WEP encryption. Note that you must set a default transmit key for the system to know which key to use in encrypting outbound traffic. The .Cm weptxkey is an alias for this request; it is provided for backwards compatibility. .It Cm dtimperiod Ar period Set the DTIM period for transmitting buffered multicast data frames when operating in ap mode. The .Ar period specifies the number of beacon intervals between DTIM and must be in the range 1 to 15. By default DTIM is 1 (i.e., DTIM occurs at each beacon). .It Cm quiet Enable the use of quiet IE. Hostap will use this to silence other stations to reduce interference for radar detection when operating on 5GHz frequency and doth support is enabled. Use .Fl quiet to disable this functionality. .It Cm quiet_period Ar period Set the QUIET .Ar period to the number of beacon intervals between the start of regularly scheduled quiet intervals defined by Quiet element. .It Cm quiet_count Ar count Set the QUIET .Ar count to the number of TBTTs until the beacon interval during which the next quiet interval shall start. A value of 1 indicates the quiet interval will start during the beacon interval starting at the next TBTT. A value 0 is reserved. .It Cm quiet_offset Ar offset Set the QUIET .Ar offset to the offset of the start of the quiet interval from the TBTT specified by the Quiet count, expressed in TUs. The value of the .Ar offset shall be less than one beacon interval. .It Cm quiet_duration Ar dur Set the QUIET .Ar dur to the duration of the Quiet interval, expressed in TUs. The value should be less than beacon interval. .It Cm dturbo Enable the use of Atheros Dynamic Turbo mode when communicating with another Dynamic Turbo-capable station. Dynamic Turbo mode is an Atheros-specific mechanism by which stations switch between normal 802.11 operation and a ``boosted'' mode in which a 40MHz wide channel is used for communication. Stations using Dynamic Turbo mode operate boosted only when the channel is free of non-dturbo stations; when a non-dturbo station is identified on the channel all stations will automatically drop back to normal operation. By default, Dynamic Turbo mode is not enabled, even if the device is capable. Note that turbo mode (dynamic or static) is only allowed on some channels depending on the regulatory constraints; use the .Cm list chan command to identify the channels where turbo mode may be used. To disable Dynamic Turbo mode use .Fl dturbo . .It Cm dwds Enable Dynamic WDS (DWDS) support. DWDS is a facility by which 4-address traffic can be carried between stations operating in infrastructure mode. A station first associates to an access point and authenticates using normal procedures (e.g., WPA). Then 4-address frames are passed to carry traffic for stations operating on either side of the wireless link. DWDS extends the normal WDS mechanism by leveraging existing security protocols and eliminating static binding. .Pp When DWDS is enabled on an access point 4-address frames received from an authorized station will generate a ``DWDS discovery'' event to user applications. This event should be used to create a WDS interface that is bound to the remote station (and usually plumbed into a bridge). Once the WDS interface is up and running 4-address traffic then logically flows through that interface. .Pp When DWDS is enabled on a station, traffic with a destination address different from the peer station are encapsulated in a 4-address frame and transmitted to the peer. All 4-address traffic uses the security information of the stations (e.g., cryptographic keys). A station is associated using 802.11n facilities may transport 4-address traffic using these same mechanisms; this depends on available resources and capabilities of the device. The DWDS implementation guards against layer 2 routing loops of multicast traffic. .It Cm ff Enable the use of Atheros Fast Frames when communicating with another Fast Frames-capable station. Fast Frames are an encapsulation technique by which two 802.3 frames are transmitted in a single 802.11 frame. This can noticeably improve throughput but requires that the receiving station understand how to decapsulate the frame. Fast frame use is negotiated using the Atheros 802.11 vendor-specific protocol extension so enabling use is safe when communicating with non-Atheros devices. By default, use of fast frames is enabled if the device is capable. To explicitly disable fast frames, use .Fl ff . .It Cm fragthreshold Ar length Set the threshold for which transmitted frames are broken into fragments. The .Ar length argument is the frame size in bytes and must be in the range 256 to 2346. Setting .Ar length to .Li 2346 , .Cm any , or .Cm - disables transmit fragmentation. Not all adapters honor the fragmentation threshold. .It Cm hidessid When operating as an access point, do not broadcast the SSID in beacon frames or respond to probe request frames unless they are directed to the ap (i.e., they include the ap's SSID). By default, the SSID is included in beacon frames and undirected probe request frames are answered. To re-enable the broadcast of the SSID etc., use .Fl hidessid . .It Cm ht Enable use of High Throughput (HT) when using 802.11n (default). The 802.11n specification includes mechanisms for operation on 20MHz and 40MHz wide channels using different signalling mechanisms than specified in 802.11b, 802.11g, and 802.11a. Stations negotiate use of these facilities, termed HT20 and HT40, when they associate. To disable all use of 802.11n use .Fl ht . To disable use of HT20 (e.g., to force only HT40 use) use .Fl ht20 . To disable use of HT40 use .Fl ht40 . .Pp HT configuration is used to ``auto promote'' operation when several choices are available. For example, if a station associates to an 11n-capable access point it controls whether the station uses legacy operation, HT20, or HT40. When an 11n-capable device is setup as an access point and Auto Channel Selection is used to locate a channel to operate on, HT configuration controls whether legacy, HT20, or HT40 operation is setup on the selected channel. If a fixed channel is specified for a station then HT configuration can be given as part of the channel specification; e.g., 6:ht/20 to setup HT20 operation on channel 6. .It Cm htcompat Enable use of compatibility support for pre-802.11n devices (default). The 802.11n protocol specification went through several incompatible iterations. Some vendors implemented 11n support to older specifications that will not interoperate with a purely 11n-compliant station. In particular the information elements included in management frames for old devices are different. When compatibility support is enabled both standard and compatible data will be provided. Stations that associate using the compatibility mechanisms are flagged in ``list sta''. To disable compatibility support use .Fl htcompat . .It Cm htprotmode Ar technique For interfaces operating in 802.11n, use the specified .Ar technique for protecting HT frames in a mixed legacy/HT network. The set of valid techniques is .Cm off , and .Cm rts (RTS/CTS, default). Technique names are case insensitive. .It Cm inact Enable inactivity processing for stations associated to an access point (default). When operating as an access point the 802.11 layer monitors the activity of each associated station. When a station is inactive for 5 minutes it will send several ``probe frames'' to see if the station is still present. If no response is received then the station is deauthenticated. Applications that prefer to handle this work can disable this facility by using .Fl inact . .It Cm indoor Set the location to use in calculating regulatory constraints. The location is also advertised in beacon and probe response frames when 802.11d is enabled with .Cm dotd . See also .Cm outdoor , .Cm anywhere , .Cm country , and .Cm regdomain . .It Cm list active Display the list of channels available for use taking into account any restrictions set with the .Cm chanlist directive. See the description of .Cm list chan for more information. .It Cm list caps Display the adaptor's capabilities, including the operating modes supported. .It Cm list chan Display the list of channels available for use. Channels are shown with their IEEE channel number, equivalent frequency, and usage modes. Channels identified as .Ql 11g are also usable in .Ql 11b mode. Channels identified as .Ql 11a Turbo may be used only for Atheros' Static Turbo mode (specified with . Cm mediaopt turbo ) . Channels marked with a .Ql * have a regulatory constraint that they be passively scanned. This means a station is not permitted to transmit on the channel until it identifies the channel is being used for 802.11 communication; typically by hearing a beacon frame from an access point operating on the channel. .Cm list freq is another way of requesting this information. By default a compacted list of channels is displayed; if the .Fl v option is specified then all channels are shown. .It Cm list countries Display the set of country codes and regulatory domains that can be used in regulatory configuration. .It Cm list mac Display the current MAC Access Control List state. Each address is prefixed with a character that indicates the current policy applied to it: .Ql + indicates the address is allowed access, .Ql - indicates the address is denied access, .Ql * indicates the address is present but the current policy open (so the ACL is not consulted). .It Cm list mesh Displays the mesh routing table, used for forwarding packets on a mesh network. .It Cm list regdomain Display the current regulatory settings including the available channels and transmit power caps. .It Cm list roam Display the parameters that govern roaming operation. .It Cm list txparam Display the parameters that govern transmit operation. .It Cm list txpower Display the transmit power caps for each channel. .It Cm list scan Display the access points and/or ad-hoc neighbors located in the vicinity. This information may be updated automatically by the adapter with a .Cm scan request or through background scanning. Depending on the capabilities of the stations the following flags can be included in the output: .Bl -tag -width 3n .It Li A Authorized. Indicates that the station is permitted to send/receive data frames. .It Li E Extended Rate Phy (ERP). Indicates that the station is operating in an 802.11g network using extended transmit rates. .It Li H High Throughput (HT). Indicates that the station is using HT transmit rates. If a `+' follows immediately after then the station associated using deprecated mechanisms supported only when .Cm htcompat is enabled. .It Li P Power Save. Indicates that the station is operating in power save mode. .It Li Q Quality of Service (QoS). Indicates that the station is using QoS encapsulation for data frame. QoS encapsulation is enabled only when WME mode is enabled. .It Li S Short Preamble. Indicates that the station is doing short preamble to optionally improve throughput performance with 802.11g and 802.11b. .It Li T Transitional Security Network (TSN). Indicates that the station associated using TSN; see also .Cm tsn below. .It Li W Wi-Fi Protected Setup (WPS). Indicates that the station associated using WPS. .El .Pp By default interesting information elements captured from the neighboring stations are displayed at the end of each row. Possible elements include: .Cm WME (station supports WME), .Cm WPA (station supports WPA), .Cm WPS (station supports WPS), .Cm RSN (station supports 802.11i/RSN), .Cm HTCAP (station supports 802.11n/HT communication), .Cm ATH (station supports Atheros protocol extensions), .Cm VEN (station supports unknown vendor-specific extensions). If the .Fl v flag is used all the information elements and their contents will be shown. Specifying the .Fl v flag also enables display of long SSIDs. The .Cm list ap command is another way of requesting this information. .It Cm list sta When operating as an access point display the stations that are currently associated. When operating in ad-hoc mode display stations identified as neighbors in the IBSS. When operating in mesh mode display stations identified as neighbors in the MBSS. When operating in station mode display the access point. Capabilities advertised by the stations are described under the .Cm scan request. Depending on the capabilities of the stations the following flags can be included in the output: .Bl -tag -width 3n .It Li A Authorized. Indicates that the station is permitted to send/receive data frames. .It Li E Extended Rate Phy (ERP). Indicates that the station is operating in an 802.11g network using extended transmit rates. .It Li H High Throughput (HT). Indicates that the station is using HT transmit rates. If a `+' follows immediately after then the station associated using deprecated mechanisms supported only when .Cm htcompat is enabled. .It Li P Power Save. Indicates that the station is operating in power save mode. .It Li Q Quality of Service (QoS). Indicates that the station is using QoS encapsulation for data frame. QoS encapsulation is enabled only when WME mode is enabled. .It Li S Short Preamble. Indicates that the station is doing short preamble to optionally improve throughput performance with 802.11g and 802.11b. .It Li T Transitional Security Network (TSN). Indicates that the station associated using TSN; see also .Cm tsn below. .It Li W Wi-Fi Protected Setup (WPS). Indicates that the station associated using WPS. .El .Pp By default information elements received from associated stations are displayed in a short form; the .Fl v flag causes this information to be displayed symbolically. .It Cm list wme Display the current channel parameters to use when operating in WME mode. If the .Fl v option is specified then both channel and BSS parameters are displayed for each AC (first channel, then BSS). When WME mode is enabled for an adaptor this information will be displayed with the regular status; this command is mostly useful for examining parameters when WME mode is disabled. See the description of the .Cm wme directive for information on the various parameters. .It Cm maxretry Ar count Set the maximum number of tries to use in sending unicast frames. The default setting is 6 but drivers may override this with a value they choose. .It Cm mcastrate Ar rate Set the rate for transmitting multicast/broadcast frames. Rates are specified as megabits/second in decimal; e.g.,\& 5.5 for 5.5 Mb/s. This rate should be valid for the current operating conditions; if an invalid rate is specified drivers are free to chose an appropriate rate. .It Cm mgtrate Ar rate Set the rate for transmitting management and/or control frames. Rates are specified as megabits/second in decimal; e.g.,\& 5.5 for 5.5 Mb/s. .It Cm outdoor Set the location to use in calculating regulatory constraints. The location is also advertised in beacon and probe response frames when 802.11d is enabled with .Cm dotd . See also .Cm anywhere , .Cm country , .Cm indoor , and .Cm regdomain . .It Cm powersave Enable powersave operation. When operating as a client, the station will conserve power by periodically turning off the radio and listening for messages from the access point telling it there are packets waiting. The station must then retrieve the packets. Not all devices support power save operation as a client. The 802.11 specification requires that all access points support power save but some drivers do not. Use .Fl powersave to disable powersave operation when operating as a client. .It Cm powersavesleep Ar sleep Set the desired max powersave sleep time in TU's (1024 usecs). By default the max powersave sleep time is 100 TU's. .It Cm protmode Ar technique For interfaces operating in 802.11g, use the specified .Ar technique for protecting OFDM frames in a mixed 11b/11g network. The set of valid techniques is .Cm off , cts (CTS to self), and .Cm rtscts (RTS/CTS). Technique names are case insensitive. Not all devices support .Cm cts as a protection technique. .It Cm pureg When operating as an access point in 802.11g mode allow only 11g-capable stations to associate (11b-only stations are not permitted to associate). To allow both 11g and 11b-only stations to associate, use .Fl pureg . .It Cm puren When operating as an access point in 802.11n mode allow only HT-capable stations to associate (legacy stations are not permitted to associate). To allow both HT and legacy stations to associate, use .Fl puren . .It Cm regdomain Ar sku Set the regulatory domain to use in calculating the regulatory constraints for operation. In particular the set of available channels, how the wireless device will operation on the channels, and the maximum transmit power that can be used on a channel are defined by this setting. Regdomain codes (SKU's) are taken from .Pa /etc/regdomain.xml and can also be viewed with the ``list countries'' request. Note that not all devices support changing the regdomain from a default setting; typically stored in EEPROM. See also .Cm country , .Cm indoor , .Cm outdoor , and .Cm anywhere . .It Cm rifs Enable use of Reduced InterFrame Spacing (RIFS) when operating in 802.11n on an HT channel. Note that RIFS must be supported by both the station and access point for it to be used. To disable RIFS use .Fl rifs . .It Cm roam:rate Ar rate Set the threshold for controlling roaming when operating in a BSS. The .Ar rate parameter specifies the transmit rate in megabits at which roaming should be considered. If the current transmit rate drops below this setting and background scanning is enabled, then the system will check if a more desirable access point is available and switch over to it. The current scan cache contents are used if they are considered valid according to the .Cm scanvalid parameter; otherwise a background scan operation is triggered before any selection occurs. Each channel type has a separate rate threshold; the default values are: 12 Mb/s (11a), 2 Mb/s (11b), 2 Mb/s (11g), MCS 1 (11na, 11ng). .It Cm roam:rssi Ar rssi Set the threshold for controlling roaming when operating in a BSS. The .Ar rssi parameter specifies the receive signal strength in dBm units at which roaming should be considered. If the current rssi drops below this setting and background scanning is enabled, then the system will check if a more desirable access point is available and switch over to it. The current scan cache contents are used if they are considered valid according to the .Cm scanvalid parameter; otherwise a background scan operation is triggered before any selection occurs. Each channel type has a separate rssi threshold; the default values are all 7 dBm. .It Cm roaming Ar mode When operating as a station, control how the system will behave when communication with the current access point is broken. The .Ar mode argument may be one of .Cm device (leave it to the hardware device to decide), .Cm auto (handle either in the device or the operating system\[em]as appropriate), .Cm manual (do nothing until explicitly instructed). By default, the device is left to handle this if it is capable; otherwise, the operating system will automatically attempt to reestablish communication. Manual mode is used by applications such as .Xr wpa_supplicant 8 that want to control the selection of an access point. .It Cm rtsthreshold Ar length Set the threshold for which transmitted frames are preceded by transmission of an RTS control frame. The .Ar length argument is the frame size in bytes and must be in the range 1 to 2346. Setting .Ar length to .Li 2346 , .Cm any , or .Cm - disables transmission of RTS frames. Not all adapters support setting the RTS threshold. .It Cm scan Initiate a scan of neighboring stations, wait for it to complete, and display all stations found. Only the super-user can initiate a scan. See .Cm list scan for information on the display. By default a background scan is done; otherwise a foreground scan is done and the station may roam to a different access point. The .Cm list scan request can be used to show recent scan results without initiating a new scan. .It Cm scanvalid Ar threshold Set the maximum time the scan cache contents are considered valid; i.e., will be used without first triggering a scan operation to refresh the data. The .Ar threshold parameter is specified in seconds and defaults to 60 seconds. The minimum setting for .Ar threshold is 10 seconds. One should take care setting this threshold; if it is set too low then attempts to roam to another access point may trigger unnecessary background scan operations. .It Cm shortgi Enable use of Short Guard Interval when operating in 802.11n on an HT channel. NB: this currently enables Short GI on both HT40 and HT20 channels. To disable Short GI use .Fl shortgi . .It Cm smps Enable use of Static Spatial Multiplexing Power Save (SMPS) when operating in 802.11n. A station operating with Static SMPS maintains only a single receive chain active (this can significantly reduce power consumption). To disable SMPS use .Fl smps . .It Cm smpsdyn Enable use of Dynamic Spatial Multiplexing Power Save (SMPS) when operating in 802.11n. A station operating with Dynamic SMPS maintains only a single receive chain active but switches to multiple receive chains when it receives an RTS frame (this can significantly reduce power consumption). Note that stations cannot distinguish between RTS/CTS intended to enable multiple receive chains and those used for other purposes. To disable SMPS use .Fl smps . .It Cm ssid Ar ssid Set the desired Service Set Identifier (aka network name). The SSID is a string up to 32 characters in length and may be specified as either a normal string or in hexadecimal when preceded by .Ql 0x . Additionally, the SSID may be cleared by setting it to .Ql - . .It Cm tdmaslot Ar slot When operating with TDMA, use the specified .Ar slot configuration. The .Ar slot is a number between 0 and the maximum number of slots in the BSS. Note that a station configured as slot 0 is a master and will broadcast beacon frames advertising the BSS; stations configured to use other slots will always scan to locate a master before they ever transmit. By default .Cm tdmaslot is set to 1. .It Cm tdmaslotcnt Ar cnt When operating with TDMA, setup a BSS with .Ar cnt slots. The slot count may be at most 8. The current implementation is only tested with two stations (i.e., point to point applications). This setting is only meaningful when a station is configured as slot 0; other stations adopt this setting from the BSS they join. By default .Cm tdmaslotcnt is set to 2. .It Cm tdmaslotlen Ar len When operating with TDMA, setup a BSS such that each station has a slot .Ar len microseconds long. The slot length must be at least 150 microseconds (1/8 TU) and no more than 65 milliseconds. Note that setting too small a slot length may result in poor channel bandwidth utilization due to factors such as timer granularity and guard time. This setting is only meaningful when a station is configured as slot 0; other stations adopt this setting from the BSS they join. By default .Cm tdmaslotlen is set to 10 milliseconds. .It Cm tdmabintval Ar intval When operating with TDMA, setup a BSS such that beacons are transmitted every .Ar intval superframes to synchronize the TDMA slot timing. A superframe is defined as the number of slots times the slot length; e.g., a BSS with two slots of 10 milliseconds has a 20 millisecond superframe. The beacon interval may not be zero. A lower setting of .Cm tdmabintval causes the timers to be resynchronized more often; this can be help if significant timer drift is observed. By default .Cm tdmabintval is set to 5. .It Cm tsn When operating as an access point with WPA/802.11i allow legacy stations to associate using static key WEP and open authentication. To disallow legacy station use of WEP, use .Fl tsn . .It Cm txpower Ar power Set the power used to transmit frames. The .Ar power argument is specified in .5 dBm units. Out of range values are truncated. Typically only a few discreet power settings are available and the driver will use the setting closest to the specified value. Not all adapters support changing the transmit power. .It Cm ucastrate Ar rate Set a fixed rate for transmitting unicast frames. Rates are specified as megabits/second in decimal; e.g.,\& 5.5 for 5.5 Mb/s. This rate should be valid for the current operating conditions; if an invalid rate is specified drivers are free to chose an appropriate rate. .It Cm wepmode Ar mode Set the desired WEP mode. Not all adapters support all modes. The set of valid modes is .Cm off , on , and .Cm mixed . The .Cm mixed mode explicitly tells the adaptor to allow association with access points which allow both encrypted and unencrypted traffic. On these adapters, .Cm on means that the access point must only allow encrypted connections. On other adapters, .Cm on is generally another name for .Cm mixed . Modes are case insensitive. .It Cm weptxkey Ar index Set the WEP key to be used for transmission. This is the same as setting the default transmission key with .Cm deftxkey . .It Cm wepkey Ar key Ns | Ns Ar index : Ns Ar key Set the selected WEP key. If an .Ar index is not given, key 1 is set. A WEP key will be either 5 or 13 characters (40 or 104 bits) depending on the local network and the capabilities of the adaptor. It may be specified either as a plain string or as a string of hexadecimal digits preceded by .Ql 0x . For maximum portability, hex keys are recommended; the mapping of text keys to WEP encryption is usually driver-specific. In particular, the .Tn Windows drivers do this mapping differently to .Fx . A key may be cleared by setting it to .Ql - . If WEP is supported then there are at least four keys. Some adapters support more than four keys. If that is the case, then the first four keys (1-4) will be the standard temporary keys and any others will be adaptor specific keys such as permanent keys stored in NVRAM. .Pp Note that you must set a default transmit key with .Cm deftxkey for the system to know which key to use in encrypting outbound traffic. .It Cm wme Enable Wireless Multimedia Extensions (WME) support, if available, for the specified interface. WME is a subset of the IEEE 802.11e standard to support the efficient communication of realtime and multimedia data. To disable WME support, use .Fl wme . Another name for this parameter is .Cm wmm . .Pp The following parameters are meaningful only when WME support is in use. Parameters are specified per-AC (Access Category) and split into those that are used by a station when acting as an access point and those for client stations in the BSS. The latter are received from the access point and may not be changed (at the station). The following Access Categories are recognized: .Pp .Bl -tag -width ".Cm AC_BK" -compact .It Cm AC_BE (or .Cm BE ) best effort delivery, .It Cm AC_BK (or .Cm BK ) background traffic, .It Cm AC_VI (or .Cm VI ) video traffic, .It Cm AC_VO (or .Cm VO ) voice traffic. .El .Pp AC parameters are case-insensitive. Traffic classification is done in the operating system using the vlan priority associated with data frames or the ToS (Type of Service) indication in IP-encapsulated frames. If neither information is present, traffic is assigned to the Best Effort (BE) category. .Bl -tag -width indent .It Cm ack Ar ac Set the ACK policy for QoS transmissions by the local station; this controls whether or not data frames transmitted by a station require an ACK response from the receiving station. To disable waiting for an ACK use .Fl ack . This parameter is applied only to the local station. .It Cm acm Ar ac Enable the Admission Control Mandatory (ACM) mechanism for transmissions by the local station. To disable the ACM use .Fl acm . On stations in a BSS this parameter is read-only and indicates the setting received from the access point. NB: ACM is not supported right now. .It Cm aifs Ar ac Ar count Set the Arbitration Inter Frame Spacing (AIFS) channel access parameter to use for transmissions by the local station. On stations in a BSS this parameter is read-only and indicates the setting received from the access point. .It Cm cwmin Ar ac Ar count Set the CWmin channel access parameter to use for transmissions by the local station. On stations in a BSS this parameter is read-only and indicates the setting received from the access point. .It Cm cwmax Ar ac Ar count Set the CWmax channel access parameter to use for transmissions by the local station. On stations in a BSS this parameter is read-only and indicates the setting received from the access point. .It Cm txoplimit Ar ac Ar limit Set the Transmission Opportunity Limit channel access parameter to use for transmissions by the local station. This parameter defines an interval of time when a WME station has the right to initiate transmissions onto the wireless medium. On stations in a BSS this parameter is read-only and indicates the setting received from the access point. .It Cm bss:aifs Ar ac Ar count Set the AIFS channel access parameter to send to stations in a BSS. This parameter is meaningful only when operating in ap mode. .It Cm bss:cwmin Ar ac Ar count Set the CWmin channel access parameter to send to stations in a BSS. This parameter is meaningful only when operating in ap mode. .It Cm bss:cwmax Ar ac Ar count Set the CWmax channel access parameter to send to stations in a BSS. This parameter is meaningful only when operating in ap mode. .It Cm bss:txoplimit Ar ac Ar limit Set the TxOpLimit channel access parameter to send to stations in a BSS. This parameter is meaningful only when operating in ap mode. .El .It Cm wps Enable Wireless Privacy Subscriber support. Note that WPS support requires a WPS-capable supplicant. To disable this function use .Fl wps . .El .Pp The following parameters support an optional access control list feature available with some adapters when operating in ap mode; see .Xr wlan_acl 4 . This facility allows an access point to accept/deny association requests based on the MAC address of the station. Note that this feature does not significantly enhance security as MAC address spoofing is easy to do. .Bl -tag -width indent .It Cm mac:add Ar address Add the specified MAC address to the database. Depending on the policy setting association requests from the specified station will be allowed or denied. .It Cm mac:allow Set the ACL policy to permit association only by stations registered in the database. .It Cm mac:del Ar address Delete the specified MAC address from the database. .It Cm mac:deny Set the ACL policy to deny association only by stations registered in the database. .It Cm mac:kick Ar address Force the specified station to be deauthenticated. This typically is done to block a station after updating the address database. .It Cm mac:open Set the ACL policy to allow all stations to associate. .It Cm mac:flush Delete all entries in the database. .It Cm mac:radius Set the ACL policy to permit association only by stations approved by a RADIUS server. Note that this feature requires the .Xr hostapd 8 program be configured to do the right thing as it handles the RADIUS processing (and marks stations as authorized). .El .Pp The following parameters are related to a wireless interface operating in mesh mode: .Bl -tag -width indent .It Cm meshid Ar meshid Set the desired Mesh Identifier. The Mesh ID is a string up to 32 characters in length. A mesh interface must have a Mesh Identifier specified to reach an operational state. .It Cm meshttl Ar ttl Set the desired ``time to live'' for mesh forwarded packets; this is the number of hops a packet may be forwarded before it is discarded. The default setting for .Cm meshttl is 31. .It Cm meshpeering Enable or disable peering with neighbor mesh stations. Stations must peer before any data packets can be exchanged. By default .Cm meshpeering is enabled. .It Cm meshforward Enable or disable forwarding packets by a mesh interface. By default .Cm meshforward is enabled. .It Cm meshgate This attribute specifies whether or not the mesh STA activates mesh gate announcements. By default .Cm meshgate is disabled. .It Cm meshmetric Ar protocol Set the specified .Ar protocol as the link metric protocol used on a mesh network. The default protocol is called .Ar AIRTIME . The mesh interface will restart after changing this setting. .It Cm meshpath Ar protocol Set the specified .Ar protocol as the path selection protocol used on a mesh network. The only available protocol at the moment is called .Ar HWMP (Hybrid Wireless Mesh Protocol). The mesh interface will restart after changing this setting. .It Cm hwmprootmode Ar mode Stations on a mesh network can operate as ``root nodes.'' Root nodes try to find paths to all mesh nodes and advertise themselves regularly. When there is a root mesh node on a network, other mesh nodes can setup paths between themselves faster because they can use the root node to find the destination. This path may not be the best, but on-demand routing will eventually find the best path. The following modes are recognized: .Pp .Bl -tag -width ".Cm PROACTIVE" -compact .It Cm DISABLED Disable root mode. .It Cm NORMAL Send broadcast path requests every two seconds. Nodes on the mesh without a path to this root mesh station with try to discover a path to us. .It Cm PROACTIVE Send broadcast path requests every two seconds and every node must reply with a path reply even if it already has a path to this root mesh station. .It Cm RANN Send broadcast root announcement (RANN) frames. Nodes on the mesh without a path to this root mesh station with try to discover a path to us. .El By default .Cm hwmprootmode is set to .Ar DISABLED . .It Cm hwmpmaxhops Ar cnt Set the maximum number of hops allowed in an HMWP path to .Ar cnt . The default setting for .Cm hwmpmaxhops is 31. .El .Pp The following parameters are for compatibility with other systems: .Bl -tag -width indent .It Cm nwid Ar ssid Another name for the .Cm ssid parameter. Included for .Nx compatibility. .It Cm stationname Ar name Set the name of this station. The station name is not part of the IEEE 802.11 protocol though some interfaces support it. As such it only seems to be meaningful to identical or virtually identical equipment. Setting the station name is identical in syntax to setting the SSID. One can also use .Cm station for .Bsx compatibility. .It Cm wep Another way of saying .Cm wepmode on . Included for .Bsx compatibility. .It Fl wep Another way of saying .Cm wepmode off . Included for .Bsx compatibility. .It Cm nwkey key Another way of saying: .Dq Li "wepmode on weptxkey 1 wepkey 1:key wepkey 2:- wepkey 3:- wepkey 4:-" . Included for .Nx compatibility. .It Cm nwkey Xo .Sm off .Ar n : k1 , k2 , k3 , k4 .Sm on .Xc Another way of saying .Dq Li "wepmode on weptxkey n wepkey 1:k1 wepkey 2:k2 wepkey 3:k3 wepkey 4:k4" . Included for .Nx compatibility. .It Fl nwkey Another way of saying .Cm wepmode off . Included for .Nx compatibility. .El .Pp The following parameters are specific to bridge interfaces: .Bl -tag -width indent .It Cm addm Ar interface Add the interface named by .Ar interface as a member of the bridge. The interface is put into promiscuous mode so that it can receive every packet sent on the network. .It Cm deletem Ar interface Remove the interface named by .Ar interface from the bridge. Promiscuous mode is disabled on the interface when it is removed from the bridge. .It Cm maxaddr Ar size Set the size of the bridge address cache to .Ar size . The default is 2000 entries. .It Cm timeout Ar seconds Set the timeout of address cache entries to .Ar seconds seconds. If .Ar seconds is zero, then address cache entries will not be expired. The default is 1200 seconds. .It Cm addr Display the addresses that have been learned by the bridge. .It Cm static Ar interface-name Ar address Add a static entry into the address cache pointing to .Ar interface-name . Static entries are never aged out of the cache or re-placed, even if the address is seen on a different interface. .It Cm deladdr Ar address Delete .Ar address from the address cache. .It Cm flush Delete all dynamically-learned addresses from the address cache. .It Cm flushall Delete all addresses, including static addresses, from the address cache. .It Cm discover Ar interface Mark an interface as a .Dq discovering interface. When the bridge has no address cache entry (either dynamic or static) for the destination address of a packet, the bridge will forward the packet to all member interfaces marked as .Dq discovering . This is the default for all interfaces added to a bridge. .It Cm -discover Ar interface Clear the .Dq discovering attribute on a member interface. For packets without the .Dq discovering attribute, the only packets forwarded on the interface are broadcast or multicast packets and packets for which the destination address is known to be on the interface's segment. .It Cm learn Ar interface Mark an interface as a .Dq learning interface. When a packet arrives on such an interface, the source address of the packet is entered into the address cache as being a destination address on the interface's segment. This is the default for all interfaces added to a bridge. .It Cm -learn Ar interface Clear the .Dq learning attribute on a member interface. .It Cm sticky Ar interface Mark an interface as a .Dq sticky interface. Dynamically learned address entries are treated at static once entered into the cache. Sticky entries are never aged out of the cache or replaced, even if the address is seen on a different interface. .It Cm -sticky Ar interface Clear the .Dq sticky attribute on a member interface. .It Cm private Ar interface Mark an interface as a .Dq private interface. A private interface does not forward any traffic to any other port that is also a private interface. .It Cm -private Ar interface Clear the .Dq private attribute on a member interface. .It Cm span Ar interface Add the interface named by .Ar interface as a span port on the bridge. Span ports transmit a copy of every frame received by the bridge. This is most useful for snooping a bridged network passively on another host connected to one of the span ports of the bridge. .It Cm -span Ar interface Delete the interface named by .Ar interface from the list of span ports of the bridge. .It Cm stp Ar interface Enable Spanning Tree protocol on .Ar interface . The .Xr if_bridge 4 driver has support for the IEEE 802.1D Spanning Tree protocol (STP). Spanning Tree is used to detect and remove loops in a network topology. .It Cm -stp Ar interface Disable Spanning Tree protocol on .Ar interface . This is the default for all interfaces added to a bridge. .It Cm edge Ar interface Set .Ar interface as an edge port. An edge port connects directly to end stations cannot create bridging loops in the network, this allows it to transition straight to forwarding. .It Cm -edge Ar interface Disable edge status on .Ar interface . .It Cm autoedge Ar interface Allow .Ar interface to automatically detect edge status. This is the default for all interfaces added to a bridge. .It Cm -autoedge Ar interface Disable automatic edge status on .Ar interface . .It Cm ptp Ar interface Set the .Ar interface as a point to point link. This is required for straight transitions to forwarding and should be enabled on a direct link to another RSTP capable switch. .It Cm -ptp Ar interface Disable point to point link status on .Ar interface . This should be disabled for a half duplex link and for an interface connected to a shared network segment, like a hub or a wireless network. .It Cm autoptp Ar interface Automatically detect the point to point status on .Ar interface by checking the full duplex link status. This is the default for interfaces added to the bridge. .It Cm -autoptp Ar interface Disable automatic point to point link detection on .Ar interface . .It Cm maxage Ar seconds Set the time that a Spanning Tree protocol configuration is valid. The default is 20 seconds. The minimum is 6 seconds and the maximum is 40 seconds. .It Cm fwddelay Ar seconds Set the time that must pass before an interface begins forwarding packets when Spanning Tree is enabled. The default is 15 seconds. The minimum is 4 seconds and the maximum is 30 seconds. .It Cm hellotime Ar seconds Set the time between broadcasting of Spanning Tree protocol configuration messages. The hello time may only be changed when operating in legacy stp mode. The default is 2 seconds. The minimum is 1 second and the maximum is 2 seconds. .It Cm priority Ar value Set the bridge priority for Spanning Tree. The default is 32768. The minimum is 0 and the maximum is 61440. .It Cm proto Ar value Set the Spanning Tree protocol. The default is rstp. The available options are stp and rstp. .It Cm holdcnt Ar value Set the transmit hold count for Spanning Tree. This is the number of packets transmitted before being rate limited. The default is 6. The minimum is 1 and the maximum is 10. .It Cm ifpriority Ar interface Ar value Set the Spanning Tree priority of .Ar interface to .Ar value . The default is 128. The minimum is 0 and the maximum is 240. .It Cm ifpathcost Ar interface Ar value Set the Spanning Tree path cost of .Ar interface to .Ar value . The default is calculated from the link speed. To change a previously selected path cost back to automatic, set the cost to 0. The minimum is 1 and the maximum is 200000000. .It Cm ifmaxaddr Ar interface Ar size Set the maximum number of hosts allowed from an interface, packets with unknown source addresses are dropped until an existing host cache entry expires or is removed. Set to 0 to disable. .El .Pp The following parameters are specific to lagg interfaces: .Bl -tag -width indent .It Cm laggport Ar interface Add the interface named by .Ar interface as a port of the aggregation interface. .It Cm -laggport Ar interface Remove the interface named by .Ar interface from the aggregation interface. .It Cm laggproto Ar proto Set the aggregation protocol. The default is .Li failover . The available options are .Li failover , .Li lacp , .Li loadbalance , .Li roundrobin , .Li broadcast and .Li none . .It Cm lagghash Ar option Ns Oo , Ns Ar option Oc Set the packet layers to hash for aggregation protocols which load balance. The default is .Dq l2,l3,l4 . The options can be combined using commas. .Pp .Bl -tag -width ".Cm l2" -compact .It Cm l2 src/dst mac address and optional vlan number. .It Cm l3 src/dst address for IPv4 or IPv6. .It Cm l4 src/dst port for TCP/UDP/SCTP. .El .It Cm use_flowid Enable local hash computation for RSS hash on the interface. The .Li loadbalance and .Li lacp modes will use the RSS hash from the network card if available to avoid computing one, this may give poor traffic distribution if the hash is invalid or uses less of the protocol header information. .Cm use_flowid disables use of RSS hash from the network card. The default value can be set via the .Va net.link.lagg.default_use_flowid .Xr sysctl 8 variable. .Li 0 means .Dq disabled and .Li 1 means .Dq enabled . .It Cm -use_flowid Disable local hash computation for RSS hash on the interface. .It Cm flowid_shift Ar number Set a shift parameter for RSS local hash computation. Hash is calculated by using flowid bits in a packet header mbuf which are shifted by the number of this parameter. .El .Pp The following parameters are specific to IP tunnel interfaces, .Xr gif 4 : .Bl -tag -width indent .It Cm tunnel Ar src_addr dest_addr Configure the physical source and destination address for IP tunnel interfaces. The arguments .Ar src_addr and .Ar dest_addr are interpreted as the outer source/destination for the encapsulating IPv4/IPv6 header. .It Fl tunnel Unconfigure the physical source and destination address for IP tunnel interfaces previously configured with .Cm tunnel . .It Cm deletetunnel Another name for the .Fl tunnel parameter. .It Cm accept_rev_ethip_ver Set a flag to accept both correct EtherIP packets and ones with reversed version field. Enabled by default. This is for backward compatibility with .Fx 6.1 , 6.2, 6.3, 7.0, and 7.1. .It Cm -accept_rev_ethip_ver Clear a flag .Cm accept_rev_ethip_ver . +.It Cm ignore_source +Set a flag to accept encapsulated packets destined to this host +independently from source address. +This may be useful for hosts, that receive encapsulated packets +from the load balancers. +.It Cm -ignore_source +Clear a flag +.Cm ignore_source . .It Cm send_rev_ethip_ver Set a flag to send EtherIP packets with reversed version field intentionally. Disabled by default. This is for backward compatibility with .Fx 6.1 , 6.2, 6.3, 7.0, and 7.1. .It Cm -send_rev_ethip_ver Clear a flag .Cm send_rev_ethip_ver . .El .Pp The following parameters are specific to GRE tunnel interfaces, .Xr gre 4 : .Bl -tag -width indent .It Cm grekey Ar key Configure the GRE key to be used for outgoing packets. Note that .Xr gre 4 will always accept GRE packets with invalid or absent keys. This command will result in a four byte MTU reduction on the interface. .El .Pp The following parameters are specific to .Xr pfsync 4 interfaces: .Bl -tag -width indent .It Cm syncdev Ar iface Use the specified interface to send and receive pfsync state synchronisation messages. .It Fl syncdev Stop sending pfsync state synchronisation messages over the network. .It Cm syncpeer Ar peer_address Make the pfsync link point-to-point rather than using multicast to broadcast the state synchronisation messages. The peer_address is the IP address of the other host taking part in the pfsync cluster. .It Fl syncpeer Broadcast the packets using multicast. .It Cm maxupd Ar n Set the maximum number of updates for a single state which can be collapsed into one. This is an 8-bit number; the default value is 128. .It Cm defer Defer transmission of the first packet in a state until a peer has acknowledged that the associated state has been inserted. .It Fl defer Do not defer the first packet in a state. This is the default. .El .Pp The following parameters are specific to .Xr vlan 4 interfaces: .Bl -tag -width indent .It Cm vlan Ar vlan_tag Set the VLAN tag value to .Ar vlan_tag . This value is a 12-bit VLAN Identifier (VID) which is used to create an 802.1Q VLAN header for packets sent from the .Xr vlan 4 interface. Note that .Cm vlan and .Cm vlandev must both be set at the same time. .It Cm vlandev Ar iface Associate the physical interface .Ar iface with a .Xr vlan 4 interface. Packets transmitted through the .Xr vlan 4 interface will be diverted to the specified physical interface .Ar iface with 802.1Q VLAN encapsulation. Packets with 802.1Q encapsulation received by the parent interface with the correct VLAN Identifier will be diverted to the associated .Xr vlan 4 pseudo-interface. The .Xr vlan 4 interface is assigned a copy of the parent interface's flags and the parent's Ethernet address. The .Cm vlandev and .Cm vlan must both be set at the same time. If the .Xr vlan 4 interface already has a physical interface associated with it, this command will fail. To change the association to another physical interface, the existing association must be cleared first. .Pp Note: if the hardware tagging capability is set on the parent interface, the .Xr vlan 4 pseudo interface's behavior changes: the .Xr vlan 4 interface recognizes that the parent interface supports insertion and extraction of VLAN tags on its own (usually in firmware) and that it should pass packets to and from the parent unaltered. .It Fl vlandev Op Ar iface If the driver is a .Xr vlan 4 pseudo device, disassociate the parent interface from it. This breaks the link between the .Xr vlan 4 interface and its parent, clears its VLAN Identifier, flags and its link address and shuts the interface down. The .Ar iface argument is useless and hence deprecated. .El .Pp The following parameters are used to configure .Xr vxlan 4 interfaces. .Bl -tag -width indent .It Cm vxlanid Ar identifier This value is a 24-bit VXLAN Network Identifier (VNI) that identifies the virtual network segment membership of the interface. .It Cm vxlanlocal Ar address The source address used in the encapsulating IPv4/IPv6 header. The address should already be assigned to an existing interface. When the interface is configured in unicast mode, the listening socket is bound to this address. .It Cm vxlanremote Ar address The interface can be configured in a unicast, or point-to-point, mode to create a tunnel between two hosts. This is the IP address of the remote end of the tunnel. .It Cm vxlangroup Ar address The interface can be configured in a multicast mode to create a virtual network of hosts. This is the IP multicast group address the interface will join. .It Cm vxlanlocalport Ar port The port number the interface will listen on. The default port number is 4789. .It Cm vxlanremoteport Ar port The destination port number used in the encapsulating IPv4/IPv6 header. The remote host should be listening on this port. The default port number is 4789. Note some other implementations, such as Linux, do not default to the IANA assigned port, but instead listen on port 8472. .It Cm vxlanportrange Ar low high The range of source ports used in the encapsulating IPv4/IPv6 header. The port selected within the range is based on a hash of the inner frame. A range is useful to provide entropy within the outer IP header for more effective load balancing. The default range is between the .Xr sysctl 8 variables .Va net.inet.ip.portrange.first and .Va net.inet.ip.portrange.last .It Cm vxlantimeout Ar timeout The maximum time, in seconds, before an entry in the forwarding table is pruned. The default is 1200 seconds (20 minutes). .It Cm vxlanmaxaddr Ar max The maximum number of entries in the forwarding table. The default is 2000. .It Cm vxlandev Ar dev When the interface is configured in multicast mode, the .Cm dev interface is used to transmit IP multicast packets. .It Cm vxlanttl Ar ttl The TTL used in the encapsulating IPv4/IPv6 header. The default is 64. .It Cm vxlanlearn The source IP address and inner source Ethernet MAC address of received packets are used to dynamically populate the forwarding table. When in multicast mode, an entry in the forwarding table allows the interface to send the frame directly to the remote host instead of broadcasting the frame to the multicast group. This is the default. .It Fl vxlanlearn The forwarding table is not populated by recevied packets. .It Cm vxlanflush Delete all dynamically-learned addresses from the forwarding table. .It Cm vxlanflushall Delete all addresses, including static addresses, from the forwarding table. .El .Pp The following parameters are used to configure .Xr carp 4 protocol on an interface: .Bl -tag -width indent .It Cm vhid Ar n Set the virtual host ID. This is a required setting to initiate .Xr carp 4 . If the virtual host ID does not exist yet, it is created and attached to the interface, otherwise configuration of an existing vhid is adjusted. If the .Cm vhid keyword is supplied along with an .Dq inet6 or .Dq inet address, then this address is configured to be run under control of the specified vhid. Whenever a last address that refers to a particular vhid is removed from an interface, the vhid is automatically removed from interface and destroyed. Any other configuration parameters for the .Xr carp 4 protocol should be supplied along with the .Cm vhid keyword. Acceptable values for vhid are 1 to 255. .It Cm advbase Ar seconds Specifies the base of the advertisement interval in seconds. The acceptable values are 1 to 255. The default value is 1. .It Cm advskew Ar interval Specifies the skew to add to the base advertisement interval to make one host advertise slower than another host. It is specified in 1/256 of seconds. The acceptable values are 1 to 254. The default value is 0. .It Cm pass Ar phrase Set the authentication key to .Ar phrase . .It Cm state Ar MASTER|BACKUP Forcibly change state of a given vhid. .El .Pp The .Nm utility displays the current configuration for a network interface when no optional parameters are supplied. If a protocol family is specified, .Nm will report only the details specific to that protocol family. .Pp If the .Fl m flag is passed before an interface name, .Nm will display the capability list and all of the supported media for the specified interface. If .Fl L flag is supplied, address lifetime is displayed for IPv6 addresses, as time offset string. .Pp Optionally, the .Fl a flag may be used instead of an interface name. This flag instructs .Nm to display information about all interfaces in the system. The .Fl d flag limits this to interfaces that are down, and .Fl u limits this to interfaces that are up. When no arguments are given, .Fl a is implied. .Pp The .Fl l flag may be used to list all available interfaces on the system, with no other additional information. If an .Ar address_family is specified, only interfaces of that type will be listed. .Fl l Dq ether will list only Ethernet adapters, excluding the loopback interface. Use of this flag is mutually exclusive with all other flags and commands, except for .Fl d (only list interfaces that are down) and .Fl u (only list interfaces that are up). .Pp The .Fl v flag may be used to get more verbose status for an interface. .Pp The .Fl C flag may be used to list all of the interface cloners available on the system, with no additional information. Use of this flag is mutually exclusive with all other flags and commands. .Pp The .Fl k flag causes keying information for the interface, if available, to be printed. For example, the values of 802.11 WEP keys and .Xr carp 4 passphrases will be printed, if accessible to the current user. This information is not printed by default, as it may be considered sensitive. .Pp If the network interface driver is not present in the kernel then .Nm will attempt to load it. The .Fl n flag disables this behavior. .Pp Only the super-user may modify the configuration of a network interface. .Sh EXAMPLES Assign the IPv4 address .Li 192.0.2.10 , with a network mask of .Li 255.255.255.0 , to the interface .Li fxp0 : .Dl # ifconfig fxp0 inet 192.0.2.10 netmask 255.255.255.0 .Pp Add the IPv4 address .Li 192.0.2.45 , with the CIDR network prefix .Li /28 , to the interface .Li ed0 , using .Cm add as a synonym for the canonical form of the option .Cm alias : .Dl # ifconfig ed0 inet 192.0.2.45/28 add .Pp Remove the IPv4 address .Li 192.0.2.45 from the interface .Li ed0 : .Dl # ifconfig ed0 inet 192.0.2.45 -alias .Pp Enable IPv6 functionality of the interface: .Dl # ifconfig em0 inet6 -ifdisabled .Pp Add the IPv6 address .Li 2001:DB8:DBDB::123/48 to the interface .Li em0 : .Dl # ifconfig em0 inet6 2001:db8:bdbd::123 prefixlen 48 alias Note that lower case hexadecimal IPv6 addresses are acceptable. .Pp Remove the IPv6 address added in the above example, using the .Li / character as shorthand for the network prefix, and using .Cm delete as a synonym for the canonical form of the option .Fl alias : .Dl # ifconfig em0 inet6 2001:db8:bdbd::123/48 delete .Pp Configure a single CARP redundant address on igb0, and then switch it to be master: .Dl # ifconfig igb0 vhid 1 10.0.0.1/24 pass foobar up .Dl # ifconfig igb0 vhid 1 state master .Pp Configure the interface .Li xl0 , to use 100baseTX, full duplex Ethernet media options: .Dl # ifconfig xl0 media 100baseTX mediaopt full-duplex .Pp Label the em0 interface as an uplink: .Dl # ifconfig em0 description \&"Uplink to Gigabit Switch 2\&" .Pp Create the software network interface .Li gif1 : .Dl # ifconfig gif1 create .Pp Destroy the software network interface .Li gif1 : .Dl # ifconfig gif1 destroy .Pp Display available wireless networks using .Li wlan0 : .Dl # ifconfig wlan0 list scan .Sh DIAGNOSTICS Messages indicating the specified interface does not exist, the requested address is unknown, or the user is not privileged and tried to alter an interface's configuration. .Sh SEE ALSO .Xr netstat 1 , .Xr carp 4 , .Xr gif 4 , .Xr netintro 4 , .Xr pfsync 4 , .Xr polling 4 , .Xr vlan 4 , .Xr vxlan 4 , .Xr devd.conf 5 , .\" .Xr eon 5 , .Xr devd 8 , .Xr jail 8 , .Xr rc 8 , .Xr routed 8 , .Xr sysctl 8 .Sh HISTORY The .Nm utility appeared in .Bx 4.2 . .Sh BUGS Basic IPv6 node operation requires a link-local address on each interface configured for IPv6. Normally, such an address is automatically configured by the kernel on each interface added to the system or enabled; this behavior may be disabled by setting per-interface flag .Cm -auto_linklocal . The default value of this flag is 1 and can be disabled by using the sysctl MIB variable .Va net.inet6.ip6.auto_linklocal . .Pp Do not configure IPv6 addresses with no link-local address by using .Nm . It can result in unexpected behaviors of the kernel. Index: projects/ci20_mips/sbin/ifconfig/ifgif.c =================================================================== --- projects/ci20_mips/sbin/ifconfig/ifgif.c (revision 283030) +++ projects/ci20_mips/sbin/ifconfig/ifgif.c (revision 283031) @@ -1,118 +1,120 @@ /*- * Copyright (c) 2009 Hiroki Sato. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ifconfig.h" -#define GIFBITS "\020\1ACCEPT_REV_ETHIP_VER\5SEND_REV_ETHIP_VER" +#define GIFBITS "\020\1ACCEPT_REV_ETHIP_VER\2IGNORE_SOURCE\5SEND_REV_ETHIP_VER" static void gif_status(int); static void gif_status(int s) { int opts; ifr.ifr_data = (caddr_t)&opts; if (ioctl(s, GIFGOPTS, &ifr) == -1) return; if (opts == 0) return; printb("\toptions", opts, GIFBITS); putchar('\n'); } static void setgifopts(const char *val, int d, int s, const struct afswtch *afp) { int opts; ifr.ifr_data = (caddr_t)&opts; if (ioctl(s, GIFGOPTS, &ifr) == -1) { warn("ioctl(GIFGOPTS)"); return; } if (d < 0) opts &= ~(-d); else opts |= d; if (ioctl(s, GIFSOPTS, &ifr) == -1) { warn("ioctl(GIFSOPTS)"); return; } } static struct cmd gif_cmds[] = { DEF_CMD("accept_rev_ethip_ver", GIF_ACCEPT_REVETHIP, setgifopts), DEF_CMD("-accept_rev_ethip_ver",-GIF_ACCEPT_REVETHIP, setgifopts), + DEF_CMD("ignore_source", GIF_IGNORE_SOURCE, setgifopts), + DEF_CMD("-ignore_source", -GIF_IGNORE_SOURCE, setgifopts), DEF_CMD("send_rev_ethip_ver", GIF_SEND_REVETHIP, setgifopts), DEF_CMD("-send_rev_ethip_ver", -GIF_SEND_REVETHIP, setgifopts), }; static struct afswtch af_gif = { .af_name = "af_gif", .af_af = AF_UNSPEC, .af_other_status = gif_status, }; static __constructor void gif_ctor(void) { #define N(a) (sizeof(a) / sizeof(a[0])) size_t i; for (i = 0; i < N(gif_cmds); i++) cmd_register(&gif_cmds[i]); af_register(&af_gif); #undef N } Index: projects/ci20_mips/sbin/ifconfig/sfp.c =================================================================== --- projects/ci20_mips/sbin/ifconfig/sfp.c (revision 283030) +++ projects/ci20_mips/sbin/ifconfig/sfp.c (revision 283031) @@ -1,827 +1,882 @@ /*- * Copyright (c) 2014 Alexander V. Chernikov. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ifconfig.h" -struct i2c_info; -typedef int (read_i2c)(struct i2c_info *ii, uint8_t addr, uint8_t off, - uint8_t len, caddr_t buf); - struct i2c_info { - int s; - int error; - int bshift; - int qsfp; - int do_diag; - struct ifreq *ifr; - read_i2c *f; - char *textbuf; - size_t bufsize; - int cfd; - int port_id; - int chip_id; + int fd; /* fd to issue SIOCGI2C */ + int error; /* Store first error */ + int qsfp; /* True if transceiver is QSFP */ + int do_diag; /* True if we need to request DDM */ + struct ifreq *ifr; /* Pointer to pre-filled ifreq */ }; +static int read_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off, + uint8_t len, uint8_t *buf); static void dump_i2c_data(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len); struct _nv { int v; const char *n; }; const char *find_value(struct _nv *x, int value); const char *find_zero_bit(struct _nv *x, int value, int sz); /* SFF-8472 Rev. 11.4 table 3.4: Connector values */ static struct _nv conn[] = { { 0x00, "Unknown" }, { 0x01, "SC" }, { 0x02, "Fibre Channel Style 1 copper" }, { 0x03, "Fibre Channel Style 2 copper" }, { 0x04, "BNC/TNC" }, { 0x05, "Fibre Channel coaxial" }, { 0x06, "FiberJack" }, { 0x07, "LC" }, { 0x08, "MT-RJ" }, { 0x09, "MU" }, { 0x0A, "SG" }, { 0x0B, "Optical pigtail" }, { 0x0C, "MPO Parallel Optic" }, { 0x20, "HSSDC II" }, { 0x21, "Copper pigtail" }, { 0x22, "RJ45" }, { 0x23, "No separate connector" }, /* SFF-8436 */ { 0, NULL } }; /* SFF-8472 Rev. 11.4 table 3.5: Transceiver codes */ /* 10G Ethernet/IB compliance codes, byte 3 */ static struct _nv eth_10g[] = { { 0x80, "10G Base-ER" }, { 0x40, "10G Base-LRM" }, { 0x20, "10G Base-LR" }, { 0x10, "10G Base-SR" }, { 0x08, "1X SX" }, { 0x04, "1X LX" }, { 0x02, "1X Copper Active" }, { 0x01, "1X Copper Passive" }, { 0, NULL } }; /* Ethernet compliance codes, byte 6 */ static struct _nv eth_compat[] = { { 0x80, "BASE-PX" }, { 0x40, "BASE-BX10" }, { 0x20, "100BASE-FX" }, { 0x10, "100BASE-LX/LX10" }, { 0x08, "1000BASE-T" }, { 0x04, "1000BASE-CX" }, { 0x02, "1000BASE-LX" }, { 0x01, "1000BASE-SX" }, { 0, NULL } }; /* FC link length, byte 7 */ static struct _nv fc_len[] = { { 0x80, "very long distance" }, { 0x40, "short distance" }, { 0x20, "intermediate distance" }, { 0x10, "long distance" }, { 0x08, "medium distance" }, { 0, NULL } }; /* Channel/Cable technology, byte 7-8 */ static struct _nv cab_tech[] = { { 0x0400, "Shortwave laser (SA)" }, { 0x0200, "Longwave laser (LC)" }, { 0x0100, "Electrical inter-enclosure (EL)" }, { 0x80, "Electrical intra-enclosure (EL)" }, { 0x40, "Shortwave laser (SN)" }, { 0x20, "Shortwave laser (SL)" }, { 0x10, "Longwave laser (LL)" }, { 0x08, "Active Cable" }, { 0x04, "Passive Cable" }, { 0, NULL } }; /* FC Transmission media, byte 9 */ static struct _nv fc_media[] = { { 0x80, "Twin Axial Pair" }, { 0x40, "Twisted Pair" }, { 0x20, "Miniature Coax" }, { 0x10, "Viao Coax" }, { 0x08, "Miltimode, 62.5um" }, { 0x04, "Multimode, 50um" }, { 0x02, "" }, { 0x01, "Single Mode" }, { 0, NULL } }; /* FC Speed, byte 10 */ static struct _nv fc_speed[] = { { 0x80, "1200 MBytes/sec" }, { 0x40, "800 MBytes/sec" }, { 0x20, "1600 MBytes/sec" }, { 0x10, "400 MBytes/sec" }, { 0x08, "3200 MBytes/sec" }, { 0x04, "200 MBytes/sec" }, { 0x01, "100 MBytes/sec" }, { 0, NULL } }; /* SFF-8436 Rev. 4.8 table 33: Specification compliance */ /* 10/40G Ethernet compliance codes, byte 128 + 3 */ static struct _nv eth_1040g[] = { { 0x80, "Reserved" }, { 0x40, "10GBASE-LRM" }, { 0x20, "10GBASE-LR" }, { 0x10, "10GBASE-SR" }, { 0x08, "40GBASE-CR4" }, { 0x04, "40GBASE-SR4" }, { 0x02, "40GBASE-LR4" }, { 0x01, "40G Active Cable" }, { 0, NULL } }; +/* SFF-8636 Rev. 2.5 table 6.3: Revision compliance */ +static struct _nv rev_compl[] = { + { 0x1, "SFF-8436 rev <=4.8" }, + { 0x2, "SFF-8436 rev <=4.8" }, + { 0x3, "SFF-8636 rev <=1.3" }, + { 0x4, "SFF-8636 rev <=1.4" }, + { 0x5, "SFF-8636 rev <=1.5" }, + { 0x6, "SFF-8636 rev <=2.0" }, + { 0x7, "SFF-8636 rev <=2.5" }, + { 0x0, "Unspecified" } +}; + const char * find_value(struct _nv *x, int value) { for (; x->n != NULL; x++) if (x->v == value) return (x->n); return (NULL); } const char * find_zero_bit(struct _nv *x, int value, int sz) { int v, m; const char *s; v = 1; for (v = 1, m = 1 << (8 * sz); v < m; v *= 2) { if ((value & v) == 0) continue; if ((s = find_value(x, value & v)) != NULL) { value &= ~v; return (s); } } return (NULL); } static void convert_sff_identifier(char *buf, size_t size, uint8_t value) { const char *x; x = NULL; if (value <= SFF_8024_ID_LAST) x = sff_8024_id[value]; else { if (value > 0x80) x = "Vendor specific"; else x = "Reserved"; } snprintf(buf, size, "%s", x); } static void convert_sff_connector(char *buf, size_t size, uint8_t value) { const char *x; if ((x = find_value(conn, value)) == NULL) { if (value >= 0x0D && value <= 0x1F) x = "Unallocated"; else if (value >= 0x24 && value <= 0x7F) x = "Unallocated"; else x = "Vendor specific"; } snprintf(buf, size, "%s", x); } static void +convert_sff_rev_compliance(char *buf, size_t size, uint8_t value) +{ + const char *x; + + if (value > 0x07) + x = "Unallocated"; + else + x = find_value(rev_compl, value); + + snprintf(buf, size, "%s", x); +} + +static void get_sfp_identifier(struct i2c_info *ii, char *buf, size_t size) { uint8_t data; - ii->f(ii, SFF_8472_BASE, SFF_8472_ID, 1, (caddr_t)&data); + read_i2c(ii, SFF_8472_BASE, SFF_8472_ID, 1, &data); convert_sff_identifier(buf, size, data); } static void get_sfp_connector(struct i2c_info *ii, char *buf, size_t size) { uint8_t data; - ii->f(ii, SFF_8472_BASE, SFF_8472_CONNECTOR, 1, (caddr_t)&data); + read_i2c(ii, SFF_8472_BASE, SFF_8472_CONNECTOR, 1, &data); convert_sff_connector(buf, size, data); } static void get_qsfp_identifier(struct i2c_info *ii, char *buf, size_t size) { uint8_t data; - ii->f(ii, SFF_8436_BASE, SFF_8436_ID, 1, (caddr_t)&data); + read_i2c(ii, SFF_8436_BASE, SFF_8436_ID, 1, &data); convert_sff_identifier(buf, size, data); } static void get_qsfp_connector(struct i2c_info *ii, char *buf, size_t size) { uint8_t data; - ii->f(ii, SFF_8436_BASE, SFF_8436_CONNECTOR, 1, (caddr_t)&data); + read_i2c(ii, SFF_8436_BASE, SFF_8436_CONNECTOR, 1, &data); convert_sff_connector(buf, size, data); } static void printf_sfp_transceiver_descr(struct i2c_info *ii, char *buf, size_t size) { char xbuf[12]; const char *tech_class, *tech_len, *tech_tech, *tech_media, *tech_speed; tech_class = NULL; tech_len = NULL; tech_tech = NULL; tech_media = NULL; tech_speed = NULL; /* Read bytes 3-10 at once */ - ii->f(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, &xbuf[3]); + read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, &xbuf[3]); /* Check 10G ethernet first */ tech_class = find_zero_bit(eth_10g, xbuf[3], 1); if (tech_class == NULL) { /* No match. Try 1G */ tech_class = find_zero_bit(eth_compat, xbuf[6], 1); } tech_len = find_zero_bit(fc_len, xbuf[7], 1); tech_tech = find_zero_bit(cab_tech, xbuf[7] << 8 | xbuf[8], 2); tech_media = find_zero_bit(fc_media, xbuf[9], 1); tech_speed = find_zero_bit(fc_speed, xbuf[10], 1); printf("Class: %s\n", tech_class); printf("Length: %s\n", tech_len); printf("Tech: %s\n", tech_tech); printf("Media: %s\n", tech_media); printf("Speed: %s\n", tech_speed); } static void get_sfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size) { const char *tech_class; uint8_t code; unsigned char qbuf[8]; - ii->f(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, (caddr_t)qbuf); + read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, (uint8_t *)qbuf); /* Check 10G Ethernet/IB first */ - ii->f(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 1, (caddr_t)&code); + read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 1, &code); tech_class = find_zero_bit(eth_10g, code, 1); if (tech_class == NULL) { /* No match. Try Ethernet 1G */ - ii->f(ii, SFF_8472_BASE, SFF_8472_TRANS_START + 3, + read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START + 3, 1, (caddr_t)&code); tech_class = find_zero_bit(eth_compat, code, 1); } if (tech_class == NULL) tech_class = "Unknown"; snprintf(buf, size, "%s", tech_class); } static void get_qsfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size) { const char *tech_class; uint8_t code; /* Check 10/40G Ethernet class only */ - ii->f(ii, SFF_8436_BASE, SFF_8436_CODE_E1040G, 1, (caddr_t)&code); + read_i2c(ii, SFF_8436_BASE, SFF_8436_CODE_E1040G, 1, &code); tech_class = find_zero_bit(eth_1040g, code, 1); if (tech_class == NULL) tech_class = "Unknown"; snprintf(buf, size, "%s", tech_class); } /* * Print SFF-8472/SFF-8436 string to supplied buffer. * All (vendor-specific) strings are padded right with '0x20'. */ static void convert_sff_name(char *buf, size_t size, char *xbuf) { char *p; for (p = &xbuf[16]; *(p - 1) == 0x20; p--) ; *p = '\0'; snprintf(buf, size, "%s", xbuf); } static void convert_sff_date(char *buf, size_t size, char *xbuf) { snprintf(buf, size, "20%c%c-%c%c-%c%c", xbuf[0], xbuf[1], xbuf[2], xbuf[3], xbuf[4], xbuf[5]); } static void get_sfp_vendor_name(struct i2c_info *ii, char *buf, size_t size) { char xbuf[17]; memset(xbuf, 0, sizeof(xbuf)); - ii->f(ii, SFF_8472_BASE, SFF_8472_VENDOR_START, 16, xbuf); + read_i2c(ii, SFF_8472_BASE, SFF_8472_VENDOR_START, 16, (uint8_t *)xbuf); convert_sff_name(buf, size, xbuf); } static void get_sfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size) { char xbuf[17]; memset(xbuf, 0, sizeof(xbuf)); - ii->f(ii, SFF_8472_BASE, SFF_8472_PN_START, 16, xbuf); + read_i2c(ii, SFF_8472_BASE, SFF_8472_PN_START, 16, (uint8_t *)xbuf); convert_sff_name(buf, size, xbuf); } static void get_sfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size) { char xbuf[17]; memset(xbuf, 0, sizeof(xbuf)); - ii->f(ii, SFF_8472_BASE, SFF_8472_SN_START, 16, xbuf); + read_i2c(ii, SFF_8472_BASE, SFF_8472_SN_START, 16, (uint8_t *)xbuf); convert_sff_name(buf, size, xbuf); } static void get_sfp_vendor_date(struct i2c_info *ii, char *buf, size_t size) { char xbuf[6]; memset(xbuf, 0, sizeof(xbuf)); /* Date code, see Table 3.8 for description */ - ii->f(ii, SFF_8472_BASE, SFF_8472_DATE_START, 6, xbuf); + read_i2c(ii, SFF_8472_BASE, SFF_8472_DATE_START, 6, (uint8_t *)xbuf); convert_sff_date(buf, size, xbuf); } static void get_qsfp_vendor_name(struct i2c_info *ii, char *buf, size_t size) { char xbuf[17]; memset(xbuf, 0, sizeof(xbuf)); - ii->f(ii, SFF_8436_BASE, SFF_8436_VENDOR_START, 16, xbuf); + read_i2c(ii, SFF_8436_BASE, SFF_8436_VENDOR_START, 16, (uint8_t *)xbuf); convert_sff_name(buf, size, xbuf); } static void get_qsfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size) { char xbuf[17]; memset(xbuf, 0, sizeof(xbuf)); - ii->f(ii, SFF_8436_BASE, SFF_8436_PN_START, 16, xbuf); + read_i2c(ii, SFF_8436_BASE, SFF_8436_PN_START, 16, (uint8_t *)xbuf); convert_sff_name(buf, size, xbuf); } static void get_qsfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size) { char xbuf[17]; memset(xbuf, 0, sizeof(xbuf)); - ii->f(ii, SFF_8436_BASE, SFF_8436_SN_START, 16, xbuf); + read_i2c(ii, SFF_8436_BASE, SFF_8436_SN_START, 16, (uint8_t *)xbuf); convert_sff_name(buf, size, xbuf); } static void get_qsfp_vendor_date(struct i2c_info *ii, char *buf, size_t size) { char xbuf[6]; memset(xbuf, 0, sizeof(xbuf)); - ii->f(ii, SFF_8436_BASE, SFF_8436_DATE_START, 6, xbuf); + read_i2c(ii, SFF_8436_BASE, SFF_8436_DATE_START, 6, (uint8_t *)xbuf); convert_sff_date(buf, size, xbuf); } static void print_sfp_vendor(struct i2c_info *ii, char *buf, size_t size) { char xbuf[80]; memset(xbuf, 0, sizeof(xbuf)); if (ii->qsfp != 0) { get_qsfp_vendor_name(ii, xbuf, 20); get_qsfp_vendor_pn(ii, &xbuf[20], 20); get_qsfp_vendor_sn(ii, &xbuf[40], 20); get_qsfp_vendor_date(ii, &xbuf[60], 20); } else { get_sfp_vendor_name(ii, xbuf, 20); get_sfp_vendor_pn(ii, &xbuf[20], 20); get_sfp_vendor_sn(ii, &xbuf[40], 20); get_sfp_vendor_date(ii, &xbuf[60], 20); } snprintf(buf, size, "vendor: %s PN: %s SN: %s DATE: %s", xbuf, &xbuf[20], &xbuf[40], &xbuf[60]); } /* * Converts internal templerature (SFF-8472, SFF-8436) * 16-bit unsigned value to human-readable representation: * * Internally measured Module temperature are represented * as a 16-bit signed twos complement value in increments of * 1/256 degrees Celsius, yielding a total range of –128C to +128C * that is considered valid between –40 and +125C. * */ static void -convert_sff_temp(char *buf, size_t size, char *xbuf) +convert_sff_temp(char *buf, size_t size, uint8_t *xbuf) { double d; - d = (double)(int8_t)xbuf[0]; - d += (double)(uint8_t)xbuf[1] / 256; + d = (double)xbuf[0]; + d += (double)xbuf[1] / 256; snprintf(buf, size, "%.2f C", d); } /* * Retrieves supplied voltage (SFF-8472, SFF-8436). * 16-bit usigned value, treated as range 0..+6.55 Volts */ static void -convert_sff_voltage(char *buf, size_t size, char *xbuf) +convert_sff_voltage(char *buf, size_t size, uint8_t *xbuf) { double d; - d = (double)(((uint8_t)xbuf[0] << 8) | (uint8_t)xbuf[1]); + d = (double)((xbuf[0] << 8) | xbuf[1]); snprintf(buf, size, "%.2f Volts", d / 10000); } /* * Converts value in @xbuf to both milliwats and dBm * human representation. */ static void -convert_sff_power(struct i2c_info *ii, char *buf, size_t size, char *xbuf) +convert_sff_power(struct i2c_info *ii, char *buf, size_t size, uint8_t *xbuf) { uint16_t mW; double dbm; - mW = ((uint8_t)xbuf[0] << 8) + (uint8_t)xbuf[1]; + mW = (xbuf[0] << 8) + xbuf[1]; /* Convert mw to dbm */ dbm = 10.0 * log10(1.0 * mW / 10000); /* * Assume internally-calibrated data. * This is always true for SFF-8346, and explicitly * checked for SFF-8472. */ /* Table 3.9, bit 5 is set, internally calibrated */ snprintf(buf, size, "%d.%02d mW (%.2f dBm)", mW / 10000, (mW % 10000) / 100, dbm); } static void get_sfp_temp(struct i2c_info *ii, char *buf, size_t size) { - char xbuf[2]; + uint8_t xbuf[2]; memset(xbuf, 0, sizeof(xbuf)); - ii->f(ii, SFF_8472_DIAG, SFF_8472_TEMP, 2, xbuf); + read_i2c(ii, SFF_8472_DIAG, SFF_8472_TEMP, 2, xbuf); convert_sff_temp(buf, size, xbuf); } static void get_sfp_voltage(struct i2c_info *ii, char *buf, size_t size) { - char xbuf[2]; + uint8_t xbuf[2]; memset(xbuf, 0, sizeof(xbuf)); - ii->f(ii, SFF_8472_DIAG, SFF_8472_VCC, 2, xbuf); + read_i2c(ii, SFF_8472_DIAG, SFF_8472_VCC, 2, xbuf); convert_sff_voltage(buf, size, xbuf); } static void get_qsfp_temp(struct i2c_info *ii, char *buf, size_t size) { - char xbuf[2]; + uint8_t xbuf[2]; memset(xbuf, 0, sizeof(xbuf)); - ii->f(ii, SFF_8436_BASE, SFF_8436_TEMP, 2, xbuf); + read_i2c(ii, SFF_8436_BASE, SFF_8436_TEMP, 2, xbuf); convert_sff_temp(buf, size, xbuf); } static void get_qsfp_voltage(struct i2c_info *ii, char *buf, size_t size) { - char xbuf[2]; + uint8_t xbuf[2]; memset(xbuf, 0, sizeof(xbuf)); - ii->f(ii, SFF_8436_BASE, SFF_8436_VCC, 2, xbuf); + read_i2c(ii, SFF_8436_BASE, SFF_8436_VCC, 2, xbuf); convert_sff_voltage(buf, size, xbuf); } static void get_sfp_rx_power(struct i2c_info *ii, char *buf, size_t size) { - char xbuf[2]; + uint8_t xbuf[2]; memset(xbuf, 0, sizeof(xbuf)); - ii->f(ii, SFF_8472_DIAG, SFF_8472_RX_POWER, 2, xbuf); + read_i2c(ii, SFF_8472_DIAG, SFF_8472_RX_POWER, 2, xbuf); convert_sff_power(ii, buf, size, xbuf); } static void get_sfp_tx_power(struct i2c_info *ii, char *buf, size_t size) { - char xbuf[2]; + uint8_t xbuf[2]; memset(xbuf, 0, sizeof(xbuf)); - ii->f(ii, SFF_8472_DIAG, SFF_8472_TX_POWER, 2, xbuf); + read_i2c(ii, SFF_8472_DIAG, SFF_8472_TX_POWER, 2, xbuf); convert_sff_power(ii, buf, size, xbuf); } static void get_qsfp_rx_power(struct i2c_info *ii, char *buf, size_t size, int chan) { - char xbuf[2]; + uint8_t xbuf[2]; memset(xbuf, 0, sizeof(xbuf)); - ii->f(ii, SFF_8436_BASE, SFF_8436_RX_CH1_MSB + (chan - 1) * 2, 2, xbuf); + read_i2c(ii, SFF_8436_BASE, SFF_8436_RX_CH1_MSB + (chan-1)*2, 2, xbuf); convert_sff_power(ii, buf, size, xbuf); } static void get_qsfp_tx_power(struct i2c_info *ii, char *buf, size_t size, int chan) { - char xbuf[2]; + uint8_t xbuf[2]; memset(xbuf, 0, sizeof(xbuf)); - ii->f(ii, SFF_8436_BASE, SFF_8436_TX_CH1_MSB + (chan -1) * 2, 2, xbuf); + read_i2c(ii, SFF_8436_BASE, SFF_8436_TX_CH1_MSB + (chan-1)*2, 2, xbuf); convert_sff_power(ii, buf, size, xbuf); } -/* Generic handler */ +static void +get_qsfp_rev_compliance(struct i2c_info *ii, char *buf, size_t size) +{ + uint8_t xbuf; + + xbuf = 0; + read_i2c(ii, SFF_8436_BASE, SFF_8436_STATUS, 1, &xbuf); + convert_sff_rev_compliance(buf, size, xbuf); +} + +static uint32_t +get_qsfp_br(struct i2c_info *ii) +{ + uint8_t xbuf; + uint32_t rate; + + xbuf = 0; + read_i2c(ii, SFF_8436_BASE, SFF_8436_BITRATE, 1, &xbuf); + rate = xbuf * 100; + if (xbuf == 0xFF) { + read_i2c(ii, SFF_8436_BASE, SFF_8636_BITRATE, 1, &xbuf); + rate = xbuf * 250; + } + + return (rate); +} + +/* + * Reads i2c data from opened kernel socket. + */ static int -read_i2c_generic(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len, - caddr_t buf) +read_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len, + uint8_t *buf) { struct ifi2creq req; int i, l; if (ii->error != 0) return (ii->error); ii->ifr->ifr_data = (caddr_t)&req; i = 0; l = 0; memset(&req, 0, sizeof(req)); req.dev_addr = addr; req.offset = off; req.len = len; while (len > 0) { l = (len > sizeof(req.data)) ? sizeof(req.data) : len; req.len = l; - if (ioctl(ii->s, SIOCGI2C, ii->ifr) != 0) { + if (ioctl(ii->fd, SIOCGI2C, ii->ifr) != 0) { ii->error = errno; return (errno); } memcpy(&buf[i], req.data, l); len -= l; i += l; req.offset += l; } return (0); } static void dump_i2c_data(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len) { unsigned char buf[16]; int i, read; while (len > 0) { memset(buf, 0, sizeof(buf)); read = (len > sizeof(buf)) ? sizeof(buf) : len; - ii->f(ii, addr, off, read, buf); + read_i2c(ii, addr, off, read, buf); if (ii->error != 0) { fprintf(stderr, "Error reading i2c info\n"); return; } printf("\t"); for (i = 0; i < read; i++) printf("%02X ", buf[i]); printf("\n"); len -= read; off += read; } } static void print_qsfp_status(struct i2c_info *ii, int verbose) { char buf[80], buf2[40], buf3[40]; uint8_t diag_type; + uint32_t bitrate; int i; /* Read diagnostic monitoring type */ - ii->f(ii, SFF_8436_BASE, SFF_8436_DIAG_TYPE, 1, (caddr_t)&diag_type); + read_i2c(ii, SFF_8436_BASE, SFF_8436_DIAG_TYPE, 1, (caddr_t)&diag_type); if (ii->error != 0) return; /* * Read monitoring data it is supplied. * XXX: It is not exactly clear from standard * how one can specify lack of measurements (passive cables case). */ if (diag_type != 0) ii->do_diag = 1; ii->qsfp = 1; /* Transceiver type */ get_qsfp_identifier(ii, buf, sizeof(buf)); get_qsfp_transceiver_class(ii, buf2, sizeof(buf2)); get_qsfp_connector(ii, buf3, sizeof(buf3)); if (ii->error == 0) printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3); print_sfp_vendor(ii, buf, sizeof(buf)); if (ii->error == 0) printf("\t%s\n", buf); + if (verbose > 1) { + get_qsfp_rev_compliance(ii, buf, sizeof(buf)); + if (ii->error == 0) + printf("\tcompliance level: %s\n", buf); + + bitrate = get_qsfp_br(ii); + if (ii->error == 0 && bitrate > 0) + printf("\tnominal bitrate: %u Mbps\n", bitrate); + } + /* Request current measurements if they are provided: */ if (ii->do_diag != 0) { get_qsfp_temp(ii, buf, sizeof(buf)); get_qsfp_voltage(ii, buf2, sizeof(buf2)); printf("\tmodule temperature: %s voltage: %s\n", buf, buf2); for (i = 1; i <= 4; i++) { get_qsfp_rx_power(ii, buf, sizeof(buf), i); get_qsfp_tx_power(ii, buf2, sizeof(buf2), i); printf("\tlane %d: RX: %s TX: %s\n", i, buf, buf2); } } if (verbose > 2) { printf("\n\tSFF8436 DUMP (0xA0 128..255 range):\n"); dump_i2c_data(ii, SFF_8436_BASE, 128, 128); printf("\n\tSFF8436 DUMP (0xA0 0..81 range):\n"); dump_i2c_data(ii, SFF_8436_BASE, 0, 82); } } static void print_sfp_status(struct i2c_info *ii, int verbose) { char buf[80], buf2[40], buf3[40]; uint8_t diag_type, flags; /* Read diagnostic monitoring type */ - ii->f(ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, (caddr_t)&diag_type); + read_i2c(ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, (caddr_t)&diag_type); if (ii->error != 0) return; /* * Read monitoring data IFF it is supplied AND is * internally calibrated */ flags = SFF_8472_DDM_DONE | SFF_8472_DDM_INTERNAL; if ((diag_type & flags) == flags) ii->do_diag = 1; /* Transceiver type */ get_sfp_identifier(ii, buf, sizeof(buf)); get_sfp_transceiver_class(ii, buf2, sizeof(buf2)); get_sfp_connector(ii, buf3, sizeof(buf3)); if (ii->error == 0) printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3); print_sfp_vendor(ii, buf, sizeof(buf)); if (ii->error == 0) printf("\t%s\n", buf); if (verbose > 5) printf_sfp_transceiver_descr(ii, buf, sizeof(buf)); /* * Request current measurements iff they are provided: */ if (ii->do_diag != 0) { get_sfp_temp(ii, buf, sizeof(buf)); get_sfp_voltage(ii, buf2, sizeof(buf2)); printf("\tmodule temperature: %s Voltage: %s\n", buf, buf2); get_sfp_rx_power(ii, buf, sizeof(buf)); get_sfp_tx_power(ii, buf2, sizeof(buf2)); printf("\tRX: %s TX: %s\n", buf, buf2); } if (verbose > 2) { printf("\n\tSFF8472 DUMP (0xA0 0..127 range):\n"); dump_i2c_data(ii, SFF_8472_BASE, 0, 128); } } void sfp_status(int s, struct ifreq *ifr, int verbose) { struct i2c_info ii; uint8_t id_byte; + /* Prepare necessary into pass to i2c reader */ memset(&ii, 0, sizeof(ii)); - /* Prepare necessary into to pass to NIC handler */ - ii.s = s; + ii.fd = s; ii.ifr = ifr; - ii.f = read_i2c_generic; /* * Try to read byte 0 from i2c: * Both SFF-8472 and SFF-8436 use it as * 'identification byte'. * Stop reading status on zero as value - * this might happen in case of empty transceiver slot. */ id_byte = 0; - ii.f(&ii, SFF_8472_BASE, SFF_8472_ID, 1, (caddr_t)&id_byte); + read_i2c(&ii, SFF_8472_BASE, SFF_8472_ID, 1, (caddr_t)&id_byte); if (ii.error != 0 || id_byte == 0) return; switch (id_byte) { case SFF_8024_ID_QSFP: case SFF_8024_ID_QSFPPLUS: print_qsfp_status(&ii, verbose); break; default: print_sfp_status(&ii, verbose); }; } Index: projects/ci20_mips/sbin =================================================================== --- projects/ci20_mips/sbin (revision 283030) +++ projects/ci20_mips/sbin (revision 283031) Property changes on: projects/ci20_mips/sbin ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sbin:r282931-283030 Index: projects/ci20_mips/share/man/man4/iic.4 =================================================================== --- projects/ci20_mips/share/man/man4/iic.4 (revision 283030) +++ projects/ci20_mips/share/man/man4/iic.4 (revision 283031) @@ -1,201 +1,258 @@ .\" Copyright (c) 2006, M. Warner Losh .\" Copyright (c) 1998, Nicolas Souchu .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd June 24, 2014 +.Dd May 15, 2015 .Dt IIC 4 .Os .Sh NAME .Nm iic .Nd I2C generic I/O device driver .Sh SYNOPSIS .Cd "device iic" .Pp .In dev/iicbus/iic.h .Sh DESCRIPTION The .Nm device driver provides generic I/O to any .Xr iicbus 4 instance. In order to control I2C devices, use .Pa /dev/iic? with the following ioctls: .Bl -tag -width ".Dv I2CRPTSTART" .It Dv I2CSTART .Pq Vt "struct iiccmd" Sends the start condition to the slave specified by the .Va slave element to the bus. The .Va slave element consists of a 7-bit address and a read/write bit -(i.e., 7-bit address << 1 | r/w). -If the read/write bit is set a read operation is initiated, if the read/write -bit is cleared a write operation is initiated. +(that is, a 7-bit address << 1 | r/w). +A read operation is initiated when the read/write bit is set, or a write +operation when it is cleared. All other elements are ignored. +If successful, the file descriptor receives exclusive +ownership of the underlying iicbus instance. .It Dv I2CRPTSTART .Pq Vt "struct iiccmd" Sends the repeated start condition to the slave specified by the .Va slave element to the bus. The slave address should be specified as in .Dv I2CSTART . All other elements are ignored. +.Dv I2CSTART +must have previously been issued on the same file descriptor. .It Dv I2CSTOP No argument is passed. Sends the stop condition to the bus. -This terminates the current transaction. +If +.Dv I2CSTART +was previously issued on the file descriptor, the current transaction is +terminated and exclusive ownership of the underlying iicbus instance is +released. +Otherwise, no action is performed. .It Dv I2CRSTCARD .Pq Vt "struct iiccmd" Resets the bus. The argument is completely ignored. +This command does not require +.Dv I2CSTART +to have been previously issued on the file descriptor. +If it was previously issued, exclusive ownership of the underlying iicbus +instance is released. .It Dv I2CWRITE .Pq Vt "struct iiccmd" Writes data to the .Xr iicbus 4 . -The bus should already be started. +The bus must already be started by a previous +.Dv I2CSTART +on the file descriptor. The .Va slave element is ignored. The .Va count element is the number of bytes to write. The .Va last element is a boolean flag. It is non-zero when additional write commands will follow. The .Va buf element is a pointer to the data to write to the bus. .It Dv I2CREAD .Pq Vt "struct iiccmd" Reads data from the .Xr iicbus 4 . -The bus should already be started. +The bus must already be started by a previous +.Dv I2CSTART +on the file descriptor. The .Va slave element is ignored. The .Va count element is the number of bytes to write. The .Va last element is a boolean flag. It is non-zero when additional write commands will follow. The .Va buf element is a pointer to where to store the data read from the bus. Short reads on the bus produce undefined results. .It Dv I2CRDWR .Pq Vt "struct iic_rdwr_data" Generic read/write interface. Allows for an arbitrary number of commands to be sent to an arbitrary number of devices on the bus. +Any previous transaction started by +.Dv I2CSTART +must be terminated by +.Dv I2CSTOP +or +.Dv I2CRSTCARD +before +.Dv I2CRDWR +can be issued on the same file descriptor. A read transfer is specified if .Dv IIC_M_RD is set in .Va flags . Otherwise the transfer is a write transfer. The .Va slave element specifies the 7-bit address with the read/write bit for the transfer. The read/write bit will be handled by the iicbus stack based on the specified transfer operation. The .Va len element is the number of .Pq Vt "struct iic_msg" messages encoded on .Pq Vt "struct iic_rdwr_data" . The .Va buf element is a buffer for that data. This ioctl is intended to be .Tn Linux compatible. +.It Dv I2CSADDR +.Pq Vt "uint8_t" +Associate the specified address with the file descriptor for use by +subsequent +.Xr read 2 +or +.Xr write 2 +calls. +The argument is an 8-bit address (that is, a 7-bit address << 1). +The read/write bit in the least-significant position is ignored. +Any subsequent read or write operation will set or clear that bit as needed. .El .Pp The following data structures are defined in .In dev/iicbus/iic.h and referenced above: .Bd -literal -offset indent struct iiccmd { u_char slave; int count; int last; char *buf; }; /* Designed to be compatible with linux's struct i2c_msg */ struct iic_msg { uint16_t slave; uint16_t flags; -#define IIC_M_RD 0x0001 /* read vs write */ +#define IIC_M_WR 0 /* Fake flag for write */ +#define IIC_M_RD 0x0001 /* read vs write */ +#define IIC_M_NOSTOP 0x0002 /* do not send a I2C stop after message */ +#define IIC_M_NOSTART 0x0004 /* do not send a I2C start before message */ uint16_t len; /* msg length */ uint8_t * buf; }; struct iic_rdwr_data { struct iic_msg *msgs; uint32_t nmsgs; }; .Ed .Pp -It is also possible to use read/write routines, then I2C start/stop handshake is -managed by the -.Xr iicbus 4 -system. -However, the address used for the read/write routines is the one -passed to last +It is also possible to use +.Xr read 2 +or +.Xr write 2 , +in which case the I2C start/stop handshake is managed by +.Xr iicbus 4 . +The address used for the read/write operation is the one passed to the most +recent .Dv I2CSTART .Xr ioctl 2 -to this device. +or +.Dv I2CSADDR +.Xr ioctl 2 +on the open +.Pa /dev/iic? +file descriptor. +Closing the file descriptor clears any addressing state established by a +previous +.Dv I2CSTART +or +.Dv I2CSADDR , +stops any transaction established by a not-yet-terminated +.Dv I2CSTART , +and releases iicbus ownership. +Because addressing state is stored on a per-file-descriptor basis, it is +permissible for multiple file descriptors to be simultaneously open on the +same +.Pa /dev/iic? +device. +Concurrent transactions on those descriptors are synchronized by the +exclusive-ownership requests issued to the underlying iicbus instance. .Sh SEE ALSO .Xr ioctl 2 , .Xr read 2 , .Xr write 2 , .Xr iicbus 4 .Sh HISTORY The .Nm manual page first appeared in .Fx 3.0 . .Sh AUTHORS .An -nosplit This manual page was written by .An Nicolas Souchu and .An M. Warner Losh . -.Sh BUGS -Only the -.Dv I2CRDWR -.Xr ioctl 2 -is thread safe. -All other interfaces suffer from some kind of race. Index: projects/ci20_mips/share/man/man4 =================================================================== --- projects/ci20_mips/share/man/man4 (revision 283030) +++ projects/ci20_mips/share/man/man4 (revision 283031) Property changes on: projects/ci20_mips/share/man/man4 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/share/man/man4:r282737-283030 Index: projects/ci20_mips/share/mk/src.libnames.mk =================================================================== --- projects/ci20_mips/share/mk/src.libnames.mk (revision 283030) +++ projects/ci20_mips/share/mk/src.libnames.mk (revision 283031) @@ -1,362 +1,362 @@ # $FreeBSD$ # # The include file define library names suitable # for INTERNALLIB and PRIVATELIB definition .if !target(____) .error src.libnames.mk cannot be included directly. .endif .include ROOTSRCDIR= ${.MAKE.MAKEFILES:M*/src.libnames.mk:H:H:H} ROOTOBJDIR= ${.OBJDIR:S/${.CURDIR}//}${ROOTSRCDIR} _PRIVATELIBS= \ atf_c \ atf_cxx \ bsdstat \ event \ heimipcc \ heimipcs \ ldns \ sqlite3 \ ssh \ ucl \ unbound _INTERNALLIBS= \ amu \ bsnmptools \ cron \ elftc \ fifolog \ ipf \ lpr \ mandoc \ netbsd \ ntp \ ntpevent \ ohash \ opts \ parse \ readline \ sl \ sm \ smdb \ smutil \ telnet \ vers _LIBRARIES= \ ${_PRIVATELIBS} \ ${_INTERNALLIBS} \ alias \ archive \ asn1 \ auditd \ begemot \ bluetooth \ bsdxml \ bsm \ bsnmp \ bz2 \ c \ c_pic \ calendar \ cam \ capsicum \ casper \ com_err \ compiler_rt \ crypt \ crypto \ ctf \ cuse \ cxxrt \ devctl \ devinfo \ devstat \ dialog \ dpv \ dwarf \ edit \ elf \ execinfo \ fetch \ figpar \ geom \ gnuregex \ gpio \ gssapi \ gssapi_krb5 \ hdb \ heimbase \ heimntlm \ heimsqlite \ hx509 \ ipsec \ jail \ kadm5clnt \ kadm5srv \ kafs5 \ kdc \ kiconv \ krb5 \ kvm \ l \ lzma \ m \ magic \ mandoc \ md \ memstat \ mp \ mt \ nandfs \ ncurses \ ncursesw \ netgraph \ ngatm \ nv \ opie \ pam \ pcap \ pcsclite \ pjdlog \ pmc \ proc \ procstat \ pthread \ radius \ readline \ roken \ rpcsec_gss \ rpcsvc \ rt \ sbuf \ sdp \ sm \ smb \ ssl \ ssp_nonshared \ stdthreads \ supcplusplus \ tacplus \ termcapw \ ufs \ ugidfw \ ulog \ usb \ usbhid \ util \ vmmapi \ wind \ wrap \ xo \ y \ ypclnt \ z _DP_archive= z bz2 lzma bsdxml .if ${MK_OPENSSL} != "no" _DP_archive+= crypto .else _DP_archive+= md .endif _DP_ssl= crypto _DP_ssh= crypto crypt .if ${MK_LDNS} != "no" _DP_ssh+= ldns z .endif _DP_edit= ncursesw .if ${MK_OPENSSL} != "no" _DP_bsnmp= crypto .endif _DP_geom= bsdxml sbuf _DP_cam= sbuf _DP_casper= capsicum nv pjdlog _DP_capsicum= nv _DP_pjdlog= util _DP_opie= md _DP_usb= pthread _DP_unbound= pthread _DP_rt= pthread .if ${MK_OPENSSL} == "no" _DP_radius= md .else _DP_radius= crypto .endif _DP_procstat= kvm util elf .if ${MK_CXX} == "yes" .if ${MK_LIBCPLUSPLUS} != "no" _DP_proc= cxxrt .else _DP_proc= supcplusplus .endif .endif .if ${MK_CDDL} != "no" _DP_proc+= ctf .endif _DP_mp= crypto _DP_memstat= kvm _DP_magic= z _DP_mt= bsdxml _DP_ldns= crypto .if ${MK_OPENSSL} != "no" _DP_fetch= ssl crypto .else _DP_fetch= md .endif _DP_execinfo= elf _DP_dwarf= elf _DP_dpv= dialog figpar util _DP_dialog= ncursesw m _DP_cuse= pthread _DP_atf_cxx= atf_c _DP_devstat= kvm _DP_pam= radius tacplus opie md util .if ${MK_KERBEROS} != "no" _DP_pam+= krb5 .endif .if ${MK_OPENSSH} != "no" _DP_pam+= ssh .endif .if ${MK_NIS} != "no" _DP_pam+= ypclnt .endif _DP_krb5+= asn1 com_err crypt crypto hx509 roken wind heimbase heimipcc \ pthread _DP_gssapi_krb5+= gssapi krb5 crypto roken asn1 com_err _DP_lzma= pthread _DP_ucl= m _DP_vmmapi= util # Define spacial cases LDADD_supcplusplus= -lsupc++ LIBATF_C= ${DESTDIR}${LIBDIR}/libprivateatf-c.a LIBATF_CXX= ${DESTDIR}${LIBDIR}/libprivateatf-c++.a LDADD_atf_c= -lprivateatf-c LDADD_atf_cxx= -lprivateatf-c++ .for _l in ${_PRIVATELIBS} LIB${_l:tu}?= ${DESTDIR}${LIBDIR}/libprivate${_l}.a .endfor .for _l in ${_LIBRARIES} .if ${_INTERNALLIBS:M${_l}} LDADD_${_l}_L+= -L${LIB${_l:tu}DIR} .endif DPADD_${_l}?= ${LIB${_l:tu}} .if ${_PRIVATELIBS:M${_l}} LDADD_${_l}?= -lprivate${_l} .else LDADD_${_l}?= ${LDADD_${_l}_L} -l${_l} .endif .if defined(_DP_${_l}) && defined(NO_SHARED) .for _d in ${_DP_${_l}} DPADD_${_l}+= ${DPADD_${_d}} LDADD_${_l}+= ${LDADD_${_d}} .endfor .endif .endfor DPADD_atf_cxx+= ${DPADD_atf_c} LDADD_atf_cxx+= ${LDADD_atf_c} DPADD_sqlite3+= ${DPADD_pthread} LDADD_sqlite3+= ${LDADD_pthread} DPADD_fifolog+= ${DPADD_z} LDADD_fifolog+= ${LDADD_z} DPADD_ipf+= ${DPADD_kvm} LDADD_ipf+= ${LDADD_kvm} DPADD_mt+= ${DPADD_sbuf} LDADD_mt+= ${LDADD_sbuf} # The following depends on libraries which are using pthread DPADD_hdb+= ${DPADD_pthread} LDADD_hdb+= ${LDADD_pthread} DPADD_kadm5srv+= ${DPADD_pthread} LDADD_kadm5srv+= ${LDADD_pthread} DPADD_krb5+= ${DPADD_pthread} LDADD_krb5+= ${LDADD_pthread} DPADD_gssapi_krb5+= ${DPADD_pthread} LDADD_gssapi_krb5+= ${LDADD_pthread} .for _l in ${LIBADD} .if ${_PRIVATELIBS:M${_l}} USEPRIVATELIB+= ${_l} .endif DPADD+= ${DPADD_${_l}:Umissing-dpadd_${_l}} LDADD+= ${LDADD_${_l}} .endfor .if defined(DPADD) && ${DPADD:Mmissing-dpadd_*} .error Missing ${DPADD:Mmissing-dpadd_*:S/missing-dpadd_//:S/^/DPADD_/} variable add "${DPADD:Mmissing-dpadd_*:S/missing-dpadd_//}" to _LIBRARIES, _INTERNALLIBS, or _PRIVATELIBS and define "${DPADD:Mmissing-dpadd_*:S/missing-dpadd_//:S/^/LIB/:tu}". .endif LIBELFTCDIR= ${ROOTOBJDIR}/lib/libelftc LIBELFTC?= ${LIBELFTCDIR}/libelftc.a LIBREADLINEDIR= ${ROOTOBJDIR}/gnu/lib/libreadline/readline LIBREADLINE?= ${LIBREADLINEDIR}/libreadline.a LIBOHASHDIR= ${ROOTOBJDIR}/lib/libohash LIBOHASH?= ${LIBOHASHDIR}/libohash.a LIBMANDOCDIR= ${ROOTOBJDIR}/lib/libmandoc LIBMANDOC?= ${LIBMANDOCDIR}/libmandoc.a LIBSMDIR= ${ROOTOBJDIR}/lib/libsm LIBSM?= ${LIBSMDIR}/libsm.a LIBSMDBDIR= ${ROOTOBJDIR}/lib/libsmdb LIBSMDB?= ${LIBSMDBDIR}/libsmdb.a LIBSMUTILDIR= ${ROOTOBJDIR}/lib/libsmutil LIBSMUTIL?= ${LIBSMDBDIR}/libsmutil.a LIBNETBSDDIR?= ${ROOTOBJDIR}/lib/libnetbsd LIBNETBSD?= ${LIBNETBSDDIR}/libnetbsd.a LIBVERSDIR?= ${ROOTOBJDIR}/kerberos5/lib/libvers LIBVERS?= ${LIBVERSDIR}/libvers.a LIBSLDIR= ${ROOTOBJDIR}/kerberos5/lib/libsl LIBSL?= ${LIBSLDIR}/libsl.a LIBIPFDIR= ${ROOTOBJDIR}/sbin/ipf/libipf LIBIPF?= ${LIBIPFDIR}/libipf.a LIBTELNETDIR= ${ROOTOBJDIR}/lib/libtelnet LIBTELNET?= ${LIBIPFDIR}/libtelnet.a LIBCRONDIR= ${ROOTOBJDIR}/usr.sbin/cron/lib LIBCRON?= ${LIBCRONDIR}/libcron.a LIBNTPDIR= ${ROOTOBJDIR}/usr.sbin/ntp/libntp LIBNTP?= ${LIBNTPDIR}/libntp.a LIBNTPEVENTDIR= ${ROOTOBJDIR}/usr.sbin/ntp/libntpevent -LIBNTPEVENT?= ${LIBNTPDIR}/libntpevent.a +LIBNTPEVENT?= ${LIBNTPEVENTDIR}/libntpevent.a LIBOPTSDIR= ${ROOTOBJDIR}/usr.sbin/ntp/libopts LIBOTPS?= ${LIBOPTSDIR}/libopts.a LIBPARSEDIR= ${ROOTOBJDIR}/usr.sbin/ntp/libparse LIBPARSE?= ${LIBPARSEDIR}/libparse.a LIBLPRDIR= ${ROOTOBJDIR}/usr.sbin/lpr/common_source LIBLPR?= ${LIBOPTSDIR}/liblpr.a LIBFIFOLOGDIR= ${ROOTOBJDIR}/usr.sbin/fifolog/lib LIBFIFOLOG?= ${LIBOPTSDIR}/libfifolog.a LIBBSNMPTOOLSDIR= ${ROOTOBJDIR}/usr.sbin/bsnmpd/tools/libbsnmptools LIBBSNMPTOOLS?= ${LIBBSNMPTOOLSDIR}/libbsnmptools.a LIBAMUDIR= ${ROOTOBJDIR}/usr.sbin/amd/libamu LIBAMU?= ${LIBAMUDIR}/libamu/libamu.a Index: projects/ci20_mips/share =================================================================== --- projects/ci20_mips/share (revision 283030) +++ projects/ci20_mips/share (revision 283031) Property changes on: projects/ci20_mips/share ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/share:r282931-283030 Index: projects/ci20_mips/sys/amd64/amd64/pmap.c =================================================================== --- projects/ci20_mips/sys/amd64/amd64/pmap.c (revision 283030) +++ projects/ci20_mips/sys/amd64/amd64/pmap.c (revision 283031) @@ -1,6982 +1,6998 @@ /*- * Copyright (c) 1991 Regents of the University of California. * All rights reserved. * Copyright (c) 1994 John S. Dyson * All rights reserved. * Copyright (c) 1994 David Greenman * All rights reserved. * Copyright (c) 2003 Peter Wemm * All rights reserved. * Copyright (c) 2005-2010 Alan L. Cox * All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department and William Jolitz of UUNET Technologies Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: @(#)pmap.c 7.7 (Berkeley) 5/12/91 */ /*- * Copyright (c) 2003 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by Jake Burkholder, * Safeport Network Services, and Network Associates Laboratories, the * Security Research Division of Network Associates, Inc. under * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA * CHATS research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define AMD64_NPT_AWARE #include __FBSDID("$FreeBSD$"); /* * Manages physical address maps. * * Since the information managed by this module is * also stored by the logical address mapping module, * this module may throw away valid virtual-to-physical * mappings at almost any time. However, invalidations * of virtual-to-physical mappings must be done as * requested. * * In order to cope with hardware architectures which * make virtual-to-physical map invalidates expensive, * this module may delay invalidate or reduced protection * operations until such time as they are actually * necessary. This module is given full information as * to which processors are currently using which maps, * and to when physical maps must be made correct. */ #include "opt_pmap.h" #include "opt_vm.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SMP #include #endif static __inline boolean_t pmap_type_guest(pmap_t pmap) { return ((pmap->pm_type == PT_EPT) || (pmap->pm_type == PT_RVI)); } static __inline boolean_t pmap_emulate_ad_bits(pmap_t pmap) { return ((pmap->pm_flags & PMAP_EMULATE_AD_BITS) != 0); } static __inline pt_entry_t pmap_valid_bit(pmap_t pmap) { pt_entry_t mask; switch (pmap->pm_type) { case PT_X86: case PT_RVI: mask = X86_PG_V; break; case PT_EPT: if (pmap_emulate_ad_bits(pmap)) mask = EPT_PG_EMUL_V; else mask = EPT_PG_READ; break; default: panic("pmap_valid_bit: invalid pm_type %d", pmap->pm_type); } return (mask); } static __inline pt_entry_t pmap_rw_bit(pmap_t pmap) { pt_entry_t mask; switch (pmap->pm_type) { case PT_X86: case PT_RVI: mask = X86_PG_RW; break; case PT_EPT: if (pmap_emulate_ad_bits(pmap)) mask = EPT_PG_EMUL_RW; else mask = EPT_PG_WRITE; break; default: panic("pmap_rw_bit: invalid pm_type %d", pmap->pm_type); } return (mask); } static __inline pt_entry_t pmap_global_bit(pmap_t pmap) { pt_entry_t mask; switch (pmap->pm_type) { case PT_X86: mask = X86_PG_G; break; case PT_RVI: case PT_EPT: mask = 0; break; default: panic("pmap_global_bit: invalid pm_type %d", pmap->pm_type); } return (mask); } static __inline pt_entry_t pmap_accessed_bit(pmap_t pmap) { pt_entry_t mask; switch (pmap->pm_type) { case PT_X86: case PT_RVI: mask = X86_PG_A; break; case PT_EPT: if (pmap_emulate_ad_bits(pmap)) mask = EPT_PG_READ; else mask = EPT_PG_A; break; default: panic("pmap_accessed_bit: invalid pm_type %d", pmap->pm_type); } return (mask); } static __inline pt_entry_t pmap_modified_bit(pmap_t pmap) { pt_entry_t mask; switch (pmap->pm_type) { case PT_X86: case PT_RVI: mask = X86_PG_M; break; case PT_EPT: if (pmap_emulate_ad_bits(pmap)) mask = EPT_PG_WRITE; else mask = EPT_PG_M; break; default: panic("pmap_modified_bit: invalid pm_type %d", pmap->pm_type); } return (mask); } extern struct pcpu __pcpu[]; #if !defined(DIAGNOSTIC) #ifdef __GNUC_GNU_INLINE__ #define PMAP_INLINE __attribute__((__gnu_inline__)) inline #else #define PMAP_INLINE extern inline #endif #else #define PMAP_INLINE #endif #ifdef PV_STATS #define PV_STAT(x) do { x ; } while (0) #else #define PV_STAT(x) do { } while (0) #endif #define pa_index(pa) ((pa) >> PDRSHIFT) #define pa_to_pvh(pa) (&pv_table[pa_index(pa)]) #define NPV_LIST_LOCKS MAXCPU #define PHYS_TO_PV_LIST_LOCK(pa) \ (&pv_list_locks[pa_index(pa) % NPV_LIST_LOCKS]) #define CHANGE_PV_LIST_LOCK_TO_PHYS(lockp, pa) do { \ struct rwlock **_lockp = (lockp); \ struct rwlock *_new_lock; \ \ _new_lock = PHYS_TO_PV_LIST_LOCK(pa); \ if (_new_lock != *_lockp) { \ if (*_lockp != NULL) \ rw_wunlock(*_lockp); \ *_lockp = _new_lock; \ rw_wlock(*_lockp); \ } \ } while (0) #define CHANGE_PV_LIST_LOCK_TO_VM_PAGE(lockp, m) \ CHANGE_PV_LIST_LOCK_TO_PHYS(lockp, VM_PAGE_TO_PHYS(m)) #define RELEASE_PV_LIST_LOCK(lockp) do { \ struct rwlock **_lockp = (lockp); \ \ if (*_lockp != NULL) { \ rw_wunlock(*_lockp); \ *_lockp = NULL; \ } \ } while (0) #define VM_PAGE_TO_PV_LIST_LOCK(m) \ PHYS_TO_PV_LIST_LOCK(VM_PAGE_TO_PHYS(m)) struct pmap kernel_pmap_store; vm_offset_t virtual_avail; /* VA of first avail page (after kernel bss) */ vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */ int nkpt; SYSCTL_INT(_machdep, OID_AUTO, nkpt, CTLFLAG_RD, &nkpt, 0, "Number of kernel page table pages allocated on bootup"); static int ndmpdp; vm_paddr_t dmaplimit; vm_offset_t kernel_vm_end = VM_MIN_KERNEL_ADDRESS; pt_entry_t pg_nx; static SYSCTL_NODE(_vm, OID_AUTO, pmap, CTLFLAG_RD, 0, "VM/pmap parameters"); static int pat_works = 1; SYSCTL_INT(_vm_pmap, OID_AUTO, pat_works, CTLFLAG_RD, &pat_works, 1, "Is page attribute table fully functional?"); static int pg_ps_enabled = 1; SYSCTL_INT(_vm_pmap, OID_AUTO, pg_ps_enabled, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &pg_ps_enabled, 0, "Are large page mappings enabled?"); #define PAT_INDEX_SIZE 8 static int pat_index[PAT_INDEX_SIZE]; /* cache mode to PAT index conversion */ static u_int64_t KPTphys; /* phys addr of kernel level 1 */ static u_int64_t KPDphys; /* phys addr of kernel level 2 */ u_int64_t KPDPphys; /* phys addr of kernel level 3 */ u_int64_t KPML4phys; /* phys addr of kernel level 4 */ static u_int64_t DMPDphys; /* phys addr of direct mapped level 2 */ static u_int64_t DMPDPphys; /* phys addr of direct mapped level 3 */ static int ndmpdpphys; /* number of DMPDPphys pages */ static struct rwlock_padalign pvh_global_lock; /* * Data for the pv entry allocation mechanism */ static TAILQ_HEAD(pch, pv_chunk) pv_chunks = TAILQ_HEAD_INITIALIZER(pv_chunks); static struct mtx pv_chunks_mutex; static struct rwlock pv_list_locks[NPV_LIST_LOCKS]; static struct md_page *pv_table; /* * All those kernel PT submaps that BSD is so fond of */ pt_entry_t *CMAP1 = 0; caddr_t CADDR1 = 0; static int pmap_flags = PMAP_PDE_SUPERPAGE; /* flags for x86 pmaps */ int pmap_pcid_enabled = 0; SYSCTL_INT(_vm_pmap, OID_AUTO, pcid_enabled, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &pmap_pcid_enabled, 0, "Is TLB Context ID enabled ?"); int invpcid_works = 0; SYSCTL_INT(_vm_pmap, OID_AUTO, invpcid_works, CTLFLAG_RD, &invpcid_works, 0, "Is the invpcid instruction available ?"); static int pmap_pcid_save_cnt_proc(SYSCTL_HANDLER_ARGS) { int i; uint64_t res; res = 0; CPU_FOREACH(i) { res += cpuid_to_pcpu[i]->pc_pm_save_cnt; } return (sysctl_handle_64(oidp, &res, 0, req)); } SYSCTL_PROC(_vm_pmap, OID_AUTO, pcid_save_cnt, CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0, pmap_pcid_save_cnt_proc, "QU", "Count of saved TLB context on switch"); /* * Crashdump maps. */ static caddr_t crashdumpmap; static void free_pv_chunk(struct pv_chunk *pc); static void free_pv_entry(pmap_t pmap, pv_entry_t pv); static pv_entry_t get_pv_entry(pmap_t pmap, struct rwlock **lockp); static int popcnt_pc_map_elem_pq(uint64_t elem); static vm_page_t reclaim_pv_chunk(pmap_t locked_pmap, struct rwlock **lockp); static void reserve_pv_entries(pmap_t pmap, int needed, struct rwlock **lockp); static void pmap_pv_demote_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa, struct rwlock **lockp); static boolean_t pmap_pv_insert_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa, struct rwlock **lockp); static void pmap_pv_promote_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa, struct rwlock **lockp); static void pmap_pvh_free(struct md_page *pvh, pmap_t pmap, vm_offset_t va); static pv_entry_t pmap_pvh_remove(struct md_page *pvh, pmap_t pmap, vm_offset_t va); static int pmap_change_attr_locked(vm_offset_t va, vm_size_t size, int mode); static boolean_t pmap_demote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va); static boolean_t pmap_demote_pde_locked(pmap_t pmap, pd_entry_t *pde, vm_offset_t va, struct rwlock **lockp); static boolean_t pmap_demote_pdpe(pmap_t pmap, pdp_entry_t *pdpe, vm_offset_t va); static boolean_t pmap_enter_pde(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, struct rwlock **lockp); static vm_page_t pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, vm_page_t mpte, struct rwlock **lockp); static void pmap_fill_ptp(pt_entry_t *firstpte, pt_entry_t newpte); static int pmap_insert_pt_page(pmap_t pmap, vm_page_t mpte); static void pmap_kenter_attr(vm_offset_t va, vm_paddr_t pa, int mode); static vm_page_t pmap_lookup_pt_page(pmap_t pmap, vm_offset_t va); static void pmap_pde_attr(pd_entry_t *pde, int cache_bits, int mask); static void pmap_promote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va, struct rwlock **lockp); static boolean_t pmap_protect_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t sva, vm_prot_t prot); static void pmap_pte_attr(pt_entry_t *pte, int cache_bits, int mask); static int pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva, struct spglist *free, struct rwlock **lockp); static int pmap_remove_pte(pmap_t pmap, pt_entry_t *ptq, vm_offset_t sva, pd_entry_t ptepde, struct spglist *free, struct rwlock **lockp); static void pmap_remove_pt_page(pmap_t pmap, vm_page_t mpte); static void pmap_remove_page(pmap_t pmap, vm_offset_t va, pd_entry_t *pde, struct spglist *free); static boolean_t pmap_try_insert_pv_entry(pmap_t pmap, vm_offset_t va, vm_page_t m, struct rwlock **lockp); static void pmap_update_pde(pmap_t pmap, vm_offset_t va, pd_entry_t *pde, pd_entry_t newpde); static void pmap_update_pde_invalidate(pmap_t, vm_offset_t va, pd_entry_t pde); static vm_page_t _pmap_allocpte(pmap_t pmap, vm_pindex_t ptepindex, struct rwlock **lockp); static vm_page_t pmap_allocpde(pmap_t pmap, vm_offset_t va, struct rwlock **lockp); static vm_page_t pmap_allocpte(pmap_t pmap, vm_offset_t va, struct rwlock **lockp); static void _pmap_unwire_ptp(pmap_t pmap, vm_offset_t va, vm_page_t m, struct spglist *free); static int pmap_unuse_pt(pmap_t, vm_offset_t, pd_entry_t, struct spglist *); static vm_offset_t pmap_kmem_choose(vm_offset_t addr); /* * Move the kernel virtual free pointer to the next * 2MB. This is used to help improve performance * by using a large (2MB) page for much of the kernel * (.text, .data, .bss) */ static vm_offset_t pmap_kmem_choose(vm_offset_t addr) { vm_offset_t newaddr = addr; newaddr = (addr + (NBPDR - 1)) & ~(NBPDR - 1); return (newaddr); } /********************/ /* Inline functions */ /********************/ /* Return a non-clipped PD index for a given VA */ static __inline vm_pindex_t pmap_pde_pindex(vm_offset_t va) { return (va >> PDRSHIFT); } /* Return various clipped indexes for a given VA */ static __inline vm_pindex_t pmap_pte_index(vm_offset_t va) { return ((va >> PAGE_SHIFT) & ((1ul << NPTEPGSHIFT) - 1)); } static __inline vm_pindex_t pmap_pde_index(vm_offset_t va) { return ((va >> PDRSHIFT) & ((1ul << NPDEPGSHIFT) - 1)); } static __inline vm_pindex_t pmap_pdpe_index(vm_offset_t va) { return ((va >> PDPSHIFT) & ((1ul << NPDPEPGSHIFT) - 1)); } static __inline vm_pindex_t pmap_pml4e_index(vm_offset_t va) { return ((va >> PML4SHIFT) & ((1ul << NPML4EPGSHIFT) - 1)); } /* Return a pointer to the PML4 slot that corresponds to a VA */ static __inline pml4_entry_t * pmap_pml4e(pmap_t pmap, vm_offset_t va) { return (&pmap->pm_pml4[pmap_pml4e_index(va)]); } /* Return a pointer to the PDP slot that corresponds to a VA */ static __inline pdp_entry_t * pmap_pml4e_to_pdpe(pml4_entry_t *pml4e, vm_offset_t va) { pdp_entry_t *pdpe; pdpe = (pdp_entry_t *)PHYS_TO_DMAP(*pml4e & PG_FRAME); return (&pdpe[pmap_pdpe_index(va)]); } /* Return a pointer to the PDP slot that corresponds to a VA */ static __inline pdp_entry_t * pmap_pdpe(pmap_t pmap, vm_offset_t va) { pml4_entry_t *pml4e; pt_entry_t PG_V; PG_V = pmap_valid_bit(pmap); pml4e = pmap_pml4e(pmap, va); if ((*pml4e & PG_V) == 0) return (NULL); return (pmap_pml4e_to_pdpe(pml4e, va)); } /* Return a pointer to the PD slot that corresponds to a VA */ static __inline pd_entry_t * pmap_pdpe_to_pde(pdp_entry_t *pdpe, vm_offset_t va) { pd_entry_t *pde; pde = (pd_entry_t *)PHYS_TO_DMAP(*pdpe & PG_FRAME); return (&pde[pmap_pde_index(va)]); } /* Return a pointer to the PD slot that corresponds to a VA */ static __inline pd_entry_t * pmap_pde(pmap_t pmap, vm_offset_t va) { pdp_entry_t *pdpe; pt_entry_t PG_V; PG_V = pmap_valid_bit(pmap); pdpe = pmap_pdpe(pmap, va); if (pdpe == NULL || (*pdpe & PG_V) == 0) return (NULL); return (pmap_pdpe_to_pde(pdpe, va)); } /* Return a pointer to the PT slot that corresponds to a VA */ static __inline pt_entry_t * pmap_pde_to_pte(pd_entry_t *pde, vm_offset_t va) { pt_entry_t *pte; pte = (pt_entry_t *)PHYS_TO_DMAP(*pde & PG_FRAME); return (&pte[pmap_pte_index(va)]); } /* Return a pointer to the PT slot that corresponds to a VA */ static __inline pt_entry_t * pmap_pte(pmap_t pmap, vm_offset_t va) { pd_entry_t *pde; pt_entry_t PG_V; PG_V = pmap_valid_bit(pmap); pde = pmap_pde(pmap, va); if (pde == NULL || (*pde & PG_V) == 0) return (NULL); if ((*pde & PG_PS) != 0) /* compat with i386 pmap_pte() */ return ((pt_entry_t *)pde); return (pmap_pde_to_pte(pde, va)); } static __inline void pmap_resident_count_inc(pmap_t pmap, int count) { PMAP_LOCK_ASSERT(pmap, MA_OWNED); pmap->pm_stats.resident_count += count; } static __inline void pmap_resident_count_dec(pmap_t pmap, int count) { PMAP_LOCK_ASSERT(pmap, MA_OWNED); KASSERT(pmap->pm_stats.resident_count >= count, ("pmap %p resident count underflow %ld %d", pmap, pmap->pm_stats.resident_count, count)); pmap->pm_stats.resident_count -= count; } PMAP_INLINE pt_entry_t * vtopte(vm_offset_t va) { u_int64_t mask = ((1ul << (NPTEPGSHIFT + NPDEPGSHIFT + NPDPEPGSHIFT + NPML4EPGSHIFT)) - 1); KASSERT(va >= VM_MAXUSER_ADDRESS, ("vtopte on a uva/gpa 0x%0lx", va)); return (PTmap + ((va >> PAGE_SHIFT) & mask)); } static __inline pd_entry_t * vtopde(vm_offset_t va) { u_int64_t mask = ((1ul << (NPDEPGSHIFT + NPDPEPGSHIFT + NPML4EPGSHIFT)) - 1); KASSERT(va >= VM_MAXUSER_ADDRESS, ("vtopde on a uva/gpa 0x%0lx", va)); return (PDmap + ((va >> PDRSHIFT) & mask)); } static u_int64_t allocpages(vm_paddr_t *firstaddr, int n) { u_int64_t ret; ret = *firstaddr; bzero((void *)ret, n * PAGE_SIZE); *firstaddr += n * PAGE_SIZE; return (ret); } CTASSERT(powerof2(NDMPML4E)); /* number of kernel PDP slots */ #define NKPDPE(ptpgs) howmany((ptpgs), NPDEPG) static void nkpt_init(vm_paddr_t addr) { int pt_pages; #ifdef NKPT pt_pages = NKPT; #else pt_pages = howmany(addr, 1 << PDRSHIFT); pt_pages += NKPDPE(pt_pages); /* * Add some slop beyond the bare minimum required for bootstrapping * the kernel. * * This is quite important when allocating KVA for kernel modules. * The modules are required to be linked in the negative 2GB of * the address space. If we run out of KVA in this region then * pmap_growkernel() will need to allocate page table pages to map * the entire 512GB of KVA space which is an unnecessary tax on * physical memory. */ pt_pages += 8; /* 16MB additional slop for kernel modules */ #endif nkpt = pt_pages; } static void create_pagetables(vm_paddr_t *firstaddr) { int i, j, ndm1g, nkpdpe; pt_entry_t *pt_p; pd_entry_t *pd_p; pdp_entry_t *pdp_p; pml4_entry_t *p4_p; /* Allocate page table pages for the direct map */ ndmpdp = (ptoa(Maxmem) + NBPDP - 1) >> PDPSHIFT; if (ndmpdp < 4) /* Minimum 4GB of dirmap */ ndmpdp = 4; ndmpdpphys = howmany(ndmpdp, NPDPEPG); if (ndmpdpphys > NDMPML4E) { /* * Each NDMPML4E allows 512 GB, so limit to that, * and then readjust ndmpdp and ndmpdpphys. */ printf("NDMPML4E limits system to %d GB\n", NDMPML4E * 512); Maxmem = atop(NDMPML4E * NBPML4); ndmpdpphys = NDMPML4E; ndmpdp = NDMPML4E * NPDEPG; } DMPDPphys = allocpages(firstaddr, ndmpdpphys); ndm1g = 0; if ((amd_feature & AMDID_PAGE1GB) != 0) ndm1g = ptoa(Maxmem) >> PDPSHIFT; if (ndm1g < ndmpdp) DMPDphys = allocpages(firstaddr, ndmpdp - ndm1g); dmaplimit = (vm_paddr_t)ndmpdp << PDPSHIFT; /* Allocate pages */ KPML4phys = allocpages(firstaddr, 1); KPDPphys = allocpages(firstaddr, NKPML4E); /* * Allocate the initial number of kernel page table pages required to * bootstrap. We defer this until after all memory-size dependent * allocations are done (e.g. direct map), so that we don't have to * build in too much slop in our estimate. * * Note that when NKPML4E > 1, we have an empty page underneath * all but the KPML4I'th one, so we need NKPML4E-1 extra (zeroed) * pages. (pmap_enter requires a PD page to exist for each KPML4E.) */ nkpt_init(*firstaddr); nkpdpe = NKPDPE(nkpt); KPTphys = allocpages(firstaddr, nkpt); KPDphys = allocpages(firstaddr, nkpdpe); /* Fill in the underlying page table pages */ /* Nominally read-only (but really R/W) from zero to physfree */ /* XXX not fully used, underneath 2M pages */ pt_p = (pt_entry_t *)KPTphys; for (i = 0; ptoa(i) < *firstaddr; i++) pt_p[i] = ptoa(i) | X86_PG_RW | X86_PG_V | X86_PG_G; /* Now map the page tables at their location within PTmap */ pd_p = (pd_entry_t *)KPDphys; for (i = 0; i < nkpt; i++) pd_p[i] = (KPTphys + ptoa(i)) | X86_PG_RW | X86_PG_V; /* Map from zero to end of allocations under 2M pages */ /* This replaces some of the KPTphys entries above */ for (i = 0; (i << PDRSHIFT) < *firstaddr; i++) pd_p[i] = (i << PDRSHIFT) | X86_PG_RW | X86_PG_V | PG_PS | X86_PG_G; /* And connect up the PD to the PDP (leaving room for L4 pages) */ pdp_p = (pdp_entry_t *)(KPDPphys + ptoa(KPML4I - KPML4BASE)); for (i = 0; i < nkpdpe; i++) pdp_p[i + KPDPI] = (KPDphys + ptoa(i)) | X86_PG_RW | X86_PG_V | PG_U; /* * Now, set up the direct map region using 2MB and/or 1GB pages. If * the end of physical memory is not aligned to a 1GB page boundary, * then the residual physical memory is mapped with 2MB pages. Later, * if pmap_mapdev{_attr}() uses the direct map for non-write-back * memory, pmap_change_attr() will demote any 2MB or 1GB page mappings * that are partially used. */ pd_p = (pd_entry_t *)DMPDphys; for (i = NPDEPG * ndm1g, j = 0; i < NPDEPG * ndmpdp; i++, j++) { pd_p[j] = (vm_paddr_t)i << PDRSHIFT; /* Preset PG_M and PG_A because demotion expects it. */ pd_p[j] |= X86_PG_RW | X86_PG_V | PG_PS | X86_PG_G | X86_PG_M | X86_PG_A; } pdp_p = (pdp_entry_t *)DMPDPphys; for (i = 0; i < ndm1g; i++) { pdp_p[i] = (vm_paddr_t)i << PDPSHIFT; /* Preset PG_M and PG_A because demotion expects it. */ pdp_p[i] |= X86_PG_RW | X86_PG_V | PG_PS | X86_PG_G | X86_PG_M | X86_PG_A; } for (j = 0; i < ndmpdp; i++, j++) { pdp_p[i] = DMPDphys + ptoa(j); pdp_p[i] |= X86_PG_RW | X86_PG_V | PG_U; } /* And recursively map PML4 to itself in order to get PTmap */ p4_p = (pml4_entry_t *)KPML4phys; p4_p[PML4PML4I] = KPML4phys; p4_p[PML4PML4I] |= X86_PG_RW | X86_PG_V | PG_U; /* Connect the Direct Map slot(s) up to the PML4. */ for (i = 0; i < ndmpdpphys; i++) { p4_p[DMPML4I + i] = DMPDPphys + ptoa(i); p4_p[DMPML4I + i] |= X86_PG_RW | X86_PG_V | PG_U; } /* Connect the KVA slots up to the PML4 */ for (i = 0; i < NKPML4E; i++) { p4_p[KPML4BASE + i] = KPDPphys + ptoa(i); p4_p[KPML4BASE + i] |= X86_PG_RW | X86_PG_V | PG_U; } } /* * Bootstrap the system enough to run with virtual memory. * * On amd64 this is called after mapping has already been enabled * and just syncs the pmap module with what has already been done. * [We can't call it easily with mapping off since the kernel is not * mapped with PA == VA, hence we would have to relocate every address * from the linked base (virtual) address "KERNBASE" to the actual * (physical) address starting relative to 0] */ void pmap_bootstrap(vm_paddr_t *firstaddr) { vm_offset_t va; pt_entry_t *pte; int i; /* * Create an initial set of page tables to run the kernel in. */ create_pagetables(firstaddr); /* * Add a physical memory segment (vm_phys_seg) corresponding to the * preallocated kernel page table pages so that vm_page structures * representing these pages will be created. The vm_page structures * are required for promotion of the corresponding kernel virtual * addresses to superpage mappings. */ vm_phys_add_seg(KPTphys, KPTphys + ptoa(nkpt)); virtual_avail = (vm_offset_t) KERNBASE + *firstaddr; virtual_avail = pmap_kmem_choose(virtual_avail); virtual_end = VM_MAX_KERNEL_ADDRESS; /* XXX do %cr0 as well */ load_cr4(rcr4() | CR4_PGE); load_cr3(KPML4phys); if (cpu_stdext_feature & CPUID_STDEXT_SMEP) load_cr4(rcr4() | CR4_SMEP); /* * Initialize the kernel pmap (which is statically allocated). */ PMAP_LOCK_INIT(kernel_pmap); kernel_pmap->pm_pml4 = (pdp_entry_t *)PHYS_TO_DMAP(KPML4phys); kernel_pmap->pm_cr3 = KPML4phys; CPU_FILL(&kernel_pmap->pm_active); /* don't allow deactivation */ TAILQ_INIT(&kernel_pmap->pm_pvchunk); kernel_pmap->pm_flags = pmap_flags; /* * Initialize the global pv list lock. */ rw_init(&pvh_global_lock, "pmap pv global"); /* * Reserve some special page table entries/VA space for temporary * mapping of pages. */ #define SYSMAP(c, p, v, n) \ v = (c)va; va += ((n)*PAGE_SIZE); p = pte; pte += (n); va = virtual_avail; pte = vtopte(va); /* * Crashdump maps. The first page is reused as CMAP1 for the * memory test. */ SYSMAP(caddr_t, CMAP1, crashdumpmap, MAXDUMPPGS) CADDR1 = crashdumpmap; virtual_avail = va; /* Initialize the PAT MSR. */ pmap_init_pat(); /* Initialize TLB Context Id. */ TUNABLE_INT_FETCH("vm.pmap.pcid_enabled", &pmap_pcid_enabled); if ((cpu_feature2 & CPUID2_PCID) != 0 && pmap_pcid_enabled) { /* Check for INVPCID support */ invpcid_works = (cpu_stdext_feature & CPUID_STDEXT_INVPCID) != 0; for (i = 0; i < MAXCPU; i++) { kernel_pmap->pm_pcids[i].pm_pcid = PMAP_PCID_KERN; kernel_pmap->pm_pcids[i].pm_gen = 1; } __pcpu[0].pc_pcid_next = PMAP_PCID_KERN + 1; __pcpu[0].pc_pcid_gen = 1; /* * pcpu area for APs is zeroed during AP startup. * pc_pcid_next and pc_pcid_gen are initialized by AP * during pcpu setup. */ -#ifdef SMP load_cr4(rcr4() | CR4_PCIDE); -#else - pmap_pcid_enabled = 0; -#endif } else { pmap_pcid_enabled = 0; } } /* * Setup the PAT MSR. */ void pmap_init_pat(void) { int pat_table[PAT_INDEX_SIZE]; uint64_t pat_msr; u_long cr0, cr4; int i; /* Bail if this CPU doesn't implement PAT. */ if ((cpu_feature & CPUID_PAT) == 0) panic("no PAT??"); /* Set default PAT index table. */ for (i = 0; i < PAT_INDEX_SIZE; i++) pat_table[i] = -1; pat_table[PAT_WRITE_BACK] = 0; pat_table[PAT_WRITE_THROUGH] = 1; pat_table[PAT_UNCACHEABLE] = 3; pat_table[PAT_WRITE_COMBINING] = 3; pat_table[PAT_WRITE_PROTECTED] = 3; pat_table[PAT_UNCACHED] = 3; /* Initialize default PAT entries. */ pat_msr = PAT_VALUE(0, PAT_WRITE_BACK) | PAT_VALUE(1, PAT_WRITE_THROUGH) | PAT_VALUE(2, PAT_UNCACHED) | PAT_VALUE(3, PAT_UNCACHEABLE) | PAT_VALUE(4, PAT_WRITE_BACK) | PAT_VALUE(5, PAT_WRITE_THROUGH) | PAT_VALUE(6, PAT_UNCACHED) | PAT_VALUE(7, PAT_UNCACHEABLE); if (pat_works) { /* * Leave the indices 0-3 at the default of WB, WT, UC-, and UC. * Program 5 and 6 as WP and WC. * Leave 4 and 7 as WB and UC. */ pat_msr &= ~(PAT_MASK(5) | PAT_MASK(6)); pat_msr |= PAT_VALUE(5, PAT_WRITE_PROTECTED) | PAT_VALUE(6, PAT_WRITE_COMBINING); pat_table[PAT_UNCACHED] = 2; pat_table[PAT_WRITE_PROTECTED] = 5; pat_table[PAT_WRITE_COMBINING] = 6; } else { /* * Just replace PAT Index 2 with WC instead of UC-. */ pat_msr &= ~PAT_MASK(2); pat_msr |= PAT_VALUE(2, PAT_WRITE_COMBINING); pat_table[PAT_WRITE_COMBINING] = 2; } /* Disable PGE. */ cr4 = rcr4(); load_cr4(cr4 & ~CR4_PGE); /* Disable caches (CD = 1, NW = 0). */ cr0 = rcr0(); load_cr0((cr0 & ~CR0_NW) | CR0_CD); /* Flushes caches and TLBs. */ wbinvd(); invltlb(); /* Update PAT and index table. */ wrmsr(MSR_PAT, pat_msr); for (i = 0; i < PAT_INDEX_SIZE; i++) pat_index[i] = pat_table[i]; /* Flush caches and TLBs again. */ wbinvd(); invltlb(); /* Restore caches and PGE. */ load_cr0(cr0); load_cr4(cr4); } /* * Initialize a vm_page's machine-dependent fields. */ void pmap_page_init(vm_page_t m) { TAILQ_INIT(&m->md.pv_list); m->md.pat_mode = PAT_WRITE_BACK; } /* * Initialize the pmap module. * Called by vm_init, to initialize any structures that the pmap * system needs to map virtual memory. */ void pmap_init(void) { vm_page_t mpte; vm_size_t s; int i, pv_npg; /* * Initialize the vm page array entries for the kernel pmap's * page table pages. */ for (i = 0; i < nkpt; i++) { mpte = PHYS_TO_VM_PAGE(KPTphys + (i << PAGE_SHIFT)); KASSERT(mpte >= vm_page_array && mpte < &vm_page_array[vm_page_array_size], ("pmap_init: page table page is out of range")); mpte->pindex = pmap_pde_pindex(KERNBASE) + i; mpte->phys_addr = KPTphys + (i << PAGE_SHIFT); } /* * If the kernel is running on a virtual machine, then it must assume * that MCA is enabled by the hypervisor. Moreover, the kernel must * be prepared for the hypervisor changing the vendor and family that * are reported by CPUID. Consequently, the workaround for AMD Family * 10h Erratum 383 is enabled if the processor's feature set does not * include at least one feature that is only supported by older Intel * or newer AMD processors. */ if (vm_guest == VM_GUEST_VM && (cpu_feature & CPUID_SS) == 0 && (cpu_feature2 & (CPUID2_SSSE3 | CPUID2_SSE41 | CPUID2_AESNI | CPUID2_AVX | CPUID2_XSAVE)) == 0 && (amd_feature2 & (AMDID2_XOP | AMDID2_FMA4)) == 0) workaround_erratum383 = 1; /* * Are large page mappings enabled? */ TUNABLE_INT_FETCH("vm.pmap.pg_ps_enabled", &pg_ps_enabled); if (pg_ps_enabled) { KASSERT(MAXPAGESIZES > 1 && pagesizes[1] == 0, ("pmap_init: can't assign to pagesizes[1]")); pagesizes[1] = NBPDR; } /* * Initialize the pv chunk list mutex. */ mtx_init(&pv_chunks_mutex, "pmap pv chunk list", NULL, MTX_DEF); /* * Initialize the pool of pv list locks. */ for (i = 0; i < NPV_LIST_LOCKS; i++) rw_init(&pv_list_locks[i], "pmap pv list"); /* * Calculate the size of the pv head table for superpages. */ pv_npg = howmany(vm_phys_segs[vm_phys_nsegs - 1].end, NBPDR); /* * Allocate memory for the pv head table for superpages. */ s = (vm_size_t)(pv_npg * sizeof(struct md_page)); s = round_page(s); pv_table = (struct md_page *)kmem_malloc(kernel_arena, s, M_WAITOK | M_ZERO); for (i = 0; i < pv_npg; i++) TAILQ_INIT(&pv_table[i].pv_list); } static SYSCTL_NODE(_vm_pmap, OID_AUTO, pde, CTLFLAG_RD, 0, "2MB page mapping counters"); static u_long pmap_pde_demotions; SYSCTL_ULONG(_vm_pmap_pde, OID_AUTO, demotions, CTLFLAG_RD, &pmap_pde_demotions, 0, "2MB page demotions"); static u_long pmap_pde_mappings; SYSCTL_ULONG(_vm_pmap_pde, OID_AUTO, mappings, CTLFLAG_RD, &pmap_pde_mappings, 0, "2MB page mappings"); static u_long pmap_pde_p_failures; SYSCTL_ULONG(_vm_pmap_pde, OID_AUTO, p_failures, CTLFLAG_RD, &pmap_pde_p_failures, 0, "2MB page promotion failures"); static u_long pmap_pde_promotions; SYSCTL_ULONG(_vm_pmap_pde, OID_AUTO, promotions, CTLFLAG_RD, &pmap_pde_promotions, 0, "2MB page promotions"); static SYSCTL_NODE(_vm_pmap, OID_AUTO, pdpe, CTLFLAG_RD, 0, "1GB page mapping counters"); static u_long pmap_pdpe_demotions; SYSCTL_ULONG(_vm_pmap_pdpe, OID_AUTO, demotions, CTLFLAG_RD, &pmap_pdpe_demotions, 0, "1GB page demotions"); /*************************************************** * Low level helper routines..... ***************************************************/ static pt_entry_t pmap_swap_pat(pmap_t pmap, pt_entry_t entry) { int x86_pat_bits = X86_PG_PTE_PAT | X86_PG_PDE_PAT; switch (pmap->pm_type) { case PT_X86: case PT_RVI: /* Verify that both PAT bits are not set at the same time */ KASSERT((entry & x86_pat_bits) != x86_pat_bits, ("Invalid PAT bits in entry %#lx", entry)); /* Swap the PAT bits if one of them is set */ if ((entry & x86_pat_bits) != 0) entry ^= x86_pat_bits; break; case PT_EPT: /* * Nothing to do - the memory attributes are represented * the same way for regular pages and superpages. */ break; default: panic("pmap_switch_pat_bits: bad pm_type %d", pmap->pm_type); } return (entry); } /* * Determine the appropriate bits to set in a PTE or PDE for a specified * caching mode. */ static int pmap_cache_bits(pmap_t pmap, int mode, boolean_t is_pde) { int cache_bits, pat_flag, pat_idx; if (mode < 0 || mode >= PAT_INDEX_SIZE || pat_index[mode] < 0) panic("Unknown caching mode %d\n", mode); switch (pmap->pm_type) { case PT_X86: case PT_RVI: /* The PAT bit is different for PTE's and PDE's. */ pat_flag = is_pde ? X86_PG_PDE_PAT : X86_PG_PTE_PAT; /* Map the caching mode to a PAT index. */ pat_idx = pat_index[mode]; /* Map the 3-bit index value into the PAT, PCD, and PWT bits. */ cache_bits = 0; if (pat_idx & 0x4) cache_bits |= pat_flag; if (pat_idx & 0x2) cache_bits |= PG_NC_PCD; if (pat_idx & 0x1) cache_bits |= PG_NC_PWT; break; case PT_EPT: cache_bits = EPT_PG_IGNORE_PAT | EPT_PG_MEMORY_TYPE(mode); break; default: panic("unsupported pmap type %d", pmap->pm_type); } return (cache_bits); } static int pmap_cache_mask(pmap_t pmap, boolean_t is_pde) { int mask; switch (pmap->pm_type) { case PT_X86: case PT_RVI: mask = is_pde ? X86_PG_PDE_CACHE : X86_PG_PTE_CACHE; break; case PT_EPT: mask = EPT_PG_IGNORE_PAT | EPT_PG_MEMORY_TYPE(0x7); break; default: panic("pmap_cache_mask: invalid pm_type %d", pmap->pm_type); } return (mask); } static __inline boolean_t pmap_ps_enabled(pmap_t pmap) { return (pg_ps_enabled && (pmap->pm_flags & PMAP_PDE_SUPERPAGE) != 0); } static void pmap_update_pde_store(pmap_t pmap, pd_entry_t *pde, pd_entry_t newpde) { switch (pmap->pm_type) { case PT_X86: break; case PT_RVI: case PT_EPT: /* * XXX * This is a little bogus since the generation number is * supposed to be bumped up when a region of the address * space is invalidated in the page tables. * * In this case the old PDE entry is valid but yet we want * to make sure that any mappings using the old entry are * invalidated in the TLB. * * The reason this works as expected is because we rendezvous * "all" host cpus and force any vcpu context to exit as a * side-effect. */ atomic_add_acq_long(&pmap->pm_eptgen, 1); break; default: panic("pmap_update_pde_store: bad pm_type %d", pmap->pm_type); } pde_store(pde, newpde); } /* * After changing the page size for the specified virtual address in the page * table, flush the corresponding entries from the processor's TLB. Only the * calling processor's TLB is affected. * * The calling thread must be pinned to a processor. */ static void pmap_update_pde_invalidate(pmap_t pmap, vm_offset_t va, pd_entry_t newpde) { pt_entry_t PG_G; if (pmap_type_guest(pmap)) return; KASSERT(pmap->pm_type == PT_X86, ("pmap_update_pde_invalidate: invalid type %d", pmap->pm_type)); PG_G = pmap_global_bit(pmap); if ((newpde & PG_PS) == 0) /* Demotion: flush a specific 2MB page mapping. */ invlpg(va); else if ((newpde & PG_G) == 0) /* * Promotion: flush every 4KB page mapping from the TLB * because there are too many to flush individually. */ invltlb(); else { /* * Promotion: flush every 4KB page mapping from the TLB, * including any global (PG_G) mappings. */ invltlb_globpcid(); } } #ifdef SMP /* * For SMP, these functions have to use the IPI mechanism for coherence. * * N.B.: Before calling any of the following TLB invalidation functions, * the calling processor must ensure that all stores updating a non- * kernel page table are globally performed. Otherwise, another * processor could cache an old, pre-update entry without being * invalidated. This can happen one of two ways: (1) The pmap becomes * active on another processor after its pm_active field is checked by * one of the following functions but before a store updating the page * table is globally performed. (2) The pmap becomes active on another * processor before its pm_active field is checked but due to * speculative loads one of the following functions stills reads the * pmap as inactive on the other processor. * * The kernel page table is exempt because its pm_active field is * immutable. The kernel page table is always active on every * processor. */ /* * Interrupt the cpus that are executing in the guest context. * This will force the vcpu to exit and the cached EPT mappings * will be invalidated by the host before the next vmresume. */ static __inline void pmap_invalidate_ept(pmap_t pmap) { int ipinum; sched_pin(); KASSERT(!CPU_ISSET(curcpu, &pmap->pm_active), ("pmap_invalidate_ept: absurd pm_active")); /* * The TLB mappings associated with a vcpu context are not * flushed each time a different vcpu is chosen to execute. * * This is in contrast with a process's vtop mappings that * are flushed from the TLB on each context switch. * * Therefore we need to do more than just a TLB shootdown on * the active cpus in 'pmap->pm_active'. To do this we keep * track of the number of invalidations performed on this pmap. * * Each vcpu keeps a cache of this counter and compares it * just before a vmresume. If the counter is out-of-date an * invept will be done to flush stale mappings from the TLB. */ atomic_add_acq_long(&pmap->pm_eptgen, 1); /* * Force the vcpu to exit and trap back into the hypervisor. */ ipinum = pmap->pm_flags & PMAP_NESTED_IPIMASK; ipi_selected(pmap->pm_active, ipinum); sched_unpin(); } void pmap_invalidate_page(pmap_t pmap, vm_offset_t va) { cpuset_t *mask; u_int cpuid, i; if (pmap_type_guest(pmap)) { pmap_invalidate_ept(pmap); return; } KASSERT(pmap->pm_type == PT_X86, ("pmap_invalidate_page: invalid type %d", pmap->pm_type)); sched_pin(); if (pmap == kernel_pmap) { invlpg(va); mask = &all_cpus; } else { cpuid = PCPU_GET(cpuid); if (pmap == PCPU_GET(curpmap)) invlpg(va); else if (pmap_pcid_enabled) pmap->pm_pcids[cpuid].pm_gen = 0; if (pmap_pcid_enabled) { CPU_FOREACH(i) { if (cpuid != i) pmap->pm_pcids[i].pm_gen = 0; } } mask = &pmap->pm_active; } smp_masked_invlpg(*mask, va); sched_unpin(); } void pmap_invalidate_range(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) { cpuset_t *mask; vm_offset_t addr; u_int cpuid, i; if (pmap_type_guest(pmap)) { pmap_invalidate_ept(pmap); return; } KASSERT(pmap->pm_type == PT_X86, ("pmap_invalidate_range: invalid type %d", pmap->pm_type)); sched_pin(); cpuid = PCPU_GET(cpuid); if (pmap == kernel_pmap) { for (addr = sva; addr < eva; addr += PAGE_SIZE) invlpg(addr); mask = &all_cpus; } else { if (pmap == PCPU_GET(curpmap)) { for (addr = sva; addr < eva; addr += PAGE_SIZE) invlpg(addr); } else if (pmap_pcid_enabled) { pmap->pm_pcids[cpuid].pm_gen = 0; } if (pmap_pcid_enabled) { CPU_FOREACH(i) { if (cpuid != i) pmap->pm_pcids[i].pm_gen = 0; } } mask = &pmap->pm_active; } smp_masked_invlpg_range(*mask, sva, eva); sched_unpin(); } void pmap_invalidate_all(pmap_t pmap) { cpuset_t *mask; struct invpcid_descr d; u_int cpuid, i; if (pmap_type_guest(pmap)) { pmap_invalidate_ept(pmap); return; } KASSERT(pmap->pm_type == PT_X86, ("pmap_invalidate_all: invalid type %d", pmap->pm_type)); sched_pin(); if (pmap == kernel_pmap) { if (pmap_pcid_enabled && invpcid_works) { bzero(&d, sizeof(d)); invpcid(&d, INVPCID_CTXGLOB); } else { invltlb_globpcid(); } mask = &all_cpus; } else { cpuid = PCPU_GET(cpuid); if (pmap == PCPU_GET(curpmap)) { if (pmap_pcid_enabled) { if (invpcid_works) { d.pcid = pmap->pm_pcids[cpuid].pm_pcid; d.pad = 0; d.addr = 0; invpcid(&d, INVPCID_CTX); } else { load_cr3(pmap->pm_cr3 | pmap->pm_pcids [PCPU_GET(cpuid)].pm_pcid); } } else { invltlb(); } } else if (pmap_pcid_enabled) { pmap->pm_pcids[cpuid].pm_gen = 0; } if (pmap_pcid_enabled) { CPU_FOREACH(i) { if (cpuid != i) pmap->pm_pcids[i].pm_gen = 0; } } mask = &pmap->pm_active; } smp_masked_invltlb(*mask, pmap); sched_unpin(); } void pmap_invalidate_cache(void) { sched_pin(); wbinvd(); smp_cache_flush(); sched_unpin(); } struct pde_action { cpuset_t invalidate; /* processors that invalidate their TLB */ pmap_t pmap; vm_offset_t va; pd_entry_t *pde; pd_entry_t newpde; u_int store; /* processor that updates the PDE */ }; static void pmap_update_pde_action(void *arg) { struct pde_action *act = arg; if (act->store == PCPU_GET(cpuid)) pmap_update_pde_store(act->pmap, act->pde, act->newpde); } static void pmap_update_pde_teardown(void *arg) { struct pde_action *act = arg; if (CPU_ISSET(PCPU_GET(cpuid), &act->invalidate)) pmap_update_pde_invalidate(act->pmap, act->va, act->newpde); } /* * Change the page size for the specified virtual address in a way that * prevents any possibility of the TLB ever having two entries that map the * same virtual address using different page sizes. This is the recommended * workaround for Erratum 383 on AMD Family 10h processors. It prevents a * machine check exception for a TLB state that is improperly diagnosed as a * hardware error. */ static void pmap_update_pde(pmap_t pmap, vm_offset_t va, pd_entry_t *pde, pd_entry_t newpde) { struct pde_action act; cpuset_t active, other_cpus; u_int cpuid; sched_pin(); cpuid = PCPU_GET(cpuid); other_cpus = all_cpus; CPU_CLR(cpuid, &other_cpus); if (pmap == kernel_pmap || pmap_type_guest(pmap)) active = all_cpus; else { active = pmap->pm_active; } if (CPU_OVERLAP(&active, &other_cpus)) { act.store = cpuid; act.invalidate = active; act.va = va; act.pmap = pmap; act.pde = pde; act.newpde = newpde; CPU_SET(cpuid, &active); smp_rendezvous_cpus(active, smp_no_rendevous_barrier, pmap_update_pde_action, pmap_update_pde_teardown, &act); } else { pmap_update_pde_store(pmap, pde, newpde); if (CPU_ISSET(cpuid, &active)) pmap_update_pde_invalidate(pmap, va, newpde); } sched_unpin(); } #else /* !SMP */ /* * Normal, non-SMP, invalidation functions. - * We inline these within pmap.c for speed. */ -PMAP_INLINE void +void pmap_invalidate_page(pmap_t pmap, vm_offset_t va) { - switch (pmap->pm_type) { - case PT_X86: - if (pmap == kernel_pmap || !CPU_EMPTY(&pmap->pm_active)) - invlpg(va); - break; - case PT_RVI: - case PT_EPT: + if (pmap->pm_type == PT_RVI || pmap->pm_type == PT_EPT) { pmap->pm_eptgen++; - break; - default: - panic("pmap_invalidate_page: unknown type: %d", pmap->pm_type); + return; } + KASSERT(pmap->pm_type == PT_X86, + ("pmap_invalidate_range: unknown type %d", pmap->pm_type)); + + if (pmap == kernel_pmap || pmap == PCPU_GET(curpmap)) + invlpg(va); + else if (pmap_pcid_enabled) + pmap->pm_pcids[0].pm_gen = 0; } -PMAP_INLINE void +void pmap_invalidate_range(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) { vm_offset_t addr; - switch (pmap->pm_type) { - case PT_X86: - if (pmap == kernel_pmap || !CPU_EMPTY(&pmap->pm_active)) - for (addr = sva; addr < eva; addr += PAGE_SIZE) - invlpg(addr); - break; - case PT_RVI: - case PT_EPT: + if (pmap->pm_type == PT_RVI || pmap->pm_type == PT_EPT) { pmap->pm_eptgen++; - break; - default: - panic("pmap_invalidate_range: unknown type: %d", pmap->pm_type); + return; } + KASSERT(pmap->pm_type == PT_X86, + ("pmap_invalidate_range: unknown type %d", pmap->pm_type)); + + if (pmap == kernel_pmap || pmap == PCPU_GET(curpmap)) { + for (addr = sva; addr < eva; addr += PAGE_SIZE) + invlpg(addr); + } else if (pmap_pcid_enabled) { + pmap->pm_pcids[0].pm_gen = 0; + } } -PMAP_INLINE void +void pmap_invalidate_all(pmap_t pmap) { + struct invpcid_descr d; - switch (pmap->pm_type) { - case PT_X86: - if (pmap == kernel_pmap || !CPU_EMPTY(&pmap->pm_active)) - invltlb(); - break; - case PT_RVI: - case PT_EPT: + if (pmap->pm_type == PT_RVI || pmap->pm_type == PT_EPT) { pmap->pm_eptgen++; - break; - default: - panic("pmap_invalidate_all: unknown type %d", pmap->pm_type); + return; } + KASSERT(pmap->pm_type == PT_X86, + ("pmap_invalidate_all: unknown type %d", pmap->pm_type)); + + if (pmap == kernel_pmap) { + if (pmap_pcid_enabled && invpcid_works) { + bzero(&d, sizeof(d)); + invpcid(&d, INVPCID_CTXGLOB); + } else { + invltlb_globpcid(); + } + } else if (pmap == PCPU_GET(curpmap)) { + if (pmap_pcid_enabled) { + if (invpcid_works) { + d.pcid = pmap->pm_pcids[0].pm_pcid; + d.pad = 0; + d.addr = 0; + invpcid(&d, INVPCID_CTX); + } else { + load_cr3(pmap->pm_cr3 | pmap->pm_pcids[0]. + pm_pcid); + } + } else { + invltlb(); + } + } else if (pmap_pcid_enabled) { + pmap->pm_pcids[0].pm_gen = 0; + } } PMAP_INLINE void pmap_invalidate_cache(void) { wbinvd(); } static void pmap_update_pde(pmap_t pmap, vm_offset_t va, pd_entry_t *pde, pd_entry_t newpde) { pmap_update_pde_store(pmap, pde, newpde); - if (pmap == kernel_pmap || !CPU_EMPTY(&pmap->pm_active)) + if (pmap == kernel_pmap || pmap == PCPU_GET(curpmap)) pmap_update_pde_invalidate(pmap, va, newpde); else - CPU_ZERO(&pmap->pm_save); + pmap->pm_pcids[0].pm_gen = 0; } #endif /* !SMP */ #define PMAP_CLFLUSH_THRESHOLD (2 * 1024 * 1024) void pmap_invalidate_cache_range(vm_offset_t sva, vm_offset_t eva, boolean_t force) { if (force) { sva &= ~(vm_offset_t)cpu_clflush_line_size; } else { KASSERT((sva & PAGE_MASK) == 0, ("pmap_invalidate_cache_range: sva not page-aligned")); KASSERT((eva & PAGE_MASK) == 0, ("pmap_invalidate_cache_range: eva not page-aligned")); } if ((cpu_feature & CPUID_SS) != 0 && !force) ; /* If "Self Snoop" is supported and allowed, do nothing. */ else if ((cpu_feature & CPUID_CLFSH) != 0 && eva - sva < PMAP_CLFLUSH_THRESHOLD) { /* * XXX: Some CPUs fault, hang, or trash the local APIC * registers if we use CLFLUSH on the local APIC * range. The local APIC is always uncached, so we * don't need to flush for that range anyway. */ if (pmap_kextract(sva) == lapic_paddr) return; /* * Otherwise, do per-cache line flush. Use the mfence * instruction to insure that previous stores are * included in the write-back. The processor * propagates flush to other processors in the cache * coherence domain. */ mfence(); for (; sva < eva; sva += cpu_clflush_line_size) clflush(sva); mfence(); } else { /* * No targeted cache flush methods are supported by CPU, * or the supplied range is bigger than 2MB. * Globally invalidate cache. */ pmap_invalidate_cache(); } } /* * Remove the specified set of pages from the data and instruction caches. * * In contrast to pmap_invalidate_cache_range(), this function does not * rely on the CPU's self-snoop feature, because it is intended for use * when moving pages into a different cache domain. */ void pmap_invalidate_cache_pages(vm_page_t *pages, int count) { vm_offset_t daddr, eva; int i; if (count >= PMAP_CLFLUSH_THRESHOLD / PAGE_SIZE || (cpu_feature & CPUID_CLFSH) == 0) pmap_invalidate_cache(); else { mfence(); for (i = 0; i < count; i++) { daddr = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(pages[i])); eva = daddr + PAGE_SIZE; for (; daddr < eva; daddr += cpu_clflush_line_size) clflush(daddr); } mfence(); } } /* * Routine: pmap_extract * Function: * Extract the physical page address associated * with the given map/virtual_address pair. */ vm_paddr_t pmap_extract(pmap_t pmap, vm_offset_t va) { pdp_entry_t *pdpe; pd_entry_t *pde; pt_entry_t *pte, PG_V; vm_paddr_t pa; pa = 0; PG_V = pmap_valid_bit(pmap); PMAP_LOCK(pmap); pdpe = pmap_pdpe(pmap, va); if (pdpe != NULL && (*pdpe & PG_V) != 0) { if ((*pdpe & PG_PS) != 0) pa = (*pdpe & PG_PS_FRAME) | (va & PDPMASK); else { pde = pmap_pdpe_to_pde(pdpe, va); if ((*pde & PG_V) != 0) { if ((*pde & PG_PS) != 0) { pa = (*pde & PG_PS_FRAME) | (va & PDRMASK); } else { pte = pmap_pde_to_pte(pde, va); pa = (*pte & PG_FRAME) | (va & PAGE_MASK); } } } } PMAP_UNLOCK(pmap); return (pa); } /* * Routine: pmap_extract_and_hold * Function: * Atomically extract and hold the physical page * with the given pmap and virtual address pair * if that mapping permits the given protection. */ vm_page_t pmap_extract_and_hold(pmap_t pmap, vm_offset_t va, vm_prot_t prot) { pd_entry_t pde, *pdep; pt_entry_t pte, PG_RW, PG_V; vm_paddr_t pa; vm_page_t m; pa = 0; m = NULL; PG_RW = pmap_rw_bit(pmap); PG_V = pmap_valid_bit(pmap); PMAP_LOCK(pmap); retry: pdep = pmap_pde(pmap, va); if (pdep != NULL && (pde = *pdep)) { if (pde & PG_PS) { if ((pde & PG_RW) || (prot & VM_PROT_WRITE) == 0) { if (vm_page_pa_tryrelock(pmap, (pde & PG_PS_FRAME) | (va & PDRMASK), &pa)) goto retry; m = PHYS_TO_VM_PAGE((pde & PG_PS_FRAME) | (va & PDRMASK)); vm_page_hold(m); } } else { pte = *pmap_pde_to_pte(pdep, va); if ((pte & PG_V) && ((pte & PG_RW) || (prot & VM_PROT_WRITE) == 0)) { if (vm_page_pa_tryrelock(pmap, pte & PG_FRAME, &pa)) goto retry; m = PHYS_TO_VM_PAGE(pte & PG_FRAME); vm_page_hold(m); } } } PA_UNLOCK_COND(pa); PMAP_UNLOCK(pmap); return (m); } vm_paddr_t pmap_kextract(vm_offset_t va) { pd_entry_t pde; vm_paddr_t pa; if (va >= DMAP_MIN_ADDRESS && va < DMAP_MAX_ADDRESS) { pa = DMAP_TO_PHYS(va); } else { pde = *vtopde(va); if (pde & PG_PS) { pa = (pde & PG_PS_FRAME) | (va & PDRMASK); } else { /* * Beware of a concurrent promotion that changes the * PDE at this point! For example, vtopte() must not * be used to access the PTE because it would use the * new PDE. It is, however, safe to use the old PDE * because the page table page is preserved by the * promotion. */ pa = *pmap_pde_to_pte(&pde, va); pa = (pa & PG_FRAME) | (va & PAGE_MASK); } } return (pa); } /*************************************************** * Low level mapping routines..... ***************************************************/ /* * Add a wired page to the kva. * Note: not SMP coherent. */ PMAP_INLINE void pmap_kenter(vm_offset_t va, vm_paddr_t pa) { pt_entry_t *pte; pte = vtopte(va); pte_store(pte, pa | X86_PG_RW | X86_PG_V | X86_PG_G); } static __inline void pmap_kenter_attr(vm_offset_t va, vm_paddr_t pa, int mode) { pt_entry_t *pte; int cache_bits; pte = vtopte(va); cache_bits = pmap_cache_bits(kernel_pmap, mode, 0); pte_store(pte, pa | X86_PG_RW | X86_PG_V | X86_PG_G | cache_bits); } /* * Remove a page from the kernel pagetables. * Note: not SMP coherent. */ PMAP_INLINE void pmap_kremove(vm_offset_t va) { pt_entry_t *pte; pte = vtopte(va); pte_clear(pte); } /* * Used to map a range of physical addresses into kernel * virtual address space. * * The value passed in '*virt' is a suggested virtual address for * the mapping. Architectures which can support a direct-mapped * physical to virtual region can return the appropriate address * within that region, leaving '*virt' unchanged. Other * architectures should map the pages starting at '*virt' and * update '*virt' with the first usable address after the mapped * region. */ vm_offset_t pmap_map(vm_offset_t *virt, vm_paddr_t start, vm_paddr_t end, int prot) { return PHYS_TO_DMAP(start); } /* * Add a list of wired pages to the kva * this routine is only used for temporary * kernel mappings that do not need to have * page modification or references recorded. * Note that old mappings are simply written * over. The page *must* be wired. * Note: SMP coherent. Uses a ranged shootdown IPI. */ void pmap_qenter(vm_offset_t sva, vm_page_t *ma, int count) { pt_entry_t *endpte, oldpte, pa, *pte; vm_page_t m; int cache_bits; oldpte = 0; pte = vtopte(sva); endpte = pte + count; while (pte < endpte) { m = *ma++; cache_bits = pmap_cache_bits(kernel_pmap, m->md.pat_mode, 0); pa = VM_PAGE_TO_PHYS(m) | cache_bits; if ((*pte & (PG_FRAME | X86_PG_PTE_CACHE)) != pa) { oldpte |= *pte; pte_store(pte, pa | X86_PG_G | X86_PG_RW | X86_PG_V); } pte++; } if (__predict_false((oldpte & X86_PG_V) != 0)) pmap_invalidate_range(kernel_pmap, sva, sva + count * PAGE_SIZE); } /* * This routine tears out page mappings from the * kernel -- it is meant only for temporary mappings. * Note: SMP coherent. Uses a ranged shootdown IPI. */ void pmap_qremove(vm_offset_t sva, int count) { vm_offset_t va; va = sva; while (count-- > 0) { KASSERT(va >= VM_MIN_KERNEL_ADDRESS, ("usermode va %lx", va)); pmap_kremove(va); va += PAGE_SIZE; } pmap_invalidate_range(kernel_pmap, sva, va); } /*************************************************** * Page table page management routines..... ***************************************************/ static __inline void pmap_free_zero_pages(struct spglist *free) { vm_page_t m; while ((m = SLIST_FIRST(free)) != NULL) { SLIST_REMOVE_HEAD(free, plinks.s.ss); /* Preserve the page's PG_ZERO setting. */ vm_page_free_toq(m); } } /* * Schedule the specified unused page table page to be freed. Specifically, * add the page to the specified list of pages that will be released to the * physical memory manager after the TLB has been updated. */ static __inline void pmap_add_delayed_free_list(vm_page_t m, struct spglist *free, boolean_t set_PG_ZERO) { if (set_PG_ZERO) m->flags |= PG_ZERO; else m->flags &= ~PG_ZERO; SLIST_INSERT_HEAD(free, m, plinks.s.ss); } /* * Inserts the specified page table page into the specified pmap's collection * of idle page table pages. Each of a pmap's page table pages is responsible * for mapping a distinct range of virtual addresses. The pmap's collection is * ordered by this virtual address range. */ static __inline int pmap_insert_pt_page(pmap_t pmap, vm_page_t mpte) { PMAP_LOCK_ASSERT(pmap, MA_OWNED); return (vm_radix_insert(&pmap->pm_root, mpte)); } /* * Looks for a page table page mapping the specified virtual address in the * specified pmap's collection of idle page table pages. Returns NULL if there * is no page table page corresponding to the specified virtual address. */ static __inline vm_page_t pmap_lookup_pt_page(pmap_t pmap, vm_offset_t va) { PMAP_LOCK_ASSERT(pmap, MA_OWNED); return (vm_radix_lookup(&pmap->pm_root, pmap_pde_pindex(va))); } /* * Removes the specified page table page from the specified pmap's collection * of idle page table pages. The specified page table page must be a member of * the pmap's collection. */ static __inline void pmap_remove_pt_page(pmap_t pmap, vm_page_t mpte) { PMAP_LOCK_ASSERT(pmap, MA_OWNED); vm_radix_remove(&pmap->pm_root, mpte->pindex); } /* * Decrements a page table page's wire count, which is used to record the * number of valid page table entries within the page. If the wire count * drops to zero, then the page table page is unmapped. Returns TRUE if the * page table page was unmapped and FALSE otherwise. */ static inline boolean_t pmap_unwire_ptp(pmap_t pmap, vm_offset_t va, vm_page_t m, struct spglist *free) { --m->wire_count; if (m->wire_count == 0) { _pmap_unwire_ptp(pmap, va, m, free); return (TRUE); } else return (FALSE); } static void _pmap_unwire_ptp(pmap_t pmap, vm_offset_t va, vm_page_t m, struct spglist *free) { PMAP_LOCK_ASSERT(pmap, MA_OWNED); /* * unmap the page table page */ if (m->pindex >= (NUPDE + NUPDPE)) { /* PDP page */ pml4_entry_t *pml4; pml4 = pmap_pml4e(pmap, va); *pml4 = 0; } else if (m->pindex >= NUPDE) { /* PD page */ pdp_entry_t *pdp; pdp = pmap_pdpe(pmap, va); *pdp = 0; } else { /* PTE page */ pd_entry_t *pd; pd = pmap_pde(pmap, va); *pd = 0; } pmap_resident_count_dec(pmap, 1); if (m->pindex < NUPDE) { /* We just released a PT, unhold the matching PD */ vm_page_t pdpg; pdpg = PHYS_TO_VM_PAGE(*pmap_pdpe(pmap, va) & PG_FRAME); pmap_unwire_ptp(pmap, va, pdpg, free); } if (m->pindex >= NUPDE && m->pindex < (NUPDE + NUPDPE)) { /* We just released a PD, unhold the matching PDP */ vm_page_t pdppg; pdppg = PHYS_TO_VM_PAGE(*pmap_pml4e(pmap, va) & PG_FRAME); pmap_unwire_ptp(pmap, va, pdppg, free); } /* * This is a release store so that the ordinary store unmapping * the page table page is globally performed before TLB shoot- * down is begun. */ atomic_subtract_rel_int(&vm_cnt.v_wire_count, 1); /* * Put page on a list so that it is released after * *ALL* TLB shootdown is done */ pmap_add_delayed_free_list(m, free, TRUE); } /* * After removing a page table entry, this routine is used to * conditionally free the page, and manage the hold/wire counts. */ static int pmap_unuse_pt(pmap_t pmap, vm_offset_t va, pd_entry_t ptepde, struct spglist *free) { vm_page_t mpte; if (va >= VM_MAXUSER_ADDRESS) return (0); KASSERT(ptepde != 0, ("pmap_unuse_pt: ptepde != 0")); mpte = PHYS_TO_VM_PAGE(ptepde & PG_FRAME); return (pmap_unwire_ptp(pmap, va, mpte, free)); } void pmap_pinit0(pmap_t pmap) { int i; PMAP_LOCK_INIT(pmap); pmap->pm_pml4 = (pml4_entry_t *)PHYS_TO_DMAP(KPML4phys); pmap->pm_cr3 = KPML4phys; pmap->pm_root.rt_root = 0; CPU_ZERO(&pmap->pm_active); - PCPU_SET(curpmap, pmap); TAILQ_INIT(&pmap->pm_pvchunk); bzero(&pmap->pm_stats, sizeof pmap->pm_stats); pmap->pm_flags = pmap_flags; CPU_FOREACH(i) { pmap->pm_pcids[i].pm_pcid = PMAP_PCID_NONE; pmap->pm_pcids[i].pm_gen = 0; } + PCPU_SET(curpmap, kernel_pmap); + pmap_activate(curthread); + CPU_FILL(&kernel_pmap->pm_active); } /* * Initialize a preallocated and zeroed pmap structure, * such as one in a vmspace structure. */ int pmap_pinit_type(pmap_t pmap, enum pmap_type pm_type, int flags) { vm_page_t pml4pg; vm_paddr_t pml4phys; int i; /* * allocate the page directory page */ while ((pml4pg = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED | VM_ALLOC_ZERO)) == NULL) VM_WAIT; pml4phys = VM_PAGE_TO_PHYS(pml4pg); pmap->pm_pml4 = (pml4_entry_t *)PHYS_TO_DMAP(pml4phys); CPU_FOREACH(i) { pmap->pm_pcids[i].pm_pcid = PMAP_PCID_NONE; pmap->pm_pcids[i].pm_gen = 0; } pmap->pm_cr3 = ~0; /* initialize to an invalid value */ if ((pml4pg->flags & PG_ZERO) == 0) pagezero(pmap->pm_pml4); /* * Do not install the host kernel mappings in the nested page * tables. These mappings are meaningless in the guest physical * address space. */ if ((pmap->pm_type = pm_type) == PT_X86) { pmap->pm_cr3 = pml4phys; /* Wire in kernel global address entries. */ for (i = 0; i < NKPML4E; i++) { pmap->pm_pml4[KPML4BASE + i] = (KPDPphys + ptoa(i)) | X86_PG_RW | X86_PG_V | PG_U; } for (i = 0; i < ndmpdpphys; i++) { pmap->pm_pml4[DMPML4I + i] = (DMPDPphys + ptoa(i)) | X86_PG_RW | X86_PG_V | PG_U; } /* install self-referential address mapping entry(s) */ pmap->pm_pml4[PML4PML4I] = VM_PAGE_TO_PHYS(pml4pg) | X86_PG_V | X86_PG_RW | X86_PG_A | X86_PG_M; } pmap->pm_root.rt_root = 0; CPU_ZERO(&pmap->pm_active); TAILQ_INIT(&pmap->pm_pvchunk); bzero(&pmap->pm_stats, sizeof pmap->pm_stats); pmap->pm_flags = flags; pmap->pm_eptgen = 0; return (1); } int pmap_pinit(pmap_t pmap) { return (pmap_pinit_type(pmap, PT_X86, pmap_flags)); } /* * This routine is called if the desired page table page does not exist. * * If page table page allocation fails, this routine may sleep before * returning NULL. It sleeps only if a lock pointer was given. * * Note: If a page allocation fails at page table level two or three, * one or two pages may be held during the wait, only to be released * afterwards. This conservative approach is easily argued to avoid * race conditions. */ static vm_page_t _pmap_allocpte(pmap_t pmap, vm_pindex_t ptepindex, struct rwlock **lockp) { vm_page_t m, pdppg, pdpg; pt_entry_t PG_A, PG_M, PG_RW, PG_V; PMAP_LOCK_ASSERT(pmap, MA_OWNED); PG_A = pmap_accessed_bit(pmap); PG_M = pmap_modified_bit(pmap); PG_V = pmap_valid_bit(pmap); PG_RW = pmap_rw_bit(pmap); /* * Allocate a page table page. */ if ((m = vm_page_alloc(NULL, ptepindex, VM_ALLOC_NOOBJ | VM_ALLOC_WIRED | VM_ALLOC_ZERO)) == NULL) { if (lockp != NULL) { RELEASE_PV_LIST_LOCK(lockp); PMAP_UNLOCK(pmap); rw_runlock(&pvh_global_lock); VM_WAIT; rw_rlock(&pvh_global_lock); PMAP_LOCK(pmap); } /* * Indicate the need to retry. While waiting, the page table * page may have been allocated. */ return (NULL); } if ((m->flags & PG_ZERO) == 0) pmap_zero_page(m); /* * Map the pagetable page into the process address space, if * it isn't already there. */ if (ptepindex >= (NUPDE + NUPDPE)) { pml4_entry_t *pml4; vm_pindex_t pml4index; /* Wire up a new PDPE page */ pml4index = ptepindex - (NUPDE + NUPDPE); pml4 = &pmap->pm_pml4[pml4index]; *pml4 = VM_PAGE_TO_PHYS(m) | PG_U | PG_RW | PG_V | PG_A | PG_M; } else if (ptepindex >= NUPDE) { vm_pindex_t pml4index; vm_pindex_t pdpindex; pml4_entry_t *pml4; pdp_entry_t *pdp; /* Wire up a new PDE page */ pdpindex = ptepindex - NUPDE; pml4index = pdpindex >> NPML4EPGSHIFT; pml4 = &pmap->pm_pml4[pml4index]; if ((*pml4 & PG_V) == 0) { /* Have to allocate a new pdp, recurse */ if (_pmap_allocpte(pmap, NUPDE + NUPDPE + pml4index, lockp) == NULL) { --m->wire_count; atomic_subtract_int(&vm_cnt.v_wire_count, 1); vm_page_free_zero(m); return (NULL); } } else { /* Add reference to pdp page */ pdppg = PHYS_TO_VM_PAGE(*pml4 & PG_FRAME); pdppg->wire_count++; } pdp = (pdp_entry_t *)PHYS_TO_DMAP(*pml4 & PG_FRAME); /* Now find the pdp page */ pdp = &pdp[pdpindex & ((1ul << NPDPEPGSHIFT) - 1)]; *pdp = VM_PAGE_TO_PHYS(m) | PG_U | PG_RW | PG_V | PG_A | PG_M; } else { vm_pindex_t pml4index; vm_pindex_t pdpindex; pml4_entry_t *pml4; pdp_entry_t *pdp; pd_entry_t *pd; /* Wire up a new PTE page */ pdpindex = ptepindex >> NPDPEPGSHIFT; pml4index = pdpindex >> NPML4EPGSHIFT; /* First, find the pdp and check that its valid. */ pml4 = &pmap->pm_pml4[pml4index]; if ((*pml4 & PG_V) == 0) { /* Have to allocate a new pd, recurse */ if (_pmap_allocpte(pmap, NUPDE + pdpindex, lockp) == NULL) { --m->wire_count; atomic_subtract_int(&vm_cnt.v_wire_count, 1); vm_page_free_zero(m); return (NULL); } pdp = (pdp_entry_t *)PHYS_TO_DMAP(*pml4 & PG_FRAME); pdp = &pdp[pdpindex & ((1ul << NPDPEPGSHIFT) - 1)]; } else { pdp = (pdp_entry_t *)PHYS_TO_DMAP(*pml4 & PG_FRAME); pdp = &pdp[pdpindex & ((1ul << NPDPEPGSHIFT) - 1)]; if ((*pdp & PG_V) == 0) { /* Have to allocate a new pd, recurse */ if (_pmap_allocpte(pmap, NUPDE + pdpindex, lockp) == NULL) { --m->wire_count; atomic_subtract_int(&vm_cnt.v_wire_count, 1); vm_page_free_zero(m); return (NULL); } } else { /* Add reference to the pd page */ pdpg = PHYS_TO_VM_PAGE(*pdp & PG_FRAME); pdpg->wire_count++; } } pd = (pd_entry_t *)PHYS_TO_DMAP(*pdp & PG_FRAME); /* Now we know where the page directory page is */ pd = &pd[ptepindex & ((1ul << NPDEPGSHIFT) - 1)]; *pd = VM_PAGE_TO_PHYS(m) | PG_U | PG_RW | PG_V | PG_A | PG_M; } pmap_resident_count_inc(pmap, 1); return (m); } static vm_page_t pmap_allocpde(pmap_t pmap, vm_offset_t va, struct rwlock **lockp) { vm_pindex_t pdpindex, ptepindex; pdp_entry_t *pdpe, PG_V; vm_page_t pdpg; PG_V = pmap_valid_bit(pmap); retry: pdpe = pmap_pdpe(pmap, va); if (pdpe != NULL && (*pdpe & PG_V) != 0) { /* Add a reference to the pd page. */ pdpg = PHYS_TO_VM_PAGE(*pdpe & PG_FRAME); pdpg->wire_count++; } else { /* Allocate a pd page. */ ptepindex = pmap_pde_pindex(va); pdpindex = ptepindex >> NPDPEPGSHIFT; pdpg = _pmap_allocpte(pmap, NUPDE + pdpindex, lockp); if (pdpg == NULL && lockp != NULL) goto retry; } return (pdpg); } static vm_page_t pmap_allocpte(pmap_t pmap, vm_offset_t va, struct rwlock **lockp) { vm_pindex_t ptepindex; pd_entry_t *pd, PG_V; vm_page_t m; PG_V = pmap_valid_bit(pmap); /* * Calculate pagetable page index */ ptepindex = pmap_pde_pindex(va); retry: /* * Get the page directory entry */ pd = pmap_pde(pmap, va); /* * This supports switching from a 2MB page to a * normal 4K page. */ if (pd != NULL && (*pd & (PG_PS | PG_V)) == (PG_PS | PG_V)) { if (!pmap_demote_pde_locked(pmap, pd, va, lockp)) { /* * Invalidation of the 2MB page mapping may have caused * the deallocation of the underlying PD page. */ pd = NULL; } } /* * If the page table page is mapped, we just increment the * hold count, and activate it. */ if (pd != NULL && (*pd & PG_V) != 0) { m = PHYS_TO_VM_PAGE(*pd & PG_FRAME); m->wire_count++; } else { /* * Here if the pte page isn't mapped, or if it has been * deallocated. */ m = _pmap_allocpte(pmap, ptepindex, lockp); if (m == NULL && lockp != NULL) goto retry; } return (m); } /*************************************************** * Pmap allocation/deallocation routines. ***************************************************/ /* * Release any resources held by the given physical map. * Called when a pmap initialized by pmap_pinit is being released. * Should only be called if the map contains no valid mappings. */ void pmap_release(pmap_t pmap) { vm_page_t m; int i; KASSERT(pmap->pm_stats.resident_count == 0, ("pmap_release: pmap resident count %ld != 0", pmap->pm_stats.resident_count)); KASSERT(vm_radix_is_empty(&pmap->pm_root), ("pmap_release: pmap has reserved page table page(s)")); KASSERT(CPU_EMPTY(&pmap->pm_active), ("releasing active pmap %p", pmap)); m = PHYS_TO_VM_PAGE(DMAP_TO_PHYS((vm_offset_t)pmap->pm_pml4)); for (i = 0; i < NKPML4E; i++) /* KVA */ pmap->pm_pml4[KPML4BASE + i] = 0; for (i = 0; i < ndmpdpphys; i++)/* Direct Map */ pmap->pm_pml4[DMPML4I + i] = 0; pmap->pm_pml4[PML4PML4I] = 0; /* Recursive Mapping */ m->wire_count--; atomic_subtract_int(&vm_cnt.v_wire_count, 1); vm_page_free_zero(m); } static int kvm_size(SYSCTL_HANDLER_ARGS) { unsigned long ksize = VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS; return sysctl_handle_long(oidp, &ksize, 0, req); } SYSCTL_PROC(_vm, OID_AUTO, kvm_size, CTLTYPE_LONG|CTLFLAG_RD, 0, 0, kvm_size, "LU", "Size of KVM"); static int kvm_free(SYSCTL_HANDLER_ARGS) { unsigned long kfree = VM_MAX_KERNEL_ADDRESS - kernel_vm_end; return sysctl_handle_long(oidp, &kfree, 0, req); } SYSCTL_PROC(_vm, OID_AUTO, kvm_free, CTLTYPE_LONG|CTLFLAG_RD, 0, 0, kvm_free, "LU", "Amount of KVM free"); /* * grow the number of kernel page table entries, if needed */ void pmap_growkernel(vm_offset_t addr) { vm_paddr_t paddr; vm_page_t nkpg; pd_entry_t *pde, newpdir; pdp_entry_t *pdpe; mtx_assert(&kernel_map->system_mtx, MA_OWNED); /* * Return if "addr" is within the range of kernel page table pages * that were preallocated during pmap bootstrap. Moreover, leave * "kernel_vm_end" and the kernel page table as they were. * * The correctness of this action is based on the following * argument: vm_map_insert() allocates contiguous ranges of the * kernel virtual address space. It calls this function if a range * ends after "kernel_vm_end". If the kernel is mapped between * "kernel_vm_end" and "addr", then the range cannot begin at * "kernel_vm_end". In fact, its beginning address cannot be less * than the kernel. Thus, there is no immediate need to allocate * any new kernel page table pages between "kernel_vm_end" and * "KERNBASE". */ if (KERNBASE < addr && addr <= KERNBASE + nkpt * NBPDR) return; addr = roundup2(addr, NBPDR); if (addr - 1 >= kernel_map->max_offset) addr = kernel_map->max_offset; while (kernel_vm_end < addr) { pdpe = pmap_pdpe(kernel_pmap, kernel_vm_end); if ((*pdpe & X86_PG_V) == 0) { /* We need a new PDP entry */ nkpg = vm_page_alloc(NULL, kernel_vm_end >> PDPSHIFT, VM_ALLOC_INTERRUPT | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED | VM_ALLOC_ZERO); if (nkpg == NULL) panic("pmap_growkernel: no memory to grow kernel"); if ((nkpg->flags & PG_ZERO) == 0) pmap_zero_page(nkpg); paddr = VM_PAGE_TO_PHYS(nkpg); *pdpe = (pdp_entry_t)(paddr | X86_PG_V | X86_PG_RW | X86_PG_A | X86_PG_M); continue; /* try again */ } pde = pmap_pdpe_to_pde(pdpe, kernel_vm_end); if ((*pde & X86_PG_V) != 0) { kernel_vm_end = (kernel_vm_end + NBPDR) & ~PDRMASK; if (kernel_vm_end - 1 >= kernel_map->max_offset) { kernel_vm_end = kernel_map->max_offset; break; } continue; } nkpg = vm_page_alloc(NULL, pmap_pde_pindex(kernel_vm_end), VM_ALLOC_INTERRUPT | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED | VM_ALLOC_ZERO); if (nkpg == NULL) panic("pmap_growkernel: no memory to grow kernel"); if ((nkpg->flags & PG_ZERO) == 0) pmap_zero_page(nkpg); paddr = VM_PAGE_TO_PHYS(nkpg); newpdir = paddr | X86_PG_V | X86_PG_RW | X86_PG_A | X86_PG_M; pde_store(pde, newpdir); kernel_vm_end = (kernel_vm_end + NBPDR) & ~PDRMASK; if (kernel_vm_end - 1 >= kernel_map->max_offset) { kernel_vm_end = kernel_map->max_offset; break; } } } /*************************************************** * page management routines. ***************************************************/ CTASSERT(sizeof(struct pv_chunk) == PAGE_SIZE); CTASSERT(_NPCM == 3); CTASSERT(_NPCPV == 168); static __inline struct pv_chunk * pv_to_chunk(pv_entry_t pv) { return ((struct pv_chunk *)((uintptr_t)pv & ~(uintptr_t)PAGE_MASK)); } #define PV_PMAP(pv) (pv_to_chunk(pv)->pc_pmap) #define PC_FREE0 0xfffffffffffffffful #define PC_FREE1 0xfffffffffffffffful #define PC_FREE2 0x000000fffffffffful static const uint64_t pc_freemask[_NPCM] = { PC_FREE0, PC_FREE1, PC_FREE2 }; #ifdef PV_STATS static int pc_chunk_count, pc_chunk_allocs, pc_chunk_frees, pc_chunk_tryfail; SYSCTL_INT(_vm_pmap, OID_AUTO, pc_chunk_count, CTLFLAG_RD, &pc_chunk_count, 0, "Current number of pv entry chunks"); SYSCTL_INT(_vm_pmap, OID_AUTO, pc_chunk_allocs, CTLFLAG_RD, &pc_chunk_allocs, 0, "Current number of pv entry chunks allocated"); SYSCTL_INT(_vm_pmap, OID_AUTO, pc_chunk_frees, CTLFLAG_RD, &pc_chunk_frees, 0, "Current number of pv entry chunks frees"); SYSCTL_INT(_vm_pmap, OID_AUTO, pc_chunk_tryfail, CTLFLAG_RD, &pc_chunk_tryfail, 0, "Number of times tried to get a chunk page but failed."); static long pv_entry_frees, pv_entry_allocs, pv_entry_count; static int pv_entry_spare; SYSCTL_LONG(_vm_pmap, OID_AUTO, pv_entry_frees, CTLFLAG_RD, &pv_entry_frees, 0, "Current number of pv entry frees"); SYSCTL_LONG(_vm_pmap, OID_AUTO, pv_entry_allocs, CTLFLAG_RD, &pv_entry_allocs, 0, "Current number of pv entry allocs"); SYSCTL_LONG(_vm_pmap, OID_AUTO, pv_entry_count, CTLFLAG_RD, &pv_entry_count, 0, "Current number of pv entries"); SYSCTL_INT(_vm_pmap, OID_AUTO, pv_entry_spare, CTLFLAG_RD, &pv_entry_spare, 0, "Current number of spare pv entries"); #endif /* * We are in a serious low memory condition. Resort to * drastic measures to free some pages so we can allocate * another pv entry chunk. * * Returns NULL if PV entries were reclaimed from the specified pmap. * * We do not, however, unmap 2mpages because subsequent accesses will * allocate per-page pv entries until repromotion occurs, thereby * exacerbating the shortage of free pv entries. */ static vm_page_t reclaim_pv_chunk(pmap_t locked_pmap, struct rwlock **lockp) { struct pch new_tail; struct pv_chunk *pc; struct md_page *pvh; pd_entry_t *pde; pmap_t pmap; pt_entry_t *pte, tpte; pt_entry_t PG_G, PG_A, PG_M, PG_RW; pv_entry_t pv; vm_offset_t va; vm_page_t m, m_pc; struct spglist free; uint64_t inuse; int bit, field, freed; rw_assert(&pvh_global_lock, RA_LOCKED); PMAP_LOCK_ASSERT(locked_pmap, MA_OWNED); KASSERT(lockp != NULL, ("reclaim_pv_chunk: lockp is NULL")); pmap = NULL; m_pc = NULL; PG_G = PG_A = PG_M = PG_RW = 0; SLIST_INIT(&free); TAILQ_INIT(&new_tail); mtx_lock(&pv_chunks_mutex); while ((pc = TAILQ_FIRST(&pv_chunks)) != NULL && SLIST_EMPTY(&free)) { TAILQ_REMOVE(&pv_chunks, pc, pc_lru); mtx_unlock(&pv_chunks_mutex); if (pmap != pc->pc_pmap) { if (pmap != NULL) { pmap_invalidate_all(pmap); if (pmap != locked_pmap) PMAP_UNLOCK(pmap); } pmap = pc->pc_pmap; /* Avoid deadlock and lock recursion. */ if (pmap > locked_pmap) { RELEASE_PV_LIST_LOCK(lockp); PMAP_LOCK(pmap); } else if (pmap != locked_pmap && !PMAP_TRYLOCK(pmap)) { pmap = NULL; TAILQ_INSERT_TAIL(&new_tail, pc, pc_lru); mtx_lock(&pv_chunks_mutex); continue; } PG_G = pmap_global_bit(pmap); PG_A = pmap_accessed_bit(pmap); PG_M = pmap_modified_bit(pmap); PG_RW = pmap_rw_bit(pmap); } /* * Destroy every non-wired, 4 KB page mapping in the chunk. */ freed = 0; for (field = 0; field < _NPCM; field++) { for (inuse = ~pc->pc_map[field] & pc_freemask[field]; inuse != 0; inuse &= ~(1UL << bit)) { bit = bsfq(inuse); pv = &pc->pc_pventry[field * 64 + bit]; va = pv->pv_va; pde = pmap_pde(pmap, va); if ((*pde & PG_PS) != 0) continue; pte = pmap_pde_to_pte(pde, va); if ((*pte & PG_W) != 0) continue; tpte = pte_load_clear(pte); if ((tpte & PG_G) != 0) pmap_invalidate_page(pmap, va); m = PHYS_TO_VM_PAGE(tpte & PG_FRAME); if ((tpte & (PG_M | PG_RW)) == (PG_M | PG_RW)) vm_page_dirty(m); if ((tpte & PG_A) != 0) vm_page_aflag_set(m, PGA_REFERENCED); CHANGE_PV_LIST_LOCK_TO_VM_PAGE(lockp, m); TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); m->md.pv_gen++; if (TAILQ_EMPTY(&m->md.pv_list) && (m->flags & PG_FICTITIOUS) == 0) { pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); if (TAILQ_EMPTY(&pvh->pv_list)) { vm_page_aflag_clear(m, PGA_WRITEABLE); } } pc->pc_map[field] |= 1UL << bit; pmap_unuse_pt(pmap, va, *pde, &free); freed++; } } if (freed == 0) { TAILQ_INSERT_TAIL(&new_tail, pc, pc_lru); mtx_lock(&pv_chunks_mutex); continue; } /* Every freed mapping is for a 4 KB page. */ pmap_resident_count_dec(pmap, freed); PV_STAT(atomic_add_long(&pv_entry_frees, freed)); PV_STAT(atomic_add_int(&pv_entry_spare, freed)); PV_STAT(atomic_subtract_long(&pv_entry_count, freed)); TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list); if (pc->pc_map[0] == PC_FREE0 && pc->pc_map[1] == PC_FREE1 && pc->pc_map[2] == PC_FREE2) { PV_STAT(atomic_subtract_int(&pv_entry_spare, _NPCPV)); PV_STAT(atomic_subtract_int(&pc_chunk_count, 1)); PV_STAT(atomic_add_int(&pc_chunk_frees, 1)); /* Entire chunk is free; return it. */ m_pc = PHYS_TO_VM_PAGE(DMAP_TO_PHYS((vm_offset_t)pc)); dump_drop_page(m_pc->phys_addr); mtx_lock(&pv_chunks_mutex); break; } TAILQ_INSERT_HEAD(&pmap->pm_pvchunk, pc, pc_list); TAILQ_INSERT_TAIL(&new_tail, pc, pc_lru); mtx_lock(&pv_chunks_mutex); /* One freed pv entry in locked_pmap is sufficient. */ if (pmap == locked_pmap) break; } TAILQ_CONCAT(&pv_chunks, &new_tail, pc_lru); mtx_unlock(&pv_chunks_mutex); if (pmap != NULL) { pmap_invalidate_all(pmap); if (pmap != locked_pmap) PMAP_UNLOCK(pmap); } if (m_pc == NULL && !SLIST_EMPTY(&free)) { m_pc = SLIST_FIRST(&free); SLIST_REMOVE_HEAD(&free, plinks.s.ss); /* Recycle a freed page table page. */ m_pc->wire_count = 1; atomic_add_int(&vm_cnt.v_wire_count, 1); } pmap_free_zero_pages(&free); return (m_pc); } /* * free the pv_entry back to the free list */ static void free_pv_entry(pmap_t pmap, pv_entry_t pv) { struct pv_chunk *pc; int idx, field, bit; rw_assert(&pvh_global_lock, RA_LOCKED); PMAP_LOCK_ASSERT(pmap, MA_OWNED); PV_STAT(atomic_add_long(&pv_entry_frees, 1)); PV_STAT(atomic_add_int(&pv_entry_spare, 1)); PV_STAT(atomic_subtract_long(&pv_entry_count, 1)); pc = pv_to_chunk(pv); idx = pv - &pc->pc_pventry[0]; field = idx / 64; bit = idx % 64; pc->pc_map[field] |= 1ul << bit; if (pc->pc_map[0] != PC_FREE0 || pc->pc_map[1] != PC_FREE1 || pc->pc_map[2] != PC_FREE2) { /* 98% of the time, pc is already at the head of the list. */ if (__predict_false(pc != TAILQ_FIRST(&pmap->pm_pvchunk))) { TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list); TAILQ_INSERT_HEAD(&pmap->pm_pvchunk, pc, pc_list); } return; } TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list); free_pv_chunk(pc); } static void free_pv_chunk(struct pv_chunk *pc) { vm_page_t m; mtx_lock(&pv_chunks_mutex); TAILQ_REMOVE(&pv_chunks, pc, pc_lru); mtx_unlock(&pv_chunks_mutex); PV_STAT(atomic_subtract_int(&pv_entry_spare, _NPCPV)); PV_STAT(atomic_subtract_int(&pc_chunk_count, 1)); PV_STAT(atomic_add_int(&pc_chunk_frees, 1)); /* entire chunk is free, return it */ m = PHYS_TO_VM_PAGE(DMAP_TO_PHYS((vm_offset_t)pc)); dump_drop_page(m->phys_addr); vm_page_unwire(m, PQ_INACTIVE); vm_page_free(m); } /* * Returns a new PV entry, allocating a new PV chunk from the system when * needed. If this PV chunk allocation fails and a PV list lock pointer was * given, a PV chunk is reclaimed from an arbitrary pmap. Otherwise, NULL is * returned. * * The given PV list lock may be released. */ static pv_entry_t get_pv_entry(pmap_t pmap, struct rwlock **lockp) { int bit, field; pv_entry_t pv; struct pv_chunk *pc; vm_page_t m; rw_assert(&pvh_global_lock, RA_LOCKED); PMAP_LOCK_ASSERT(pmap, MA_OWNED); PV_STAT(atomic_add_long(&pv_entry_allocs, 1)); retry: pc = TAILQ_FIRST(&pmap->pm_pvchunk); if (pc != NULL) { for (field = 0; field < _NPCM; field++) { if (pc->pc_map[field]) { bit = bsfq(pc->pc_map[field]); break; } } if (field < _NPCM) { pv = &pc->pc_pventry[field * 64 + bit]; pc->pc_map[field] &= ~(1ul << bit); /* If this was the last item, move it to tail */ if (pc->pc_map[0] == 0 && pc->pc_map[1] == 0 && pc->pc_map[2] == 0) { TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list); TAILQ_INSERT_TAIL(&pmap->pm_pvchunk, pc, pc_list); } PV_STAT(atomic_add_long(&pv_entry_count, 1)); PV_STAT(atomic_subtract_int(&pv_entry_spare, 1)); return (pv); } } /* No free items, allocate another chunk */ m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED); if (m == NULL) { if (lockp == NULL) { PV_STAT(pc_chunk_tryfail++); return (NULL); } m = reclaim_pv_chunk(pmap, lockp); if (m == NULL) goto retry; } PV_STAT(atomic_add_int(&pc_chunk_count, 1)); PV_STAT(atomic_add_int(&pc_chunk_allocs, 1)); dump_add_page(m->phys_addr); pc = (void *)PHYS_TO_DMAP(m->phys_addr); pc->pc_pmap = pmap; pc->pc_map[0] = PC_FREE0 & ~1ul; /* preallocated bit 0 */ pc->pc_map[1] = PC_FREE1; pc->pc_map[2] = PC_FREE2; mtx_lock(&pv_chunks_mutex); TAILQ_INSERT_TAIL(&pv_chunks, pc, pc_lru); mtx_unlock(&pv_chunks_mutex); pv = &pc->pc_pventry[0]; TAILQ_INSERT_HEAD(&pmap->pm_pvchunk, pc, pc_list); PV_STAT(atomic_add_long(&pv_entry_count, 1)); PV_STAT(atomic_add_int(&pv_entry_spare, _NPCPV - 1)); return (pv); } /* * Returns the number of one bits within the given PV chunk map element. * * The erratas for Intel processors state that "POPCNT Instruction May * Take Longer to Execute Than Expected". It is believed that the * issue is the spurious dependency on the destination register. * Provide a hint to the register rename logic that the destination * value is overwritten, by clearing it, as suggested in the * optimization manual. It should be cheap for unaffected processors * as well. * * Reference numbers for erratas are * 4th Gen Core: HSD146 * 5th Gen Core: BDM85 */ static int popcnt_pc_map_elem_pq(uint64_t elem) { u_long result; __asm __volatile("xorl %k0,%k0;popcntq %1,%0" : "=&r" (result) : "rm" (elem)); return (result); } /* * Ensure that the number of spare PV entries in the specified pmap meets or * exceeds the given count, "needed". * * The given PV list lock may be released. */ static void reserve_pv_entries(pmap_t pmap, int needed, struct rwlock **lockp) { struct pch new_tail; struct pv_chunk *pc; int avail, free; vm_page_t m; rw_assert(&pvh_global_lock, RA_LOCKED); PMAP_LOCK_ASSERT(pmap, MA_OWNED); KASSERT(lockp != NULL, ("reserve_pv_entries: lockp is NULL")); /* * Newly allocated PV chunks must be stored in a private list until * the required number of PV chunks have been allocated. Otherwise, * reclaim_pv_chunk() could recycle one of these chunks. In * contrast, these chunks must be added to the pmap upon allocation. */ TAILQ_INIT(&new_tail); retry: avail = 0; TAILQ_FOREACH(pc, &pmap->pm_pvchunk, pc_list) { if ((cpu_feature2 & CPUID2_POPCNT) == 0) { free = bitcount64(pc->pc_map[0]); free += bitcount64(pc->pc_map[1]); free += bitcount64(pc->pc_map[2]); } else { free = popcnt_pc_map_elem_pq(pc->pc_map[0]); free += popcnt_pc_map_elem_pq(pc->pc_map[1]); free += popcnt_pc_map_elem_pq(pc->pc_map[2]); } if (free == 0) break; avail += free; if (avail >= needed) break; } for (; avail < needed; avail += _NPCPV) { m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED); if (m == NULL) { m = reclaim_pv_chunk(pmap, lockp); if (m == NULL) goto retry; } PV_STAT(atomic_add_int(&pc_chunk_count, 1)); PV_STAT(atomic_add_int(&pc_chunk_allocs, 1)); dump_add_page(m->phys_addr); pc = (void *)PHYS_TO_DMAP(m->phys_addr); pc->pc_pmap = pmap; pc->pc_map[0] = PC_FREE0; pc->pc_map[1] = PC_FREE1; pc->pc_map[2] = PC_FREE2; TAILQ_INSERT_HEAD(&pmap->pm_pvchunk, pc, pc_list); TAILQ_INSERT_TAIL(&new_tail, pc, pc_lru); PV_STAT(atomic_add_int(&pv_entry_spare, _NPCPV)); } if (!TAILQ_EMPTY(&new_tail)) { mtx_lock(&pv_chunks_mutex); TAILQ_CONCAT(&pv_chunks, &new_tail, pc_lru); mtx_unlock(&pv_chunks_mutex); } } /* * First find and then remove the pv entry for the specified pmap and virtual * address from the specified pv list. Returns the pv entry if found and NULL * otherwise. This operation can be performed on pv lists for either 4KB or * 2MB page mappings. */ static __inline pv_entry_t pmap_pvh_remove(struct md_page *pvh, pmap_t pmap, vm_offset_t va) { pv_entry_t pv; rw_assert(&pvh_global_lock, RA_LOCKED); TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) { if (pmap == PV_PMAP(pv) && va == pv->pv_va) { TAILQ_REMOVE(&pvh->pv_list, pv, pv_next); pvh->pv_gen++; break; } } return (pv); } /* * After demotion from a 2MB page mapping to 512 4KB page mappings, * destroy the pv entry for the 2MB page mapping and reinstantiate the pv * entries for each of the 4KB page mappings. */ static void pmap_pv_demote_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa, struct rwlock **lockp) { struct md_page *pvh; struct pv_chunk *pc; pv_entry_t pv; vm_offset_t va_last; vm_page_t m; int bit, field; rw_assert(&pvh_global_lock, RA_LOCKED); PMAP_LOCK_ASSERT(pmap, MA_OWNED); KASSERT((pa & PDRMASK) == 0, ("pmap_pv_demote_pde: pa is not 2mpage aligned")); CHANGE_PV_LIST_LOCK_TO_PHYS(lockp, pa); /* * Transfer the 2mpage's pv entry for this mapping to the first * page's pv list. Once this transfer begins, the pv list lock * must not be released until the last pv entry is reinstantiated. */ pvh = pa_to_pvh(pa); va = trunc_2mpage(va); pv = pmap_pvh_remove(pvh, pmap, va); KASSERT(pv != NULL, ("pmap_pv_demote_pde: pv not found")); m = PHYS_TO_VM_PAGE(pa); TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); m->md.pv_gen++; /* Instantiate the remaining NPTEPG - 1 pv entries. */ PV_STAT(atomic_add_long(&pv_entry_allocs, NPTEPG - 1)); va_last = va + NBPDR - PAGE_SIZE; for (;;) { pc = TAILQ_FIRST(&pmap->pm_pvchunk); KASSERT(pc->pc_map[0] != 0 || pc->pc_map[1] != 0 || pc->pc_map[2] != 0, ("pmap_pv_demote_pde: missing spare")); for (field = 0; field < _NPCM; field++) { while (pc->pc_map[field]) { bit = bsfq(pc->pc_map[field]); pc->pc_map[field] &= ~(1ul << bit); pv = &pc->pc_pventry[field * 64 + bit]; va += PAGE_SIZE; pv->pv_va = va; m++; KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_pv_demote_pde: page %p is not managed", m)); TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); m->md.pv_gen++; if (va == va_last) goto out; } } TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list); TAILQ_INSERT_TAIL(&pmap->pm_pvchunk, pc, pc_list); } out: if (pc->pc_map[0] == 0 && pc->pc_map[1] == 0 && pc->pc_map[2] == 0) { TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list); TAILQ_INSERT_TAIL(&pmap->pm_pvchunk, pc, pc_list); } PV_STAT(atomic_add_long(&pv_entry_count, NPTEPG - 1)); PV_STAT(atomic_subtract_int(&pv_entry_spare, NPTEPG - 1)); } /* * After promotion from 512 4KB page mappings to a single 2MB page mapping, * replace the many pv entries for the 4KB page mappings by a single pv entry * for the 2MB page mapping. */ static void pmap_pv_promote_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa, struct rwlock **lockp) { struct md_page *pvh; pv_entry_t pv; vm_offset_t va_last; vm_page_t m; rw_assert(&pvh_global_lock, RA_LOCKED); KASSERT((pa & PDRMASK) == 0, ("pmap_pv_promote_pde: pa is not 2mpage aligned")); CHANGE_PV_LIST_LOCK_TO_PHYS(lockp, pa); /* * Transfer the first page's pv entry for this mapping to the 2mpage's * pv list. Aside from avoiding the cost of a call to get_pv_entry(), * a transfer avoids the possibility that get_pv_entry() calls * reclaim_pv_chunk() and that reclaim_pv_chunk() removes one of the * mappings that is being promoted. */ m = PHYS_TO_VM_PAGE(pa); va = trunc_2mpage(va); pv = pmap_pvh_remove(&m->md, pmap, va); KASSERT(pv != NULL, ("pmap_pv_promote_pde: pv not found")); pvh = pa_to_pvh(pa); TAILQ_INSERT_TAIL(&pvh->pv_list, pv, pv_next); pvh->pv_gen++; /* Free the remaining NPTEPG - 1 pv entries. */ va_last = va + NBPDR - PAGE_SIZE; do { m++; va += PAGE_SIZE; pmap_pvh_free(&m->md, pmap, va); } while (va < va_last); } /* * First find and then destroy the pv entry for the specified pmap and virtual * address. This operation can be performed on pv lists for either 4KB or 2MB * page mappings. */ static void pmap_pvh_free(struct md_page *pvh, pmap_t pmap, vm_offset_t va) { pv_entry_t pv; pv = pmap_pvh_remove(pvh, pmap, va); KASSERT(pv != NULL, ("pmap_pvh_free: pv not found")); free_pv_entry(pmap, pv); } /* * Conditionally create the PV entry for a 4KB page mapping if the required * memory can be allocated without resorting to reclamation. */ static boolean_t pmap_try_insert_pv_entry(pmap_t pmap, vm_offset_t va, vm_page_t m, struct rwlock **lockp) { pv_entry_t pv; rw_assert(&pvh_global_lock, RA_LOCKED); PMAP_LOCK_ASSERT(pmap, MA_OWNED); /* Pass NULL instead of the lock pointer to disable reclamation. */ if ((pv = get_pv_entry(pmap, NULL)) != NULL) { pv->pv_va = va; CHANGE_PV_LIST_LOCK_TO_VM_PAGE(lockp, m); TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); m->md.pv_gen++; return (TRUE); } else return (FALSE); } /* * Conditionally create the PV entry for a 2MB page mapping if the required * memory can be allocated without resorting to reclamation. */ static boolean_t pmap_pv_insert_pde(pmap_t pmap, vm_offset_t va, vm_paddr_t pa, struct rwlock **lockp) { struct md_page *pvh; pv_entry_t pv; rw_assert(&pvh_global_lock, RA_LOCKED); PMAP_LOCK_ASSERT(pmap, MA_OWNED); /* Pass NULL instead of the lock pointer to disable reclamation. */ if ((pv = get_pv_entry(pmap, NULL)) != NULL) { pv->pv_va = va; CHANGE_PV_LIST_LOCK_TO_PHYS(lockp, pa); pvh = pa_to_pvh(pa); TAILQ_INSERT_TAIL(&pvh->pv_list, pv, pv_next); pvh->pv_gen++; return (TRUE); } else return (FALSE); } /* * Fills a page table page with mappings to consecutive physical pages. */ static void pmap_fill_ptp(pt_entry_t *firstpte, pt_entry_t newpte) { pt_entry_t *pte; for (pte = firstpte; pte < firstpte + NPTEPG; pte++) { *pte = newpte; newpte += PAGE_SIZE; } } /* * Tries to demote a 2MB page mapping. If demotion fails, the 2MB page * mapping is invalidated. */ static boolean_t pmap_demote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va) { struct rwlock *lock; boolean_t rv; lock = NULL; rv = pmap_demote_pde_locked(pmap, pde, va, &lock); if (lock != NULL) rw_wunlock(lock); return (rv); } static boolean_t pmap_demote_pde_locked(pmap_t pmap, pd_entry_t *pde, vm_offset_t va, struct rwlock **lockp) { pd_entry_t newpde, oldpde; pt_entry_t *firstpte, newpte; pt_entry_t PG_A, PG_G, PG_M, PG_RW, PG_V; vm_paddr_t mptepa; vm_page_t mpte; struct spglist free; int PG_PTE_CACHE; PG_G = pmap_global_bit(pmap); PG_A = pmap_accessed_bit(pmap); PG_M = pmap_modified_bit(pmap); PG_RW = pmap_rw_bit(pmap); PG_V = pmap_valid_bit(pmap); PG_PTE_CACHE = pmap_cache_mask(pmap, 0); PMAP_LOCK_ASSERT(pmap, MA_OWNED); oldpde = *pde; KASSERT((oldpde & (PG_PS | PG_V)) == (PG_PS | PG_V), ("pmap_demote_pde: oldpde is missing PG_PS and/or PG_V")); if ((oldpde & PG_A) != 0 && (mpte = pmap_lookup_pt_page(pmap, va)) != NULL) pmap_remove_pt_page(pmap, mpte); else { KASSERT((oldpde & PG_W) == 0, ("pmap_demote_pde: page table page for a wired mapping" " is missing")); /* * Invalidate the 2MB page mapping and return "failure" if the * mapping was never accessed or the allocation of the new * page table page fails. If the 2MB page mapping belongs to * the direct map region of the kernel's address space, then * the page allocation request specifies the highest possible * priority (VM_ALLOC_INTERRUPT). Otherwise, the priority is * normal. Page table pages are preallocated for every other * part of the kernel address space, so the direct map region * is the only part of the kernel address space that must be * handled here. */ if ((oldpde & PG_A) == 0 || (mpte = vm_page_alloc(NULL, pmap_pde_pindex(va), (va >= DMAP_MIN_ADDRESS && va < DMAP_MAX_ADDRESS ? VM_ALLOC_INTERRUPT : VM_ALLOC_NORMAL) | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED)) == NULL) { SLIST_INIT(&free); pmap_remove_pde(pmap, pde, trunc_2mpage(va), &free, lockp); pmap_invalidate_page(pmap, trunc_2mpage(va)); pmap_free_zero_pages(&free); CTR2(KTR_PMAP, "pmap_demote_pde: failure for va %#lx" " in pmap %p", va, pmap); return (FALSE); } if (va < VM_MAXUSER_ADDRESS) pmap_resident_count_inc(pmap, 1); } mptepa = VM_PAGE_TO_PHYS(mpte); firstpte = (pt_entry_t *)PHYS_TO_DMAP(mptepa); newpde = mptepa | PG_M | PG_A | (oldpde & PG_U) | PG_RW | PG_V; KASSERT((oldpde & PG_A) != 0, ("pmap_demote_pde: oldpde is missing PG_A")); KASSERT((oldpde & (PG_M | PG_RW)) != PG_RW, ("pmap_demote_pde: oldpde is missing PG_M")); newpte = oldpde & ~PG_PS; newpte = pmap_swap_pat(pmap, newpte); /* * If the page table page is new, initialize it. */ if (mpte->wire_count == 1) { mpte->wire_count = NPTEPG; pmap_fill_ptp(firstpte, newpte); } KASSERT((*firstpte & PG_FRAME) == (newpte & PG_FRAME), ("pmap_demote_pde: firstpte and newpte map different physical" " addresses")); /* * If the mapping has changed attributes, update the page table * entries. */ if ((*firstpte & PG_PTE_PROMOTE) != (newpte & PG_PTE_PROMOTE)) pmap_fill_ptp(firstpte, newpte); /* * The spare PV entries must be reserved prior to demoting the * mapping, that is, prior to changing the PDE. Otherwise, the state * of the PDE and the PV lists will be inconsistent, which can result * in reclaim_pv_chunk() attempting to remove a PV entry from the * wrong PV list and pmap_pv_demote_pde() failing to find the expected * PV entry for the 2MB page mapping that is being demoted. */ if ((oldpde & PG_MANAGED) != 0) reserve_pv_entries(pmap, NPTEPG - 1, lockp); /* * Demote the mapping. This pmap is locked. The old PDE has * PG_A set. If the old PDE has PG_RW set, it also has PG_M * set. Thus, there is no danger of a race with another * processor changing the setting of PG_A and/or PG_M between * the read above and the store below. */ if (workaround_erratum383) pmap_update_pde(pmap, va, pde, newpde); else pde_store(pde, newpde); /* * Invalidate a stale recursive mapping of the page table page. */ if (va >= VM_MAXUSER_ADDRESS) pmap_invalidate_page(pmap, (vm_offset_t)vtopte(va)); /* * Demote the PV entry. */ if ((oldpde & PG_MANAGED) != 0) pmap_pv_demote_pde(pmap, va, oldpde & PG_PS_FRAME, lockp); atomic_add_long(&pmap_pde_demotions, 1); CTR2(KTR_PMAP, "pmap_demote_pde: success for va %#lx" " in pmap %p", va, pmap); return (TRUE); } /* * pmap_remove_kernel_pde: Remove a kernel superpage mapping. */ static void pmap_remove_kernel_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va) { pd_entry_t newpde; vm_paddr_t mptepa; vm_page_t mpte; KASSERT(pmap == kernel_pmap, ("pmap %p is not kernel_pmap", pmap)); PMAP_LOCK_ASSERT(pmap, MA_OWNED); mpte = pmap_lookup_pt_page(pmap, va); if (mpte == NULL) panic("pmap_remove_kernel_pde: Missing pt page."); pmap_remove_pt_page(pmap, mpte); mptepa = VM_PAGE_TO_PHYS(mpte); newpde = mptepa | X86_PG_M | X86_PG_A | X86_PG_RW | X86_PG_V; /* * Initialize the page table page. */ pagezero((void *)PHYS_TO_DMAP(mptepa)); /* * Demote the mapping. */ if (workaround_erratum383) pmap_update_pde(pmap, va, pde, newpde); else pde_store(pde, newpde); /* * Invalidate a stale recursive mapping of the page table page. */ pmap_invalidate_page(pmap, (vm_offset_t)vtopte(va)); } /* * pmap_remove_pde: do the things to unmap a superpage in a process */ static int pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva, struct spglist *free, struct rwlock **lockp) { struct md_page *pvh; pd_entry_t oldpde; vm_offset_t eva, va; vm_page_t m, mpte; pt_entry_t PG_G, PG_A, PG_M, PG_RW; PG_G = pmap_global_bit(pmap); PG_A = pmap_accessed_bit(pmap); PG_M = pmap_modified_bit(pmap); PG_RW = pmap_rw_bit(pmap); PMAP_LOCK_ASSERT(pmap, MA_OWNED); KASSERT((sva & PDRMASK) == 0, ("pmap_remove_pde: sva is not 2mpage aligned")); oldpde = pte_load_clear(pdq); if (oldpde & PG_W) pmap->pm_stats.wired_count -= NBPDR / PAGE_SIZE; /* * Machines that don't support invlpg, also don't support * PG_G. */ if (oldpde & PG_G) pmap_invalidate_page(kernel_pmap, sva); pmap_resident_count_dec(pmap, NBPDR / PAGE_SIZE); if (oldpde & PG_MANAGED) { CHANGE_PV_LIST_LOCK_TO_PHYS(lockp, oldpde & PG_PS_FRAME); pvh = pa_to_pvh(oldpde & PG_PS_FRAME); pmap_pvh_free(pvh, pmap, sva); eva = sva + NBPDR; for (va = sva, m = PHYS_TO_VM_PAGE(oldpde & PG_PS_FRAME); va < eva; va += PAGE_SIZE, m++) { if ((oldpde & (PG_M | PG_RW)) == (PG_M | PG_RW)) vm_page_dirty(m); if (oldpde & PG_A) vm_page_aflag_set(m, PGA_REFERENCED); if (TAILQ_EMPTY(&m->md.pv_list) && TAILQ_EMPTY(&pvh->pv_list)) vm_page_aflag_clear(m, PGA_WRITEABLE); } } if (pmap == kernel_pmap) { pmap_remove_kernel_pde(pmap, pdq, sva); } else { mpte = pmap_lookup_pt_page(pmap, sva); if (mpte != NULL) { pmap_remove_pt_page(pmap, mpte); pmap_resident_count_dec(pmap, 1); KASSERT(mpte->wire_count == NPTEPG, ("pmap_remove_pde: pte page wire count error")); mpte->wire_count = 0; pmap_add_delayed_free_list(mpte, free, FALSE); atomic_subtract_int(&vm_cnt.v_wire_count, 1); } } return (pmap_unuse_pt(pmap, sva, *pmap_pdpe(pmap, sva), free)); } /* * pmap_remove_pte: do the things to unmap a page in a process */ static int pmap_remove_pte(pmap_t pmap, pt_entry_t *ptq, vm_offset_t va, pd_entry_t ptepde, struct spglist *free, struct rwlock **lockp) { struct md_page *pvh; pt_entry_t oldpte, PG_A, PG_M, PG_RW; vm_page_t m; PG_A = pmap_accessed_bit(pmap); PG_M = pmap_modified_bit(pmap); PG_RW = pmap_rw_bit(pmap); PMAP_LOCK_ASSERT(pmap, MA_OWNED); oldpte = pte_load_clear(ptq); if (oldpte & PG_W) pmap->pm_stats.wired_count -= 1; pmap_resident_count_dec(pmap, 1); if (oldpte & PG_MANAGED) { m = PHYS_TO_VM_PAGE(oldpte & PG_FRAME); if ((oldpte & (PG_M | PG_RW)) == (PG_M | PG_RW)) vm_page_dirty(m); if (oldpte & PG_A) vm_page_aflag_set(m, PGA_REFERENCED); CHANGE_PV_LIST_LOCK_TO_VM_PAGE(lockp, m); pmap_pvh_free(&m->md, pmap, va); if (TAILQ_EMPTY(&m->md.pv_list) && (m->flags & PG_FICTITIOUS) == 0) { pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); if (TAILQ_EMPTY(&pvh->pv_list)) vm_page_aflag_clear(m, PGA_WRITEABLE); } } return (pmap_unuse_pt(pmap, va, ptepde, free)); } /* * Remove a single page from a process address space */ static void pmap_remove_page(pmap_t pmap, vm_offset_t va, pd_entry_t *pde, struct spglist *free) { struct rwlock *lock; pt_entry_t *pte, PG_V; PG_V = pmap_valid_bit(pmap); PMAP_LOCK_ASSERT(pmap, MA_OWNED); if ((*pde & PG_V) == 0) return; pte = pmap_pde_to_pte(pde, va); if ((*pte & PG_V) == 0) return; lock = NULL; pmap_remove_pte(pmap, pte, va, *pde, free, &lock); if (lock != NULL) rw_wunlock(lock); pmap_invalidate_page(pmap, va); } /* * Remove the given range of addresses from the specified map. * * It is assumed that the start and end are properly * rounded to the page size. */ void pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) { struct rwlock *lock; vm_offset_t va, va_next; pml4_entry_t *pml4e; pdp_entry_t *pdpe; pd_entry_t ptpaddr, *pde; pt_entry_t *pte, PG_G, PG_V; struct spglist free; int anyvalid; PG_G = pmap_global_bit(pmap); PG_V = pmap_valid_bit(pmap); /* * Perform an unsynchronized read. This is, however, safe. */ if (pmap->pm_stats.resident_count == 0) return; anyvalid = 0; SLIST_INIT(&free); rw_rlock(&pvh_global_lock); PMAP_LOCK(pmap); /* * special handling of removing one page. a very * common operation and easy to short circuit some * code. */ if (sva + PAGE_SIZE == eva) { pde = pmap_pde(pmap, sva); if (pde && (*pde & PG_PS) == 0) { pmap_remove_page(pmap, sva, pde, &free); goto out; } } lock = NULL; for (; sva < eva; sva = va_next) { if (pmap->pm_stats.resident_count == 0) break; pml4e = pmap_pml4e(pmap, sva); if ((*pml4e & PG_V) == 0) { va_next = (sva + NBPML4) & ~PML4MASK; if (va_next < sva) va_next = eva; continue; } pdpe = pmap_pml4e_to_pdpe(pml4e, sva); if ((*pdpe & PG_V) == 0) { va_next = (sva + NBPDP) & ~PDPMASK; if (va_next < sva) va_next = eva; continue; } /* * Calculate index for next page table. */ va_next = (sva + NBPDR) & ~PDRMASK; if (va_next < sva) va_next = eva; pde = pmap_pdpe_to_pde(pdpe, sva); ptpaddr = *pde; /* * Weed out invalid mappings. */ if (ptpaddr == 0) continue; /* * Check for large page. */ if ((ptpaddr & PG_PS) != 0) { /* * Are we removing the entire large page? If not, * demote the mapping and fall through. */ if (sva + NBPDR == va_next && eva >= va_next) { /* * The TLB entry for a PG_G mapping is * invalidated by pmap_remove_pde(). */ if ((ptpaddr & PG_G) == 0) anyvalid = 1; pmap_remove_pde(pmap, pde, sva, &free, &lock); continue; } else if (!pmap_demote_pde_locked(pmap, pde, sva, &lock)) { /* The large page mapping was destroyed. */ continue; } else ptpaddr = *pde; } /* * Limit our scan to either the end of the va represented * by the current page table page, or to the end of the * range being removed. */ if (va_next > eva) va_next = eva; va = va_next; for (pte = pmap_pde_to_pte(pde, sva); sva != va_next; pte++, sva += PAGE_SIZE) { if (*pte == 0) { if (va != va_next) { pmap_invalidate_range(pmap, va, sva); va = va_next; } continue; } if ((*pte & PG_G) == 0) anyvalid = 1; else if (va == va_next) va = sva; if (pmap_remove_pte(pmap, pte, sva, ptpaddr, &free, &lock)) { sva += PAGE_SIZE; break; } } if (va != va_next) pmap_invalidate_range(pmap, va, sva); } if (lock != NULL) rw_wunlock(lock); out: if (anyvalid) pmap_invalidate_all(pmap); rw_runlock(&pvh_global_lock); PMAP_UNLOCK(pmap); pmap_free_zero_pages(&free); } /* * Routine: pmap_remove_all * Function: * Removes this physical page from * all physical maps in which it resides. * Reflects back modify bits to the pager. * * Notes: * Original versions of this routine were very * inefficient because they iteratively called * pmap_remove (slow...) */ void pmap_remove_all(vm_page_t m) { struct md_page *pvh; pv_entry_t pv; pmap_t pmap; pt_entry_t *pte, tpte, PG_A, PG_M, PG_RW; pd_entry_t *pde; vm_offset_t va; struct spglist free; KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_all: page %p is not managed", m)); SLIST_INIT(&free); rw_wlock(&pvh_global_lock); if ((m->flags & PG_FICTITIOUS) != 0) goto small_mappings; pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); while ((pv = TAILQ_FIRST(&pvh->pv_list)) != NULL) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); va = pv->pv_va; pde = pmap_pde(pmap, va); (void)pmap_demote_pde(pmap, pde, va); PMAP_UNLOCK(pmap); } small_mappings: while ((pv = TAILQ_FIRST(&m->md.pv_list)) != NULL) { pmap = PV_PMAP(pv); PMAP_LOCK(pmap); PG_A = pmap_accessed_bit(pmap); PG_M = pmap_modified_bit(pmap); PG_RW = pmap_rw_bit(pmap); pmap_resident_count_dec(pmap, 1); pde = pmap_pde(pmap, pv->pv_va); KASSERT((*pde & PG_PS) == 0, ("pmap_remove_all: found" " a 2mpage in page %p's pv list", m)); pte = pmap_pde_to_pte(pde, pv->pv_va); tpte = pte_load_clear(pte); if (tpte & PG_W) pmap->pm_stats.wired_count--; if (tpte & PG_A) vm_page_aflag_set(m, PGA_REFERENCED); /* * Update the vm_page_t clean and reference bits. */ if ((tpte & (PG_M | PG_RW)) == (PG_M | PG_RW)) vm_page_dirty(m); pmap_unuse_pt(pmap, pv->pv_va, *pde, &free); pmap_invalidate_page(pmap, pv->pv_va); TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); m->md.pv_gen++; free_pv_entry(pmap, pv); PMAP_UNLOCK(pmap); } vm_page_aflag_clear(m, PGA_WRITEABLE); rw_wunlock(&pvh_global_lock); pmap_free_zero_pages(&free); } /* * pmap_protect_pde: do the things to protect a 2mpage in a process */ static boolean_t pmap_protect_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t sva, vm_prot_t prot) { pd_entry_t newpde, oldpde; vm_offset_t eva, va; vm_page_t m; boolean_t anychanged; pt_entry_t PG_G, PG_M, PG_RW; PG_G = pmap_global_bit(pmap); PG_M = pmap_modified_bit(pmap); PG_RW = pmap_rw_bit(pmap); PMAP_LOCK_ASSERT(pmap, MA_OWNED); KASSERT((sva & PDRMASK) == 0, ("pmap_protect_pde: sva is not 2mpage aligned")); anychanged = FALSE; retry: oldpde = newpde = *pde; if (oldpde & PG_MANAGED) { eva = sva + NBPDR; for (va = sva, m = PHYS_TO_VM_PAGE(oldpde & PG_PS_FRAME); va < eva; va += PAGE_SIZE, m++) if ((oldpde & (PG_M | PG_RW)) == (PG_M | PG_RW)) vm_page_dirty(m); } if ((prot & VM_PROT_WRITE) == 0) newpde &= ~(PG_RW | PG_M); if ((prot & VM_PROT_EXECUTE) == 0) newpde |= pg_nx; if (newpde != oldpde) { if (!atomic_cmpset_long(pde, oldpde, newpde)) goto retry; if (oldpde & PG_G) pmap_invalidate_page(pmap, sva); else anychanged = TRUE; } return (anychanged); } /* * Set the physical protection on the * specified range of this map as requested. */ void pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot) { vm_offset_t va_next; pml4_entry_t *pml4e; pdp_entry_t *pdpe; pd_entry_t ptpaddr, *pde; pt_entry_t *pte, PG_G, PG_M, PG_RW, PG_V; boolean_t anychanged, pv_lists_locked; KASSERT((prot & ~VM_PROT_ALL) == 0, ("invalid prot %x", prot)); if (prot == VM_PROT_NONE) { pmap_remove(pmap, sva, eva); return; } if ((prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) == (VM_PROT_WRITE|VM_PROT_EXECUTE)) return; PG_G = pmap_global_bit(pmap); PG_M = pmap_modified_bit(pmap); PG_V = pmap_valid_bit(pmap); PG_RW = pmap_rw_bit(pmap); pv_lists_locked = FALSE; resume: anychanged = FALSE; PMAP_LOCK(pmap); for (; sva < eva; sva = va_next) { pml4e = pmap_pml4e(pmap, sva); if ((*pml4e & PG_V) == 0) { va_next = (sva + NBPML4) & ~PML4MASK; if (va_next < sva) va_next = eva; continue; } pdpe = pmap_pml4e_to_pdpe(pml4e, sva); if ((*pdpe & PG_V) == 0) { va_next = (sva + NBPDP) & ~PDPMASK; if (va_next < sva) va_next = eva; continue; } va_next = (sva + NBPDR) & ~PDRMASK; if (va_next < sva) va_next = eva; pde = pmap_pdpe_to_pde(pdpe, sva); ptpaddr = *pde; /* * Weed out invalid mappings. */ if (ptpaddr == 0) continue; /* * Check for large page. */ if ((ptpaddr & PG_PS) != 0) { /* * Are we protecting the entire large page? If not, * demote the mapping and fall through. */ if (sva + NBPDR == va_next && eva >= va_next) { /* * The TLB entry for a PG_G mapping is * invalidated by pmap_protect_pde(). */ if (pmap_protect_pde(pmap, pde, sva, prot)) anychanged = TRUE; continue; } else { if (!pv_lists_locked) { pv_lists_locked = TRUE; if (!rw_try_rlock(&pvh_global_lock)) { if (anychanged) pmap_invalidate_all( pmap); PMAP_UNLOCK(pmap); rw_rlock(&pvh_global_lock); goto resume; } } if (!pmap_demote_pde(pmap, pde, sva)) { /* * The large page mapping was * destroyed. */ continue; } } } if (va_next > eva) va_next = eva; for (pte = pmap_pde_to_pte(pde, sva); sva != va_next; pte++, sva += PAGE_SIZE) { pt_entry_t obits, pbits; vm_page_t m; retry: obits = pbits = *pte; if ((pbits & PG_V) == 0) continue; if ((prot & VM_PROT_WRITE) == 0) { if ((pbits & (PG_MANAGED | PG_M | PG_RW)) == (PG_MANAGED | PG_M | PG_RW)) { m = PHYS_TO_VM_PAGE(pbits & PG_FRAME); vm_page_dirty(m); } pbits &= ~(PG_RW | PG_M); } if ((prot & VM_PROT_EXECUTE) == 0) pbits |= pg_nx; if (pbits != obits) { if (!atomic_cmpset_long(pte, obits, pbits)) goto retry; if (obits & PG_G) pmap_invalidate_page(pmap, sva); else anychanged = TRUE; } } } if (anychanged) pmap_invalidate_all(pmap); if (pv_lists_locked) rw_runlock(&pvh_global_lock); PMAP_UNLOCK(pmap); } /* * Tries to promote the 512, contiguous 4KB page mappings that are within a * single page table page (PTP) to a single 2MB page mapping. For promotion * to occur, two conditions must be met: (1) the 4KB page mappings must map * aligned, contiguous physical memory and (2) the 4KB page mappings must have * identical characteristics. */ static void pmap_promote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va, struct rwlock **lockp) { pd_entry_t newpde; pt_entry_t *firstpte, oldpte, pa, *pte; pt_entry_t PG_G, PG_A, PG_M, PG_RW, PG_V; vm_offset_t oldpteva; vm_page_t mpte; int PG_PTE_CACHE; PG_A = pmap_accessed_bit(pmap); PG_G = pmap_global_bit(pmap); PG_M = pmap_modified_bit(pmap); PG_V = pmap_valid_bit(pmap); PG_RW = pmap_rw_bit(pmap); PG_PTE_CACHE = pmap_cache_mask(pmap, 0); PMAP_LOCK_ASSERT(pmap, MA_OWNED); /* * Examine the first PTE in the specified PTP. Abort if this PTE is * either invalid, unused, or does not map the first 4KB physical page * within a 2MB page. */ firstpte = (pt_entry_t *)PHYS_TO_DMAP(*pde & PG_FRAME); setpde: newpde = *firstpte; if ((newpde & ((PG_FRAME & PDRMASK) | PG_A | PG_V)) != (PG_A | PG_V)) { atomic_add_long(&pmap_pde_p_failures, 1); CTR2(KTR_PMAP, "pmap_promote_pde: failure for va %#lx" " in pmap %p", va, pmap); return; } if ((newpde & (PG_M | PG_RW)) == PG_RW) { /* * When PG_M is already clear, PG_RW can be cleared without * a TLB invalidation. */ if (!atomic_cmpset_long(firstpte, newpde, newpde & ~PG_RW)) goto setpde; newpde &= ~PG_RW; } /* * Examine each of the other PTEs in the specified PTP. Abort if this * PTE maps an unexpected 4KB physical page or does not have identical * characteristics to the first PTE. */ pa = (newpde & (PG_PS_FRAME | PG_A | PG_V)) + NBPDR - PAGE_SIZE; for (pte = firstpte + NPTEPG - 1; pte > firstpte; pte--) { setpte: oldpte = *pte; if ((oldpte & (PG_FRAME | PG_A | PG_V)) != pa) { atomic_add_long(&pmap_pde_p_failures, 1); CTR2(KTR_PMAP, "pmap_promote_pde: failure for va %#lx" " in pmap %p", va, pmap); return; } if ((oldpte & (PG_M | PG_RW)) == PG_RW) { /* * When PG_M is already clear, PG_RW can be cleared * without a TLB invalidation. */ if (!atomic_cmpset_long(pte, oldpte, oldpte & ~PG_RW)) goto setpte; oldpte &= ~PG_RW; oldpteva = (oldpte & PG_FRAME & PDRMASK) | (va & ~PDRMASK); CTR2(KTR_PMAP, "pmap_promote_pde: protect for va %#lx" " in pmap %p", oldpteva, pmap); } if ((oldpte & PG_PTE_PROMOTE) != (newpde & PG_PTE_PROMOTE)) { atomic_add_long(&pmap_pde_p_failures, 1); CTR2(KTR_PMAP, "pmap_promote_pde: failure for va %#lx" " in pmap %p", va, pmap); return; } pa -= PAGE_SIZE; } /* * Save the page table page in its current state until the PDE * mapping the superpage is demoted by pmap_demote_pde() or * destroyed by pmap_remove_pde(). */ mpte = PHYS_TO_VM_PAGE(*pde & PG_FRAME); KASSERT(mpte >= vm_page_array && mpte < &vm_page_array[vm_page_array_size], ("pmap_promote_pde: page table page is out of range")); KASSERT(mpte->pindex == pmap_pde_pindex(va), ("pmap_promote_pde: page table page's pindex is wrong")); if (pmap_insert_pt_page(pmap, mpte)) { atomic_add_long(&pmap_pde_p_failures, 1); CTR2(KTR_PMAP, "pmap_promote_pde: failure for va %#lx in pmap %p", va, pmap); return; } /* * Promote the pv entries. */ if ((newpde & PG_MANAGED) != 0) pmap_pv_promote_pde(pmap, va, newpde & PG_PS_FRAME, lockp); /* * Propagate the PAT index to its proper position. */ newpde = pmap_swap_pat(pmap, newpde); /* * Map the superpage. */ if (workaround_erratum383) pmap_update_pde(pmap, va, pde, PG_PS | newpde); else pde_store(pde, PG_PS | newpde); atomic_add_long(&pmap_pde_promotions, 1); CTR2(KTR_PMAP, "pmap_promote_pde: success for va %#lx" " in pmap %p", va, pmap); } /* * Insert the given physical page (p) at * the specified virtual address (v) in the * target physical map with the protection requested. * * If specified, the page will be wired down, meaning * that the related pte can not be reclaimed. * * NB: This is the only routine which MAY NOT lazy-evaluate * or lose information. That is, this routine must actually * insert this page into the given map NOW. */ int pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, u_int flags, int8_t psind __unused) { struct rwlock *lock; pd_entry_t *pde; pt_entry_t *pte, PG_G, PG_A, PG_M, PG_RW, PG_V; pt_entry_t newpte, origpte; pv_entry_t pv; vm_paddr_t opa, pa; vm_page_t mpte, om; boolean_t nosleep; PG_A = pmap_accessed_bit(pmap); PG_G = pmap_global_bit(pmap); PG_M = pmap_modified_bit(pmap); PG_V = pmap_valid_bit(pmap); PG_RW = pmap_rw_bit(pmap); va = trunc_page(va); KASSERT(va <= VM_MAX_KERNEL_ADDRESS, ("pmap_enter: toobig")); KASSERT(va < UPT_MIN_ADDRESS || va >= UPT_MAX_ADDRESS, ("pmap_enter: invalid to pmap_enter page table pages (va: 0x%lx)", va)); KASSERT((m->oflags & VPO_UNMANAGED) != 0 || va < kmi.clean_sva || va >= kmi.clean_eva, ("pmap_enter: managed mapping within the clean submap")); if ((m->oflags & VPO_UNMANAGED) == 0 && !vm_page_xbusied(m)) VM_OBJECT_ASSERT_LOCKED(m->object); pa = VM_PAGE_TO_PHYS(m); newpte = (pt_entry_t)(pa | PG_A | PG_V); if ((flags & VM_PROT_WRITE) != 0) newpte |= PG_M; if ((prot & VM_PROT_WRITE) != 0) newpte |= PG_RW; KASSERT((newpte & (PG_M | PG_RW)) != PG_M, ("pmap_enter: flags includes VM_PROT_WRITE but prot doesn't")); if ((prot & VM_PROT_EXECUTE) == 0) newpte |= pg_nx; if ((flags & PMAP_ENTER_WIRED) != 0) newpte |= PG_W; if (va < VM_MAXUSER_ADDRESS) newpte |= PG_U; if (pmap == kernel_pmap) newpte |= PG_G; newpte |= pmap_cache_bits(pmap, m->md.pat_mode, 0); /* * Set modified bit gratuitously for writeable mappings if * the page is unmanaged. We do not want to take a fault * to do the dirty bit accounting for these mappings. */ if ((m->oflags & VPO_UNMANAGED) != 0) { if ((newpte & PG_RW) != 0) newpte |= PG_M; } mpte = NULL; lock = NULL; rw_rlock(&pvh_global_lock); PMAP_LOCK(pmap); /* * In the case that a page table page is not * resident, we are creating it here. */ retry: pde = pmap_pde(pmap, va); if (pde != NULL && (*pde & PG_V) != 0 && ((*pde & PG_PS) == 0 || pmap_demote_pde_locked(pmap, pde, va, &lock))) { pte = pmap_pde_to_pte(pde, va); if (va < VM_MAXUSER_ADDRESS && mpte == NULL) { mpte = PHYS_TO_VM_PAGE(*pde & PG_FRAME); mpte->wire_count++; } } else if (va < VM_MAXUSER_ADDRESS) { /* * Here if the pte page isn't mapped, or if it has been * deallocated. */ nosleep = (flags & PMAP_ENTER_NOSLEEP) != 0; mpte = _pmap_allocpte(pmap, pmap_pde_pindex(va), nosleep ? NULL : &lock); if (mpte == NULL && nosleep) { if (lock != NULL) rw_wunlock(lock); rw_runlock(&pvh_global_lock); PMAP_UNLOCK(pmap); return (KERN_RESOURCE_SHORTAGE); } goto retry; } else panic("pmap_enter: invalid page directory va=%#lx", va); origpte = *pte; /* * Is the specified virtual address already mapped? */ if ((origpte & PG_V) != 0) { /* * Wiring change, just update stats. We don't worry about * wiring PT pages as they remain resident as long as there * are valid mappings in them. Hence, if a user page is wired, * the PT page will be also. */ if ((newpte & PG_W) != 0 && (origpte & PG_W) == 0) pmap->pm_stats.wired_count++; else if ((newpte & PG_W) == 0 && (origpte & PG_W) != 0) pmap->pm_stats.wired_count--; /* * Remove the extra PT page reference. */ if (mpte != NULL) { mpte->wire_count--; KASSERT(mpte->wire_count > 0, ("pmap_enter: missing reference to page table page," " va: 0x%lx", va)); } /* * Has the physical page changed? */ opa = origpte & PG_FRAME; if (opa == pa) { /* * No, might be a protection or wiring change. */ if ((origpte & PG_MANAGED) != 0) { newpte |= PG_MANAGED; if ((newpte & PG_RW) != 0) vm_page_aflag_set(m, PGA_WRITEABLE); } if (((origpte ^ newpte) & ~(PG_M | PG_A)) == 0) goto unchanged; goto validate; } } else { /* * Increment the counters. */ if ((newpte & PG_W) != 0) pmap->pm_stats.wired_count++; pmap_resident_count_inc(pmap, 1); } /* * Enter on the PV list if part of our managed memory. */ if ((m->oflags & VPO_UNMANAGED) == 0) { newpte |= PG_MANAGED; pv = get_pv_entry(pmap, &lock); pv->pv_va = va; CHANGE_PV_LIST_LOCK_TO_PHYS(&lock, pa); TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); m->md.pv_gen++; if ((newpte & PG_RW) != 0) vm_page_aflag_set(m, PGA_WRITEABLE); } /* * Update the PTE. */ if ((origpte & PG_V) != 0) { validate: origpte = pte_load_store(pte, newpte); opa = origpte & PG_FRAME; if (opa != pa) { if ((origpte & PG_MANAGED) != 0) { om = PHYS_TO_VM_PAGE(opa); if ((origpte & (PG_M | PG_RW)) == (PG_M | PG_RW)) vm_page_dirty(om); if ((origpte & PG_A) != 0) vm_page_aflag_set(om, PGA_REFERENCED); CHANGE_PV_LIST_LOCK_TO_PHYS(&lock, opa); pmap_pvh_free(&om->md, pmap, va); if ((om->aflags & PGA_WRITEABLE) != 0 && TAILQ_EMPTY(&om->md.pv_list) && ((om->flags & PG_FICTITIOUS) != 0 || TAILQ_EMPTY(&pa_to_pvh(opa)->pv_list))) vm_page_aflag_clear(om, PGA_WRITEABLE); } } else if ((newpte & PG_M) == 0 && (origpte & (PG_M | PG_RW)) == (PG_M | PG_RW)) { if ((origpte & PG_MANAGED) != 0) vm_page_dirty(m); /* * Although the PTE may still have PG_RW set, TLB * invalidation may nonetheless be required because * the PTE no longer has PG_M set. */ } else if ((origpte & PG_NX) != 0 || (newpte & PG_NX) == 0) { /* * This PTE change does not require TLB invalidation. */ goto unchanged; } if ((origpte & PG_A) != 0) pmap_invalidate_page(pmap, va); } else pte_store(pte, newpte); unchanged: /* * If both the page table page and the reservation are fully * populated, then attempt promotion. */ if ((mpte == NULL || mpte->wire_count == NPTEPG) && pmap_ps_enabled(pmap) && (m->flags & PG_FICTITIOUS) == 0 && vm_reserv_level_iffullpop(m) == 0) pmap_promote_pde(pmap, pde, va, &lock); if (lock != NULL) rw_wunlock(lock); rw_runlock(&pvh_global_lock); PMAP_UNLOCK(pmap); return (KERN_SUCCESS); } /* * Tries to create a 2MB page mapping. Returns TRUE if successful and FALSE * otherwise. Fails if (1) a page table page cannot be allocated without * blocking, (2) a mapping already exists at the specified virtual address, or * (3) a pv entry cannot be allocated without reclaiming another pv entry. */ static boolean_t pmap_enter_pde(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, struct rwlock **lockp) { pd_entry_t *pde, newpde; pt_entry_t PG_V; vm_page_t mpde; struct spglist free; PG_V = pmap_valid_bit(pmap); rw_assert(&pvh_global_lock, RA_LOCKED); PMAP_LOCK_ASSERT(pmap, MA_OWNED); if ((mpde = pmap_allocpde(pmap, va, NULL)) == NULL) { CTR2(KTR_PMAP, "pmap_enter_pde: failure for va %#lx" " in pmap %p", va, pmap); return (FALSE); } pde = (pd_entry_t *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(mpde)); pde = &pde[pmap_pde_index(va)]; if ((*pde & PG_V) != 0) { KASSERT(mpde->wire_count > 1, ("pmap_enter_pde: mpde's wire count is too low")); mpde->wire_count--; CTR2(KTR_PMAP, "pmap_enter_pde: failure for va %#lx" " in pmap %p", va, pmap); return (FALSE); } newpde = VM_PAGE_TO_PHYS(m) | pmap_cache_bits(pmap, m->md.pat_mode, 1) | PG_PS | PG_V; if ((m->oflags & VPO_UNMANAGED) == 0) { newpde |= PG_MANAGED; /* * Abort this mapping if its PV entry could not be created. */ if (!pmap_pv_insert_pde(pmap, va, VM_PAGE_TO_PHYS(m), lockp)) { SLIST_INIT(&free); if (pmap_unwire_ptp(pmap, va, mpde, &free)) { pmap_invalidate_page(pmap, va); pmap_free_zero_pages(&free); } CTR2(KTR_PMAP, "pmap_enter_pde: failure for va %#lx" " in pmap %p", va, pmap); return (FALSE); } } if ((prot & VM_PROT_EXECUTE) == 0) newpde |= pg_nx; if (va < VM_MAXUSER_ADDRESS) newpde |= PG_U; /* * Increment counters. */ pmap_resident_count_inc(pmap, NBPDR / PAGE_SIZE); /* * Map the superpage. */ pde_store(pde, newpde); atomic_add_long(&pmap_pde_mappings, 1); CTR2(KTR_PMAP, "pmap_enter_pde: success for va %#lx" " in pmap %p", va, pmap); return (TRUE); } /* * Maps a sequence of resident pages belonging to the same object. * The sequence begins with the given page m_start. This page is * mapped at the given virtual address start. Each subsequent page is * mapped at a virtual address that is offset from start by the same * amount as the page is offset from m_start within the object. The * last page in the sequence is the page with the largest offset from * m_start that can be mapped at a virtual address less than the given * virtual address end. Not every virtual page between start and end * is mapped; only those for which a resident page exists with the * corresponding offset from m_start are mapped. */ void pmap_enter_object(pmap_t pmap, vm_offset_t start, vm_offset_t end, vm_page_t m_start, vm_prot_t prot) { struct rwlock *lock; vm_offset_t va; vm_page_t m, mpte; vm_pindex_t diff, psize; VM_OBJECT_ASSERT_LOCKED(m_start->object); psize = atop(end - start); mpte = NULL; m = m_start; lock = NULL; rw_rlock(&pvh_global_lock); PMAP_LOCK(pmap); while (m != NULL && (diff = m->pindex - m_start->pindex) < psize) { va = start + ptoa(diff); if ((va & PDRMASK) == 0 && va + NBPDR <= end && m->psind == 1 && pmap_ps_enabled(pmap) && pmap_enter_pde(pmap, va, m, prot, &lock)) m = &m[NBPDR / PAGE_SIZE - 1]; else mpte = pmap_enter_quick_locked(pmap, va, m, prot, mpte, &lock); m = TAILQ_NEXT(m, listq); } if (lock != NULL) rw_wunlock(lock); rw_runlock(&pvh_global_lock); PMAP_UNLOCK(pmap); } /* * this code makes some *MAJOR* assumptions: * 1. Current pmap & pmap exists. * 2. Not wired. * 3. Read access. * 4. No page table pages. * but is *MUCH* faster than pmap_enter... */ void pmap_enter_quick(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot) { struct rwlock *lock; lock = NULL; rw_rlock(&pvh_global_lock); PMAP_LOCK(pmap); (void)pmap_enter_quick_locked(pmap, va, m, prot, NULL, &lock); if (lock != NULL) rw_wunlock(lock); rw_runlock(&pvh_global_lock); PMAP_UNLOCK(pmap); } static vm_page_t pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, vm_page_t mpte, struct rwlock **lockp) { struct spglist free; pt_entry_t *pte, PG_V; vm_paddr_t pa; KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva || (m->oflags & VPO_UNMANAGED) != 0, ("pmap_enter_quick_locked: managed mapping within the clean submap")); PG_V = pmap_valid_bit(pmap); rw_assert(&pvh_global_lock, RA_LOCKED); PMAP_LOCK_ASSERT(pmap, MA_OWNED); /* * In the case that a page table page is not * resident, we are creating it here. */ if (va < VM_MAXUSER_ADDRESS) { vm_pindex_t ptepindex; pd_entry_t *ptepa; /* * Calculate pagetable page index */ ptepindex = pmap_pde_pindex(va); if (mpte && (mpte->pindex == ptepindex)) { mpte->wire_count++; } else { /* * Get the page directory entry */ ptepa = pmap_pde(pmap, va); /* * If the page table page is mapped, we just increment * the hold count, and activate it. Otherwise, we * attempt to allocate a page table page. If this * attempt fails, we don't retry. Instead, we give up. */ if (ptepa && (*ptepa & PG_V) != 0) { if (*ptepa & PG_PS) return (NULL); mpte = PHYS_TO_VM_PAGE(*ptepa & PG_FRAME); mpte->wire_count++; } else { /* * Pass NULL instead of the PV list lock * pointer, because we don't intend to sleep. */ mpte = _pmap_allocpte(pmap, ptepindex, NULL); if (mpte == NULL) return (mpte); } } pte = (pt_entry_t *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(mpte)); pte = &pte[pmap_pte_index(va)]; } else { mpte = NULL; pte = vtopte(va); } if (*pte) { if (mpte != NULL) { mpte->wire_count--; mpte = NULL; } return (mpte); } /* * Enter on the PV list if part of our managed memory. */ if ((m->oflags & VPO_UNMANAGED) == 0 && !pmap_try_insert_pv_entry(pmap, va, m, lockp)) { if (mpte != NULL) { SLIST_INIT(&free); if (pmap_unwire_ptp(pmap, va, mpte, &free)) { pmap_invalidate_page(pmap, va); pmap_free_zero_pages(&free); } mpte = NULL; } return (mpte); } /* * Increment counters */ pmap_resident_count_inc(pmap, 1); pa = VM_PAGE_TO_PHYS(m) | pmap_cache_bits(pmap, m->md.pat_mode, 0); if ((prot & VM_PROT_EXECUTE) == 0) pa |= pg_nx; /* * Now validate mapping with RO protection */ if ((m->oflags & VPO_UNMANAGED) != 0) pte_store(pte, pa | PG_V | PG_U); else pte_store(pte, pa | PG_V | PG_U | PG_MANAGED); return (mpte); } /* * Make a temporary mapping for a physical address. This is only intended * to be used for panic dumps. */ void * pmap_kenter_temporary(vm_paddr_t pa, int i) { vm_offset_t va; va = (vm_offset_t)crashdumpmap + (i * PAGE_SIZE); pmap_kenter(va, pa); invlpg(va); return ((void *)crashdumpmap); } /* * This code maps large physical mmap regions into the * processor address space. Note that some shortcuts * are taken, but the code works. */ void pmap_object_init_pt(pmap_t pmap, vm_offset_t addr, vm_object_t object, vm_pindex_t pindex, vm_size_t size) { pd_entry_t *pde; pt_entry_t PG_A, PG_M, PG_RW, PG_V; vm_paddr_t pa, ptepa; vm_page_t p, pdpg; int pat_mode; PG_A = pmap_accessed_bit(pmap); PG_M = pmap_modified_bit(pmap); PG_V = pmap_valid_bit(pmap); PG_RW = pmap_rw_bit(pmap); VM_OBJECT_ASSERT_WLOCKED(object); KASSERT(object->type == OBJT_DEVICE || object->type == OBJT_SG, ("pmap_object_init_pt: non-device object")); if ((addr & (NBPDR - 1)) == 0 && (size & (NBPDR - 1)) == 0) { if (!pmap_ps_enabled(pmap)) return; if (!vm_object_populate(object, pindex, pindex + atop(size))) return; p = vm_page_lookup(object, pindex); KASSERT(p->valid == VM_PAGE_BITS_ALL, ("pmap_object_init_pt: invalid page %p", p)); pat_mode = p->md.pat_mode; /* * Abort the mapping if the first page is not physically * aligned to a 2MB page boundary. */ ptepa = VM_PAGE_TO_PHYS(p); if (ptepa & (NBPDR - 1)) return; /* * Skip the first page. Abort the mapping if the rest of * the pages are not physically contiguous or have differing * memory attributes. */ p = TAILQ_NEXT(p, listq); for (pa = ptepa + PAGE_SIZE; pa < ptepa + size; pa += PAGE_SIZE) { KASSERT(p->valid == VM_PAGE_BITS_ALL, ("pmap_object_init_pt: invalid page %p", p)); if (pa != VM_PAGE_TO_PHYS(p) || pat_mode != p->md.pat_mode) return; p = TAILQ_NEXT(p, listq); } /* * Map using 2MB pages. Since "ptepa" is 2M aligned and * "size" is a multiple of 2M, adding the PAT setting to "pa" * will not affect the termination of this loop. */ PMAP_LOCK(pmap); for (pa = ptepa | pmap_cache_bits(pmap, pat_mode, 1); pa < ptepa + size; pa += NBPDR) { pdpg = pmap_allocpde(pmap, addr, NULL); if (pdpg == NULL) { /* * The creation of mappings below is only an * optimization. If a page directory page * cannot be allocated without blocking, * continue on to the next mapping rather than * blocking. */ addr += NBPDR; continue; } pde = (pd_entry_t *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(pdpg)); pde = &pde[pmap_pde_index(addr)]; if ((*pde & PG_V) == 0) { pde_store(pde, pa | PG_PS | PG_M | PG_A | PG_U | PG_RW | PG_V); pmap_resident_count_inc(pmap, NBPDR / PAGE_SIZE); atomic_add_long(&pmap_pde_mappings, 1); } else { /* Continue on if the PDE is already valid. */ pdpg->wire_count--; KASSERT(pdpg->wire_count > 0, ("pmap_object_init_pt: missing reference " "to page directory page, va: 0x%lx", addr)); } addr += NBPDR; } PMAP_UNLOCK(pmap); } } /* * Clear the wired attribute from the mappings for the specified range of * addresses in the given pmap. Every valid mapping within that range * must have the wired attribute set. In contrast, invalid mappings * cannot have the wired attribute set, so they are ignored. * * The wired attribute of the page table entry is not a hardware feature, * so there is no need to invalidate any TLB entries. */ void pmap_unwire(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) { vm_offset_t va_next; pml4_entry_t *pml4e; pdp_entry_t *pdpe; pd_entry_t *pde; pt_entry_t *pte, PG_V; boolean_t pv_lists_locked; PG_V = pmap_valid_bit(pmap); pv_lists_locked = FALSE; resume: PMAP_LOCK(pmap); for (; sva < eva; sva = va_next) { pml4e = pmap_pml4e(pmap, sva); if ((*pml4e & PG_V) == 0) { va_next = (sva + NBPML4) & ~PML4MASK; if (va_next < sva) va_next = eva; continue; } pdpe = pmap_pml4e_to_pdpe(pml4e, sva); if ((*pdpe & PG_V) == 0) { va_next = (sva + NBPDP) & ~PDPMASK; if (va_next < sva) va_next = eva; continue; } va_next = (sva + NBPDR) & ~PDRMASK; if (va_next < sva) va_next = eva; pde = pmap_pdpe_to_pde(pdpe, sva); if ((*pde & PG_V) == 0) continue; if ((*pde & PG_PS) != 0) { if ((*pde & PG_W) == 0) panic("pmap_unwire: pde %#jx is missing PG_W", (uintmax_t)*pde); /* * Are we unwiring the entire large page? If not, * demote the mapping and fall through. */ if (sva + NBPDR == va_next && eva >= va_next) { atomic_clear_long(pde, PG_W); pmap->pm_stats.wired_count -= NBPDR / PAGE_SIZE; continue; } else { if (!pv_lists_locked) { pv_lists_locked = TRUE; if (!rw_try_rlock(&pvh_global_lock)) { PMAP_UNLOCK(pmap); rw_rlock(&pvh_global_lock); /* Repeat sva. */ goto resume; } } if (!pmap_demote_pde(pmap, pde, sva)) panic("pmap_unwire: demotion failed"); } } if (va_next > eva) va_next = eva; for (pte = pmap_pde_to_pte(pde, sva); sva != va_next; pte++, sva += PAGE_SIZE) { if ((*pte & PG_V) == 0) continue; if ((*pte & PG_W) == 0) panic("pmap_unwire: pte %#jx is missing PG_W", (uintmax_t)*pte); /* * PG_W must be cleared atomically. Although the pmap * lock synchronizes access to PG_W, another processor * could be setting PG_M and/or PG_A concurrently. */ atomic_clear_long(pte, PG_W); pmap->pm_stats.wired_count--; } } if (pv_lists_locked) rw_runlock(&pvh_global_lock); PMAP_UNLOCK(pmap); } /* * Copy the range specified by src_addr/len * from the source map to the range dst_addr/len * in the destination map. * * This routine is only advisory and need not do anything. */ void pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len, vm_offset_t src_addr) { struct rwlock *lock; struct spglist free; vm_offset_t addr; vm_offset_t end_addr = src_addr + len; vm_offset_t va_next; pt_entry_t PG_A, PG_M, PG_V; if (dst_addr != src_addr) return; if (dst_pmap->pm_type != src_pmap->pm_type) return; /* * EPT page table entries that require emulation of A/D bits are * sensitive to clearing the PG_A bit (aka EPT_PG_READ). Although * we clear PG_M (aka EPT_PG_WRITE) concomitantly, the PG_U bit * (aka EPT_PG_EXECUTE) could still be set. Since some EPT * implementations flag an EPT misconfiguration for exec-only * mappings we skip this function entirely for emulated pmaps. */ if (pmap_emulate_ad_bits(dst_pmap)) return; lock = NULL; rw_rlock(&pvh_global_lock); if (dst_pmap < src_pmap) { PMAP_LOCK(dst_pmap); PMAP_LOCK(src_pmap); } else { PMAP_LOCK(src_pmap); PMAP_LOCK(dst_pmap); } PG_A = pmap_accessed_bit(dst_pmap); PG_M = pmap_modified_bit(dst_pmap); PG_V = pmap_valid_bit(dst_pmap); for (addr = src_addr; addr < end_addr; addr = va_next) { pt_entry_t *src_pte, *dst_pte; vm_page_t dstmpde, dstmpte, srcmpte; pml4_entry_t *pml4e; pdp_entry_t *pdpe; pd_entry_t srcptepaddr, *pde; KASSERT(addr < UPT_MIN_ADDRESS, ("pmap_copy: invalid to pmap_copy page tables")); pml4e = pmap_pml4e(src_pmap, addr); if ((*pml4e & PG_V) == 0) { va_next = (addr + NBPML4) & ~PML4MASK; if (va_next < addr) va_next = end_addr; continue; } pdpe = pmap_pml4e_to_pdpe(pml4e, addr); if ((*pdpe & PG_V) == 0) { va_next = (addr + NBPDP) & ~PDPMASK; if (va_next < addr) va_next = end_addr; continue; } va_next = (addr + NBPDR) & ~PDRMASK; if (va_next < addr) va_next = end_addr; pde = pmap_pdpe_to_pde(pdpe, addr); srcptepaddr = *pde; if (srcptepaddr == 0) continue; if (srcptepaddr & PG_PS) { if ((addr & PDRMASK) != 0 || addr + NBPDR > end_addr) continue; dstmpde = pmap_allocpde(dst_pmap, addr, NULL); if (dstmpde == NULL) break; pde = (pd_entry_t *) PHYS_TO_DMAP(VM_PAGE_TO_PHYS(dstmpde)); pde = &pde[pmap_pde_index(addr)]; if (*pde == 0 && ((srcptepaddr & PG_MANAGED) == 0 || pmap_pv_insert_pde(dst_pmap, addr, srcptepaddr & PG_PS_FRAME, &lock))) { *pde = srcptepaddr & ~PG_W; pmap_resident_count_inc(dst_pmap, NBPDR / PAGE_SIZE); } else dstmpde->wire_count--; continue; } srcptepaddr &= PG_FRAME; srcmpte = PHYS_TO_VM_PAGE(srcptepaddr); KASSERT(srcmpte->wire_count > 0, ("pmap_copy: source page table page is unused")); if (va_next > end_addr) va_next = end_addr; src_pte = (pt_entry_t *)PHYS_TO_DMAP(srcptepaddr); src_pte = &src_pte[pmap_pte_index(addr)]; dstmpte = NULL; while (addr < va_next) { pt_entry_t ptetemp; ptetemp = *src_pte; /* * we only virtual copy managed pages */ if ((ptetemp & PG_MANAGED) != 0) { if (dstmpte != NULL && dstmpte->pindex == pmap_pde_pindex(addr)) dstmpte->wire_count++; else if ((dstmpte = pmap_allocpte(dst_pmap, addr, NULL)) == NULL) goto out; dst_pte = (pt_entry_t *) PHYS_TO_DMAP(VM_PAGE_TO_PHYS(dstmpte)); dst_pte = &dst_pte[pmap_pte_index(addr)]; if (*dst_pte == 0 && pmap_try_insert_pv_entry(dst_pmap, addr, PHYS_TO_VM_PAGE(ptetemp & PG_FRAME), &lock)) { /* * Clear the wired, modified, and * accessed (referenced) bits * during the copy. */ *dst_pte = ptetemp & ~(PG_W | PG_M | PG_A); pmap_resident_count_inc(dst_pmap, 1); } else { SLIST_INIT(&free); if (pmap_unwire_ptp(dst_pmap, addr, dstmpte, &free)) { pmap_invalidate_page(dst_pmap, addr); pmap_free_zero_pages(&free); } goto out; } if (dstmpte->wire_count >= srcmpte->wire_count) break; } addr += PAGE_SIZE; src_pte++; } } out: if (lock != NULL) rw_wunlock(lock); rw_runlock(&pvh_global_lock); PMAP_UNLOCK(src_pmap); PMAP_UNLOCK(dst_pmap); } /* * pmap_zero_page zeros the specified hardware page by mapping * the page into KVM and using bzero to clear its contents. */ void pmap_zero_page(vm_page_t m) { vm_offset_t va = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)); pagezero((void *)va); } /* * pmap_zero_page_area zeros the specified hardware page by mapping * the page into KVM and using bzero to clear its contents. * * off and size may not cover an area beyond a single hardware page. */ void pmap_zero_page_area(vm_page_t m, int off, int size) { vm_offset_t va = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)); if (off == 0 && size == PAGE_SIZE) pagezero((void *)va); else bzero((char *)va + off, size); } /* * pmap_zero_page_idle zeros the specified hardware page by mapping * the page into KVM and using bzero to clear its contents. This * is intended to be called from the vm_pagezero process only and * outside of Giant. */ void pmap_zero_page_idle(vm_page_t m) { vm_offset_t va = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)); pagezero((void *)va); } /* * pmap_copy_page copies the specified (machine independent) * page by mapping the page into virtual memory and using * bcopy to copy the page, one machine dependent page at a * time. */ void pmap_copy_page(vm_page_t msrc, vm_page_t mdst) { vm_offset_t src = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(msrc)); vm_offset_t dst = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(mdst)); pagecopy((void *)src, (void *)dst); } int unmapped_buf_allowed = 1; void pmap_copy_pages(vm_page_t ma[], vm_offset_t a_offset, vm_page_t mb[], vm_offset_t b_offset, int xfersize) { void *a_cp, *b_cp; vm_page_t pages[2]; vm_offset_t vaddr[2], a_pg_offset, b_pg_offset; int cnt; boolean_t mapped; while (xfersize > 0) { a_pg_offset = a_offset & PAGE_MASK; pages[0] = ma[a_offset >> PAGE_SHIFT]; b_pg_offset = b_offset & PAGE_MASK; pages[1] = mb[b_offset >> PAGE_SHIFT]; cnt = min(xfersize, PAGE_SIZE - a_pg_offset); cnt = min(cnt, PAGE_SIZE - b_pg_offset); mapped = pmap_map_io_transient(pages, vaddr, 2, FALSE); a_cp = (char *)vaddr[0] + a_pg_offset; b_cp = (char *)vaddr[1] + b_pg_offset; bcopy(a_cp, b_cp, cnt); if (__predict_false(mapped)) pmap_unmap_io_transient(pages, vaddr, 2, FALSE); a_offset += cnt; b_offset += cnt; xfersize -= cnt; } } /* * Returns true if the pmap's pv is one of the first * 16 pvs linked to from this page. This count may * be changed upwards or downwards in the future; it * is only necessary that true be returned for a small * subset of pmaps for proper page aging. */ boolean_t pmap_page_exists_quick(pmap_t pmap, vm_page_t m) { struct md_page *pvh; struct rwlock *lock; pv_entry_t pv; int loops = 0; boolean_t rv; KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_page_exists_quick: page %p is not managed", m)); rv = FALSE; rw_rlock(&pvh_global_lock); lock = VM_PAGE_TO_PV_LIST_LOCK(m); rw_rlock(lock); TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { if (PV_PMAP(pv) == pmap) { rv = TRUE; break; } loops++; if (loops >= 16) break; } if (!rv && loops < 16 && (m->flags & PG_FICTITIOUS) == 0) { pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) { if (PV_PMAP(pv) == pmap) { rv = TRUE; break; } loops++; if (loops >= 16) break; } } rw_runlock(lock); rw_runlock(&pvh_global_lock); return (rv); } /* * pmap_page_wired_mappings: * * Return the number of managed mappings to the given physical page * that are wired. */ int pmap_page_wired_mappings(vm_page_t m) { struct rwlock *lock; struct md_page *pvh; pmap_t pmap; pt_entry_t *pte; pv_entry_t pv; int count, md_gen, pvh_gen; if ((m->oflags & VPO_UNMANAGED) != 0) return (0); rw_rlock(&pvh_global_lock); lock = VM_PAGE_TO_PV_LIST_LOCK(m); rw_rlock(lock); restart: count = 0; TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { pmap = PV_PMAP(pv); if (!PMAP_TRYLOCK(pmap)) { md_gen = m->md.pv_gen; rw_runlock(lock); PMAP_LOCK(pmap); rw_rlock(lock); if (md_gen != m->md.pv_gen) { PMAP_UNLOCK(pmap); goto restart; } } pte = pmap_pte(pmap, pv->pv_va); if ((*pte & PG_W) != 0) count++; PMAP_UNLOCK(pmap); } if ((m->flags & PG_FICTITIOUS) == 0) { pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) { pmap = PV_PMAP(pv); if (!PMAP_TRYLOCK(pmap)) { md_gen = m->md.pv_gen; pvh_gen = pvh->pv_gen; rw_runlock(lock); PMAP_LOCK(pmap); rw_rlock(lock); if (md_gen != m->md.pv_gen || pvh_gen != pvh->pv_gen) { PMAP_UNLOCK(pmap); goto restart; } } pte = pmap_pde(pmap, pv->pv_va); if ((*pte & PG_W) != 0) count++; PMAP_UNLOCK(pmap); } } rw_runlock(lock); rw_runlock(&pvh_global_lock); return (count); } /* * Returns TRUE if the given page is mapped individually or as part of * a 2mpage. Otherwise, returns FALSE. */ boolean_t pmap_page_is_mapped(vm_page_t m) { struct rwlock *lock; boolean_t rv; if ((m->oflags & VPO_UNMANAGED) != 0) return (FALSE); rw_rlock(&pvh_global_lock); lock = VM_PAGE_TO_PV_LIST_LOCK(m); rw_rlock(lock); rv = !TAILQ_EMPTY(&m->md.pv_list) || ((m->flags & PG_FICTITIOUS) == 0 && !TAILQ_EMPTY(&pa_to_pvh(VM_PAGE_TO_PHYS(m))->pv_list)); rw_runlock(lock); rw_runlock(&pvh_global_lock); return (rv); } /* * Destroy all managed, non-wired mappings in the given user-space * pmap. This pmap cannot be active on any processor besides the * caller. * * This function cannot be applied to the kernel pmap. Moreover, it * is not intended for general use. It is only to be used during * process termination. Consequently, it can be implemented in ways * that make it faster than pmap_remove(). First, it can more quickly * destroy mappings by iterating over the pmap's collection of PV * entries, rather than searching the page table. Second, it doesn't * have to test and clear the page table entries atomically, because * no processor is currently accessing the user address space. In * particular, a page table entry's dirty bit won't change state once * this function starts. */ void pmap_remove_pages(pmap_t pmap) { pd_entry_t ptepde; pt_entry_t *pte, tpte; pt_entry_t PG_M, PG_RW, PG_V; struct spglist free; vm_page_t m, mpte, mt; pv_entry_t pv; struct md_page *pvh; struct pv_chunk *pc, *npc; struct rwlock *lock; int64_t bit; uint64_t inuse, bitmask; int allfree, field, freed, idx; boolean_t superpage; vm_paddr_t pa; /* * Assert that the given pmap is only active on the current * CPU. Unfortunately, we cannot block another CPU from * activating the pmap while this function is executing. */ KASSERT(pmap == PCPU_GET(curpmap), ("non-current pmap %p", pmap)); #ifdef INVARIANTS { cpuset_t other_cpus; other_cpus = all_cpus; critical_enter(); CPU_CLR(PCPU_GET(cpuid), &other_cpus); CPU_AND(&other_cpus, &pmap->pm_active); critical_exit(); KASSERT(CPU_EMPTY(&other_cpus), ("pmap active %p", pmap)); } #endif lock = NULL; PG_M = pmap_modified_bit(pmap); PG_V = pmap_valid_bit(pmap); PG_RW = pmap_rw_bit(pmap); SLIST_INIT(&free); rw_rlock(&pvh_global_lock); PMAP_LOCK(pmap); TAILQ_FOREACH_SAFE(pc, &pmap->pm_pvchunk, pc_list, npc) { allfree = 1; freed = 0; for (field = 0; field < _NPCM; field++) { inuse = ~pc->pc_map[field] & pc_freemask[field]; while (inuse != 0) { bit = bsfq(inuse); bitmask = 1UL << bit; idx = field * 64 + bit; pv = &pc->pc_pventry[idx]; inuse &= ~bitmask; pte = pmap_pdpe(pmap, pv->pv_va); ptepde = *pte; pte = pmap_pdpe_to_pde(pte, pv->pv_va); tpte = *pte; if ((tpte & (PG_PS | PG_V)) == PG_V) { superpage = FALSE; ptepde = tpte; pte = (pt_entry_t *)PHYS_TO_DMAP(tpte & PG_FRAME); pte = &pte[pmap_pte_index(pv->pv_va)]; tpte = *pte; } else { /* * Keep track whether 'tpte' is a * superpage explicitly instead of * relying on PG_PS being set. * * This is because PG_PS is numerically * identical to PG_PTE_PAT and thus a * regular page could be mistaken for * a superpage. */ superpage = TRUE; } if ((tpte & PG_V) == 0) { panic("bad pte va %lx pte %lx", pv->pv_va, tpte); } /* * We cannot remove wired pages from a process' mapping at this time */ if (tpte & PG_W) { allfree = 0; continue; } if (superpage) pa = tpte & PG_PS_FRAME; else pa = tpte & PG_FRAME; m = PHYS_TO_VM_PAGE(pa); KASSERT(m->phys_addr == pa, ("vm_page_t %p phys_addr mismatch %016jx %016jx", m, (uintmax_t)m->phys_addr, (uintmax_t)tpte)); KASSERT((m->flags & PG_FICTITIOUS) != 0 || m < &vm_page_array[vm_page_array_size], ("pmap_remove_pages: bad tpte %#jx", (uintmax_t)tpte)); pte_clear(pte); /* * Update the vm_page_t clean/reference bits. */ if ((tpte & (PG_M | PG_RW)) == (PG_M | PG_RW)) { if (superpage) { for (mt = m; mt < &m[NBPDR / PAGE_SIZE]; mt++) vm_page_dirty(mt); } else vm_page_dirty(m); } CHANGE_PV_LIST_LOCK_TO_VM_PAGE(&lock, m); /* Mark free */ pc->pc_map[field] |= bitmask; if (superpage) { pmap_resident_count_dec(pmap, NBPDR / PAGE_SIZE); pvh = pa_to_pvh(tpte & PG_PS_FRAME); TAILQ_REMOVE(&pvh->pv_list, pv, pv_next); pvh->pv_gen++; if (TAILQ_EMPTY(&pvh->pv_list)) { for (mt = m; mt < &m[NBPDR / PAGE_SIZE]; mt++) if ((mt->aflags & PGA_WRITEABLE) != 0 && TAILQ_EMPTY(&mt->md.pv_list)) vm_page_aflag_clear(mt, PGA_WRITEABLE); } mpte = pmap_lookup_pt_page(pmap, pv->pv_va); if (mpte != NULL) { pmap_remove_pt_page(pmap, mpte); pmap_resident_count_dec(pmap, 1); KASSERT(mpte->wire_count == NPTEPG, ("pmap_remove_pages: pte page wire count error")); mpte->wire_count = 0; pmap_add_delayed_free_list(mpte, &free, FALSE); atomic_subtract_int(&vm_cnt.v_wire_count, 1); } } else { pmap_resident_count_dec(pmap, 1); TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); m->md.pv_gen++; if ((m->aflags & PGA_WRITEABLE) != 0 && TAILQ_EMPTY(&m->md.pv_list) && (m->flags & PG_FICTITIOUS) == 0) { pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); if (TAILQ_EMPTY(&pvh->pv_list)) vm_page_aflag_clear(m, PGA_WRITEABLE); } } pmap_unuse_pt(pmap, pv->pv_va, ptepde, &free); freed++; } } PV_STAT(atomic_add_long(&pv_entry_frees, freed)); PV_STAT(atomic_add_int(&pv_entry_spare, freed)); PV_STAT(atomic_subtract_long(&pv_entry_count, freed)); if (allfree) { TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list); free_pv_chunk(pc); } } if (lock != NULL) rw_wunlock(lock); pmap_invalidate_all(pmap); rw_runlock(&pvh_global_lock); PMAP_UNLOCK(pmap); pmap_free_zero_pages(&free); } static boolean_t pmap_page_test_mappings(vm_page_t m, boolean_t accessed, boolean_t modified) { struct rwlock *lock; pv_entry_t pv; struct md_page *pvh; pt_entry_t *pte, mask; pt_entry_t PG_A, PG_M, PG_RW, PG_V; pmap_t pmap; int md_gen, pvh_gen; boolean_t rv; rv = FALSE; rw_rlock(&pvh_global_lock); lock = VM_PAGE_TO_PV_LIST_LOCK(m); rw_rlock(lock); restart: TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { pmap = PV_PMAP(pv); if (!PMAP_TRYLOCK(pmap)) { md_gen = m->md.pv_gen; rw_runlock(lock); PMAP_LOCK(pmap); rw_rlock(lock); if (md_gen != m->md.pv_gen) { PMAP_UNLOCK(pmap); goto restart; } } pte = pmap_pte(pmap, pv->pv_va); mask = 0; if (modified) { PG_M = pmap_modified_bit(pmap); PG_RW = pmap_rw_bit(pmap); mask |= PG_RW | PG_M; } if (accessed) { PG_A = pmap_accessed_bit(pmap); PG_V = pmap_valid_bit(pmap); mask |= PG_V | PG_A; } rv = (*pte & mask) == mask; PMAP_UNLOCK(pmap); if (rv) goto out; } if ((m->flags & PG_FICTITIOUS) == 0) { pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); TAILQ_FOREACH(pv, &pvh->pv_list, pv_next) { pmap = PV_PMAP(pv); if (!PMAP_TRYLOCK(pmap)) { md_gen = m->md.pv_gen; pvh_gen = pvh->pv_gen; rw_runlock(lock); PMAP_LOCK(pmap); rw_rlock(lock); if (md_gen != m->md.pv_gen || pvh_gen != pvh->pv_gen) { PMAP_UNLOCK(pmap); goto restart; } } pte = pmap_pde(pmap, pv->pv_va); mask = 0; if (modified) { PG_M = pmap_modified_bit(pmap); PG_RW = pmap_rw_bit(pmap); mask |= PG_RW | PG_M; } if (accessed) { PG_A = pmap_accessed_bit(pmap); PG_V = pmap_valid_bit(pmap); mask |= PG_V | PG_A; } rv = (*pte & mask) == mask; PMAP_UNLOCK(pmap); if (rv) goto out; } } out: rw_runlock(lock); rw_runlock(&pvh_global_lock); return (rv); } /* * pmap_is_modified: * * Return whether or not the specified physical page was modified * in any physical maps. */ boolean_t pmap_is_modified(vm_page_t m) { KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_modified: page %p is not managed", m)); /* * If the page is not exclusive busied, then PGA_WRITEABLE cannot be * concurrently set while the object is locked. Thus, if PGA_WRITEABLE * is clear, no PTEs can have PG_M set. */ VM_OBJECT_ASSERT_WLOCKED(m->object); if (!vm_page_xbusied(m) && (m->aflags & PGA_WRITEABLE) == 0) return (FALSE); return (pmap_page_test_mappings(m, FALSE, TRUE)); } /* * pmap_is_prefaultable: * * Return whether or not the specified virtual address is eligible * for prefault. */ boolean_t pmap_is_prefaultable(pmap_t pmap, vm_offset_t addr) { pd_entry_t *pde; pt_entry_t *pte, PG_V; boolean_t rv; PG_V = pmap_valid_bit(pmap); rv = FALSE; PMAP_LOCK(pmap); pde = pmap_pde(pmap, addr); if (pde != NULL && (*pde & (PG_PS | PG_V)) == PG_V) { pte = pmap_pde_to_pte(pde, addr); rv = (*pte & PG_V) == 0; } PMAP_UNLOCK(pmap); return (rv); } /* * pmap_is_referenced: * * Return whether or not the specified physical page was referenced * in any physical maps. */ boolean_t pmap_is_referenced(vm_page_t m) { KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_referenced: page %p is not managed", m)); return (pmap_page_test_mappings(m, TRUE, FALSE)); } /* * Clear the write and modified bits in each of the given page's mappings. */ void pmap_remove_write(vm_page_t m) { struct md_page *pvh; pmap_t pmap; struct rwlock *lock; pv_entry_t next_pv, pv; pd_entry_t *pde; pt_entry_t oldpte, *pte, PG_M, PG_RW; vm_offset_t va; int pvh_gen, md_gen; KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_write: page %p is not managed", m)); /* * If the page is not exclusive busied, then PGA_WRITEABLE cannot be * set by another thread while the object is locked. Thus, * if PGA_WRITEABLE is clear, no page table entries need updating. */ VM_OBJECT_ASSERT_WLOCKED(m->object); if (!vm_page_xbusied(m) && (m->aflags & PGA_WRITEABLE) == 0) return; rw_rlock(&pvh_global_lock); lock = VM_PAGE_TO_PV_LIST_LOCK(m); pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); retry_pv_loop: rw_wlock(lock); if ((m->flags & PG_FICTITIOUS) != 0) goto small_mappings; TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_next, next_pv) { pmap = PV_PMAP(pv); if (!PMAP_TRYLOCK(pmap)) { pvh_gen = pvh->pv_gen; rw_wunlock(lock); PMAP_LOCK(pmap); rw_wlock(lock); if (pvh_gen != pvh->pv_gen) { PMAP_UNLOCK(pmap); rw_wunlock(lock); goto retry_pv_loop; } } PG_RW = pmap_rw_bit(pmap); va = pv->pv_va; pde = pmap_pde(pmap, va); if ((*pde & PG_RW) != 0) (void)pmap_demote_pde_locked(pmap, pde, va, &lock); KASSERT(lock == VM_PAGE_TO_PV_LIST_LOCK(m), ("inconsistent pv lock %p %p for page %p", lock, VM_PAGE_TO_PV_LIST_LOCK(m), m)); PMAP_UNLOCK(pmap); } small_mappings: TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { pmap = PV_PMAP(pv); if (!PMAP_TRYLOCK(pmap)) { pvh_gen = pvh->pv_gen; md_gen = m->md.pv_gen; rw_wunlock(lock); PMAP_LOCK(pmap); rw_wlock(lock); if (pvh_gen != pvh->pv_gen || md_gen != m->md.pv_gen) { PMAP_UNLOCK(pmap); rw_wunlock(lock); goto retry_pv_loop; } } PG_M = pmap_modified_bit(pmap); PG_RW = pmap_rw_bit(pmap); pde = pmap_pde(pmap, pv->pv_va); KASSERT((*pde & PG_PS) == 0, ("pmap_remove_write: found a 2mpage in page %p's pv list", m)); pte = pmap_pde_to_pte(pde, pv->pv_va); retry: oldpte = *pte; if (oldpte & PG_RW) { if (!atomic_cmpset_long(pte, oldpte, oldpte & ~(PG_RW | PG_M))) goto retry; if ((oldpte & PG_M) != 0) vm_page_dirty(m); pmap_invalidate_page(pmap, pv->pv_va); } PMAP_UNLOCK(pmap); } rw_wunlock(lock); vm_page_aflag_clear(m, PGA_WRITEABLE); rw_runlock(&pvh_global_lock); } static __inline boolean_t safe_to_clear_referenced(pmap_t pmap, pt_entry_t pte) { if (!pmap_emulate_ad_bits(pmap)) return (TRUE); KASSERT(pmap->pm_type == PT_EPT, ("invalid pm_type %d", pmap->pm_type)); /* * XWR = 010 or 110 will cause an unconditional EPT misconfiguration * so we don't let the referenced (aka EPT_PG_READ) bit to be cleared * if the EPT_PG_WRITE bit is set. */ if ((pte & EPT_PG_WRITE) != 0) return (FALSE); /* * XWR = 100 is allowed only if the PMAP_SUPPORTS_EXEC_ONLY is set. */ if ((pte & EPT_PG_EXECUTE) == 0 || ((pmap->pm_flags & PMAP_SUPPORTS_EXEC_ONLY) != 0)) return (TRUE); else return (FALSE); } #define PMAP_TS_REFERENCED_MAX 5 /* * pmap_ts_referenced: * * Return a count of reference bits for a page, clearing those bits. * It is not necessary for every reference bit to be cleared, but it * is necessary that 0 only be returned when there are truly no * reference bits set. * * XXX: The exact number of bits to check and clear is a matter that * should be tested and standardized at some point in the future for * optimal aging of shared pages. */ int pmap_ts_referenced(vm_page_t m) { struct md_page *pvh; pv_entry_t pv, pvf; pmap_t pmap; struct rwlock *lock; pd_entry_t oldpde, *pde; pt_entry_t *pte, PG_A; vm_offset_t va; vm_paddr_t pa; int cleared, md_gen, not_cleared, pvh_gen; struct spglist free; boolean_t demoted; KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_ts_referenced: page %p is not managed", m)); SLIST_INIT(&free); cleared = 0; pa = VM_PAGE_TO_PHYS(m); lock = PHYS_TO_PV_LIST_LOCK(pa); pvh = pa_to_pvh(pa); rw_rlock(&pvh_global_lock); rw_wlock(lock); retry: not_cleared = 0; if ((m->flags & PG_FICTITIOUS) != 0 || (pvf = TAILQ_FIRST(&pvh->pv_list)) == NULL) goto small_mappings; pv = pvf; do { if (pvf == NULL) pvf = pv; pmap = PV_PMAP(pv); if (!PMAP_TRYLOCK(pmap)) { pvh_gen = pvh->pv_gen; rw_wunlock(lock); PMAP_LOCK(pmap); rw_wlock(lock); if (pvh_gen != pvh->pv_gen) { PMAP_UNLOCK(pmap); goto retry; } } PG_A = pmap_accessed_bit(pmap); va = pv->pv_va; pde = pmap_pde(pmap, pv->pv_va); oldpde = *pde; if ((*pde & PG_A) != 0) { /* * Since this reference bit is shared by 512 4KB * pages, it should not be cleared every time it is * tested. Apply a simple "hash" function on the * physical page number, the virtual superpage number, * and the pmap address to select one 4KB page out of * the 512 on which testing the reference bit will * result in clearing that reference bit. This * function is designed to avoid the selection of the * same 4KB page for every 2MB page mapping. * * On demotion, a mapping that hasn't been referenced * is simply destroyed. To avoid the possibility of a * subsequent page fault on a demoted wired mapping, * always leave its reference bit set. Moreover, * since the superpage is wired, the current state of * its reference bit won't affect page replacement. */ if ((((pa >> PAGE_SHIFT) ^ (pv->pv_va >> PDRSHIFT) ^ (uintptr_t)pmap) & (NPTEPG - 1)) == 0 && (*pde & PG_W) == 0) { if (safe_to_clear_referenced(pmap, oldpde)) { atomic_clear_long(pde, PG_A); pmap_invalidate_page(pmap, pv->pv_va); demoted = FALSE; } else if (pmap_demote_pde_locked(pmap, pde, pv->pv_va, &lock)) { /* * Remove the mapping to a single page * so that a subsequent access may * repromote. Since the underlying * page table page is fully populated, * this removal never frees a page * table page. */ demoted = TRUE; va += VM_PAGE_TO_PHYS(m) - (oldpde & PG_PS_FRAME); pte = pmap_pde_to_pte(pde, va); pmap_remove_pte(pmap, pte, va, *pde, NULL, &lock); pmap_invalidate_page(pmap, va); } else demoted = TRUE; if (demoted) { /* * The superpage mapping was removed * entirely and therefore 'pv' is no * longer valid. */ if (pvf == pv) pvf = NULL; pv = NULL; } cleared++; KASSERT(lock == VM_PAGE_TO_PV_LIST_LOCK(m), ("inconsistent pv lock %p %p for page %p", lock, VM_PAGE_TO_PV_LIST_LOCK(m), m)); } else not_cleared++; } PMAP_UNLOCK(pmap); /* Rotate the PV list if it has more than one entry. */ if (pv != NULL && TAILQ_NEXT(pv, pv_next) != NULL) { TAILQ_REMOVE(&pvh->pv_list, pv, pv_next); TAILQ_INSERT_TAIL(&pvh->pv_list, pv, pv_next); pvh->pv_gen++; } if (cleared + not_cleared >= PMAP_TS_REFERENCED_MAX) goto out; } while ((pv = TAILQ_FIRST(&pvh->pv_list)) != pvf); small_mappings: if ((pvf = TAILQ_FIRST(&m->md.pv_list)) == NULL) goto out; pv = pvf; do { if (pvf == NULL) pvf = pv; pmap = PV_PMAP(pv); if (!PMAP_TRYLOCK(pmap)) { pvh_gen = pvh->pv_gen; md_gen = m->md.pv_gen; rw_wunlock(lock); PMAP_LOCK(pmap); rw_wlock(lock); if (pvh_gen != pvh->pv_gen || md_gen != m->md.pv_gen) { PMAP_UNLOCK(pmap); goto retry; } } PG_A = pmap_accessed_bit(pmap); pde = pmap_pde(pmap, pv->pv_va); KASSERT((*pde & PG_PS) == 0, ("pmap_ts_referenced: found a 2mpage in page %p's pv list", m)); pte = pmap_pde_to_pte(pde, pv->pv_va); if ((*pte & PG_A) != 0) { if (safe_to_clear_referenced(pmap, *pte)) { atomic_clear_long(pte, PG_A); pmap_invalidate_page(pmap, pv->pv_va); cleared++; } else if ((*pte & PG_W) == 0) { /* * Wired pages cannot be paged out so * doing accessed bit emulation for * them is wasted effort. We do the * hard work for unwired pages only. */ pmap_remove_pte(pmap, pte, pv->pv_va, *pde, &free, &lock); pmap_invalidate_page(pmap, pv->pv_va); cleared++; if (pvf == pv) pvf = NULL; pv = NULL; KASSERT(lock == VM_PAGE_TO_PV_LIST_LOCK(m), ("inconsistent pv lock %p %p for page %p", lock, VM_PAGE_TO_PV_LIST_LOCK(m), m)); } else not_cleared++; } PMAP_UNLOCK(pmap); /* Rotate the PV list if it has more than one entry. */ if (pv != NULL && TAILQ_NEXT(pv, pv_next) != NULL) { TAILQ_REMOVE(&m->md.pv_list, pv, pv_next); TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_next); m->md.pv_gen++; } } while ((pv = TAILQ_FIRST(&m->md.pv_list)) != pvf && cleared + not_cleared < PMAP_TS_REFERENCED_MAX); out: rw_wunlock(lock); rw_runlock(&pvh_global_lock); pmap_free_zero_pages(&free); return (cleared + not_cleared); } /* * Apply the given advice to the specified range of addresses within the * given pmap. Depending on the advice, clear the referenced and/or * modified flags in each mapping and set the mapped page's dirty field. */ void pmap_advise(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, int advice) { struct rwlock *lock; pml4_entry_t *pml4e; pdp_entry_t *pdpe; pd_entry_t oldpde, *pde; pt_entry_t *pte, PG_A, PG_G, PG_M, PG_RW, PG_V; vm_offset_t va_next; vm_page_t m; boolean_t anychanged, pv_lists_locked; if (advice != MADV_DONTNEED && advice != MADV_FREE) return; /* * A/D bit emulation requires an alternate code path when clearing * the modified and accessed bits below. Since this function is * advisory in nature we skip it entirely for pmaps that require * A/D bit emulation. */ if (pmap_emulate_ad_bits(pmap)) return; PG_A = pmap_accessed_bit(pmap); PG_G = pmap_global_bit(pmap); PG_M = pmap_modified_bit(pmap); PG_V = pmap_valid_bit(pmap); PG_RW = pmap_rw_bit(pmap); pv_lists_locked = FALSE; resume: anychanged = FALSE; PMAP_LOCK(pmap); for (; sva < eva; sva = va_next) { pml4e = pmap_pml4e(pmap, sva); if ((*pml4e & PG_V) == 0) { va_next = (sva + NBPML4) & ~PML4MASK; if (va_next < sva) va_next = eva; continue; } pdpe = pmap_pml4e_to_pdpe(pml4e, sva); if ((*pdpe & PG_V) == 0) { va_next = (sva + NBPDP) & ~PDPMASK; if (va_next < sva) va_next = eva; continue; } va_next = (sva + NBPDR) & ~PDRMASK; if (va_next < sva) va_next = eva; pde = pmap_pdpe_to_pde(pdpe, sva); oldpde = *pde; if ((oldpde & PG_V) == 0) continue; else if ((oldpde & PG_PS) != 0) { if ((oldpde & PG_MANAGED) == 0) continue; if (!pv_lists_locked) { pv_lists_locked = TRUE; if (!rw_try_rlock(&pvh_global_lock)) { if (anychanged) pmap_invalidate_all(pmap); PMAP_UNLOCK(pmap); rw_rlock(&pvh_global_lock); goto resume; } } lock = NULL; if (!pmap_demote_pde_locked(pmap, pde, sva, &lock)) { if (lock != NULL) rw_wunlock(lock); /* * The large page mapping was destroyed. */ continue; } /* * Unless the page mappings are wired, remove the * mapping to a single page so that a subsequent * access may repromote. Since the underlying page * table page is fully populated, this removal never * frees a page table page. */ if ((oldpde & PG_W) == 0) { pte = pmap_pde_to_pte(pde, sva); KASSERT((*pte & PG_V) != 0, ("pmap_advise: invalid PTE")); pmap_remove_pte(pmap, pte, sva, *pde, NULL, &lock); anychanged = TRUE; } if (lock != NULL) rw_wunlock(lock); } if (va_next > eva) va_next = eva; for (pte = pmap_pde_to_pte(pde, sva); sva != va_next; pte++, sva += PAGE_SIZE) { if ((*pte & (PG_MANAGED | PG_V)) != (PG_MANAGED | PG_V)) continue; else if ((*pte & (PG_M | PG_RW)) == (PG_M | PG_RW)) { if (advice == MADV_DONTNEED) { /* * Future calls to pmap_is_modified() * can be avoided by making the page * dirty now. */ m = PHYS_TO_VM_PAGE(*pte & PG_FRAME); vm_page_dirty(m); } atomic_clear_long(pte, PG_M | PG_A); } else if ((*pte & PG_A) != 0) atomic_clear_long(pte, PG_A); else continue; if ((*pte & PG_G) != 0) pmap_invalidate_page(pmap, sva); else anychanged = TRUE; } } if (anychanged) pmap_invalidate_all(pmap); if (pv_lists_locked) rw_runlock(&pvh_global_lock); PMAP_UNLOCK(pmap); } /* * Clear the modify bits on the specified physical page. */ void pmap_clear_modify(vm_page_t m) { struct md_page *pvh; pmap_t pmap; pv_entry_t next_pv, pv; pd_entry_t oldpde, *pde; pt_entry_t oldpte, *pte, PG_M, PG_RW, PG_V; struct rwlock *lock; vm_offset_t va; int md_gen, pvh_gen; KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_modify: page %p is not managed", m)); VM_OBJECT_ASSERT_WLOCKED(m->object); KASSERT(!vm_page_xbusied(m), ("pmap_clear_modify: page %p is exclusive busied", m)); /* * If the page is not PGA_WRITEABLE, then no PTEs can have PG_M set. * If the object containing the page is locked and the page is not * exclusive busied, then PGA_WRITEABLE cannot be concurrently set. */ if ((m->aflags & PGA_WRITEABLE) == 0) return; pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); rw_rlock(&pvh_global_lock); lock = VM_PAGE_TO_PV_LIST_LOCK(m); rw_wlock(lock); restart: if ((m->flags & PG_FICTITIOUS) != 0) goto small_mappings; TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_next, next_pv) { pmap = PV_PMAP(pv); if (!PMAP_TRYLOCK(pmap)) { pvh_gen = pvh->pv_gen; rw_wunlock(lock); PMAP_LOCK(pmap); rw_wlock(lock); if (pvh_gen != pvh->pv_gen) { PMAP_UNLOCK(pmap); goto restart; } } PG_M = pmap_modified_bit(pmap); PG_V = pmap_valid_bit(pmap); PG_RW = pmap_rw_bit(pmap); va = pv->pv_va; pde = pmap_pde(pmap, va); oldpde = *pde; if ((oldpde & PG_RW) != 0) { if (pmap_demote_pde_locked(pmap, pde, va, &lock)) { if ((oldpde & PG_W) == 0) { /* * Write protect the mapping to a * single page so that a subsequent * write access may repromote. */ va += VM_PAGE_TO_PHYS(m) - (oldpde & PG_PS_FRAME); pte = pmap_pde_to_pte(pde, va); oldpte = *pte; if ((oldpte & PG_V) != 0) { while (!atomic_cmpset_long(pte, oldpte, oldpte & ~(PG_M | PG_RW))) oldpte = *pte; vm_page_dirty(m); pmap_invalidate_page(pmap, va); } } } } PMAP_UNLOCK(pmap); } small_mappings: TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) { pmap = PV_PMAP(pv); if (!PMAP_TRYLOCK(pmap)) { md_gen = m->md.pv_gen; pvh_gen = pvh->pv_gen; rw_wunlock(lock); PMAP_LOCK(pmap); rw_wlock(lock); if (pvh_gen != pvh->pv_gen || md_gen != m->md.pv_gen) { PMAP_UNLOCK(pmap); goto restart; } } PG_M = pmap_modified_bit(pmap); PG_RW = pmap_rw_bit(pmap); pde = pmap_pde(pmap, pv->pv_va); KASSERT((*pde & PG_PS) == 0, ("pmap_clear_modify: found" " a 2mpage in page %p's pv list", m)); pte = pmap_pde_to_pte(pde, pv->pv_va); if ((*pte & (PG_M | PG_RW)) == (PG_M | PG_RW)) { atomic_clear_long(pte, PG_M); pmap_invalidate_page(pmap, pv->pv_va); } PMAP_UNLOCK(pmap); } rw_wunlock(lock); rw_runlock(&pvh_global_lock); } /* * Miscellaneous support routines follow */ /* Adjust the cache mode for a 4KB page mapped via a PTE. */ static __inline void pmap_pte_attr(pt_entry_t *pte, int cache_bits, int mask) { u_int opte, npte; /* * The cache mode bits are all in the low 32-bits of the * PTE, so we can just spin on updating the low 32-bits. */ do { opte = *(u_int *)pte; npte = opte & ~mask; npte |= cache_bits; } while (npte != opte && !atomic_cmpset_int((u_int *)pte, opte, npte)); } /* Adjust the cache mode for a 2MB page mapped via a PDE. */ static __inline void pmap_pde_attr(pd_entry_t *pde, int cache_bits, int mask) { u_int opde, npde; /* * The cache mode bits are all in the low 32-bits of the * PDE, so we can just spin on updating the low 32-bits. */ do { opde = *(u_int *)pde; npde = opde & ~mask; npde |= cache_bits; } while (npde != opde && !atomic_cmpset_int((u_int *)pde, opde, npde)); } /* * Map a set of physical memory pages into the kernel virtual * address space. Return a pointer to where it is mapped. This * routine is intended to be used for mapping device memory, * NOT real memory. */ void * pmap_mapdev_attr(vm_paddr_t pa, vm_size_t size, int mode) { vm_offset_t va, offset; vm_size_t tmpsize; /* * If the specified range of physical addresses fits within the direct * map window, use the direct map. */ if (pa < dmaplimit && pa + size < dmaplimit) { va = PHYS_TO_DMAP(pa); if (!pmap_change_attr(va, size, mode)) return ((void *)va); } offset = pa & PAGE_MASK; size = round_page(offset + size); va = kva_alloc(size); if (!va) panic("pmap_mapdev: Couldn't alloc kernel virtual memory"); pa = trunc_page(pa); for (tmpsize = 0; tmpsize < size; tmpsize += PAGE_SIZE) pmap_kenter_attr(va + tmpsize, pa + tmpsize, mode); pmap_invalidate_range(kernel_pmap, va, va + tmpsize); pmap_invalidate_cache_range(va, va + tmpsize, FALSE); return ((void *)(va + offset)); } void * pmap_mapdev(vm_paddr_t pa, vm_size_t size) { return (pmap_mapdev_attr(pa, size, PAT_UNCACHEABLE)); } void * pmap_mapbios(vm_paddr_t pa, vm_size_t size) { return (pmap_mapdev_attr(pa, size, PAT_WRITE_BACK)); } void pmap_unmapdev(vm_offset_t va, vm_size_t size) { vm_offset_t base, offset; /* If we gave a direct map region in pmap_mapdev, do nothing */ if (va >= DMAP_MIN_ADDRESS && va < DMAP_MAX_ADDRESS) return; base = trunc_page(va); offset = va & PAGE_MASK; size = round_page(offset + size); kva_free(base, size); } /* * Tries to demote a 1GB page mapping. */ static boolean_t pmap_demote_pdpe(pmap_t pmap, pdp_entry_t *pdpe, vm_offset_t va) { pdp_entry_t newpdpe, oldpdpe; pd_entry_t *firstpde, newpde, *pde; pt_entry_t PG_A, PG_M, PG_RW, PG_V; vm_paddr_t mpdepa; vm_page_t mpde; PG_A = pmap_accessed_bit(pmap); PG_M = pmap_modified_bit(pmap); PG_V = pmap_valid_bit(pmap); PG_RW = pmap_rw_bit(pmap); PMAP_LOCK_ASSERT(pmap, MA_OWNED); oldpdpe = *pdpe; KASSERT((oldpdpe & (PG_PS | PG_V)) == (PG_PS | PG_V), ("pmap_demote_pdpe: oldpdpe is missing PG_PS and/or PG_V")); if ((mpde = vm_page_alloc(NULL, va >> PDPSHIFT, VM_ALLOC_INTERRUPT | VM_ALLOC_NOOBJ | VM_ALLOC_WIRED)) == NULL) { CTR2(KTR_PMAP, "pmap_demote_pdpe: failure for va %#lx" " in pmap %p", va, pmap); return (FALSE); } mpdepa = VM_PAGE_TO_PHYS(mpde); firstpde = (pd_entry_t *)PHYS_TO_DMAP(mpdepa); newpdpe = mpdepa | PG_M | PG_A | (oldpdpe & PG_U) | PG_RW | PG_V; KASSERT((oldpdpe & PG_A) != 0, ("pmap_demote_pdpe: oldpdpe is missing PG_A")); KASSERT((oldpdpe & (PG_M | PG_RW)) != PG_RW, ("pmap_demote_pdpe: oldpdpe is missing PG_M")); newpde = oldpdpe; /* * Initialize the page directory page. */ for (pde = firstpde; pde < firstpde + NPDEPG; pde++) { *pde = newpde; newpde += NBPDR; } /* * Demote the mapping. */ *pdpe = newpdpe; /* * Invalidate a stale recursive mapping of the page directory page. */ pmap_invalidate_page(pmap, (vm_offset_t)vtopde(va)); pmap_pdpe_demotions++; CTR2(KTR_PMAP, "pmap_demote_pdpe: success for va %#lx" " in pmap %p", va, pmap); return (TRUE); } /* * Sets the memory attribute for the specified page. */ void pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma) { m->md.pat_mode = ma; /* * If "m" is a normal page, update its direct mapping. This update * can be relied upon to perform any cache operations that are * required for data coherence. */ if ((m->flags & PG_FICTITIOUS) == 0 && pmap_change_attr(PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)), PAGE_SIZE, m->md.pat_mode)) panic("memory attribute change on the direct map failed"); } /* * Changes the specified virtual address range's memory type to that given by * the parameter "mode". The specified virtual address range must be * completely contained within either the direct map or the kernel map. If * the virtual address range is contained within the kernel map, then the * memory type for each of the corresponding ranges of the direct map is also * changed. (The corresponding ranges of the direct map are those ranges that * map the same physical pages as the specified virtual address range.) These * changes to the direct map are necessary because Intel describes the * behavior of their processors as "undefined" if two or more mappings to the * same physical page have different memory types. * * Returns zero if the change completed successfully, and either EINVAL or * ENOMEM if the change failed. Specifically, EINVAL is returned if some part * of the virtual address range was not mapped, and ENOMEM is returned if * there was insufficient memory available to complete the change. In the * latter case, the memory type may have been changed on some part of the * virtual address range or the direct map. */ int pmap_change_attr(vm_offset_t va, vm_size_t size, int mode) { int error; PMAP_LOCK(kernel_pmap); error = pmap_change_attr_locked(va, size, mode); PMAP_UNLOCK(kernel_pmap); return (error); } static int pmap_change_attr_locked(vm_offset_t va, vm_size_t size, int mode) { vm_offset_t base, offset, tmpva; vm_paddr_t pa_start, pa_end; pdp_entry_t *pdpe; pd_entry_t *pde; pt_entry_t *pte; int cache_bits_pte, cache_bits_pde, error; boolean_t changed; PMAP_LOCK_ASSERT(kernel_pmap, MA_OWNED); base = trunc_page(va); offset = va & PAGE_MASK; size = round_page(offset + size); /* * Only supported on kernel virtual addresses, including the direct * map but excluding the recursive map. */ if (base < DMAP_MIN_ADDRESS) return (EINVAL); cache_bits_pde = pmap_cache_bits(kernel_pmap, mode, 1); cache_bits_pte = pmap_cache_bits(kernel_pmap, mode, 0); changed = FALSE; /* * Pages that aren't mapped aren't supported. Also break down 2MB pages * into 4KB pages if required. */ for (tmpva = base; tmpva < base + size; ) { pdpe = pmap_pdpe(kernel_pmap, tmpva); if (*pdpe == 0) return (EINVAL); if (*pdpe & PG_PS) { /* * If the current 1GB page already has the required * memory type, then we need not demote this page. Just * increment tmpva to the next 1GB page frame. */ if ((*pdpe & X86_PG_PDE_CACHE) == cache_bits_pde) { tmpva = trunc_1gpage(tmpva) + NBPDP; continue; } /* * If the current offset aligns with a 1GB page frame * and there is at least 1GB left within the range, then * we need not break down this page into 2MB pages. */ if ((tmpva & PDPMASK) == 0 && tmpva + PDPMASK < base + size) { tmpva += NBPDP; continue; } if (!pmap_demote_pdpe(kernel_pmap, pdpe, tmpva)) return (ENOMEM); } pde = pmap_pdpe_to_pde(pdpe, tmpva); if (*pde == 0) return (EINVAL); if (*pde & PG_PS) { /* * If the current 2MB page already has the required * memory type, then we need not demote this page. Just * increment tmpva to the next 2MB page frame. */ if ((*pde & X86_PG_PDE_CACHE) == cache_bits_pde) { tmpva = trunc_2mpage(tmpva) + NBPDR; continue; } /* * If the current offset aligns with a 2MB page frame * and there is at least 2MB left within the range, then * we need not break down this page into 4KB pages. */ if ((tmpva & PDRMASK) == 0 && tmpva + PDRMASK < base + size) { tmpva += NBPDR; continue; } if (!pmap_demote_pde(kernel_pmap, pde, tmpva)) return (ENOMEM); } pte = pmap_pde_to_pte(pde, tmpva); if (*pte == 0) return (EINVAL); tmpva += PAGE_SIZE; } error = 0; /* * Ok, all the pages exist, so run through them updating their * cache mode if required. */ pa_start = pa_end = 0; for (tmpva = base; tmpva < base + size; ) { pdpe = pmap_pdpe(kernel_pmap, tmpva); if (*pdpe & PG_PS) { if ((*pdpe & X86_PG_PDE_CACHE) != cache_bits_pde) { pmap_pde_attr(pdpe, cache_bits_pde, X86_PG_PDE_CACHE); changed = TRUE; } if (tmpva >= VM_MIN_KERNEL_ADDRESS) { if (pa_start == pa_end) { /* Start physical address run. */ pa_start = *pdpe & PG_PS_FRAME; pa_end = pa_start + NBPDP; } else if (pa_end == (*pdpe & PG_PS_FRAME)) pa_end += NBPDP; else { /* Run ended, update direct map. */ error = pmap_change_attr_locked( PHYS_TO_DMAP(pa_start), pa_end - pa_start, mode); if (error != 0) break; /* Start physical address run. */ pa_start = *pdpe & PG_PS_FRAME; pa_end = pa_start + NBPDP; } } tmpva = trunc_1gpage(tmpva) + NBPDP; continue; } pde = pmap_pdpe_to_pde(pdpe, tmpva); if (*pde & PG_PS) { if ((*pde & X86_PG_PDE_CACHE) != cache_bits_pde) { pmap_pde_attr(pde, cache_bits_pde, X86_PG_PDE_CACHE); changed = TRUE; } if (tmpva >= VM_MIN_KERNEL_ADDRESS) { if (pa_start == pa_end) { /* Start physical address run. */ pa_start = *pde & PG_PS_FRAME; pa_end = pa_start + NBPDR; } else if (pa_end == (*pde & PG_PS_FRAME)) pa_end += NBPDR; else { /* Run ended, update direct map. */ error = pmap_change_attr_locked( PHYS_TO_DMAP(pa_start), pa_end - pa_start, mode); if (error != 0) break; /* Start physical address run. */ pa_start = *pde & PG_PS_FRAME; pa_end = pa_start + NBPDR; } } tmpva = trunc_2mpage(tmpva) + NBPDR; } else { pte = pmap_pde_to_pte(pde, tmpva); if ((*pte & X86_PG_PTE_CACHE) != cache_bits_pte) { pmap_pte_attr(pte, cache_bits_pte, X86_PG_PTE_CACHE); changed = TRUE; } if (tmpva >= VM_MIN_KERNEL_ADDRESS) { if (pa_start == pa_end) { /* Start physical address run. */ pa_start = *pte & PG_FRAME; pa_end = pa_start + PAGE_SIZE; } else if (pa_end == (*pte & PG_FRAME)) pa_end += PAGE_SIZE; else { /* Run ended, update direct map. */ error = pmap_change_attr_locked( PHYS_TO_DMAP(pa_start), pa_end - pa_start, mode); if (error != 0) break; /* Start physical address run. */ pa_start = *pte & PG_FRAME; pa_end = pa_start + PAGE_SIZE; } } tmpva += PAGE_SIZE; } } if (error == 0 && pa_start != pa_end) error = pmap_change_attr_locked(PHYS_TO_DMAP(pa_start), pa_end - pa_start, mode); /* * Flush CPU caches if required to make sure any data isn't cached that * shouldn't be, etc. */ if (changed) { pmap_invalidate_range(kernel_pmap, base, tmpva); pmap_invalidate_cache_range(base, tmpva, FALSE); } return (error); } /* * Demotes any mapping within the direct map region that covers more than the * specified range of physical addresses. This range's size must be a power * of two and its starting address must be a multiple of its size. Since the * demotion does not change any attributes of the mapping, a TLB invalidation * is not mandatory. The caller may, however, request a TLB invalidation. */ void pmap_demote_DMAP(vm_paddr_t base, vm_size_t len, boolean_t invalidate) { pdp_entry_t *pdpe; pd_entry_t *pde; vm_offset_t va; boolean_t changed; if (len == 0) return; KASSERT(powerof2(len), ("pmap_demote_DMAP: len is not a power of 2")); KASSERT((base & (len - 1)) == 0, ("pmap_demote_DMAP: base is not a multiple of len")); if (len < NBPDP && base < dmaplimit) { va = PHYS_TO_DMAP(base); changed = FALSE; PMAP_LOCK(kernel_pmap); pdpe = pmap_pdpe(kernel_pmap, va); if ((*pdpe & X86_PG_V) == 0) panic("pmap_demote_DMAP: invalid PDPE"); if ((*pdpe & PG_PS) != 0) { if (!pmap_demote_pdpe(kernel_pmap, pdpe, va)) panic("pmap_demote_DMAP: PDPE failed"); changed = TRUE; } if (len < NBPDR) { pde = pmap_pdpe_to_pde(pdpe, va); if ((*pde & X86_PG_V) == 0) panic("pmap_demote_DMAP: invalid PDE"); if ((*pde & PG_PS) != 0) { if (!pmap_demote_pde(kernel_pmap, pde, va)) panic("pmap_demote_DMAP: PDE failed"); changed = TRUE; } } if (changed && invalidate) pmap_invalidate_page(kernel_pmap, va); PMAP_UNLOCK(kernel_pmap); } } /* * perform the pmap work for mincore */ int pmap_mincore(pmap_t pmap, vm_offset_t addr, vm_paddr_t *locked_pa) { pd_entry_t *pdep; pt_entry_t pte, PG_A, PG_M, PG_RW, PG_V; vm_paddr_t pa; int val; PG_A = pmap_accessed_bit(pmap); PG_M = pmap_modified_bit(pmap); PG_V = pmap_valid_bit(pmap); PG_RW = pmap_rw_bit(pmap); PMAP_LOCK(pmap); retry: pdep = pmap_pde(pmap, addr); if (pdep != NULL && (*pdep & PG_V)) { if (*pdep & PG_PS) { pte = *pdep; /* Compute the physical address of the 4KB page. */ pa = ((*pdep & PG_PS_FRAME) | (addr & PDRMASK)) & PG_FRAME; val = MINCORE_SUPER; } else { pte = *pmap_pde_to_pte(pdep, addr); pa = pte & PG_FRAME; val = 0; } } else { pte = 0; pa = 0; val = 0; } if ((pte & PG_V) != 0) { val |= MINCORE_INCORE; if ((pte & (PG_M | PG_RW)) == (PG_M | PG_RW)) val |= MINCORE_MODIFIED | MINCORE_MODIFIED_OTHER; if ((pte & PG_A) != 0) val |= MINCORE_REFERENCED | MINCORE_REFERENCED_OTHER; } if ((val & (MINCORE_MODIFIED_OTHER | MINCORE_REFERENCED_OTHER)) != (MINCORE_MODIFIED_OTHER | MINCORE_REFERENCED_OTHER) && (pte & (PG_MANAGED | PG_V)) == (PG_MANAGED | PG_V)) { /* Ensure that "PHYS_TO_VM_PAGE(pa)->object" doesn't change. */ if (vm_page_pa_tryrelock(pmap, pa, locked_pa)) goto retry; } else PA_UNLOCK_COND(*locked_pa); PMAP_UNLOCK(pmap); return (val); } static uint64_t pmap_pcid_alloc(pmap_t pmap, u_int cpuid) { uint32_t gen, new_gen, pcid_next; CRITICAL_ASSERT(curthread); gen = PCPU_GET(pcid_gen); if (pmap->pm_pcids[cpuid].pm_pcid == PMAP_PCID_KERN || pmap->pm_pcids[cpuid].pm_gen == gen) return (CR3_PCID_SAVE); pcid_next = PCPU_GET(pcid_next); KASSERT(pcid_next <= PMAP_PCID_OVERMAX, ("cpu %d pcid_next %#x", cpuid, pcid_next)); if (pcid_next == PMAP_PCID_OVERMAX) { new_gen = gen + 1; if (new_gen == 0) new_gen = 1; PCPU_SET(pcid_gen, new_gen); pcid_next = PMAP_PCID_KERN + 1; } else { new_gen = gen; } pmap->pm_pcids[cpuid].pm_pcid = pcid_next; pmap->pm_pcids[cpuid].pm_gen = new_gen; PCPU_SET(pcid_next, pcid_next + 1); return (0); } void pmap_activate_sw(struct thread *td) { pmap_t oldpmap, pmap; uint64_t cached, cr3; u_int cpuid; oldpmap = PCPU_GET(curpmap); pmap = vmspace_pmap(td->td_proc->p_vmspace); if (oldpmap == pmap) return; cpuid = PCPU_GET(cpuid); #ifdef SMP CPU_SET_ATOMIC(cpuid, &pmap->pm_active); #else CPU_SET(cpuid, &pmap->pm_active); #endif cr3 = rcr3(); if (pmap_pcid_enabled) { cached = pmap_pcid_alloc(pmap, cpuid); KASSERT(pmap->pm_pcids[cpuid].pm_pcid >= 0 && pmap->pm_pcids[cpuid].pm_pcid < PMAP_PCID_OVERMAX, ("pmap %p cpu %d pcid %#x", pmap, cpuid, pmap->pm_pcids[cpuid].pm_pcid)); KASSERT(pmap->pm_pcids[cpuid].pm_pcid != PMAP_PCID_KERN || pmap == kernel_pmap, ("non-kernel pmap thread %p pmap %p cpu %d pcid %#x", td, pmap, cpuid, pmap->pm_pcids[cpuid].pm_pcid)); if (!cached || (cr3 & ~CR3_PCID_MASK) != pmap->pm_cr3) { load_cr3(pmap->pm_cr3 | pmap->pm_pcids[cpuid].pm_pcid | cached); if (cached) PCPU_INC(pm_save_cnt); } } else if (cr3 != pmap->pm_cr3) { load_cr3(pmap->pm_cr3); } PCPU_SET(curpmap, pmap); #ifdef SMP CPU_CLR_ATOMIC(cpuid, &oldpmap->pm_active); #else CPU_CLR(cpuid, &oldpmap->pm_active); #endif } void pmap_activate(struct thread *td) { critical_enter(); pmap_activate_sw(td); critical_exit(); } void pmap_sync_icache(pmap_t pm, vm_offset_t va, vm_size_t sz) { } /* * Increase the starting virtual address of the given mapping if a * different alignment might result in more superpage mappings. */ void pmap_align_superpage(vm_object_t object, vm_ooffset_t offset, vm_offset_t *addr, vm_size_t size) { vm_offset_t superpage_offset; if (size < NBPDR) return; if (object != NULL && (object->flags & OBJ_COLORED) != 0) offset += ptoa(object->pg_color); superpage_offset = offset & PDRMASK; if (size - ((NBPDR - superpage_offset) & PDRMASK) < NBPDR || (*addr & PDRMASK) == superpage_offset) return; if ((*addr & PDRMASK) < superpage_offset) *addr = (*addr & ~PDRMASK) + superpage_offset; else *addr = ((*addr + PDRMASK) & ~PDRMASK) + superpage_offset; } #ifdef INVARIANTS static unsigned long num_dirty_emulations; SYSCTL_ULONG(_vm_pmap, OID_AUTO, num_dirty_emulations, CTLFLAG_RW, &num_dirty_emulations, 0, NULL); static unsigned long num_accessed_emulations; SYSCTL_ULONG(_vm_pmap, OID_AUTO, num_accessed_emulations, CTLFLAG_RW, &num_accessed_emulations, 0, NULL); static unsigned long num_superpage_accessed_emulations; SYSCTL_ULONG(_vm_pmap, OID_AUTO, num_superpage_accessed_emulations, CTLFLAG_RW, &num_superpage_accessed_emulations, 0, NULL); static unsigned long ad_emulation_superpage_promotions; SYSCTL_ULONG(_vm_pmap, OID_AUTO, ad_emulation_superpage_promotions, CTLFLAG_RW, &ad_emulation_superpage_promotions, 0, NULL); #endif /* INVARIANTS */ int pmap_emulate_accessed_dirty(pmap_t pmap, vm_offset_t va, int ftype) { int rv; struct rwlock *lock; vm_page_t m, mpte; pd_entry_t *pde; pt_entry_t *pte, PG_A, PG_M, PG_RW, PG_V; boolean_t pv_lists_locked; KASSERT(ftype == VM_PROT_READ || ftype == VM_PROT_WRITE, ("pmap_emulate_accessed_dirty: invalid fault type %d", ftype)); if (!pmap_emulate_ad_bits(pmap)) return (-1); PG_A = pmap_accessed_bit(pmap); PG_M = pmap_modified_bit(pmap); PG_V = pmap_valid_bit(pmap); PG_RW = pmap_rw_bit(pmap); rv = -1; lock = NULL; pv_lists_locked = FALSE; retry: PMAP_LOCK(pmap); pde = pmap_pde(pmap, va); if (pde == NULL || (*pde & PG_V) == 0) goto done; if ((*pde & PG_PS) != 0) { if (ftype == VM_PROT_READ) { #ifdef INVARIANTS atomic_add_long(&num_superpage_accessed_emulations, 1); #endif *pde |= PG_A; rv = 0; } goto done; } pte = pmap_pde_to_pte(pde, va); if ((*pte & PG_V) == 0) goto done; if (ftype == VM_PROT_WRITE) { if ((*pte & PG_RW) == 0) goto done; /* * Set the modified and accessed bits simultaneously. * * Intel EPT PTEs that do software emulation of A/D bits map * PG_A and PG_M to EPT_PG_READ and EPT_PG_WRITE respectively. * An EPT misconfiguration is triggered if the PTE is writable * but not readable (WR=10). This is avoided by setting PG_A * and PG_M simultaneously. */ *pte |= PG_M | PG_A; } else { *pte |= PG_A; } /* try to promote the mapping */ if (va < VM_MAXUSER_ADDRESS) mpte = PHYS_TO_VM_PAGE(*pde & PG_FRAME); else mpte = NULL; m = PHYS_TO_VM_PAGE(*pte & PG_FRAME); if ((mpte == NULL || mpte->wire_count == NPTEPG) && pmap_ps_enabled(pmap) && (m->flags & PG_FICTITIOUS) == 0 && vm_reserv_level_iffullpop(m) == 0) { if (!pv_lists_locked) { pv_lists_locked = TRUE; if (!rw_try_rlock(&pvh_global_lock)) { PMAP_UNLOCK(pmap); rw_rlock(&pvh_global_lock); goto retry; } } pmap_promote_pde(pmap, pde, va, &lock); #ifdef INVARIANTS atomic_add_long(&ad_emulation_superpage_promotions, 1); #endif } #ifdef INVARIANTS if (ftype == VM_PROT_WRITE) atomic_add_long(&num_dirty_emulations, 1); else atomic_add_long(&num_accessed_emulations, 1); #endif rv = 0; /* success */ done: if (lock != NULL) rw_wunlock(lock); if (pv_lists_locked) rw_runlock(&pvh_global_lock); PMAP_UNLOCK(pmap); return (rv); } void pmap_get_mapping(pmap_t pmap, vm_offset_t va, uint64_t *ptr, int *num) { pml4_entry_t *pml4; pdp_entry_t *pdp; pd_entry_t *pde; pt_entry_t *pte, PG_V; int idx; idx = 0; PG_V = pmap_valid_bit(pmap); PMAP_LOCK(pmap); pml4 = pmap_pml4e(pmap, va); ptr[idx++] = *pml4; if ((*pml4 & PG_V) == 0) goto done; pdp = pmap_pml4e_to_pdpe(pml4, va); ptr[idx++] = *pdp; if ((*pdp & PG_V) == 0 || (*pdp & PG_PS) != 0) goto done; pde = pmap_pdpe_to_pde(pdp, va); ptr[idx++] = *pde; if ((*pde & PG_V) == 0 || (*pde & PG_PS) != 0) goto done; pte = pmap_pde_to_pte(pde, va); ptr[idx++] = *pte; done: PMAP_UNLOCK(pmap); *num = idx; } /** * Get the kernel virtual address of a set of physical pages. If there are * physical addresses not covered by the DMAP perform a transient mapping * that will be removed when calling pmap_unmap_io_transient. * * \param page The pages the caller wishes to obtain the virtual * address on the kernel memory map. * \param vaddr On return contains the kernel virtual memory address * of the pages passed in the page parameter. * \param count Number of pages passed in. * \param can_fault TRUE if the thread using the mapped pages can take * page faults, FALSE otherwise. * * \returns TRUE if the caller must call pmap_unmap_io_transient when * finished or FALSE otherwise. * */ boolean_t pmap_map_io_transient(vm_page_t page[], vm_offset_t vaddr[], int count, boolean_t can_fault) { vm_paddr_t paddr; boolean_t needs_mapping; pt_entry_t *pte; int cache_bits, error, i; /* * Allocate any KVA space that we need, this is done in a separate * loop to prevent calling vmem_alloc while pinned. */ needs_mapping = FALSE; for (i = 0; i < count; i++) { paddr = VM_PAGE_TO_PHYS(page[i]); if (__predict_false(paddr >= dmaplimit)) { error = vmem_alloc(kernel_arena, PAGE_SIZE, M_BESTFIT | M_WAITOK, &vaddr[i]); KASSERT(error == 0, ("vmem_alloc failed: %d", error)); needs_mapping = TRUE; } else { vaddr[i] = PHYS_TO_DMAP(paddr); } } /* Exit early if everything is covered by the DMAP */ if (!needs_mapping) return (FALSE); /* * NB: The sequence of updating a page table followed by accesses * to the corresponding pages used in the !DMAP case is subject to * the situation described in the "AMD64 Architecture Programmer's * Manual Volume 2: System Programming" rev. 3.23, "7.3.1 Special * Coherency Considerations". Therefore, issuing the INVLPG right * after modifying the PTE bits is crucial. */ if (!can_fault) sched_pin(); for (i = 0; i < count; i++) { paddr = VM_PAGE_TO_PHYS(page[i]); if (paddr >= dmaplimit) { if (can_fault) { /* * Slow path, since we can get page faults * while mappings are active don't pin the * thread to the CPU and instead add a global * mapping visible to all CPUs. */ pmap_qenter(vaddr[i], &page[i], 1); } else { pte = vtopte(vaddr[i]); cache_bits = pmap_cache_bits(kernel_pmap, page[i]->md.pat_mode, 0); pte_store(pte, paddr | X86_PG_RW | X86_PG_V | cache_bits); invlpg(vaddr[i]); } } } return (needs_mapping); } void pmap_unmap_io_transient(vm_page_t page[], vm_offset_t vaddr[], int count, boolean_t can_fault) { vm_paddr_t paddr; int i; if (!can_fault) sched_unpin(); for (i = 0; i < count; i++) { paddr = VM_PAGE_TO_PHYS(page[i]); if (paddr >= dmaplimit) { if (can_fault) pmap_qremove(vaddr[i], 1); vmem_free(kernel_arena, vaddr[i], PAGE_SIZE); } } } #include "opt_ddb.h" #ifdef DDB #include DB_SHOW_COMMAND(pte, pmap_print_pte) { pmap_t pmap; pml4_entry_t *pml4; pdp_entry_t *pdp; pd_entry_t *pde; pt_entry_t *pte, PG_V; vm_offset_t va; if (have_addr) { va = (vm_offset_t)addr; pmap = PCPU_GET(curpmap); /* XXX */ } else { db_printf("show pte addr\n"); return; } PG_V = pmap_valid_bit(pmap); pml4 = pmap_pml4e(pmap, va); db_printf("VA %#016lx pml4e %#016lx", va, *pml4); if ((*pml4 & PG_V) == 0) { db_printf("\n"); return; } pdp = pmap_pml4e_to_pdpe(pml4, va); db_printf(" pdpe %#016lx", *pdp); if ((*pdp & PG_V) == 0 || (*pdp & PG_PS) != 0) { db_printf("\n"); return; } pde = pmap_pdpe_to_pde(pdp, va); db_printf(" pde %#016lx", *pde); if ((*pde & PG_V) == 0 || (*pde & PG_PS) != 0) { db_printf("\n"); return; } pte = pmap_pde_to_pte(pde, va); db_printf(" pte %#016lx\n", *pte); } DB_SHOW_COMMAND(phys2dmap, pmap_phys2dmap) { vm_paddr_t a; if (have_addr) { a = (vm_paddr_t)addr; db_printf("0x%jx\n", (uintmax_t)PHYS_TO_DMAP(a)); } else { db_printf("show phys2dmap addr\n"); } } #endif Index: projects/ci20_mips/sys/arm/annapurna/alpine/files.alpine =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/files.alpine (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/files.alpine (revision 283031) @@ -0,0 +1,16 @@ +# $FreeBSD$ + +kern/kern_clocksource.c standard + +arm/arm/bus_space_base.c standard +arm/arm/bus_space_generic.c standard +arm/arm/bus_space_asm_generic.S standard + +arm/versatile/sp804.c standard +arm/versatile/versatile_timer.c standard +dev/uart/uart_dev_ns8250.c optional uart +dev/ofw/ofw_cpu.c standard + +arm/annapurna/alpine/common.c standard +arm/annapurna/alpine/alpine_machdep.c standard +arm/annapurna/alpine/alpine_machdep_mp.c optional smp Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/files.alpine ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/std.alpine =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/std.alpine (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/std.alpine (revision 283031) @@ -0,0 +1,23 @@ +# $FreeBSD$ + +makeoption ARM_LITTLE_ENDIAN + +cpu CPU_CORTEXA +machine arm armv6 +makeoptions CONF_CFLAGS="-march=armv7a -DAL_HAVE_TYPES" + +makeoptions KERNPHYSADDR=0x00200000 +options KERNPHYSADDR=0x00200000 + +makeoptions KERNVIRTADDR=0xa0200000 +options KERNVIRTADDR=0xa0200000 + +makeoptions KERNBASE=0xa0000000 +options KERNBASE=0xa0000000 + +options ARM_L2_PIPT + +options IPI_IRQ_START=0 +options IPI_IRQ_END=15 + +files "../annapurna/alpine/files.alpine" Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/std.alpine ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/alpine_machdep.c =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/alpine_machdep.c (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/alpine_machdep.c (revision 283031) @@ -0,0 +1,148 @@ +/*- + * Copyright (c) 2013 Ruslan Bukin + * Copyright (c) 2015 Semihalf + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#define _ARM32_BUS_DMA_PRIVATE +#include +#include +#include +#include +#include + +#include +#include + +#include +#include /* For trapframe_t, used in */ +#include +#include +#include +#include +#include + +#include + +#include "opt_ddb.h" +#include "opt_platform.h" + +struct mtx al_dbg_lock; + +#define DEVMAP_MAX_VA_ADDRESS 0xF0000000 +bus_addr_t al_devmap_pa; +bus_addr_t al_devmap_size; + +#define AL_NB_SERVICE_OFFSET 0x70000 +#define AL_NB_CCU_OFFSET 0x90000 +#define AL_CCU_SNOOP_CONTROL_IOFAB_0_OFFSET 0x4000 +#define AL_CCU_SNOOP_CONTROL_IOFAB_1_OFFSET 0x5000 +#define AL_CCU_SPECULATION_CONTROL_OFFSET 0x4 + +#define AL_NB_ACF_MISC_OFFSET 0xD0 +#define AL_NB_ACF_MISC_READ_BYPASS (1 << 30) + +int alpine_get_devmap_base(bus_addr_t *pa, bus_addr_t *size); + +vm_offset_t +platform_lastaddr(void) +{ + + return (DEVMAP_MAX_VA_ADDRESS); +} + +void +platform_probe_and_attach(void) +{ + +} + +void +platform_gpio_init(void) +{ + +} + +void +platform_late_init(void) +{ + bus_addr_t reg_baddr; + uint32_t val; + + if (!mtx_initialized(&al_dbg_lock)) + mtx_init(&al_dbg_lock, "ALDBG", "ALDBG", MTX_SPIN); + + /* configure system fabric */ + if (bus_space_map(fdtbus_bs_tag, al_devmap_pa, al_devmap_size, 0, + ®_baddr)) + panic("Couldn't map Register Space area"); + + /* do not allow reads to bypass writes to different addresses */ + val = bus_space_read_4(fdtbus_bs_tag, reg_baddr, + AL_NB_SERVICE_OFFSET + AL_NB_ACF_MISC_OFFSET); + val &= ~AL_NB_ACF_MISC_READ_BYPASS; + bus_space_write_4(fdtbus_bs_tag, reg_baddr, + AL_NB_SERVICE_OFFSET + AL_NB_ACF_MISC_OFFSET, val); + + /* enable cache snoop */ + bus_space_write_4(fdtbus_bs_tag, reg_baddr, + AL_NB_CCU_OFFSET + AL_CCU_SNOOP_CONTROL_IOFAB_0_OFFSET, 1); + bus_space_write_4(fdtbus_bs_tag, reg_baddr, + AL_NB_CCU_OFFSET + AL_CCU_SNOOP_CONTROL_IOFAB_1_OFFSET, 1); + + /* disable speculative fetches from masters */ + bus_space_write_4(fdtbus_bs_tag, reg_baddr, + AL_NB_CCU_OFFSET + AL_CCU_SPECULATION_CONTROL_OFFSET, 7); + + bus_space_unmap(fdtbus_bs_tag, reg_baddr, al_devmap_size); +} + +/* + * Construct pmap_devmap[] with DT-derived config data. + */ +int +platform_devmap_init(void) +{ + alpine_get_devmap_base(&al_devmap_pa, &al_devmap_size); + arm_devmap_add_entry(al_devmap_pa, al_devmap_size); + return (0); +} + +struct arm32_dma_range * +bus_dma_get_range(void) +{ + + return (NULL); +} + +int +bus_dma_get_range_nb(void) +{ + + return (0); +} Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/alpine_machdep.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/alpine_machdep_mp.c =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/alpine_machdep_mp.c (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/alpine_machdep_mp.c (revision 283031) @@ -0,0 +1,335 @@ +/*- + * Copyright (c) 2013 Ruslan Bukin + * Copyright (c) 2015 Semihalf + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#define AL_CPU_RESUME_WATERMARK_REG 0x00 +#define AL_CPU_RESUME_FLAGS_REG 0x04 +#define AL_CPU_RESUME_PCPU_RADDR_REG(cpu) (0x08 + 0x04 + 8*(cpu)) +#define AL_CPU_RESUME_PCPU_FLAGS(cpu) (0x08 + 8*(cpu)) + +/* Per-CPU flags */ +#define AL_CPU_RESUME_FLG_PERCPU_DONT_RESUME (1 << 2) + +/* The expected magic number for validating the resume addresses */ +#define AL_CPU_RESUME_MAGIC_NUM 0xf0e1d200 +#define AL_CPU_RESUME_MAGIC_NUM_MASK 0xffffff00 + +/* The expected minimal version number for validating the capabilities */ +#define AL_CPU_RESUME_MIN_VER 0x000000c3 +#define AL_CPU_RESUME_MIN_VER_MASK 0x000000ff + +/* Field controlling the boot-up of companion cores */ +#define AL_NB_INIT_CONTROL (0x8) +#define AL_NB_CONFIG_STATUS_PWR_CTRL(cpu) (0x2020 + (cpu)*0x100) + +#define SERDES_NUM_GROUPS 4 +#define SERDES_GROUP_SIZE 0x400 + +extern bus_addr_t al_devmap_pa; +extern bus_addr_t al_devmap_size; + +extern void mpentry(void); + +int alpine_serdes_resource_get(uint32_t group, bus_space_tag_t *tag, + bus_addr_t *baddr); +static int platform_mp_get_core_cnt(void); +static int alpine_get_cpu_resume_base(u_long *pbase, u_long *psize); +static int alpine_get_nb_base(u_long *pbase, u_long *psize); +static int alpine_get_serdes_base(u_long *pbase, u_long *psize); +int alpine_serdes_resource_get(uint32_t group, bus_space_tag_t *tag, + bus_addr_t *baddr); +static boolean_t alpine_validate_cpu(u_int, phandle_t, u_int, pcell_t *); + +static boolean_t +alpine_validate_cpu(u_int id, phandle_t child, u_int addr_cell, pcell_t *reg) +{ + return fdt_is_compatible(child, "arm,cortex-a15"); +} + +static int +platform_mp_get_core_cnt(void) +{ + static int ncores = 0; + int nchilds; + uint32_t reg; + + /* Calculate ncores value only once */ + if (ncores) + return (ncores); + + reg = cp15_l2ctlr_get(); + ncores = CPUV7_L2CTLR_NPROC(reg); + + nchilds = ofw_cpu_early_foreach(alpine_validate_cpu, false); + + /* Limit CPUs if DTS has configured less than available */ + if ((nchilds > 0) && (nchilds < ncores)) { + printf("SMP: limiting number of active CPUs to %d out of %d\n", + nchilds, ncores); + ncores = nchilds; + } + + return (ncores); +} + +void +platform_mp_init_secondary(void) +{ + + arm_init_secondary_ic(); +} + +void +platform_mp_setmaxid(void) +{ + int core_cnt; + + core_cnt = platform_mp_get_core_cnt(); + mp_maxid = core_cnt - 1; +} + +int +platform_mp_probe(void) +{ + mp_ncpus = platform_mp_get_core_cnt(); + return (1); +} + +static int +alpine_get_cpu_resume_base(u_long *pbase, u_long *psize) +{ + phandle_t node; + u_long base = 0; + u_long size = 0; + + if (pbase == NULL || psize == NULL) + return (EINVAL); + + if ((node = OF_finddevice("/")) == -1) + return (EFAULT); + + if ((node = + ofw_bus_find_compatible(node, "annapurna-labs,al-cpu-resume")) == 0) + return (EFAULT); + + if (fdt_regsize(node, &base, &size)) + return (EFAULT); + + *pbase = base; + *psize = size; + + return (0); +} + +static int +alpine_get_nb_base(u_long *pbase, u_long *psize) +{ + phandle_t node; + u_long base = 0; + u_long size = 0; + + if (pbase == NULL || psize == NULL) + return (EINVAL); + + if ((node = OF_finddevice("/")) == -1) + return (EFAULT); + + if ((node = + ofw_bus_find_compatible(node, "annapurna-labs,al-nb-service")) == 0) + return (EFAULT); + + if (fdt_regsize(node, &base, &size)) + return (EFAULT); + + *pbase = base; + *psize = size; + + return (0); +} + +void +platform_mp_start_ap(void) +{ + uint32_t physaddr; + vm_offset_t vaddr; + uint32_t val; + uint32_t start_mask; + u_long cpu_resume_base; + u_long nb_base; + u_long cpu_resume_size; + u_long nb_size; + bus_addr_t cpu_resume_baddr; + bus_addr_t nb_baddr; + int a; + + if (alpine_get_cpu_resume_base(&cpu_resume_base, &cpu_resume_size)) + panic("Couldn't resolve cpu_resume_base address\n"); + + if (alpine_get_nb_base(&nb_base, &nb_size)) + panic("Couldn't resolve_nb_base address\n"); + + /* Proceed with start addresses for additional CPUs */ + if (bus_space_map(fdtbus_bs_tag, al_devmap_pa + cpu_resume_base, + cpu_resume_size, 0, &cpu_resume_baddr)) + panic("Couldn't map CPU-resume area"); + if (bus_space_map(fdtbus_bs_tag, al_devmap_pa + nb_base, + nb_size, 0, &nb_baddr)) + panic("Couldn't map NB-service area"); + + /* Proceed with start addresses for additional CPUs */ + val = bus_space_read_4(fdtbus_bs_tag, cpu_resume_baddr, + AL_CPU_RESUME_WATERMARK_REG); + if (((val & AL_CPU_RESUME_MAGIC_NUM_MASK) != AL_CPU_RESUME_MAGIC_NUM) || + ((val & AL_CPU_RESUME_MIN_VER_MASK) < AL_CPU_RESUME_MIN_VER)) { + panic("CPU-resume device is not compatible"); + } + + vaddr = (vm_offset_t)mpentry; + physaddr = pmap_kextract(vaddr); + + for (a = 1; a < platform_mp_get_core_cnt(); a++) { + /* Power up the core */ + bus_space_write_4(fdtbus_bs_tag, nb_baddr, + AL_NB_CONFIG_STATUS_PWR_CTRL(a), 0); + mb(); + + /* Enable resume */ + val = bus_space_read_4(fdtbus_bs_tag, cpu_resume_baddr, + AL_CPU_RESUME_PCPU_FLAGS(a)); + val &= ~AL_CPU_RESUME_FLG_PERCPU_DONT_RESUME; + bus_space_write_4(fdtbus_bs_tag, cpu_resume_baddr, + AL_CPU_RESUME_PCPU_FLAGS(a), val); + mb(); + + /* Set resume physical address */ + bus_space_write_4(fdtbus_bs_tag, cpu_resume_baddr, + AL_CPU_RESUME_PCPU_RADDR_REG(a), physaddr); + mb(); + } + + /* Release cores from reset */ + if (bus_space_map(fdtbus_bs_tag, al_devmap_pa + nb_base, + nb_size, 0, &nb_baddr)) + panic("Couldn't map NB-service area"); + + start_mask = (1 << platform_mp_get_core_cnt()) - 1; + + /* Release cores from reset */ + val = bus_space_read_4(fdtbus_bs_tag, nb_baddr, AL_NB_INIT_CONTROL); + val |= start_mask; + bus_space_write_4(fdtbus_bs_tag, nb_baddr, AL_NB_INIT_CONTROL, val); + dsb(); + + bus_space_unmap(fdtbus_bs_tag, nb_baddr, nb_size); + bus_space_unmap(fdtbus_bs_tag, cpu_resume_baddr, cpu_resume_size); +} + +static int +alpine_get_serdes_base(u_long *pbase, u_long *psize) +{ + phandle_t node; + u_long base = 0; + u_long size = 0; + + if (pbase == NULL || psize == NULL) + return (EINVAL); + + if ((node = OF_finddevice("/")) == -1) + return (EFAULT); + + if ((node = + ofw_bus_find_compatible(node, "annapurna-labs,al-serdes")) == 0) + return (EFAULT); + + if (fdt_regsize(node, &base, &size)) + return (EFAULT); + + *pbase = base; + *psize = size; + + return (0); +} + +int +alpine_serdes_resource_get(uint32_t group, bus_space_tag_t *tag, bus_addr_t *baddr) +{ + u_long serdes_base, serdes_size; + int ret; + static bus_addr_t baddr_mapped[SERDES_NUM_GROUPS]; + + if (group >= SERDES_NUM_GROUPS) + return (EINVAL); + + if (baddr_mapped[group]) { + *tag = fdtbus_bs_tag; + *baddr = baddr_mapped[group]; + return (0); + } + + ret = alpine_get_serdes_base(&serdes_base, &serdes_size); + if (ret) + return (ret); + + ret = bus_space_map(fdtbus_bs_tag, + al_devmap_pa + serdes_base + group * SERDES_GROUP_SIZE, + (SERDES_NUM_GROUPS - group) * SERDES_GROUP_SIZE, 0, baddr); + if (ret) + return (ret); + + baddr_mapped[group] = *baddr; + + return (0); +} + +void +platform_ipi_send(cpuset_t cpus, u_int ipi) +{ + + pic_ipi_send(cpus, ipi); +} Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/alpine_machdep_mp.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/common.c =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/common.c (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/common.c (revision 283031) @@ -0,0 +1,158 @@ +/*- + * Copyright (c) 2013 Ruslan Bukin + * Copyright (c) 2015 Semihalf. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define WDTLOAD 0x000 +#define LOAD_MIN 0x00000001 +#define LOAD_MAX 0xFFFFFFFF +#define WDTVALUE 0x004 +#define WDTCONTROL 0x008 +/* control register masks */ +#define INT_ENABLE (1 << 0) +#define RESET_ENABLE (1 << 1) +#define WDTLOCK 0xC00 +#define UNLOCK 0x1ACCE551 +#define LOCK 0x00000001 + +extern bus_addr_t al_devmap_pa; +struct fdt_fixup_entry fdt_fixup_table[] = { + { NULL, NULL } +}; + +static int alpine_get_wdt_base(uint32_t *pbase, uint32_t *psize); +static int alpine_pic_decode_fdt(uint32_t iparent, uint32_t *intr, + int *interrupt, int *trig, int *pol); + +int alpine_get_devmap_base(bus_addr_t *pa, bus_addr_t *size); + +int alpine_get_devmap_base(bus_addr_t *pa, bus_addr_t *size) +{ + phandle_t node; + + if ((node = OF_finddevice("/")) == 0) + return (ENXIO); + + if ((node = fdt_find_compatible(node, "simple-bus", 1)) == 0) + return (ENXIO); + + return fdt_get_range(node, 0, pa, size); +} + +static int +alpine_get_wdt_base(uint32_t *pbase, uint32_t *psize) +{ + phandle_t node; + u_long base = 0; + u_long size = 0; + + if (pbase == NULL || psize == NULL) + return (EINVAL); + + if ((node = OF_finddevice("/")) == -1) + return (EFAULT); + + if ((node = fdt_find_compatible(node, "simple-bus", 1)) == 0) + return (EFAULT); + + if ((node = + fdt_find_compatible(node, "arm,sp805", 1)) == 0) + return (EFAULT); + + if (fdt_regsize(node, &base, &size)) + return (EFAULT); + + *pbase = base; + *psize = size; + + return (0); +} + +void +cpu_reset(void) +{ + uint32_t wdbase, wdsize; + bus_addr_t wdbaddr; + int ret; + + ret = alpine_get_wdt_base(&wdbase, &wdsize); + if (ret) { + printf("Unable to get WDT base, do power down manually..."); + goto infinite; + } + + ret = bus_space_map(fdtbus_bs_tag, al_devmap_pa + wdbase, + wdsize, 0, &wdbaddr); + if (ret) { + printf("Unable to map WDT base, do power down manually..."); + goto infinite; + } + + bus_space_write_4(fdtbus_bs_tag, wdbaddr, WDTLOCK, UNLOCK); + bus_space_write_4(fdtbus_bs_tag, wdbaddr, WDTLOAD, LOAD_MIN); + bus_space_write_4(fdtbus_bs_tag, wdbaddr, WDTCONTROL, INT_ENABLE | RESET_ENABLE); + +infinite: + while (1) {} +} + +static int +alpine_pic_decode_fdt(uint32_t iparent, uint32_t *intr, int *interrupt, + int *trig, int *pol) +{ + int rv = 0; + + rv = gic_decode_fdt(iparent, intr, interrupt, trig, pol); + if (rv == 0) { + /* This was recognized as our PIC and decoded. */ + interrupt = FDT_MAP_IRQ(iparent, interrupt); + + /* Configure the interrupt if callback provided */ + if (arm_config_irq) + (*arm_config_irq)(*interrupt, *trig, *pol); + } + return (rv); +} + +fdt_pic_decode_t fdt_pic_table[] = { + &alpine_pic_decode_fdt, + NULL +}; Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/common.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_common.h =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_common.h (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_common.h (revision 283031) @@ -0,0 +1,70 @@ +/*- +******************************************************************************** +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/** + * @defgroup group_common HAL Common Layer + * Includes all common header files used by HAL + * @{ + * @file al_hal_common.h + * + */ + +#ifndef __AL_HAL_COMMON_H__ +#define __AL_HAL_COMMON_H__ + +#include "al_hal_plat_types.h" +#include "al_hal_plat_services.h" + +#include "al_hal_types.h" +#include "al_hal_reg_utils.h" + +/* Get the maximal value out of two typed values */ +#define al_max_t(type, x, y) ({ \ + type __max1 = (x); \ + type __max2 = (y); \ + __max1 > __max2 ? __max1 : __max2; }) + +/* Get the minimal value out of two typed values */ +#define al_min_t(type, x, y) ({ \ + type __min1 = (x); \ + type __min2 = (y); \ + __min1 < __min2 ? __min1 : __min2; }) + +/* Get the number of elements in an array */ +#define AL_ARR_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +/** @} end of Common group */ +#endif /* __AL_HAL_COMMON_H__ */ Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_common.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_iofic.h =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_iofic.h (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_iofic.h (revision 283031) @@ -0,0 +1,222 @@ +/*- +******************************************************************************** +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/** + * @defgroup group_interrupts Common I/O Fabric Interrupt Controller + * This HAL provides the API for programming the Common I/O Fabric Interrupt + * Controller (IOFIC) found in most of the units attached to the I/O Fabric of + * Alpine platform + * @{ + * @file al_hal_iofic.h + * + * @brief Header file for the interrupt controller that's embedded in various units + * + */ + +#ifndef __AL_HAL_IOFIC_H__ +#define __AL_HAL_IOFIC_H__ + +#include + +/* *INDENT-OFF* */ +#ifdef __cplusplus +extern "C" { +#endif +/* *INDENT-ON* */ + +#define AL_IOFIC_MAX_GROUPS 4 + +/* + * Configurations + */ + +/** + * Configure the interrupt controller registers, actual interrupts are still + * masked at this stage. + * + * @param regs_base regs pointer to interrupt controller registers + * @param group the interrupt group. + * @param flags flags of Interrupt Control Register + * + * @return 0 on success. -EINVAL otherwise. + */ +int al_iofic_config(void __iomem *regs_base, int group, + uint32_t flags); + +/** + * configure the moderation timer resolution for a given group + * Applies for both msix and legacy mode. + * + * @param regs_base pointer to unit registers + * @param group the interrupt group + * @param resolution resolution of the timer interval, the resolution determines the rate + * of decrementing the interval timer, setting value N means that the interval + * timer will be decremented each (N+1) * (0.68) micro seconds. + * + * @return 0 on success. -EINVAL otherwise. + */ +int al_iofic_moder_res_config(void __iomem *regs_base, int group, + uint8_t resolution); + +/** + * configure the moderation timer interval for a given legacy interrupt group + * + * @param regs_base regs pointer to unit registers + * @param group the interrupt group + * @param interval between interrupts in resolution units. 0 disable + * + * @return 0 on success. -EINVAL otherwise. + */ +int al_iofic_legacy_moder_interval_config(void __iomem *regs_base, int group, + uint8_t interval); + +/** + * configure the moderation timer interval for a given msix vector + * + * @param regs_base pointer to unit registers + * @param group the interrupt group + * @param vector vector index + * @param interval interval between interrupts, 0 disable + * + * @return 0 on success. -EINVAL otherwise. + */ +int al_iofic_msix_moder_interval_config(void __iomem *regs_base, int group, + uint8_t vector, uint8_t interval); + +/** +* configure the vmid attributes for a given msix vector. +* +* @param group the interrupt group +* @param vector index +* @param vmid the vmid value +* @param vmid_en take vmid from the intc +* +* @return 0 on success. -EINVAL otherwise. +*/ +int al_iofic_msix_vmid_attributes_config(void __iomem *regs_base, int group, + uint8_t vector, uint32_t vmid, uint8_t vmid_en); + +/** + * return the offset of the unmask register for a given group. + * this function can be used when the upper layer wants to directly + * access the unmask regiter and bypass the al_iofic_unmask() API. + * + * @param regs_base regs pointer to unit registers + * @param group the interrupt group + * @return the offset of the unmask register. + */ +uint32_t __iomem * al_iofic_unmask_offset_get(void __iomem *regs_base, int group); + +/** + * unmask specific interrupts for a given group + * this functions guarantees atomic operations, it is performance optimized as + * it will not require read-modify-write. The unmask done using the interrupt + * mask clear register, so it's safe to call it while the mask is changed by + * the HW (auto mask) or another core. + * + * @param regs_base pointer to unit registers + * @param group the interrupt group + * @param mask bitwise of interrupts to unmask, set bits will be unmasked. + */ +void al_iofic_unmask(void __iomem *regs_base, int group, uint32_t mask); + +/** + * mask specific interrupts for a given group + * this functions modifies interrupt mask register, the callee must make sure + * the mask is not changed by another cpu. + * + * @param regs_base pointer to unit registers + * @param group the interrupt group + * @param mask bitwise of interrupts to mask, set bits will be masked. + */ +void al_iofic_mask(void __iomem *regs_base, int group, uint32_t mask); + +/** + * read the mask register for a given group + * this functions return the interrupt mask register + * + * @param regs_base pointer to unit registers + * @param group the interrupt group + */ +uint32_t al_iofic_read_mask(void __iomem *regs_base, int group); + +/** + * read interrupt cause register for a given group + * this will clear the set bits if the Clear on Read mode enabled. + * @param regs_base pointer to unit registers + * @param group the interrupt group + */ +uint32_t al_iofic_read_cause(void __iomem *regs_base, int group); + +/** + * clear bits in the interrupt cause register for a given group + * + * @param regs_base pointer to unit registers + * @param group the interrupt group + * @param mask bitwise of bits to be cleared, set bits will be cleared. + */ +void al_iofic_clear_cause(void __iomem *regs_base, int group, uint32_t mask); + +/** + * set the cause register for a given group + * this function set the cause register. It will generate an interrupt (if + * the the interrupt isn't masked ) + * + * @param regs_base pointer to unit registers + * @param group the interrupt group + * @param mask bitwise of bits to be set. + */ +void al_iofic_set_cause(void __iomem *regs_base, int group, uint32_t mask); + +/** + * unmask specific interrupts from aborting the udma a given group + * + * @param regs_base pointer to unit registers + * @param group the interrupt group + * @param mask bitwise of interrupts to mask + */ +void al_iofic_abort_mask(void __iomem *regs_base, int group, uint32_t mask); + +/** + * trigger all interrupts that are waiting for moderation timers to expire + * + * @param regs_base pointer to unit registers + * @param group the interrupt group + */ +void al_iofic_interrupt_moderation_reset(void __iomem *regs_base, int group); + +#endif +/** @} end of interrupt controller group */ Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_iofic.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_iofic_regs.h =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_iofic_regs.h (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_iofic_regs.h (revision 283031) @@ -0,0 +1,127 @@ +/*_ +******************************************************************************** +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __AL_HAL_IOFIC_REG_H +#define __AL_HAL_IOFIC_REG_H + +#ifdef __cplusplus +extern "C" { +#endif +/* +* Unit Registers +*/ + +struct al_iofic_grp_ctrl { + uint32_t int_cause_grp; /* Interrupt Cause RegisterSet by hardware */ + uint32_t rsrvd1; + uint32_t int_cause_set_grp; /* Interrupt Cause Set RegisterWriting 1 to a bit in t ... */ + uint32_t rsrvd2; + uint32_t int_mask_grp; /* Interrupt Mask RegisterIf Auto-mask control bit =TR ... */ + uint32_t rsrvd3; + uint32_t int_mask_clear_grp; /* Interrupt Mask Clear RegisterUsed when auto-mask co ... */ + uint32_t rsrvd4; + uint32_t int_status_grp; /* Interrupt status RegisterThis register latch the st ... */ + uint32_t rsrvd5; + uint32_t int_control_grp; /* Interrupt Control Register */ + uint32_t rsrvd6; + uint32_t int_abort_msk_grp; /* Interrupt Mask RegisterEach bit in this register ma ... */ + uint32_t rsrvd7; + uint32_t int_log_msk_grp; /* Interrupt Log RegisterEach bit in this register mas ... */ + uint32_t rsrvd8; +}; + +struct al_iofic_grp_mod { + uint32_t grp_int_mod_reg; /* Interrupt moderation registerDedicated moderation in ... */ + uint32_t grp_int_vmid_reg; +}; + +struct al_iofic_regs { + struct al_iofic_grp_ctrl ctrl[0]; + uint32_t rsrvd1[0x400 >> 2]; + struct al_iofic_grp_mod grp_int_mod[0][32]; +}; + + +/* +* Registers Fields +*/ + + +/**** int_control_grp register ****/ +/* When Clear_on_Read =1, All bits of Cause register ... */ +#define INT_CONTROL_GRP_CLEAR_ON_READ (1 << 0) +/* (must be set only when MSIX is enabled)When Auto-Ma ... */ +#define INT_CONTROL_GRP_AUTO_MASK (1 << 1) +/* Auto_Clear (RW)When Auto-Clear =1, the bits in the ... */ +#define INT_CONTROL_GRP_AUTO_CLEAR (1 << 2) +/* When Set_on_Posedge =1, the bits in the interrupt c ... */ +#define INT_CONTROL_GRP_SET_ON_POSEDGE (1 << 3) +/* When Moderation_Reset =1, all Moderation timers ass ... */ +#define INT_CONTROL_GRP_MOD_RST (1 << 4) +/* When mask_msi_x =1, No MSI-X from this group is sen ... */ +#define INT_CONTROL_GRP_MASK_MSI_X (1 << 5) +/* MSI-X AWID value, same ID for all cause bits */ +#define INT_CONTROL_GRP_AWID_MASK 0x00000F00 +#define INT_CONTROL_GRP_AWID_SHIFT 8 +/* This value determines the interval between interrup ... */ +#define INT_CONTROL_GRP_MOD_INTV_MASK 0x00FF0000 +#define INT_CONTROL_GRP_MOD_INTV_SHIFT 16 +/* This value determines the Moderation_Timer_Clock sp ... */ +#define INT_CONTROL_GRP_MOD_RES_MASK 0x0F000000 +#define INT_CONTROL_GRP_MOD_RES_SHIFT 24 + +/**** grp_int_mod_reg register ****/ +/* Interrupt Moderation Interval registerDedicated reg ... */ +#define INT_MOD_INTV_MASK 0x000000FF +#define INT_MOD_INTV_SHIFT 0 + +/**** grp_int_vmid_reg register ****/ +/* Interrupt vmid value registerDedicated reg ... */ +#define INT_MSIX_VMID_MASK 0x0000FFFF +#define INT_MSIX_VMID_SHIFT 0 +/* Interrupt vmid_en value registerDedicated reg ... */ +#define INT_MSIX_VMID_EN_SHIFT 31 + +#ifdef __cplusplus +} +#endif + +#endif /* __AL_HAL_IOFIC_REG_H */ + + + + Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_iofic_regs.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_nb_regs.h =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_nb_regs.h (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_nb_regs.h (revision 283031) @@ -0,0 +1,1823 @@ +/*- +******************************************************************************** +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/** + * @{ + * @file al_hal_nb_regs.h + * + * @brief North Bridge service registers + * + */ + +#ifndef __AL_HAL_NB_REGS_H__ +#define __AL_HAL_NB_REGS_H__ + +#include "al_hal_plat_types.h" + +#ifdef __cplusplus +extern "C" { +#endif +/* +* Unit Registers +*/ + + + +struct al_nb_global { + /* [0x0] */ + uint32_t cpus_config; + /* [0x4] */ + uint32_t cpus_secure; + /* [0x8] Force init reset. */ + uint32_t cpus_init_control; + /* [0xc] Force init reset per DECEI mode. */ + uint32_t cpus_init_status; + /* [0x10] */ + uint32_t nb_int_cause; + /* [0x14] */ + uint32_t sev_int_cause; + /* [0x18] */ + uint32_t pmus_int_cause; + /* [0x1c] */ + uint32_t sev_mask; + /* [0x20] */ + uint32_t cpus_hold_reset; + /* [0x24] */ + uint32_t cpus_software_reset; + /* [0x28] */ + uint32_t wd_timer0_reset; + /* [0x2c] */ + uint32_t wd_timer1_reset; + /* [0x30] */ + uint32_t wd_timer2_reset; + /* [0x34] */ + uint32_t wd_timer3_reset; + /* [0x38] */ + uint32_t ddrc_hold_reset; + /* [0x3c] */ + uint32_t fabric_software_reset; + /* [0x40] */ + uint32_t cpus_power_ctrl; + uint32_t rsrvd_0[7]; + /* [0x60] */ + uint32_t acf_base_high; + /* [0x64] */ + uint32_t acf_base_low; + /* [0x68] */ + uint32_t acf_control_override; + /* [0x6c] Read-only that reflects CPU Cluster Local GIC base high address */ + uint32_t lgic_base_high; + /* [0x70] Read-only that reflects CPU Cluster Local GIC base low address */ + uint32_t lgic_base_low; + /* [0x74] Read-only that reflects the device's IOGIC base high address. */ + uint32_t iogic_base_high; + /* [0x78] Read-only that reflects IOGIC base low address */ + uint32_t iogic_base_low; + /* [0x7c] */ + uint32_t io_wr_split_control; + /* [0x80] */ + uint32_t io_rd_rob_control; + /* [0x84] */ + uint32_t sb_pos_error_log_1; + /* [0x88] */ + uint32_t sb_pos_error_log_0; + /* [0x8c] */ + uint32_t c2swb_config; + /* [0x90] */ + uint32_t msix_error_log; + /* [0x94] */ + uint32_t error_cause; + /* [0x98] */ + uint32_t error_mask; + uint32_t rsrvd_1; + /* [0xa0] */ + uint32_t qos_peak_control; + /* [0xa4] */ + uint32_t qos_set_control; + /* [0xa8] */ + uint32_t ddr_qos; + uint32_t rsrvd_2[9]; + /* [0xd0] */ + uint32_t acf_misc; + /* [0xd4] */ + uint32_t config_bus_control; + uint32_t rsrvd_3[2]; + /* [0xe0] */ + uint32_t pos_id_match; + uint32_t rsrvd_4[3]; + /* [0xf0] */ + uint32_t sb_sel_override_awuser; + /* [0xf4] */ + uint32_t sb_override_awuser; + /* [0xf8] */ + uint32_t sb_sel_override_aruser; + /* [0xfc] */ + uint32_t sb_override_aruser; + /* [0x100] */ + uint32_t cpu_max_pd_timer; + /* [0x104] */ + uint32_t cpu_max_pu_timer; + uint32_t rsrvd_5[2]; + /* [0x110] */ + uint32_t auto_ddr_self_refresh_counter; + uint32_t rsrvd_6[3]; + /* [0x120] */ + uint32_t coresight_pd; + /* [0x124] */ + uint32_t coresight_internal_0; + /* [0x128] */ + uint32_t coresight_dbgromaddr; + /* [0x12c] */ + uint32_t coresight_dbgselfaddr; + /* [0x130] */ + uint32_t coresght_targetid; + /* [0x134] */ + uint32_t coresght_targetid0; + uint32_t rsrvd_7[10]; + /* [0x160] */ + uint32_t sb_force_same_id_cfg_0; + /* [0x164] */ + uint32_t sb_mstr_force_same_id_sel_0; + /* [0x168] */ + uint32_t sb_force_same_id_cfg_1; + /* [0x16c] */ + uint32_t sb_mstr_force_same_id_sel_1; + uint32_t rsrvd[932]; +}; +struct al_nb_system_counter { + /* [0x0] */ + uint32_t cnt_control; + /* [0x4] */ + uint32_t cnt_base_freq; + /* [0x8] */ + uint32_t cnt_low; + /* [0xc] */ + uint32_t cnt_high; + /* [0x10] */ + uint32_t cnt_init_low; + /* [0x14] */ + uint32_t cnt_init_high; + uint32_t rsrvd[58]; +}; +struct al_nb_rams_control_misc { + /* [0x0] */ + uint32_t ca15_rf_misc; + uint32_t rsrvd_0; + /* [0x8] */ + uint32_t nb_rf_misc; + uint32_t rsrvd[61]; +}; +struct al_nb_ca15_rams_control { + /* [0x0] */ + uint32_t rf_0; + /* [0x4] */ + uint32_t rf_1; + /* [0x8] */ + uint32_t rf_2; + uint32_t rsrvd; +}; +struct al_nb_semaphores { + /* [0x0] This configuration is only sampled during reset of the processor */ + uint32_t lockn; +}; +struct al_nb_debug { + /* [0x0] */ + uint32_t ca15_outputs_1; + /* [0x4] */ + uint32_t ca15_outputs_2; + uint32_t rsrvd_0[2]; + /* [0x10] */ + uint32_t cpu_msg[4]; + /* [0x20] */ + uint32_t rsv0_config; + /* [0x24] */ + uint32_t rsv1_config; + uint32_t rsrvd_1[2]; + /* [0x30] */ + uint32_t rsv0_status; + /* [0x34] */ + uint32_t rsv1_status; + uint32_t rsrvd_2[2]; + /* [0x40] */ + uint32_t ddrc; + /* [0x44] */ + uint32_t ddrc_phy_smode_control; + /* [0x48] */ + uint32_t ddrc_phy_smode_status; + uint32_t rsrvd_3[5]; + /* [0x60] */ + uint32_t pmc; + uint32_t rsrvd_4[3]; + /* [0x70] */ + uint32_t cpus_general; + /* [0x74] */ + uint32_t cpus_general_1; + uint32_t rsrvd_5[2]; + /* [0x80] */ + uint32_t cpus_int_out; + uint32_t rsrvd_6[3]; + /* [0x90] */ + uint32_t latch_pc_req; + uint32_t rsrvd_7; + /* [0x98] */ + uint32_t latch_pc_low; + /* [0x9c] */ + uint32_t latch_pc_high; + uint32_t rsrvd_8[24]; + /* [0x100] */ + uint32_t track_dump_ctrl; + /* [0x104] */ + uint32_t track_dump_rdata_0; + /* [0x108] */ + uint32_t track_dump_rdata_1; + uint32_t rsrvd_9[5]; + /* [0x120] */ + uint32_t track_events; + uint32_t rsrvd_10[3]; + /* [0x130] */ + uint32_t pos_track_dump_ctrl; + /* [0x134] */ + uint32_t pos_track_dump_rdata_0; + /* [0x138] */ + uint32_t pos_track_dump_rdata_1; + uint32_t rsrvd_11; + /* [0x140] */ + uint32_t c2swb_track_dump_ctrl; + /* [0x144] */ + uint32_t c2swb_track_dump_rdata_0; + /* [0x148] */ + uint32_t c2swb_track_dump_rdata_1; + uint32_t rsrvd_12; + /* [0x150] */ + uint32_t cpus_track_dump_ctrl; + /* [0x154] */ + uint32_t cpus_track_dump_rdata_0; + /* [0x158] */ + uint32_t cpus_track_dump_rdata_1; + uint32_t rsrvd_13; + /* [0x160] */ + uint32_t c2swb_bar_ovrd_high; + /* [0x164] */ + uint32_t c2swb_bar_ovrd_low; + uint32_t rsrvd[38]; +}; +struct al_nb_cpun_config_status { + /* [0x0] This configuration is only sampled during reset of the processor. */ + uint32_t config; + /* [0x4] This configuration is only sampled during reset of the processor. */ + uint32_t config_aarch64; + /* [0x8] */ + uint32_t local_cause_mask; + uint32_t rsrvd_0; + /* [0x10] */ + uint32_t pmus_cause_mask; + /* [0x14] */ + uint32_t sei_cause_mask; + uint32_t rsrvd_1[2]; + /* [0x20] Specifies the state of the CPU with reference to power modes. */ + uint32_t power_ctrl; + /* [0x24] */ + uint32_t power_status; + /* [0x28] */ + uint32_t resume_addr_l; + /* [0x2c] */ + uint32_t resume_addr_h; + uint32_t rsrvd_2[4]; + /* [0x40] */ + uint32_t warm_rst_ctl; + uint32_t rsrvd_3; + /* [0x48] */ + uint32_t rvbar_low; + /* [0x4c] */ + uint32_t rvbar_high; + /* [0x50] */ + uint32_t pmu_snapshot; + uint32_t rsrvd_4[3]; + /* [0x60] */ + uint32_t cpu_msg_in; + uint32_t rsrvd[39]; +}; +struct al_nb_mc_pmu { + /* [0x0] PMU Global Control Register */ + uint32_t pmu_control; + /* [0x4] PMU Global Control Register */ + uint32_t overflow; + uint32_t rsrvd[62]; +}; +struct al_nb_mc_pmu_counters { + /* [0x0] Counter Configuration Register */ + uint32_t cfg; + /* [0x4] Counter Control Register */ + uint32_t cntl; + /* [0x8] Counter Control Register */ + uint32_t low; + /* [0xc] Counter Control Register */ + uint32_t high; + uint32_t rsrvd[4]; +}; +struct al_nb_nb_version { + /* [0x0] Northbridge Revision */ + uint32_t version; + uint32_t rsrvd; +}; +struct al_nb_sriov { + /* [0x0] */ + uint32_t cpu_vmid[4]; + uint32_t rsrvd[4]; +}; +struct al_nb_dram_channels { + /* [0x0] */ + uint32_t dram_0_control; + uint32_t rsrvd_0; + /* [0x8] */ + uint32_t dram_0_status; + uint32_t rsrvd_1; + /* [0x10] */ + uint32_t ddr_int_cause; + uint32_t rsrvd_2; + /* [0x18] */ + uint32_t ddr_cause_mask; + uint32_t rsrvd_3; + /* [0x20] */ + uint32_t address_map; + uint32_t rsrvd_4[3]; + /* [0x30] */ + uint32_t reorder_id_mask_0; + /* [0x34] */ + uint32_t reorder_id_value_0; + /* [0x38] */ + uint32_t reorder_id_mask_1; + /* [0x3c] */ + uint32_t reorder_id_value_1; + /* [0x40] */ + uint32_t reorder_id_mask_2; + /* [0x44] */ + uint32_t reorder_id_value_2; + /* [0x48] */ + uint32_t reorder_id_mask_3; + /* [0x4c] */ + uint32_t reorder_id_value_3; + /* [0x50] */ + uint32_t mrr_control_status; + uint32_t rsrvd[43]; +}; +struct al_nb_ddr_0_mrr { + /* [0x0] Counter Configuration Register */ + uint32_t val; +}; +struct al_nb_push_packet { + /* [0x0] */ + uint32_t pp_config; + uint32_t rsrvd_0[3]; + /* [0x10] */ + uint32_t pp_ext_awuser; + uint32_t rsrvd_1[3]; + /* [0x20] */ + uint32_t pp_base_low; + /* [0x24] */ + uint32_t pp_base_high; + uint32_t rsrvd_2[2]; + /* [0x30] */ + uint32_t pp_sel_awuser; + uint32_t rsrvd[51]; +}; + +struct al_nb_regs { + struct al_nb_global global; /* [0x0] */ + struct al_nb_system_counter system_counter; /* [0x1000] */ + struct al_nb_rams_control_misc rams_control_misc; /* [0x1100] */ + struct al_nb_ca15_rams_control ca15_rams_control[5]; /* [0x1200] */ + uint32_t rsrvd_0[108]; + struct al_nb_semaphores semaphores[64]; /* [0x1400] */ + uint32_t rsrvd_1[320]; + struct al_nb_debug debug; /* [0x1a00] */ + uint32_t rsrvd_2[256]; + struct al_nb_cpun_config_status cpun_config_status[4]; /* [0x2000] */ + uint32_t rsrvd_3[1792]; + struct al_nb_mc_pmu mc_pmu; /* [0x4000] */ + struct al_nb_mc_pmu_counters mc_pmu_counters[4]; /* [0x4100] */ + uint32_t rsrvd_4[160]; + struct al_nb_nb_version nb_version; /* [0x4400] */ + uint32_t rsrvd_5[126]; + struct al_nb_sriov sriov; /* [0x4600] */ + uint32_t rsrvd_6[120]; + struct al_nb_dram_channels dram_channels; /* [0x4800] */ + struct al_nb_ddr_0_mrr ddr_0_mrr[9]; /* [0x4900] */ + uint32_t rsrvd_7[439]; + uint32_t rsrvd_8[1024]; /* [0x5000] */ + struct al_nb_push_packet push_packet; /* [0x6000] */ +}; + + +/* +* Registers Fields +*/ + + +/**** CPUs_Config register ****/ +/* Disable broadcast of barrier onto system bus. +Connect to Processor Cluster SYSBARDISABLE. */ +#define NB_GLOBAL_CPUS_CONFIG_SYSBARDISABLE (1 << 0) +/* Enable broadcast of inner shareable transactions from CPUs. +Connect to Processor Cluster BROADCASTINNER. */ +#define NB_GLOBAL_CPUS_CONFIG_BROADCASTINNER (1 << 1) +/* Disable broadcast of cache maintenance system bus. +Connect to Processor Cluster BROADCASTCACHEMAIN */ +#define NB_GLOBAL_CPUS_CONFIG_BROADCASTCACHEMAINT (1 << 2) +/* Enable broadcast of outer shareable transactions from CPUs. +Connect to Processor Cluster BROADCASTOUTER. */ +#define NB_GLOBAL_CPUS_CONFIG_BROADCASTOUTER (1 << 3) +/* Defines the internal CPU GIC operating frequency ratio with the main CPU clock. +0x0: 1:1 +0x1: 1:2 +0x2: 1:3 +0x3: 1:4 + +Note: This is not in used with CA57 */ +#define NB_GLOBAL_CPUS_CONFIG_PERIPHCLKEN_MASK 0x00000030 +#define NB_GLOBAL_CPUS_CONFIG_PERIPHCLKEN_SHIFT 4 +/* Disables the GIC CPU interface logic and routes the legacy nIRQ, nFIQ, nVIRQ, and nVFIQ +signals directly to the processor: +0 Enable the GIC CPU interface logic. +1 Disable the GIC CPU interface logic. +The processor only samples this signal as it exits reset. */ +#define NB_GLOBAL_CPUS_CONFIG_GIC_DISABLE (1 << 6) +/* Disable L1 data cache and L2 snoop tag RAMs automatic invalidate on reset functionality */ +#define NB_GLOBAL_CPUS_CONFIG_DBG_L1_RESET_DISABLE (1 << 7) +/* Value read in the Cluster ID Affinity Level-1 field, bits[15:8], of the Multiprocessor Affinity +Register (MPIDR). +This signal is only sampled during reset of the processor. */ +#define NB_GLOBAL_CPUS_CONFIG_CLUSTERIDAFF1_MASK 0x00FF0000 +#define NB_GLOBAL_CPUS_CONFIG_CLUSTERIDAFF1_SHIFT 16 +/* Value read in the Cluster ID Affinity Level-2 field, bits[23:16], of the Multiprocessor Affinity +Register (MPIDR). +This signal is only sampled during reset of the processor.. */ +#define NB_GLOBAL_CPUS_CONFIG_CLUSTERIDAFF2_MASK 0xFF000000 +#define NB_GLOBAL_CPUS_CONFIG_CLUSTERIDAFF2_SHIFT 24 + +/**** CPUs_Secure register ****/ +/* DBGEN + */ +#define NB_GLOBAL_CPUS_SECURE_DBGEN (1 << 0) +/* NIDEN + */ +#define NB_GLOBAL_CPUS_SECURE_NIDEN (1 << 1) +/* SPIDEN + */ +#define NB_GLOBAL_CPUS_SECURE_SPIDEN (1 << 2) +/* SPNIDEN + */ +#define NB_GLOBAL_CPUS_SECURE_SPNIDEN (1 << 3) +/* Disable write access to some secure GIC registers */ +#define NB_GLOBAL_CPUS_SECURE_CFGSDISABLE (1 << 4) +/* Disable write access to some secure IOGIC registers */ +#define NB_GLOBAL_CPUS_SECURE_IOGIC_CFGSDISABLE (1 << 5) + +/**** CPUs_Init_Control register ****/ +/* CPU Init Done +Specifies which CPUs' inits are done and can exit poreset. +By default, CPU0 only exits poreset when the CPUs cluster exits power-on-reset and then kicks other CPUs. +If this bit is cleared for a specific CPU, setting it by primary CPU as part of the initialization process will initiate power-on-reset to this specific CPU. */ +#define NB_GLOBAL_CPUS_INIT_CONTROL_CPUS_INITDONE_MASK 0x0000000F +#define NB_GLOBAL_CPUS_INIT_CONTROL_CPUS_INITDONE_SHIFT 0 +/* DBGPWRDNREQ Mask +When CPU does not exist, its DBGPWRDNREQ must be asserted. +If corresponding mask bit is set, the DBGPWDNREQ is deasserted. */ +#define NB_GLOBAL_CPUS_INIT_CONTROL_DBGPWRDNREQ_MASK_MASK 0x000000F0 +#define NB_GLOBAL_CPUS_INIT_CONTROL_DBGPWRDNREQ_MASK_SHIFT 4 +/* Force CPU init power-on-reset exit. +For debug purposes only. */ +#define NB_GLOBAL_CPUS_INIT_CONTROL_FORCE_CPUPOR_MASK 0x00000F00 +#define NB_GLOBAL_CPUS_INIT_CONTROL_FORCE_CPUPOR_SHIFT 8 +/* Force dbgpwrdup signal high +If dbgpwrdup is clear on the processor interface it indicates that the process debug resources are not available for APB access. */ +#define NB_GLOBAL_CPUS_INIT_CONTROL_FORCE_DBGPWRDUP_MASK 0x0000F000 +#define NB_GLOBAL_CPUS_INIT_CONTROL_FORCE_DBGPWRDUP_SHIFT 12 + +/**** CPUs_Init_Status register ****/ +/* Specifies which CPUs are enabled in the device configuration. +sample at rst_cpus_exist[3:0] reset strap. */ +#define NB_GLOBAL_CPUS_INIT_STATUS_CPUS_EXIST_MASK 0x0000000F +#define NB_GLOBAL_CPUS_INIT_STATUS_CPUS_EXIST_SHIFT 0 + +/**** NB_Int_Cause register ****/ +/* + * Each bit corresponds to an IRQ. + * value is 1 for level irq, 0 for trigger irq + * Level IRQ indices: 12-13, 23, 24, 26-29 + */ +#define NB_GLOBAL_NB_INT_CAUSE_LEVEL_IRQ_MASK 0x3D803000 +/* Cross trigger interrupt */ +#define NB_GLOBAL_NB_INT_CAUSE_NCTIIRQ_MASK 0x0000000F +#define NB_GLOBAL_NB_INT_CAUSE_NCTIIRQ_SHIFT 0 +/* Communications channel receive. Receive portion of Data Transfer Register full flag */ +#define NB_GLOBAL_NB_INT_CAUSE_COMMRX_MASK 0x000000F0 +#define NB_GLOBAL_NB_INT_CAUSE_COMMRX_SHIFT 4 +/* Communication channel transmit. Transmit portion of Data Transfer Register empty flag. */ +#define NB_GLOBAL_NB_INT_CAUSE_COMMTX_MASK 0x00000F00 +#define NB_GLOBAL_NB_INT_CAUSE_COMMTX_SHIFT 8 +/* Reserved, read undefined must write as zeros. */ +#define NB_GLOBAL_NB_INT_CAUSE_RESERVED_15_15 (1 << 15) +/* Error indicator for AXI write transactions with a BRESP error condition. Writing 0 to bit[29] of the L2ECTLR clears the error indicator connected to CA15 nAXIERRIRQ. */ +#define NB_GLOBAL_NB_INT_CAUSE_CPU_AXIERRIRQ (1 << 16) +/* Error indicator for: L2 RAM double-bit ECC error, illegal writes to the GIC memory-map region. */ +#define NB_GLOBAL_NB_INT_CAUSE_CPU_INTERRIRQ (1 << 17) +/* Coherent fabric error summary interrupt */ +#define NB_GLOBAL_NB_INT_CAUSE_ACF_ERRORIRQ (1 << 18) +/* DDR Controller ECC Correctable error summary interrupt */ +#define NB_GLOBAL_NB_INT_CAUSE_MCTL_ECC_CORR_ERR (1 << 19) +/* DDR Controller ECC Uncorrectable error summary interrupt */ +#define NB_GLOBAL_NB_INT_CAUSE_MCTL_ECC_UNCORR_ERR (1 << 20) +/* DRAM parity error interrupt */ +#define NB_GLOBAL_NB_INT_CAUSE_MCTL_PARITY_ERR (1 << 21) +/* Reserved, not functional */ +#define NB_GLOBAL_NB_INT_CAUSE_MCTL_WDATARAM_PAR (1 << 22) +/* Error cause summary interrupt */ +#define NB_GLOBAL_NB_INT_CAUSE_ERR_CAUSE_SUM_A0 (1 << 23) +/* SB PoS error */ +#define NB_GLOBAL_NB_INT_CAUSE_SB_POS_ERR (1 << 24) +/* Received msix is not mapped to local GIC or IO-GIC spin */ +#define NB_GLOBAL_NB_INT_CAUSE_MSIX_ERR_INT_M0 (1 << 25) +/* Coresight timestamp overflow */ +#define NB_GLOBAL_NB_INT_CAUSE_CORESIGHT_TS_OVERFLOW_M0 (1 << 26) + +/**** SEV_Int_Cause register ****/ +/* SMMU 0/1 global non-secure fault interrupt */ +#define NB_GLOBAL_SEV_INT_CAUSE_SMMU_GBL_FLT_IRPT_NS_MASK 0x00000003 +#define NB_GLOBAL_SEV_INT_CAUSE_SMMU_GBL_FLT_IRPT_NS_SHIFT 0 +/* SMMU 0/1 non-secure context interrupt */ +#define NB_GLOBAL_SEV_INT_CAUSE_SMMU_CXT_IRPT_NS_MASK 0x0000000C +#define NB_GLOBAL_SEV_INT_CAUSE_SMMU_CXT_IRPT_NS_SHIFT 2 +/* SMMU0/1 Non-secure configuration access fault interrupt */ +#define NB_GLOBAL_SEV_INT_CAUSE_SMMU_CFG_FLT_IRPT_S_MASK 0x00000030 +#define NB_GLOBAL_SEV_INT_CAUSE_SMMU_CFG_FLT_IRPT_S_SHIFT 4 +/* Reserved. Read undefined; must write as zeros. */ +#define NB_GLOBAL_SEV_INT_CAUSE_RESERVED_11_6_MASK 0x00000FC0 +#define NB_GLOBAL_SEV_INT_CAUSE_RESERVED_11_6_SHIFT 6 +/* Reserved. Read undefined; must write as zeros. */ +#define NB_GLOBAL_SEV_INT_CAUSE_RESERVED_31_20_MASK 0xFFF00000 +#define NB_GLOBAL_SEV_INT_CAUSE_RESERVED_31_20_SHIFT 20 + +/**** PMUs_Int_Cause register ****/ +/* CPUs PMU Overflow interrupt */ +#define NB_GLOBAL_PMUS_INT_CAUSE_CPUS_OVFL_MASK 0x0000000F +#define NB_GLOBAL_PMUS_INT_CAUSE_CPUS_OVFL_SHIFT 0 +/* Northbridge PMU overflow */ +#define NB_GLOBAL_PMUS_INT_CAUSE_NB_OVFL (1 << 4) +/* Memory Controller PMU overflow */ +#define NB_GLOBAL_PMUS_INT_CAUSE_MCTL_OVFL (1 << 5) +/* Coherency Interconnect PMU overflow */ +#define NB_GLOBAL_PMUS_INT_CAUSE_CCI_OVFL_MASK 0x000007C0 +#define NB_GLOBAL_PMUS_INT_CAUSE_CCI_OVFL_SHIFT 6 +/* Coherency Interconnect PMU overflow */ +#define NB_GLOBAL_PMUS_INT_CAUSE_SMMU_OVFL_MASK 0x00001800 +#define NB_GLOBAL_PMUS_INT_CAUSE_SMMU_OVFL_SHIFT 11 +/* Reserved. Read undefined; must write as zeros. */ +#define NB_GLOBAL_PMUS_INT_CAUSE_RESERVED_23_13_MASK 0x00FFE000 +#define NB_GLOBAL_PMUS_INT_CAUSE_RESERVED_23_13_SHIFT 13 +/* Southbridge PMUs overflow */ +#define NB_GLOBAL_PMUS_INT_CAUSE_SB_PMUS_OVFL_MASK 0xFF000000 +#define NB_GLOBAL_PMUS_INT_CAUSE_SB_PMUS_OVFL_SHIFT 24 + +/**** CPUs_Hold_Reset register ****/ +/* Shared L2 memory system, interrupt controller and timer logic reset. +Reset is applied only when all processors are in STNDBYWFI state. */ +#define NB_GLOBAL_CPUS_HOLD_RESET_L2RESET (1 << 0) +/* Shared debug domain reset */ +#define NB_GLOBAL_CPUS_HOLD_RESET_PRESETDBG (1 << 1) +/* Individual CPU debug, PTM, watchpoint and breakpoint logic reset */ +#define NB_GLOBAL_CPUS_HOLD_RESET_CPU_DBGRESET_MASK 0x000000F0 +#define NB_GLOBAL_CPUS_HOLD_RESET_CPU_DBGRESET_SHIFT 4 +/* Individual CPU core and VFP/NEON logic reset. +Reset is applied only when specific CPU is in STNDBYWFI state. */ +#define NB_GLOBAL_CPUS_HOLD_RESET_CPU_CORERESET_MASK 0x00000F00 +#define NB_GLOBAL_CPUS_HOLD_RESET_CPU_CORERESET_SHIFT 8 +/* Individual CPU por-on-reset. +Reset is applied only when specific CPU is in STNDBYWFI state. */ +#define NB_GLOBAL_CPUS_HOLD_RESET_CPU_PORESET_MASK 0x0000F000 +#define NB_GLOBAL_CPUS_HOLD_RESET_CPU_PORESET_SHIFT 12 +/* Wait for interrupt mask. +If set, reset is applied without waiting for the specified CPU's STNDBYWFI state. */ +#define NB_GLOBAL_CPUS_HOLD_RESET_WFI_MASK_MASK 0x000F0000 +#define NB_GLOBAL_CPUS_HOLD_RESET_WFI_MASK_SHIFT 16 + +/**** CPUs_Software_Reset register ****/ +/* Write 1. Apply the software reset. */ +#define NB_GLOBAL_CPUS_SOFTWARE_RESET_SWRESET_REQ (1 << 0) +/* Defines the level of software reset. +0x0 - cpu_core: Individual CPU core reset. +0x1 - cpu_poreset: Individual CPU power-on-reset. +0x2 - cpu_dbg: Individual CPU debug reset. +0x3 - cluster_no_dbg: A Cluster reset puts each core into core reset (no dbg) and also resets the interrupt controller and L2 logic. +0x4 - cluster: A Cluster reset puts each core into power-on-reset and also resets the interrupt controller and L2 logic. Debug is active. +0x5 - cluster_poreset: A Cluster power-on-reset puts each core into power-on-reset and also resets the interrupt controller and L2 logic. This include the cluster debug logic. */ +#define NB_GLOBAL_CPUS_SOFTWARE_RESET_LEVEL_MASK 0x0000000E +#define NB_GLOBAL_CPUS_SOFTWARE_RESET_LEVEL_SHIFT 1 +/* Individual CPU core reset. */ +#define NB_GLOBAL_CPUS_SOFTWARE_RESET_LEVEL_CPU_CORE \ + (0x0 << NB_GLOBAL_CPUS_SOFTWARE_RESET_LEVEL_SHIFT) +/* Individual CPU power-on-reset. */ +#define NB_GLOBAL_CPUS_SOFTWARE_RESET_LEVEL_CPU_PORESET \ + (0x1 << NB_GLOBAL_CPUS_SOFTWARE_RESET_LEVEL_SHIFT) +/* Individual CPU debug reset. */ +#define NB_GLOBAL_CPUS_SOFTWARE_RESET_LEVEL_CPU_DBG \ + (0x2 << NB_GLOBAL_CPUS_SOFTWARE_RESET_LEVEL_SHIFT) +/* A Cluster reset puts each core into core reset (no dbg) and a ... */ +#define NB_GLOBAL_CPUS_SOFTWARE_RESET_LEVEL_CLUSTER_NO_DBG \ + (0x3 << NB_GLOBAL_CPUS_SOFTWARE_RESET_LEVEL_SHIFT) +/* A Cluster reset puts each core into power-on-reset and also r ... */ +#define NB_GLOBAL_CPUS_SOFTWARE_RESET_LEVEL_CLUSTER \ + (0x4 << NB_GLOBAL_CPUS_SOFTWARE_RESET_LEVEL_SHIFT) +/* A Cluster power-on-reset puts each core into power-on-reset a ... */ +#define NB_GLOBAL_CPUS_SOFTWARE_RESET_LEVEL_CLUSTER_PORESET \ + (0x5 << NB_GLOBAL_CPUS_SOFTWARE_RESET_LEVEL_SHIFT) +/* Defines which cores to reset when no cluster_poreset is requested. */ +#define NB_GLOBAL_CPUS_SOFTWARE_RESET_CORES_MASK 0x000000F0 +#define NB_GLOBAL_CPUS_SOFTWARE_RESET_CORES_SHIFT 4 +/* CPUn wait for interrupt enable. +Defines which CPU WFI indication to wait for before applying the software reset. */ +#define NB_GLOBAL_CPUS_SOFTWARE_RESET_WFI_MASK_MASK 0x000F0000 +#define NB_GLOBAL_CPUS_SOFTWARE_RESET_WFI_MASK_SHIFT 16 + +/**** WD_Timer0_Reset register ****/ +/* Shared L2 memory system, interrupt controller and timer logic reset */ +#define NB_GLOBAL_WD_TIMER0_RESET_L2RESET (1 << 0) +/* Shared debug domain reset */ +#define NB_GLOBAL_WD_TIMER0_RESET_PRESETDBG (1 << 1) +/* Individual CPU debug PTM, watchpoint and breakpoint logic reset */ +#define NB_GLOBAL_WD_TIMER0_RESET_CPU_DBGRESET_MASK 0x000000F0 +#define NB_GLOBAL_WD_TIMER0_RESET_CPU_DBGRESET_SHIFT 4 +/* Individual CPU core and VFP/NEON logic reset */ +#define NB_GLOBAL_WD_TIMER0_RESET_CPU_CORERESET_MASK 0x00000F00 +#define NB_GLOBAL_WD_TIMER0_RESET_CPU_CORERESET_SHIFT 8 +/* Individual CPU por-on-reset */ +#define NB_GLOBAL_WD_TIMER0_RESET_CPU_PORESET_MASK 0x0000F000 +#define NB_GLOBAL_WD_TIMER0_RESET_CPU_PORESET_SHIFT 12 + +/**** WD_Timer1_Reset register ****/ +/* Shared L2 memory system, interrupt controller and timer logic reset */ +#define NB_GLOBAL_WD_TIMER1_RESET_L2RESET (1 << 0) +/* Shared debug domain reset */ +#define NB_GLOBAL_WD_TIMER1_RESET_PRESETDBG (1 << 1) +/* Individual CPU debug PTM, watchpoint and breakpoint logic reset */ +#define NB_GLOBAL_WD_TIMER1_RESET_CPU_DBGRESET_MASK 0x000000F0 +#define NB_GLOBAL_WD_TIMER1_RESET_CPU_DBGRESET_SHIFT 4 +/* Individual CPU core and VFP/NEON logic reset */ +#define NB_GLOBAL_WD_TIMER1_RESET_CPU_CORERESET_MASK 0x00000F00 +#define NB_GLOBAL_WD_TIMER1_RESET_CPU_CORERESET_SHIFT 8 +/* Individual CPU por-on-reset */ +#define NB_GLOBAL_WD_TIMER1_RESET_CPU_PORESET_MASK 0x0000F000 +#define NB_GLOBAL_WD_TIMER1_RESET_CPU_PORESET_SHIFT 12 + +/**** WD_Timer2_Reset register ****/ +/* Shared L2 memory system, interrupt controller and timer logic reset */ +#define NB_GLOBAL_WD_TIMER2_RESET_L2RESET (1 << 0) +/* Shared debug domain reset */ +#define NB_GLOBAL_WD_TIMER2_RESET_PRESETDBG (1 << 1) +/* Individual CPU debug, PTM, watchpoint and breakpoint logic reset */ +#define NB_GLOBAL_WD_TIMER2_RESET_CPU_DBGRESET_MASK 0x000000F0 +#define NB_GLOBAL_WD_TIMER2_RESET_CPU_DBGRESET_SHIFT 4 +/* Individual CPU core and VFP/NEON logic reset */ +#define NB_GLOBAL_WD_TIMER2_RESET_CPU_CORERESET_MASK 0x00000F00 +#define NB_GLOBAL_WD_TIMER2_RESET_CPU_CORERESET_SHIFT 8 +/* Individual CPU por-on-reset */ +#define NB_GLOBAL_WD_TIMER2_RESET_CPU_PORESET_MASK 0x0000F000 +#define NB_GLOBAL_WD_TIMER2_RESET_CPU_PORESET_SHIFT 12 + +/**** WD_Timer3_Reset register ****/ +/* Shared L2 memory system, interrupt controller and timer logic reset */ +#define NB_GLOBAL_WD_TIMER3_RESET_L2RESET (1 << 0) +/* Shared debug domain reset */ +#define NB_GLOBAL_WD_TIMER3_RESET_PRESETDBG (1 << 1) +/* Individual CPU debug, PTM, watchpoint and breakpoint logic reset */ +#define NB_GLOBAL_WD_TIMER3_RESET_CPU_DBGRESET_MASK 0x000000F0 +#define NB_GLOBAL_WD_TIMER3_RESET_CPU_DBGRESET_SHIFT 4 +/* Individual CPU core and VFP/NEON logic reset */ +#define NB_GLOBAL_WD_TIMER3_RESET_CPU_CORERESET_MASK 0x00000F00 +#define NB_GLOBAL_WD_TIMER3_RESET_CPU_CORERESET_SHIFT 8 +/* Individual CPU por-on-reset */ +#define NB_GLOBAL_WD_TIMER3_RESET_CPU_PORESET_MASK 0x0000F000 +#define NB_GLOBAL_WD_TIMER3_RESET_CPU_PORESET_SHIFT 12 + +/**** DDRC_Hold_Reset register ****/ +/* DDR Control and PHY memory mapped registers reset control +0 - Reset is deasserted. +1 - Reset is asserted (active). */ +#define NB_GLOBAL_DDRC_HOLD_RESET_APB_SYNC_RESET (1 << 0) +/* DDR Control Core reset control +0 - Reset is deasserted. +1 - Reset is asserted. +This field must be set to 0 to start the initialization process after configuring the DDR Controller registers. */ +#define NB_GLOBAL_DDRC_HOLD_RESET_CORE_SYNC_RESET (1 << 1) +/* DDR Control AXI Interface reset control +0 - Reset is deasserted. +1 - Reset is asserted. +This field must not be set to 0 while core_sync_reset is set to 1. */ +#define NB_GLOBAL_DDRC_HOLD_RESET_AXI_SYNC_RESET (1 << 2) +/* DDR PUB Controller reset control +0 - Reset is deasserted. +1 - Reset is asserted. +This field must be set to 0 to start the initialization process after configuring the PUB Controller registers. */ +#define NB_GLOBAL_DDRC_HOLD_RESET_PUB_CTL_SYNC_RESET (1 << 3) +/* DDR PUB SDR Controller reset control +0 - Reset is deasserted. +1 - Reset is asserted. +This field must be set to 0 to start the initialization process after configuring the PUB Controller registers. */ +#define NB_GLOBAL_DDRC_HOLD_RESET_PUB_SDR_SYNC_RESET (1 << 4) +/* DDR PHY reset control +0 - Reset is deasserted. +1 - Reset is asserted. */ +#define NB_GLOBAL_DDRC_HOLD_RESET_PHY_SYNC_RESET (1 << 5) +/* Memory initialization input to DDR SRAM for parity check support */ +#define NB_GLOBAL_DDRC_HOLD_RESET_DDR_UNIT_MEM_INIT (1 << 6) + +/**** Fabric_Software_Reset register ****/ +/* Write 1 apply the software reset. */ +#define NB_GLOBAL_FABRIC_SOFTWARE_RESET_SWRESET_REQ (1 << 0) +/* Defines the level of software reset: +0x0 - fabric: Fabric reset +0x1 - gic: GIC reset +0x2 - smmu: SMMU reset */ +#define NB_GLOBAL_FABRIC_SOFTWARE_RESET_LEVEL_MASK 0x0000000E +#define NB_GLOBAL_FABRIC_SOFTWARE_RESET_LEVEL_SHIFT 1 +/* Fabric reset */ +#define NB_GLOBAL_FABRIC_SOFTWARE_RESET_LEVEL_FABRIC \ + (0x0 << NB_GLOBAL_FABRIC_SOFTWARE_RESET_LEVEL_SHIFT) +/* GIC reset */ +#define NB_GLOBAL_FABRIC_SOFTWARE_RESET_LEVEL_GIC \ + (0x1 << NB_GLOBAL_FABRIC_SOFTWARE_RESET_LEVEL_SHIFT) +/* SMMU reset */ +#define NB_GLOBAL_FABRIC_SOFTWARE_RESET_LEVEL_SMMU \ + (0x2 << NB_GLOBAL_FABRIC_SOFTWARE_RESET_LEVEL_SHIFT) +/* CPUn waiting for interrupt enable. +Defines which CPU WFI indication to wait before applying the software reset. */ +#define NB_GLOBAL_FABRIC_SOFTWARE_RESET_WFI_MASK_MASK 0x000F0000 +#define NB_GLOBAL_FABRIC_SOFTWARE_RESET_WFI_MASK_SHIFT 16 + +/**** CPUs_Power_Ctrl register ****/ +/* L2 WFI enable +When all the processors are in WFI mode or powered-down, the shared L2 memory system Power Management controller resumes clock on any interrupt. +Power management controller resumes clock on snoop request. +NOT IMPLEMENTED */ +#define NB_GLOBAL_CPUS_POWER_CTRL_L2WFI_EN (1 << 0) +/* L2 WFI status */ +#define NB_GLOBAL_CPUS_POWER_CTRL_L2WFI_STATUS (1 << 1) +/* L2 RAMs Power Down +Power down the L2 RAMs. L2 caches must be flushed prior to entering this state. */ +#define NB_GLOBAL_CPUS_POWER_CTRL_L2RAMS_PWRDN_EN (1 << 2) +/* L2 RAMs power down status */ +#define NB_GLOBAL_CPUS_POWER_CTRL_L2RAMS_PWRDN_STATUS (1 << 3) +/* CPU state condition to enable L2 RAM power down +0 - Power down +1 - WFI +NOT IMPLEMENTED */ +#define NB_GLOBAL_CPUS_POWER_CTRL_L2RAMS_PWRDN_CPUS_STATE_MASK 0x000000F0 +#define NB_GLOBAL_CPUS_POWER_CTRL_L2RAMS_PWRDN_CPUS_STATE_SHIFT 4 +/* Enable external debugger over power-down. +Provides support for external debug over power down. If any or all of the processors are powered down, the SoC can still use the debug facilities if the debug PCLKDBG domain is powered up. */ +#define NB_GLOBAL_CPUS_POWER_CTRL_EXT_DEBUGGER_OVER_PD_EN (1 << 8) +/* L2 hardware flush request. This signal indicates: +0 L2 hardware flush request is not asserted. flush is performed by SW +1 L2 hardware flush request is asserted by power management block as part of cluster rams power down flow. HW starts L2 flush flow when all CPUs are in WFI */ +#define NB_GLOBAL_CPUS_POWER_CTRL_L2FLUSH_EN (1 << 9) +/* Force wakeup the CPU in L2RAM power down +INTERNAL DEBUG PURPOSE ONLY */ +#define NB_GLOBAL_CPUS_POWER_CTRL_FORCE_CPUS_OK_PWRUP (1 << 27) +/* L2 RAMs power down SM status */ +#define NB_GLOBAL_CPUS_POWER_CTRL_L2RAMS_PWRDN_SM_STATUS_MASK 0xF0000000 +#define NB_GLOBAL_CPUS_POWER_CTRL_L2RAMS_PWRDN_SM_STATUS_SHIFT 28 + +/**** ACF_Base_High register ****/ +/* Coherency Fabric registers base [39:32]. */ +#define NB_GLOBAL_ACF_BASE_HIGH_BASE_39_32_MASK 0x000000FF +#define NB_GLOBAL_ACF_BASE_HIGH_BASE_39_32_SHIFT 0 +/* Coherency Fabric registers base [31:15] */ +#define NB_GLOBAL_ACF_BASE_LOW_BASED_31_15_MASK 0xFFFF8000 +#define NB_GLOBAL_ACF_BASE_LOW_BASED_31_15_SHIFT 15 + +/**** ACF_Control_Override register ****/ +/* Override the AWCACHE[0] and ARCACHE[0] outputs to be +non-bufferable. One bit exists for each master interface. +Connected to BUFFERABLEOVERRIDE[2:0] */ +#define NB_GLOBAL_ACF_CONTROL_OVERRIDE_BUFFOVRD_MASK 0x00000007 +#define NB_GLOBAL_ACF_CONTROL_OVERRIDE_BUFFOVRD_SHIFT 0 +/* Overrides the ARQOS and AWQOS input signals. One bit exists for each slave +interface. +Connected to QOSOVERRIDE[4:0] */ +#define NB_GLOBAL_ACF_CONTROL_OVERRIDE_QOSOVRD_MASK 0x000000F8 +#define NB_GLOBAL_ACF_CONTROL_OVERRIDE_QOSOVRD_SHIFT 3 +/* If LOW, then AC requests are never issued on the corresponding slave +interface. One bit exists for each slave interface. +Connected to ACCHANNELEN[4:0]. */ +#define NB_GLOBAL_ACF_CONTROL_OVERRIDE_ACE_CH_EN_MASK 0x00001F00 +#define NB_GLOBAL_ACF_CONTROL_OVERRIDE_ACE_CH_EN_SHIFT 8 +/* Internal register: +Enables 4k hazard of post-barrier vs pre-barrier transactions. Otherwise, 64B hazard granularity is applied. */ +#define NB_GLOBAL_ACF_CONTROL_OVERRIDE_DMB_4K_HAZARD_EN (1 << 13) + +/**** LGIC_Base_High register ****/ +/* GIC registers base [39:32]. +This value is sampled into the CP15 Configuration Base Address Register (CBAR) at reset. */ +#define NB_GLOBAL_LGIC_BASE_HIGH_BASE_39_32_MASK 0x000000FF +#define NB_GLOBAL_LGIC_BASE_HIGH_BASE_39_32_SHIFT 0 +#define NB_GLOBAL_LGIC_BASE_HIGH_BASE_43_32_MASK_PKR 0x00000FFF +#define NB_GLOBAL_LGIC_BASE_HIGH_BASE_43_32_SHIFT_PKR 0 +/* GIC registers base [31:15]. +This value is sampled into the CP15 Configuration Base Address Register (CBAR) at reset */ +#define NB_GLOBAL_LGIC_BASE_LOW_BASED_31_15_MASK 0xFFFF8000 +#define NB_GLOBAL_LGIC_BASE_LOW_BASED_31_15_SHIFT 15 + +/**** IOGIC_Base_High register ****/ +/* IOGIC registers base [39:32] */ +#define NB_GLOBAL_IOGIC_BASE_HIGH_BASE_39_32_MASK 0x000000FF +#define NB_GLOBAL_IOGIC_BASE_HIGH_BASE_39_32_SHIFT 0 +/* IOGIC registers base [31:15] */ +#define NB_GLOBAL_IOGIC_BASE_LOW_BASED_31_15_MASK 0xFFFF8000 +#define NB_GLOBAL_IOGIC_BASE_LOW_BASED_31_15_SHIFT 15 + +/**** IO_Wr_Split_Control register ****/ +/* Write splitters bypass. +[0] Splitter 0 bypass enable +[1] Splitter 1 bypass enable */ +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR_SPLT_BYPASS_MASK 0x00000003 +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR_SPLT_BYPASS_SHIFT 0 +/* Write splitters store and forward. +If store and forward is disabled, splitter does not check non-active BE in the middle of a transaction. */ +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR_SPLT_ST_FW_MASK 0x0000000C +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR_SPLT_ST_FW_SHIFT 2 +/* Write splitters unmodify snoop type. +Disables modifying snoop type from Clean & Invalidate to Invalidate when conditions enable it. Only split operation to 64B is applied. */ +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR_SPLT_UNMODIFY_SNP_MASK 0x00000030 +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR_SPLT_UNMODIFY_SNP_SHIFT 4 +/* Write splitters unsplit non-coherent access. +Disables splitting of non-coherent access to cache-line chunks. */ +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR_SPLT_UNSPLIT_NOSNP_MASK 0x000000C0 +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR_SPLT_UNSPLIT_NOSNP_SHIFT 6 +/* Write splitter rate limit. */ +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR0_SPLT_RATE_LIMIT_MASK 0x00001F00 +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR0_SPLT_RATE_LIMIT_SHIFT 8 +/* Write splitter rate limit */ +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR1_SPLT_RATE_LIMIT_MASK 0x0003E000 +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR1_SPLT_RATE_LIMIT_SHIFT 13 +/* Write splitters 64bit remap enable +Enables remapping of 64bit transactions */ +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR_SPLT_REMAP_64BIT_EN_MASK 0x000C0000 +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR_SPLT_REMAP_64BIT_EN_SHIFT 18 +/* Clear is not supported. This bit was changed to wr_pack_disable. +In default mode, AWADDR waits for WDATA. */ +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR_SPLT_CLEAR_MASK 0xC0000000 +#define NB_GLOBAL_IO_WR_SPLIT_CONTROL_WR_SPLT_CLEAR_SHIFT 30 + +/**** IO_Rd_ROB_Control register ****/ +/* Read ROB Bypass +[0] Rd ROB 0 bypass enable. +[1] Rd ROB 1 bypass enable. */ +#define NB_GLOBAL_IO_RD_ROB_CONTROL_RD_ROB_BYPASS_MASK 0x00000003 +#define NB_GLOBAL_IO_RD_ROB_CONTROL_RD_ROB_BYPASS_SHIFT 0 +/* Read ROB in order. +Return data in the order of request acceptance. */ +#define NB_GLOBAL_IO_RD_ROB_CONTROL_RD_ROB_INORDER_MASK 0x0000000C +#define NB_GLOBAL_IO_RD_ROB_CONTROL_RD_ROB_INORDER_SHIFT 2 +/* Read ROB response rate +When enabled drops one cycle from back to back read responses */ +#define NB_GLOBAL_IO_RD_ROB_CONTROL_RD_ROB_RSP_RATE_MASK 0x00000030 +#define NB_GLOBAL_IO_RD_ROB_CONTROL_RD_ROB_RSP_RATE_SHIFT 4 +/* Read splitter rate limit */ +#define NB_GLOBAL_IO_RD_ROB_CONTROL_RD0_ROB_RATE_LIMIT_MASK 0x00001F00 +#define NB_GLOBAL_IO_RD_ROB_CONTROL_RD0_ROB_RATE_LIMIT_SHIFT 8 +/* Read splitter rate limit */ +#define NB_GLOBAL_IO_RD_ROB_CONTROL_RD1_ROB_RATE_LIMIT_MASK 0x0003E000 +#define NB_GLOBAL_IO_RD_ROB_CONTROL_RD1_ROB_RATE_LIMIT_SHIFT 13 + +/**** SB_PoS_Error_Log_1 register ****/ +/* Error Log 1 +[7:0] address_high +[16:8] request id +[18:17] bresp */ +#define NB_GLOBAL_SB_POS_ERROR_LOG_1_ERR_LOG_MASK 0x7FFFFFFF +#define NB_GLOBAL_SB_POS_ERROR_LOG_1_ERR_LOG_SHIFT 0 +/* Valid logged error +Set on SB PoS error occurrence on capturing the error information. Subsequent errors will not be captured until the valid bit is cleared. +The SB PoS reports on write errors. +When valid, an interrupt is set in the NB Cause Register. */ +#define NB_GLOBAL_SB_POS_ERROR_LOG_1_VALID (1 << 31) + +/**** MSIx_Error_Log register ****/ +/* Error Log +Corresponds to MSIx address message [30:0]. */ +#define NB_GLOBAL_MSIX_ERROR_LOG_ERR_LOG_MASK 0x7FFFFFFF +#define NB_GLOBAL_MSIX_ERROR_LOG_ERR_LOG_SHIFT 0 +/* Valid logged error */ +#define NB_GLOBAL_MSIX_ERROR_LOG_VALID (1 << 31) + +/**** Error_Cause register ****/ +/* Received msix is not mapped to local GIC or IO-GIC spin */ +#define NB_GLOBAL_ERROR_CAUSE_MSIX_ERR_INT (1 << 2) +/* Coresight timestamp overflow */ +#define NB_GLOBAL_ERROR_CAUSE_CORESIGHT_TS_OVERFLOW (1 << 3) +/* Write data parity error from SB channel 0. */ +#define NB_GLOBAL_ERROR_CAUSE_SB0_WRDATA_PERR (1 << 4) +/* Write data parity error from SB channel 1. */ +#define NB_GLOBAL_ERROR_CAUSE_SB1_WRDATA_PERR (1 << 5) +/* Read data parity error from SB slaves. */ +#define NB_GLOBAL_ERROR_CAUSE_SB_SLV_RDATA_PERR (1 << 6) +/* Local GIC uncorrectable ECC error */ +#define NB_GLOBAL_ERROR_CAUSE_LOCAL_GIC_ECC_FATAL (1 << 7) +/* SB PoS error */ +#define NB_GLOBAL_ERROR_CAUSE_SB_POS_ERR (1 << 8) +/* Coherent fabric error summary interrupt */ +#define NB_GLOBAL_ERROR_CAUSE_ACF_ERRORIRQ (1 << 9) +/* Error indicator for AXI write transactions with a BRESP error condition. Writing 0 to bit[29] of the L2ECTLR clears the error indicator connected to CA15 nAXIERRIRQ. */ +#define NB_GLOBAL_ERROR_CAUSE_CPU_AXIERRIRQ (1 << 10) +/* Error indicator for: L2 RAM double-bit ECC error, illegal writes to the GIC memory-map region. */ +#define NB_GLOBAL_ERROR_CAUSE_CPU_INTERRIRQ (1 << 12) +/* DDR cause summery interrupt */ +#define NB_GLOBAL_ERROR_CAUSE_DDR_CAUSE_SUM (1 << 14) + +/**** QoS_Peak_Control register ****/ +/* Peak Read Low Threshold +When the number of outstanding read transactions from SB masters is below this value, the CPU is assigned high-priority QoS. */ +#define NB_GLOBAL_QOS_PEAK_CONTROL_PEAK_RD_L_THRESHOLD_MASK 0x0000007F +#define NB_GLOBAL_QOS_PEAK_CONTROL_PEAK_RD_L_THRESHOLD_SHIFT 0 +/* Peak Read High Threshold +When the number of outstanding read transactions from SB masters exceeds this value, the CPU is assigned high-priority QoS. */ +#define NB_GLOBAL_QOS_PEAK_CONTROL_PEAK_RD_H_THRESHOLD_MASK 0x00007F00 +#define NB_GLOBAL_QOS_PEAK_CONTROL_PEAK_RD_H_THRESHOLD_SHIFT 8 +/* Peak Write Low Threshold +When the number of outstanding write transactions from SB masters is below this value, the CPU is assigned high-priority QoS */ +#define NB_GLOBAL_QOS_PEAK_CONTROL_PEAK_WR_L_THRESHOLD_MASK 0x007F0000 +#define NB_GLOBAL_QOS_PEAK_CONTROL_PEAK_WR_L_THRESHOLD_SHIFT 16 +/* Peak Write High Threshold +When the number of outstanding write transactions from SB masters exceeds this value, the CPU is assigned high-priority QoS. */ +#define NB_GLOBAL_QOS_PEAK_CONTROL_PEAK_WR_H_THRESHOLD_MASK 0x7F000000 +#define NB_GLOBAL_QOS_PEAK_CONTROL_PEAK_WR_H_THRESHOLD_SHIFT 24 + +/**** QoS_Set_Control register ****/ +/* CPU Low priority Read QoS */ +#define NB_GLOBAL_QOS_SET_CONTROL_CPU_LP_ARQOS_MASK 0x0000000F +#define NB_GLOBAL_QOS_SET_CONTROL_CPU_LP_ARQOS_SHIFT 0 +/* CPU High priority Read QoS */ +#define NB_GLOBAL_QOS_SET_CONTROL_CPU_HP_ARQOS_MASK 0x000000F0 +#define NB_GLOBAL_QOS_SET_CONTROL_CPU_HP_ARQOS_SHIFT 4 +/* CPU Low priority Write QoS */ +#define NB_GLOBAL_QOS_SET_CONTROL_CPU_LP_AWQOS_MASK 0x00000F00 +#define NB_GLOBAL_QOS_SET_CONTROL_CPU_LP_AWQOS_SHIFT 8 +/* CPU High priority Write QoS */ +#define NB_GLOBAL_QOS_SET_CONTROL_CPU_HP_AWQOS_MASK 0x0000F000 +#define NB_GLOBAL_QOS_SET_CONTROL_CPU_HP_AWQOS_SHIFT 12 +/* SB Low priority Read QoS */ +#define NB_GLOBAL_QOS_SET_CONTROL_SB_LP_ARQOS_MASK 0x000F0000 +#define NB_GLOBAL_QOS_SET_CONTROL_SB_LP_ARQOS_SHIFT 16 +/* SB Low-priority Write QoS */ +#define NB_GLOBAL_QOS_SET_CONTROL_SB_LP_AWQOS_MASK 0x00F00000 +#define NB_GLOBAL_QOS_SET_CONTROL_SB_LP_AWQOS_SHIFT 20 + +/**** DDR_QoS register ****/ +/* High Priority Read Threshold +Limits the number of outstanding high priority reads in the system through the memory controller. +This parameter is programmed in conjunction with number of outstanding high priority reads supported by the DDR controller. */ +#define NB_GLOBAL_DDR_QOS_HIGH_PRIO_THRESHOLD_MASK 0x0000007F +#define NB_GLOBAL_DDR_QOS_HIGH_PRIO_THRESHOLD_SHIFT 0 +/* DDR Low Priority QoS +Fabric priority below this value is mapped to DDR low priority queue. */ +#define NB_GLOBAL_DDR_QOS_LP_QOS_MASK 0x00000F00 +#define NB_GLOBAL_DDR_QOS_LP_QOS_SHIFT 8 + +/**** ACF_Misc register ****/ +/* Disable DDR Write Chop +Performance optimization feature to chop non-active data beats to the DDR. */ +#define NB_GLOBAL_ACF_MISC_DDR_WR_CHOP_DIS (1 << 0) +/* Disable SB-2-SB path through NB fabric. */ +#define NB_GLOBAL_ACF_MISC_SB2SB_PATH_DIS (1 << 1) +/* Disable ETR tracing to non-DDR. */ +#define NB_GLOBAL_ACF_MISC_ETR2SB_PATH_DIS (1 << 2) +/* Disable ETR tracing to non-DDR. */ +#define NB_GLOBAL_ACF_MISC_CPU2MSIX_DIS (1 << 3) +/* Disable CPU generation of MSIx +By default, the CPU can set any MSIx message results by setting any SPIn bit in the local and IO-GIC. */ +#define NB_GLOBAL_ACF_MISC_MSIX_TERMINATE_DIS (1 << 4) +/* Disable snoop override for MSIx +By default, an MSIx transaction is downgraded to non-coherent. */ +#define NB_GLOBAL_ACF_MISC_MSIX_SNOOPOVRD_DIS (1 << 5) +/* POS bypass */ +#define NB_GLOBAL_ACF_MISC_POS_BYPASS (1 << 6) +/* PoS ReadStronglyOrdered enable +SO read forces flushing of all prior writes */ +#define NB_GLOBAL_ACF_MISC_POS_RSO_EN (1 << 7) +/* WRAP to INC transfer enable */ +#define NB_GLOBAL_ACF_MISC_POS_WRAP2INC (1 << 8) +/* PoS DSB flush Disable +On DSB from CPU, PoS blocks the progress of post-barrier reads and writes until all pre-barrier writes have been completed. */ +#define NB_GLOBAL_ACF_MISC_POS_DSB_FLUSH_DIS (1 << 9) +/* PoS DMB Flush Disable +On DMB from CPU, the PoS blocks the progress of post-barrier non-buffereable reads or writes when there are outstanding non-bufferable writes that have not yet been completed. +Other access types are hazard check against the pre-barrier requests. */ +#define NB_GLOBAL_ACF_MISC_POS_DMB_FLUSH_DIS (1 << 10) +/* change DMB functionality to DSB (block and drain) */ +#define NB_GLOBAL_ACF_MISC_POS_DMB_TO_DSB_EN (1 << 11) +/* Disable write after read stall when accessing IO fabric slaves. */ +#define NB_GLOBAL_ACF_MISC_M0_WAR_STALL_DIS (1 << 12) +/* Disable write after read stall when accessing DDR */ +#define NB_GLOBAL_ACF_MISC_M1_WAR_STALL_DIS (1 << 13) +/* Disable counter (wait 1000 NB cycles) before applying PoS enable/disable configuration */ +#define NB_GLOBAL_ACF_MISC_POS_CONFIG_CNT_DIS (1 << 14) +/* Disable wr spliter A0 bug fixes */ +#define NB_GLOBAL_ACF_MISC_WRSPLT_ALPINE_M0_MODE (1 << 16) +/* Disable wr spliter PKR bug fixes */ +#define NB_GLOBAL_ACF_MISC_WRSPLT_ALPINE_A0_MODE (1 << 17) +/* Override the address parity calucation for write transactions going to IO-fabric */ +#define NB_GLOBAL_ACF_MISC_NB_NIC_AWADDR_PAR_OVRD (1 << 18) +/* Override the data parity calucation for write transactions going to IO-fabric */ +#define NB_GLOBAL_ACF_MISC_NB_NIC_WDATA_PAR_OVRD (1 << 19) +/* Override the address parity calucation for read transactions going to IO-fabric */ +#define NB_GLOBAL_ACF_MISC_NB_NIC_ARADDR_PAR_OVRD (1 << 20) +/* Halts CPU AXI interface (Ar/Aw channels), not allowing the CPU to send additional transactions */ +#define NB_GLOBAL_ACF_MISC_CPU_AXI_HALT (1 << 23) +/* Disable early arbar termination when fabric write buffer is enabled. */ +#define NB_GLOBAL_ACF_MISC_CCIWB_EARLY_ARBAR_TERM_DIS (1 << 24) +/* Enable wire interrupts connectivity to IO-GIC IRQs */ +#define NB_GLOBAL_ACF_MISC_IOGIC_CHIP_SPI_EN (1 << 25) +/* Enable DMB flush request to NB to SB PoS when barrier is terminted inside the processor cluster */ +#define NB_GLOBAL_ACF_MISC_CPU_DSB_FLUSH_DIS (1 << 26) +/* Enable DMB flush request to NB to SB PoS when barrier is terminted inside the processor cluster */ +#define NB_GLOBAL_ACF_MISC_CPU_DMB_FLUSH_DIS (1 << 27) +/* Peakrock only: remap CPU address above 40 bits to Slave Error +INTERNAL */ +#define NB_GLOBAL_ACF_MISC_ADDR43_40_REMAP_DIS (1 << 28) +/* Enable CPU WriteUnique to WriteNoSnoop trasform */ +#define NB_GLOBAL_ACF_MISC_CPU_WU2WNS_EN (1 << 29) +/* Disable device after device check */ +#define NB_GLOBAL_ACF_MISC_WR_POS_DEV_AFTER_DEV_DIS (1 << 30) +/* Disable wrap to inc on write */ +#define NB_GLOBAL_ACF_MISC_WR_INC2WRAP_EN (1 << 31) + +/**** Config_Bus_Control register ****/ +/* Write slave error enable */ +#define NB_GLOBAL_CONFIG_BUS_CONTROL_WR_SLV_ERR_EN (1 << 0) +/* Write decode error enable */ +#define NB_GLOBAL_CONFIG_BUS_CONTROL_WR_DEC_ERR_EN (1 << 1) +/* Read slave error enable */ +#define NB_GLOBAL_CONFIG_BUS_CONTROL_RD_SLV_ERR_EN (1 << 2) +/* Read decode error enable */ +#define NB_GLOBAL_CONFIG_BUS_CONTROL_RD_DEC_ERR_EN (1 << 3) +/* Ignore Write ID */ +#define NB_GLOBAL_CONFIG_BUS_CONTROL_IGNORE_WR_ID (1 << 4) +/* Timeout limit before terminating configuration bus access with slave error */ +#define NB_GLOBAL_CONFIG_BUS_CONTROL_TIMEOUT_LIMIT_MASK 0xFFFFFF00 +#define NB_GLOBAL_CONFIG_BUS_CONTROL_TIMEOUT_LIMIT_SHIFT 8 + +/**** Pos_ID_Match register ****/ +/* Enable Device (GRE and nGRE) after Device ID hazard */ +#define NB_GLOBAL_POS_ID_MATCH_ENABLE (1 << 0) +/* ID Field Mask +If set, corresonpding ID bits are not used for ID match */ +#define NB_GLOBAL_POS_ID_MATCH_MASK_MASK 0xFFFF0000 +#define NB_GLOBAL_POS_ID_MATCH_MASK_SHIFT 16 + +/**** sb_sel_override_awuser register ****/ +/* Select whether to use transaction awuser or sb_override_awuser value for awuser field on outgoing write transactions to SB. +Each bit if set to 1 selects the corresponding sb_override_awuser bit. Otherwise, selects the corersponding transaction awuser bit. */ +#define NB_GLOBAL_SB_SEL_OVERRIDE_AWUSER_SEL_MASK 0x03FFFFFF +#define NB_GLOBAL_SB_SEL_OVERRIDE_AWUSER_SEL_SHIFT 0 + +/**** sb_override_awuser register ****/ +/* Awuser to use on overriden transactions +Only applicable if sel_override_awuser.sel is set to 1'b1 for the coressponding bit */ +#define NB_GLOBAL_SB_OVERRIDE_AWUSER_AWUSER_MASK 0x03FFFFFF +#define NB_GLOBAL_SB_OVERRIDE_AWUSER_AWUSER_SHIFT 0 + +/**** sb_sel_override_aruser register ****/ +/* Select whether to use transaction aruser or sb_override_aruser value for aruser field on outgoing read transactions to SB. +Each bit if set to 1 selects the corresponding sb_override_aruser bit. Otherwise, selects the corersponding transaction aruser bit. */ +#define NB_GLOBAL_SB_SEL_OVERRIDE_ARUSER_SEL_MASK 0x03FFFFFF +#define NB_GLOBAL_SB_SEL_OVERRIDE_ARUSER_SEL_SHIFT 0 + +/**** sb_override_aruser register ****/ +/* Aruser to use on overriden transactions +Only applicable if sb_sel_override_aruser.sel is set to 1'b1 for the coressponding bit */ +#define NB_GLOBAL_SB_OVERRIDE_ARUSER_ARUSER_MASK 0x03FFFFFF +#define NB_GLOBAL_SB_OVERRIDE_ARUSER_ARUSER_SHIFT 0 + +/**** Coresight_PD register ****/ +/* ETF0 RAM force power down */ +#define NB_GLOBAL_CORESIGHT_PD_ETF0_RAM_FORCE_PD (1 << 0) +/* ETF1 RAM force power down */ +#define NB_GLOBAL_CORESIGHT_PD_ETF1_RAM_FORCE_PD (1 << 1) +/* ETF0 RAM force clock gate */ +#define NB_GLOBAL_CORESIGHT_PD_ETF0_RAM_FORCE_CG (1 << 2) +/* ETF1 RAM force clock gate */ +#define NB_GLOBAL_CORESIGHT_PD_ETF1_RAM_FORCE_CG (1 << 3) +/* APBIC clock enable */ +#define NB_GLOBAL_CORESIGHT_PD_APBICLKEN (1 << 4) +/* DAP system clock enable */ +#define NB_GLOBAL_CORESIGHT_PD_DAP_SYS_CLKEN (1 << 5) + +/**** Coresight_INTERNAL_0 register ****/ + +#define NB_GLOBAL_CORESIGHT_INTERNAL_0_CTIAPBSBYPASS (1 << 0) +/* CA15 CTM and Coresight CTI operate at same clock, bypass modes can be enabled but it's being set to bypass disable to break timing path. */ +#define NB_GLOBAL_CORESIGHT_INTERNAL_0_CISBYPASS (1 << 1) +/* CA15 CTM and Coresight CTI operate according to the same clock. +Bypass modes can be enabled, but it is set to bypass disable, to break the timing path. */ +#define NB_GLOBAL_CORESIGHT_INTERNAL_0_CIHSBYPASS_MASK 0x0000003C +#define NB_GLOBAL_CORESIGHT_INTERNAL_0_CIHSBYPASS_SHIFT 2 + +/**** Coresight_DBGROMADDR register ****/ +/* Valid signal for DBGROMADDR. +Connected to DBGROMADDRV */ +#define NB_GLOBAL_CORESIGHT_DBGROMADDR_VALID (1 << 0) +/* Specifies bits [39:12] of the ROM table physical address. */ +#define NB_GLOBAL_CORESIGHT_DBGROMADDR_ADDR_39_12_MASK 0x3FFFFFFC +#define NB_GLOBAL_CORESIGHT_DBGROMADDR_ADDR_39_12_SHIFT 2 + +/**** Coresight_DBGSELFADDR register ****/ +/* Valid signal for DBGROMADDR. +Connected to DBGROMADDRV */ +#define NB_GLOBAL_CORESIGHT_DBGSELFADDR_VALID (1 << 0) +/* Specifies bits [18:17] of the two's complement signed offset from the ROM table physical address to the physical address where the debug registers are memory-mapped. +Note: The CA15 debug unit starts at offset 0x1 within the Coresight cluster. */ +#define NB_GLOBAL_CORESIGHT_DBGSELFADDR_ADDR_18_17_MASK 0x00000180 +#define NB_GLOBAL_CORESIGHT_DBGSELFADDR_ADDR_18_17_SHIFT 7 +/* Specifies bits [39:19] of the two's complement signed offset from the ROM table physical address to the physical address where the debug registers are memory-mapped. +Note: The CA15 debug unit starts at offset 0x1 within the Coresight cluster, so this offset if fixed to zero. */ +#define NB_GLOBAL_CORESIGHT_DBGSELFADDR_ADDR_39_19_MASK 0x3FFFFE00 +#define NB_GLOBAL_CORESIGHT_DBGSELFADDR_ADDR_39_19_SHIFT 9 + +/**** SB_force_same_id_cfg_0 register ****/ +/* Enables force same id mechanism for SB port 0 */ +#define NB_GLOBAL_SB_FORCE_SAME_ID_CFG_0_FORCE_SAME_ID_EN (1 << 0) +/* Enables MSIx stall when write transactions from same ID mechanism are in progress for SB port 0 */ +#define NB_GLOBAL_SB_FORCE_SAME_ID_CFG_0_FORCE_SAME_ID_MSIX_STALL_EN (1 << 1) +/* Mask for choosing which ID bits to match for indicating the originating master */ +#define NB_GLOBAL_SB_FORCE_SAME_ID_CFG_0_SB_MSTR_ID_MASK_MASK 0x000000F8 +#define NB_GLOBAL_SB_FORCE_SAME_ID_CFG_0_SB_MSTR_ID_MASK_SHIFT 3 + +/**** SB_force_same_id_cfg_1 register ****/ +/* Enables force same id mechanism for SB port 1 */ +#define NB_GLOBAL_SB_FORCE_SAME_ID_CFG_1_FORCE_SAME_ID_EN (1 << 0) +/* Enables MSIx stall when write transactions from same ID mechanism are in progress for SB port 1 */ +#define NB_GLOBAL_SB_FORCE_SAME_ID_CFG_1_FORCE_SAME_ID_MSIX_STALL_EN (1 << 1) +/* Mask for choosing which ID bits to match for indicating the originating master */ +#define NB_GLOBAL_SB_FORCE_SAME_ID_CFG_1_SB_MSTR_ID_MASK_MASK 0x000000F8 +#define NB_GLOBAL_SB_FORCE_SAME_ID_CFG_1_SB_MSTR_ID_MASK_SHIFT 3 + +/**** Cnt_Control register ****/ +/* System counter enable +Counter is enabled after reset. */ +#define NB_SYSTEM_COUNTER_CNT_CONTROL_EN (1 << 0) +/* System counter restart +Initial value is reloaded from Counter_Init_L and Counter_Init_H registers. +Transition from 0 to 1 reloads the register. */ +#define NB_SYSTEM_COUNTER_CNT_CONTROL_RESTART (1 << 1) +/* Disable CTI trigger out that halt the counter progress */ +#define NB_SYSTEM_COUNTER_CNT_CONTROL_CTI_TRIGOUT_HALT_DIS (1 << 2) +/* System counter tick +Specifies the counter tick rate relative to the Northbridge clock, e.g., the counter is incremented every 16 NB cycles if programmed to 0x0f. */ +#define NB_SYSTEM_COUNTER_CNT_CONTROL_SCALE_MASK 0x0000FF00 +#define NB_SYSTEM_COUNTER_CNT_CONTROL_SCALE_SHIFT 8 + +/**** CA15_RF_Misc register ****/ + +#define NB_RAMS_CONTROL_MISC_CA15_RF_MISC_NONECPU_RF_MISC_MASK 0x0000000F +#define NB_RAMS_CONTROL_MISC_CA15_RF_MISC_NONECPU_RF_MISC_SHIFT 0 + +#define NB_RAMS_CONTROL_MISC_CA15_RF_MISC_CPU_RF_MISC_MASK 0x00FFFF00 +#define NB_RAMS_CONTROL_MISC_CA15_RF_MISC_CPU_RF_MISC_SHIFT 8 +/* Pause for CPUs from the time all power is up to the time the SRAMs start opening. */ +#define NB_RAMS_CONTROL_MISC_CA15_RF_MISC_PWR_UP_PAUSE_MASK 0xF8000000 +#define NB_RAMS_CONTROL_MISC_CA15_RF_MISC_PWR_UP_PAUSE_SHIFT 27 + +/**** NB_RF_Misc register ****/ +/* SMMU TLB RAMs force power down */ +#define NB_RAMS_CONTROL_MISC_NB_RF_MISC_SMMU_RAM_FORCE_PD (1 << 0) + +/**** Lockn register ****/ +/* Semaphore Lock +CPU reads it: +If current value ==0, return 0 to CPU but set bit to 1. (CPU knows it captured the semaphore.) +If current value ==1, return 1 to CPU. (CPU knows it is already used and waits.) +CPU writes 0 to it to release the semaphore. */ +#define NB_SEMAPHORES_LOCKN_LOCK (1 << 0) + +/**** CA15_outputs_1 register ****/ +/* + */ +#define NB_DEBUG_CA15_OUTPUTS_1_STANDBYWFI_MASK 0x0000000F +#define NB_DEBUG_CA15_OUTPUTS_1_STANDBYWFI_SHIFT 0 +/* + */ +#define NB_DEBUG_CA15_OUTPUTS_1_CPU_PWR_DN_ACK_MASK 0x000000F0 +#define NB_DEBUG_CA15_OUTPUTS_1_CPU_PWR_DN_ACK_SHIFT 4 +/* + */ +#define NB_DEBUG_CA15_OUTPUTS_1_IRQOUT_N_MASK 0x00000F00 +#define NB_DEBUG_CA15_OUTPUTS_1_IRQOUT_N_SHIFT 8 +/* + */ +#define NB_DEBUG_CA15_OUTPUTS_1_FIQOUT_N_MASK 0x0000F000 +#define NB_DEBUG_CA15_OUTPUTS_1_FIQOUT_N_SHIFT 12 +/* + */ +#define NB_DEBUG_CA15_OUTPUTS_1_CNTHPIRQ_N_MASK 0x000F0000 +#define NB_DEBUG_CA15_OUTPUTS_1_CNTHPIRQ_N_SHIFT 16 +/* + */ +#define NB_DEBUG_CA15_OUTPUTS_1_NCNTPNSIRQ_N_MASK 0x00F00000 +#define NB_DEBUG_CA15_OUTPUTS_1_NCNTPNSIRQ_N_SHIFT 20 +/* + */ +#define NB_DEBUG_CA15_OUTPUTS_1_NCNTPSIRQ_N_MASK 0x0F000000 +#define NB_DEBUG_CA15_OUTPUTS_1_NCNTPSIRQ_N_SHIFT 24 +/* + */ +#define NB_DEBUG_CA15_OUTPUTS_1_NCNTVIRQ_N_MASK 0xF0000000 +#define NB_DEBUG_CA15_OUTPUTS_1_NCNTVIRQ_N_SHIFT 28 + +/**** CA15_outputs_2 register ****/ +/* + */ +#define NB_DEBUG_CA15_OUTPUTS_2_STANDBYWFIL2 (1 << 0) +/* + */ +#define NB_DEBUG_CA15_OUTPUTS_2_L2RAM_PWR_DN_ACK (1 << 1) +/* Indicates for each CPU if coherency is enabled + */ +#define NB_DEBUG_CA15_OUTPUTS_2_SMPEN_MASK 0x0000003C +#define NB_DEBUG_CA15_OUTPUTS_2_SMPEN_SHIFT 2 + +/**** cpu_msg register ****/ +/* Status/ASCII code */ +#define NB_DEBUG_CPU_MSG_STATUS_MASK 0x000000FF +#define NB_DEBUG_CPU_MSG_STATUS_SHIFT 0 +/* Toggle with each ASCII write */ +#define NB_DEBUG_CPU_MSG_ASCII_TOGGLE (1 << 8) +/* Signals ASCII */ +#define NB_DEBUG_CPU_MSG_ASCII (1 << 9) + +#define NB_DEBUG_CPU_MSG_RESERVED_11_10_MASK 0x00000C00 +#define NB_DEBUG_CPU_MSG_RESERVED_11_10_SHIFT 10 +/* Signals new section started in S/W */ +#define NB_DEBUG_CPU_MSG_SECTION_START (1 << 12) + +#define NB_DEBUG_CPU_MSG_RESERVED_13 (1 << 13) +/* Signals a single CPU is done. */ +#define NB_DEBUG_CPU_MSG_CPU_DONE (1 << 14) +/* Signals test is done */ +#define NB_DEBUG_CPU_MSG_TEST_DONE (1 << 15) + +/**** ddrc register ****/ +/* External DLL calibration request. Also compensates for VT variations, such as an external request for the controller (can be performed automatically by the controller at the normal settings). */ +#define NB_DEBUG_DDRC_DLL_CALIB_EXT_REQ (1 << 0) +/* External request to perform short (long is performed during initialization) and/or ODT calibration. */ +#define NB_DEBUG_DDRC_ZQ_SHORT_CALIB_EXT_REQ (1 << 1) +/* External request to perform a refresh command to a specific bank. Usually performed automatically by the controller, however, the controller supports disabling of the automatic mechanism, and use of an external pulse instead. */ +#define NB_DEBUG_DDRC_RANK_REFRESH_EXT_REQ_MASK 0x0000003C +#define NB_DEBUG_DDRC_RANK_REFRESH_EXT_REQ_SHIFT 2 + +/**** ddrc_phy_smode_control register ****/ +/* DDR PHY special mode */ +#define NB_DEBUG_DDRC_PHY_SMODE_CONTROL_CTL_MASK 0x0000FFFF +#define NB_DEBUG_DDRC_PHY_SMODE_CONTROL_CTL_SHIFT 0 + +/**** ddrc_phy_smode_status register ****/ +/* DDR PHY special mode */ +#define NB_DEBUG_DDRC_PHY_SMODE_STATUS_STT_MASK 0x0000FFFF +#define NB_DEBUG_DDRC_PHY_SMODE_STATUS_STT_SHIFT 0 + +/**** pmc register ****/ +/* Enable system control on NB DRO */ +#define NB_DEBUG_PMC_SYS_EN (1 << 0) +/* NB PMC HVT35 counter value */ +#define NB_DEBUG_PMC_HVT35_VAL_14_0_MASK 0x0000FFFE +#define NB_DEBUG_PMC_HVT35_VAL_14_0_SHIFT 1 +/* NB PMC SVT31 counter value */ +#define NB_DEBUG_PMC_SVT31_VAL_14_0_MASK 0x7FFF0000 +#define NB_DEBUG_PMC_SVT31_VAL_14_0_SHIFT 16 + +/**** cpus_general register ****/ +/* Swaps sysaddr[16:14] with sysaddr[19:17] for DDR access*/ +#define NB_DEBUG_CPUS_GENERAL_ADDR_MAP_ECO (1 << 23) + +/**** cpus_int_out register ****/ +/* Defines which CPUs' FIQ will be triggered out through the cpus_int_out[1] pinout. */ +#define NB_DEBUG_CPUS_INT_OUT_FIQ_EN_MASK 0x0000000F +#define NB_DEBUG_CPUS_INT_OUT_FIQ_EN_SHIFT 0 +/* Defines which CPUs' IRQ will be triggered out through the cpus_int_out[0] pinout. */ +#define NB_DEBUG_CPUS_INT_OUT_IRQ_EN_MASK 0x000000F0 +#define NB_DEBUG_CPUS_INT_OUT_IRQ_EN_SHIFT 4 +/* Defines which CPUs' SEI will be triggered out through the cpus_int_out[0] pinout. */ +#define NB_DEBUG_CPUS_INT_OUT_IRQ_SEI_EN_MASK 0x00000F00 +#define NB_DEBUG_CPUS_INT_OUT_IRQ_SEI_EN_SHIFT 8 + +/**** latch_pc_req register ****/ +/* If set, request to latch execution PC from processor cluster */ +#define NB_DEBUG_LATCH_PC_REQ_EN (1 << 0) +/* target CPU id to latch its execution PC */ +#define NB_DEBUG_LATCH_PC_REQ_CPU_ID_MASK 0x000000F0 +#define NB_DEBUG_LATCH_PC_REQ_CPU_ID_SHIFT 4 + +/**** latch_pc_low register ****/ +/* Set by hardware when the processor cluster ack the PC latch request. +Clear on read latch_pc_high */ +#define NB_DEBUG_LATCH_PC_LOW_VALID (1 << 0) +/* Latched PC value [31:1] */ +#define NB_DEBUG_LATCH_PC_LOW_VAL_MASK 0xFFFFFFFE +#define NB_DEBUG_LATCH_PC_LOW_VAL_SHIFT 1 + +/**** track_dump_ctrl register ****/ +/* [24:16]: Queue entry pointer +[2] Target queue: 1'b0: HazardTrack or 1'b1: AmiRMI queues +[1:0]: CCI target master: 2'b00: M0, 2'b01: M1, 2'b10: M2 */ +#define NB_DEBUG_TRACK_DUMP_CTRL_PTR_MASK 0x7FFFFFFF +#define NB_DEBUG_TRACK_DUMP_CTRL_PTR_SHIFT 0 +/* Track Dump Request +If set, queue entry info is latched on track_dump_rdata register. +Program the pointer and target queue. +This is a full handshake register. +Read bit from track_dump_rdata register. If set, clear the request field before triggering a new request. */ +#define NB_DEBUG_TRACK_DUMP_CTRL_REQ (1 << 31) + +/**** track_dump_rdata_0 register ****/ +/* Valid */ +#define NB_DEBUG_TRACK_DUMP_RDATA_0_VALID (1 << 0) +/* Low data */ +#define NB_DEBUG_TRACK_DUMP_RDATA_0_DATA_MASK 0xFFFFFFFE +#define NB_DEBUG_TRACK_DUMP_RDATA_0_DATA_SHIFT 1 + +/**** pos_track_dump_ctrl register ****/ +/* [24:16]: queue entry pointer */ +#define NB_DEBUG_POS_TRACK_DUMP_CTRL_PTR_MASK 0x7FFFFFFF +#define NB_DEBUG_POS_TRACK_DUMP_CTRL_PTR_SHIFT 0 +/* Track Dump Request +If set, queue entry info is latched on track_dump_rdata register. +Program the pointer and target queue. +This is a full handshake register +Read bit from track_dump_rdata register. If set, clear the request field before triggering a new request. */ +#define NB_DEBUG_POS_TRACK_DUMP_CTRL_REQ (1 << 31) + +/**** pos_track_dump_rdata_0 register ****/ +/* Valid */ +#define NB_DEBUG_POS_TRACK_DUMP_RDATA_0_VALID (1 << 0) +/* Low data */ +#define NB_DEBUG_POS_TRACK_DUMP_RDATA_0_DATA_MASK 0xFFFFFFFE +#define NB_DEBUG_POS_TRACK_DUMP_RDATA_0_DATA_SHIFT 1 + +/**** c2swb_track_dump_ctrl register ****/ +/* [24:16]: Queue entry pointer */ +#define NB_DEBUG_C2SWB_TRACK_DUMP_CTRL_PTR_MASK 0x7FFFFFFF +#define NB_DEBUG_C2SWB_TRACK_DUMP_CTRL_PTR_SHIFT 0 +/* Track Dump Request +If set, queue entry info is latched on track_dump_rdata register. +Program the pointer and target queue. +This is a full handshake register +Read bit from track_dump_rdata register. If set, clear the request field before triggering a new request. */ +#define NB_DEBUG_C2SWB_TRACK_DUMP_CTRL_REQ (1 << 31) + +/**** c2swb_track_dump_rdata_0 register ****/ +/* Valid */ +#define NB_DEBUG_C2SWB_TRACK_DUMP_RDATA_0_VALID (1 << 0) +/* Low data */ +#define NB_DEBUG_C2SWB_TRACK_DUMP_RDATA_0_DATA_MASK 0xFFFFFFFE +#define NB_DEBUG_C2SWB_TRACK_DUMP_RDATA_0_DATA_SHIFT 1 + +/**** cpus_track_dump_ctrl register ****/ +/* [24:16]: Queue entry pointer +[3:2] Target queue - 0:ASI, 1: AMI +[1:0]: Target Processor Cluster - 0: Cluster0, 1: Cluster1 */ +#define NB_DEBUG_CPUS_TRACK_DUMP_CTRL_PTR_MASK 0x7FFFFFFF +#define NB_DEBUG_CPUS_TRACK_DUMP_CTRL_PTR_SHIFT 0 +/* Track Dump Request +If set, queue entry info is latched on track_dump_rdata register. +Program the pointer and target queue. +This is a full handshake register +Read bit from track_dump_rdata register. If set, clear the request field before triggering a new request. */ +#define NB_DEBUG_CPUS_TRACK_DUMP_CTRL_REQ (1 << 31) + +/**** cpus_track_dump_rdata_0 register ****/ +/* Valid */ +#define NB_DEBUG_CPUS_TRACK_DUMP_RDATA_0_VALID (1 << 0) +/* Low data */ +#define NB_DEBUG_CPUS_TRACK_DUMP_RDATA_0_DATA_MASK 0xFFFFFFFE +#define NB_DEBUG_CPUS_TRACK_DUMP_RDATA_0_DATA_SHIFT 1 + +/**** c2swb_bar_ovrd_high register ****/ +/* Read barrier is progressed downstream when not terminated in the CCI. +By specification, barrier address is 0x0. +This register enables barrier address OVRD to a programmable value. */ +#define NB_DEBUG_C2SWB_BAR_OVRD_HIGH_RD_ADDR_OVRD_EN (1 << 0) +/* Address bits 39:32 */ +#define NB_DEBUG_C2SWB_BAR_OVRD_HIGH_ADDR_39_32_MASK 0x00FF0000 +#define NB_DEBUG_C2SWB_BAR_OVRD_HIGH_ADDR_39_32_SHIFT 16 + +/**** Config register ****/ +/* Individual processor control of the endianness configuration at reset. It sets the initial value of the EE bit in the CP15 System Control Register (SCTLR) related to CFGEND input: +little - 0x0: Little endian +bit - 0x1: Bit endian */ +#define NB_CPUN_CONFIG_STATUS_CONFIG_ENDIAN (1 << 0) +/* Individual processor control of the default exception handling state. It sets the initial value of the TE bit in the CP15 System Control Register (SCTLR) related to CFGTE input: +arm: 0x0: Exception operates ARM code. +Thumb: 0x1: Exception operates Thumb code. */ +#define NB_CPUN_CONFIG_STATUS_CONFIG_TE (1 << 1) +/* Individual processor control of the location of the exception vectors at reset. It sets the initial value of the V bit in the CP15 System Control Register (SCTLR). +Connected to VINITHIGH input. +low - 0x0: Exception vectors start at address 0x00000000. +high - 0x1: Exception vectors start at address 0xFFFF0000. */ +#define NB_CPUN_CONFIG_STATUS_CONFIG_VINITHI (1 << 2) +/* Individual processor control to disable write access to some secure CP15 registers +connected to CP15SDISABLE input. */ +#define NB_CPUN_CONFIG_STATUS_CONFIG_CP15DISABLE (1 << 3) +/* Force Write init implementation to ConfigAARch64 register */ +#define NB_CPUN_CONFIG_STATUS_CONFIG_AARCH64_REG_FORCE_WINIT (1 << 4) +/* Force Write Once implementation to ConfigAARch64 register. */ +#define NB_CPUN_CONFIG_STATUS_CONFIG_AARCH64_REG_FORCE_WONCE (1 << 5) + +/**** Config_AARch64 register ****/ +/* Individual processor register width state. The register width states are: +0 AArch32. +1 AArch64. +This signal is only sampled during reset of the processor. +This is Write Init register */ +#define NB_CPUN_CONFIG_STATUS_CONFIG_AARCH64_AA64_NAA32 (1 << 0) +/* Individual processor Cryptography engine disable: +0 Enable the Cryptography engine. +1 Disable the Cryptography engine. +This signal is only sampled during reset of the processor */ +#define NB_CPUN_CONFIG_STATUS_CONFIG_AARCH64_CRYPTO_DIS (1 << 1) + +/**** Power_Ctrl register ****/ +/* Individual CPU power mode transition request +If requested to enter power mode other than normal mode, low power state is resumed whenever CPU reenters STNDBYWFI state: +normal: 0x0: normal power state +deep_idle: 0x2: Dormant power mode state +poweredoff: 0x3: Powered-off power mode */ +#define NB_CPUN_CONFIG_STATUS_POWER_CTRL_PM_REQ_MASK 0x00000003 +#define NB_CPUN_CONFIG_STATUS_POWER_CTRL_PM_REQ_SHIFT 0 +/* Normal power mode state */ +#define NB_CPUN_CONFIG_STATUS_POWER_CTRL_PM_REQ_NORMAL \ + (0x0 << NB_CPUN_CONFIG_STATUS_POWER_CTRL_PM_REQ_SHIFT) +/* Dormant power mode state */ +#define NB_CPUN_CONFIG_STATUS_POWER_CTRL_PM_REQ_DEEP_IDLE \ + (0x2 << NB_CPUN_CONFIG_STATUS_POWER_CTRL_PM_REQ_SHIFT) +/* Powered-off power mode */ +#define NB_CPUN_CONFIG_STATUS_POWER_CTRL_PM_REQ_POWEREDOFF \ + (0x3 << NB_CPUN_CONFIG_STATUS_POWER_CTRL_PM_REQ_SHIFT) +/* Power down regret disable +When power down regret is enabled, the powerdown enter flow can be halted whenever a valid wakeup event occurs. */ +#define NB_CPUN_CONFIG_STATUS_POWER_CTRL_PWRDN_RGRT_DIS (1 << 16) +/* Power down emulation enable +If set, the entire power down sequence is applied, but the CPU is placed in soft reset instead of hardware power down. */ +#define NB_CPUN_CONFIG_STATUS_POWER_CTRL_PWRDN_EMULATE (1 << 17) +/* Disable wakeup from Local--GIC FIQ. */ +#define NB_CPUN_CONFIG_STATUS_POWER_CTRL_WU_LGIC_FIQ_DIS (1 << 18) +/* Disable wakeup from Local-GIC IRQ. */ +#define NB_CPUN_CONFIG_STATUS_POWER_CTRL_WU_LGIC_IRQ_DIS (1 << 19) +/* Disable wakeup from IO-GIC FIQ. */ +#define NB_CPUN_CONFIG_STATUS_POWER_CTRL_WU_IOGIC_FIQ_DIS (1 << 20) +/* Disable wakeup from IO-GIC IRQ. */ +#define NB_CPUN_CONFIG_STATUS_POWER_CTRL_WU_IOGIC_IRQ_DIS (1 << 21) +/* Disable scheduling of interrrupts in GIC(500) to non-active CPU */ +#define NB_CPUN_CONFIG_STATUS_POWER_CTRL_IOGIC_DIS_CPU (1 << 22) + +/**** Power_Status register ****/ +/* Read-only bits that reflect the individual CPU power mode status. +Default value for non-exist CPU is 2b11: +normal - 0x0: Normal mode +por - 0x1: por on reset mode +deep_idle - 0x2: Dormant power mode state +poweredoff - 0x3: Powered-off power mode */ +#define NB_CPUN_CONFIG_STATUS_POWER_STATUS_CPU_PM_MASK 0x00000003 +#define NB_CPUN_CONFIG_STATUS_POWER_STATUS_CPU_PM_SHIFT 0 +/* Normal power mode state */ +#define NB_CPUN_CONFIG_STATUS_POWER_STATUS_CPU_PM_NORMAL \ + (0x0 << NB_CPUN_CONFIG_STATUS_POWER_STATUS_CPU_PM_SHIFT) +/* Idle power mode state (WFI) */ +#define NB_CPUN_CONFIG_STATUS_POWER_STATUS_CPU_PM_IDLE \ + (0x1 << NB_CPUN_CONFIG_STATUS_POWER_STATUS_CPU_PM_SHIFT) +/* Dormant power mode state */ +#define NB_CPUN_CONFIG_STATUS_POWER_STATUS_CPU_PM_DEEP_IDLE \ + (0x2 << NB_CPUN_CONFIG_STATUS_POWER_STATUS_CPU_PM_SHIFT) +/* Powered-off power mode */ +#define NB_CPUN_CONFIG_STATUS_POWER_STATUS_CPU_PM_POWEREDOFF \ + (0x3 << NB_CPUN_CONFIG_STATUS_POWER_STATUS_CPU_PM_SHIFT) +/* WFI status */ +#define NB_CPUN_CONFIG_STATUS_POWER_STATUS_WFI (1 << 2) +/* WFE status */ +#define NB_CPUN_CONFIG_STATUS_POWER_STATUS_WFE (1 << 3) + +/**** Warm_Rst_Ctl register ****/ +/* Disable CPU Warm Reset when warmrstreq is asserted + +When the Reset Request bit in the RMR or RMR_EL3 register is set to 1 in the CPU Core , the processor asserts the WARMRSTREQ signal and the SoC reset controller use this request to trigger a Warm reset of the processor and change the register width state. */ +#define NB_CPUN_CONFIG_STATUS_WARM_RST_CTL_REQ_DIS (1 << 0) +/* Disable waiting WFI on Warm Reset */ +#define NB_CPUN_CONFIG_STATUS_WARM_RST_CTL_WFI_DIS (1 << 1) +/* CPU Core AARach64 reset vector bar +This is Write Once register (controlled by aarch64_reg_force_* fields) */ +#define NB_CPUN_CONFIG_STATUS_RVBAR_LOW_ADDR_31_2_MASK 0xFFFFFFFC +#define NB_CPUN_CONFIG_STATUS_RVBAR_LOW_ADDR_31_2_SHIFT 2 + +/**** Rvbar_High register ****/ +/* CPU Core AARach64 reset vector bar high bits +This is Write Once register (controlled by aarch64_reg_force_* fields) */ +#define NB_CPUN_CONFIG_STATUS_RVBAR_HIGH_ADDR_43_32_MASK 0x00000FFF +#define NB_CPUN_CONFIG_STATUS_RVBAR_HIGH_ADDR_43_32_SHIFT 0 + +/**** pmu_snapshot register ****/ +/* PMU Snapshot Request */ +#define NB_CPUN_CONFIG_STATUS_PMU_SNAPSHOT_REQ (1 << 0) +/* 0: HW deassert requests when received ack +1: SW deasserts request when received done */ +#define NB_CPUN_CONFIG_STATUS_PMU_SNAPSHOT_MODE (1 << 1) +/* Snapshot process completed */ +#define NB_CPUN_CONFIG_STATUS_PMU_SNAPSHOT_DONE (1 << 31) + +/**** cpu_msg_in register ****/ +/* CPU read this register to receive input (char) from simulation. */ +#define NB_CPUN_CONFIG_STATUS_CPU_MSG_IN_DATA_MASK 0x000000FF +#define NB_CPUN_CONFIG_STATUS_CPU_MSG_IN_DATA_SHIFT 0 +/* Indicates the data is valid. +Cleared on read */ +#define NB_CPUN_CONFIG_STATUS_CPU_MSG_IN_VALID (1 << 8) + +/**** PMU_Control register ****/ +/* Disable all counters +When this bit is clear, counter state is determined through the specific counter control register */ +#define NB_MC_PMU_PMU_CONTROL_DISABLE_ALL (1 << 0) +/* Pause all counters. +When this bit is clear, counter state is determined through the specific counter control register. */ +#define NB_MC_PMU_PMU_CONTROL_PAUSE_ALL (1 << 1) +/* Overflow interrupt enable: +disable - 0x0: Disable interrupt on overflow. +enable - 0x1: Enable interrupt on overflow. */ +#define NB_MC_PMU_PMU_CONTROL_OVRF_INTR_EN (1 << 2) +/* Number of monitored events supported by the PMU. */ +#define NB_MC_PMU_PMU_CONTROL_NUM_OF_EVENTS_MASK 0x00FC0000 +#define NB_MC_PMU_PMU_CONTROL_NUM_OF_EVENTS_SHIFT 18 +#define NB_MC_PMU_PMU_CONTROL_NUM_OF_EVENTS_SHIFT_ALPINE 19 +/* Number of counters implemented by PMU. */ +#define NB_MC_PMU_PMU_CONTROL_NUM_OF_CNTS_MASK 0x0F000000 +#define NB_MC_PMU_PMU_CONTROL_NUM_OF_CNTS_SHIFT 24 + +/**** Cfg register ****/ +/* Event select */ +#define NB_MC_PMU_COUNTERS_CFG_EVENT_SEL_MASK 0x0000003F +#define NB_MC_PMU_COUNTERS_CFG_EVENT_SEL_SHIFT 0 +/* Enable setting of counter low overflow status bit: +disable - 0x0: Disable setting. +enable - 0x1: Enable setting. */ +#define NB_MC_PMU_COUNTERS_CFG_OVRF_LOW_STT_EN (1 << 6) +/* Enable setting of counter high overflow status bit: +disable - 0x0: Disable setting. +enable - 0x1: Enable setting. */ +#define NB_MC_PMU_COUNTERS_CFG_OVRF_HIGH_STT_EN (1 << 7) +/* Enable pause on trigger in assertion: +disable - 0x0: Disable pause. +enable - 0x1: Enable pause. */ +#define NB_MC_PMU_COUNTERS_CFG_TRIGIN_PAUSE_EN (1 << 8) +/* Enable increment trigger out for trace. +Trigger is generated whenever counter reaches value: +disable - 0x0: Disable trigger out. +enable - 0x1: Enable trigger out. */ +#define NB_MC_PMU_COUNTERS_CFG_TRIGOUT_EN (1 << 9) +/* Trigger out granule value +Specifies the number of events counted between two consecutive trigger out events +0x0: 1 - Trigger out on every event occurrence. +0x1: 2 - Trigger out on every two events. +... +0xn: 2^(n-1) - Trigger out on event 2^(n-1) events. +... +0x1F: 2^31 */ +#define NB_MC_PMU_COUNTERS_CFG_TRIGOUT_GRANULA_MASK 0x00007C00 +#define NB_MC_PMU_COUNTERS_CFG_TRIGOUT_GRANULA_SHIFT 10 +/* Pause on overflow bitmask +If set for counter , current counter pauses counting when counter is overflowed, including self-pause. +Bit [16]: counter 0 +Bit [17]: counter 1 +Note: This field must be changed for larger counters. */ +#define NB_MC_PMU_COUNTERS_CFG_PAUSE_ON_OVRF_BITMASK_MASK 0x000F0000 +#define NB_MC_PMU_COUNTERS_CFG_PAUSE_ON_OVRF_BITMASK_SHIFT 16 + +/**** Cntl register ****/ +/* Set the counter state to disable, enable, or pause: +0x0 - disable: Disable counter. +0x1 - enable: Enable counter. +0x3 - pause: Pause counter. */ +#define NB_MC_PMU_COUNTERS_CNTL_CNT_STATE_MASK 0x00000003 +#define NB_MC_PMU_COUNTERS_CNTL_CNT_STATE_SHIFT 0 +/* Disable counter. */ +#define NB_MC_PMU_COUNTERS_CNTL_CNT_STATE_DISABLE \ + (0x0 << NB_MC_PMU_COUNTERS_CNTL_CNT_STATE_SHIFT) +/* Enable counter. */ +#define NB_MC_PMU_COUNTERS_CNTL_CNT_STATE_ENABLE \ + (0x1 << NB_MC_PMU_COUNTERS_CNTL_CNT_STATE_SHIFT) +/* Pause counter. */ +#define NB_MC_PMU_COUNTERS_CNTL_CNT_STATE_PAUSE \ + (0x3 << NB_MC_PMU_COUNTERS_CNTL_CNT_STATE_SHIFT) + +/**** High register ****/ +/* Counter high value */ +#define NB_MC_PMU_COUNTERS_HIGH_COUNTER_MASK 0x0000FFFF +#define NB_MC_PMU_COUNTERS_HIGH_COUNTER_SHIFT 0 + +/**** version register ****/ +/* Revision number (Minor) */ +#define NB_NB_VERSION_VERSION_RELEASE_NUM_MINOR_MASK 0x000000FF +#define NB_NB_VERSION_VERSION_RELEASE_NUM_MINOR_SHIFT 0 +/* Revision number (Major) */ +#define NB_NB_VERSION_VERSION_RELEASE_NUM_MAJOR_MASK 0x0000FF00 +#define NB_NB_VERSION_VERSION_RELEASE_NUM_MAJOR_SHIFT 8 +/* Date of release */ +#define NB_NB_VERSION_VERSION_DATE_DAY_MASK 0x001F0000 +#define NB_NB_VERSION_VERSION_DATE_DAY_SHIFT 16 +/* Month of release */ +#define NB_NB_VERSION_VERSION_DATA_MONTH_MASK 0x01E00000 +#define NB_NB_VERSION_VERSION_DATA_MONTH_SHIFT 21 +/* Year of release (starting from 2000) */ +#define NB_NB_VERSION_VERSION_DATE_YEAR_MASK 0x3E000000 +#define NB_NB_VERSION_VERSION_DATE_YEAR_SHIFT 25 +/* Reserved */ +#define NB_NB_VERSION_VERSION_RESERVED_MASK 0xC0000000 +#define NB_NB_VERSION_VERSION_RESERVED_SHIFT 30 + +/**** cpu_vmid register ****/ +/* Target VMID */ +#define NB_SRIOV_CPU_VMID_VAL_MASK 0x000000FF +#define NB_SRIOV_CPU_VMID_VAL_SHIFT 0 + +/**** DRAM_0_Control register ****/ +/* Controller Idle +Indicates to the DDR PHY, if set, that the memory controller is idle */ +#define NB_DRAM_CHANNELS_DRAM_0_CONTROL_DDR_PHY_CTL_IDLE (1 << 0) +/* Disable clear exclusive monitor request from DDR controller to CPU +Clear request is triggered whenever an exlusive monitor inside the DDR controller is being invalidated. */ +#define NB_DRAM_CHANNELS_DRAM_0_CONTROL_DDR_EXMON_REQ_DIS (1 << 1) + +/**** DRAM_0_Status register ****/ +/* Bypass Mode: Indicates if set that the PHY is in PLL bypass mod */ +#define NB_DRAM_CHANNELS_DRAM_0_STATUS_DDR_PHY_BYP_MODE (1 << 0) +/* Number of available AXI transactions (used positions) in the DDR controller read address FIFO. */ +#define NB_DRAM_CHANNELS_DRAM_0_STATUS_RAQ_WCOUNT_MASK 0x00000030 +#define NB_DRAM_CHANNELS_DRAM_0_STATUS_RAQ_WCOUNT_SHIFT 4 +/* Number of available AXI transactions (used positions) in the DDR controller write address FIFO */ +#define NB_DRAM_CHANNELS_DRAM_0_STATUS_WAQ_WCOUNT_0_MASK 0x000000C0 +#define NB_DRAM_CHANNELS_DRAM_0_STATUS_WAQ_WCOUNT_0_SHIFT 6 +/* Number of available Low priority read CAM slots (free positions) in the DDR controller. +Each slots holds a DRAM burst */ +#define NB_DRAM_CHANNELS_DRAM_0_STATUS_LPR_CREDIT_CNT_MASK 0x00007F00 +#define NB_DRAM_CHANNELS_DRAM_0_STATUS_LPR_CREDIT_CNT_SHIFT 8 +/* Number of available High priority read CAM slots (free positions) in the DDR controller. +Each slots holds a DRAM burst */ +#define NB_DRAM_CHANNELS_DRAM_0_STATUS_HPR_CREDIT_CNT_MASK 0x003F8000 +#define NB_DRAM_CHANNELS_DRAM_0_STATUS_HPR_CREDIT_CNT_SHIFT 15 +/* Number of available write CAM slots (free positions) in the DDR controller. +Each slots holds a DRAM burst */ +#define NB_DRAM_CHANNELS_DRAM_0_STATUS_WR_CREDIT_CNT_MASK 0x1FC00000 +#define NB_DRAM_CHANNELS_DRAM_0_STATUS_WR_CREDIT_CNT_SHIFT 22 + +/**** DDR_Int_Cause register ****/ +/* This interrupt is asserted when a correctable ECC error is detected */ +#define NB_DRAM_CHANNELS_DDR_INT_CAUSE_ECC_CORRECTED_ERR (1 << 0) +/* This interrupt is asserted when a uncorrectable ECC error is detected */ +#define NB_DRAM_CHANNELS_DDR_INT_CAUSE_ECC_UNCORRECTED_ERR (1 << 1) +/* This interrupt is asserted when a parity or CRC error is detected on the DFI interface */ +#define NB_DRAM_CHANNELS_DDR_INT_CAUSE_DFI_ALERT_ERR (1 << 2) +/* On-Chip Write data parity error interrupt on output */ +#define NB_DRAM_CHANNELS_DDR_INT_CAUSE_PAR_WDATA_OUT_ERR (1 << 3) +/* This interrupt is asserted when a parity error due to MRS is detected on the DFI interface */ +#define NB_DRAM_CHANNELS_DDR_INT_CAUSE_DFI_ALERT_ERR_FATL (1 << 4) +/* This interrupt is asserted when the CRC/parity retry counter reaches it maximum value */ +#define NB_DRAM_CHANNELS_DDR_INT_CAUSE_DFI_ALERT_ERR_MAX_REACHED (1 << 5) +/* AXI Read address parity error interrupt. +This interrupt is asserted when an on-chip parity error occurred on the DDR controller AXI read address. */ +#define NB_DRAM_CHANNELS_DDR_INT_CAUSE_PAR_RADDR_ERR (1 << 6) +/* AXI Read data parity error interrupt. +This interrupt is asserted when an on-chip parity error occurred on the DDR controller AXI read data */ +#define NB_DRAM_CHANNELS_DDR_INT_CAUSE_PAR_RDATA_ERR (1 << 7) +/* AXI Write address parity error interrupt. +This interrupt is asserted when an on-chip parity error occurred on the DDR controller AXI write address. */ +#define NB_DRAM_CHANNELS_DDR_INT_CAUSE_PAR_WADDR_ERR (1 << 8) +/* AXI Write data parity error interrupt on input. +This interrupt is asserted when an on-chip parity error occurred on the DDR controller AXI write data */ +#define NB_DRAM_CHANNELS_DDR_INT_CAUSE_PAR_WDATA_IN_ERR (1 << 9) + +/**** Address_Map register ****/ +/* Controls which system address bit will be mapped to DDR row bit 2. +This field is only used when addrmap_part_en == 1 */ +#define NB_DRAM_CHANNELS_ADDRESS_MAP_ADDRMAP_ROW_B2_MASK 0x0000000F +#define NB_DRAM_CHANNELS_ADDRESS_MAP_ADDRMAP_ROW_B2_SHIFT 0 +/* Controls which system address bit will be mapped to DDR row bit 3. +This field is only used when addrmap_part_en == 1 */ +#define NB_DRAM_CHANNELS_ADDRESS_MAP_ADDRMAP_ROW_B3_MASK 0x000003C0 +#define NB_DRAM_CHANNELS_ADDRESS_MAP_ADDRMAP_ROW_B3_SHIFT 6 +/* Controls which system address bit will be mapped to DDR row bit 4. +This field is only used when addrmap_part_en == 1 */ +#define NB_DRAM_CHANNELS_ADDRESS_MAP_ADDRMAP_ROW_B4_MASK 0x0000F000 +#define NB_DRAM_CHANNELS_ADDRESS_MAP_ADDRMAP_ROW_B4_SHIFT 12 +/* Controls which system address bit will be mapped to DDR row bit 5. +This field is only used when addrmap_part_en == 1 */ +#define NB_DRAM_CHANNELS_ADDRESS_MAP_ADDRMAP_ROW_B5_MASK 0x003C0000 +#define NB_DRAM_CHANNELS_ADDRESS_MAP_ADDRMAP_ROW_B5_SHIFT 18 +/* Enables partitioning of the address mapping control. +When set, addrmap_row_b2-5 are used inside DDR controler instead of the built in address mapping registers */ +#define NB_DRAM_CHANNELS_ADDRESS_MAP_ADDRMAP_PART_EN (1 << 31) + +/**** Reorder_ID_Mask register ****/ +/* DDR Read Reorder buffer ID mask. +If incoming read transaction ID ANDed with mask is equal Reorder_ID_Value, then the transaction is mapped to the DDR controller bypass channel. +Setting this register to 0 will disable the check */ +#define NB_DRAM_CHANNELS_REORDER_ID_MASK_MASK_MASK 0x003FFFFF +#define NB_DRAM_CHANNELS_REORDER_ID_MASK_MASK_SHIFT 0 + +/**** Reorder_ID_Value register ****/ +/* DDR Read Reorder buffer ID value +If incoming read transaction ID ANDed with Reorder_ID_Mask is equal to this register, then the transaction is mapped to the DDR controller bypass channel */ +#define NB_DRAM_CHANNELS_REORDER_ID_VALUE_VALUE_MASK 0x003FFFFF +#define NB_DRAM_CHANNELS_REORDER_ID_VALUE_VALUE_SHIFT 0 + +/**** MRR_Control_Status register ****/ +/* DDR4 Mode Register Read Data Valid */ +#define NB_DRAM_CHANNELS_MRR_CONTROL_STATUS_MRR_VLD (1 << 0) +/* MRR Ack, when asserted it clears the mrr_val indication and ready to load new MRR data. Write 1 to clear and then 0 */ +#define NB_DRAM_CHANNELS_MRR_CONTROL_STATUS_MRR_ACK (1 << 16) + +/**** pp_config register ****/ +/* Bypass PP module (formality equivalent) */ +#define NB_PUSH_PACKET_PP_CONFIG_FM_BYPASS (1 << 0) +/* Bypass PP module */ +#define NB_PUSH_PACKET_PP_CONFIG_BYPASS (1 << 1) +/* Force Cleanup of entries */ +#define NB_PUSH_PACKET_PP_CONFIG_CLEAR (1 << 2) +/* Enable forwarding DECERR response */ +#define NB_PUSH_PACKET_PP_CONFIG_DECERR_EN (1 << 3) +/* Enable forwarding SLVERR response */ +#define NB_PUSH_PACKET_PP_CONFIG_SLVERR_EN (1 << 4) +/* Enable forwarding of data parity generation */ +#define NB_PUSH_PACKET_PP_CONFIG_PAR_GEN_EN (1 << 5) +/* Select channel on 8K boundaries ([15:13]) instead of 64k boundaries ([18:16]). */ +#define NB_PUSH_PACKET_PP_CONFIG_SEL_8K (1 << 6) +/* Forces awuser to be as configured in ext_awuser register. +Not functional */ +#define NB_PUSH_PACKET_PP_CONFIG_SEL_EXT_AWUSER (1 << 7) +/* Enables PP channel. +1 bit per channel */ +#define NB_PUSH_PACKET_PP_CONFIG_CHANNEL_ENABLE_MASK 0x00030000 +#define NB_PUSH_PACKET_PP_CONFIG_CHANNEL_ENABLE_SHIFT 16 + +#define NB_PUSH_PACKET_PP_CONFIG_CHANNEL_ENABLE(i) \ + (1 << (NB_PUSH_PACKET_PP_CONFIG_CHANNEL_ENABLE_SHIFT + i)) + +/**** pp_ext_awuser register ****/ +/* Awuser to use on PP transactions +Only applicable if config.sel_ext_awuser is set to 1'b1 +Parity bits are still generated per transaction */ +#define NB_PUSH_PACKET_PP_EXT_AWUSER_AWUSER_MASK 0x03FFFFFF +#define NB_PUSH_PACKET_PP_EXT_AWUSER_AWUSER_SHIFT 0 + +/**** pp_sel_awuser register ****/ +/* Select whether to use addr[63:48] or PP awmisc as vmid. +Each bit if set to 1 selects the corresponding address bit. Otherwise, selects the corersponding awmis bit. */ +#define NB_PUSH_PACKET_PP_SEL_AWUSER_SEL_MASK 0x0000FFFF +#define NB_PUSH_PACKET_PP_SEL_AWUSER_SEL_SHIFT 0 + +#ifdef __cplusplus +} +#endif + +#endif /* __AL_HAL_NB_REGS_H__ */ + +/** @} end of ... group */ + + Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_nb_regs.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pbs_regs.h =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pbs_regs.h (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pbs_regs.h (revision 283031) @@ -0,0 +1,2751 @@ +/*- +******************************************************************************** +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/** + * @{ + * @file al_hal_pbs_regs.h + * + * @brief ... registers + * + */ + +#ifndef __AL_HAL_PBS_REGS_H__ +#define __AL_HAL_PBS_REGS_H__ + +#include "al_hal_plat_types.h" + +#ifdef __cplusplus +extern "C" { +#endif +/* +* Unit Registers +*/ + + + +struct al_pbs_unit { + /* [0x0] Conf_bus, Configuration of the SB */ + uint32_t conf_bus; + /* [0x4] PASW high */ + uint32_t dram_0_nb_bar_high; + /* [0x8] PASW low */ + uint32_t dram_0_nb_bar_low; + /* [0xc] PASW high */ + uint32_t dram_1_nb_bar_high; + /* [0x10] PASW low */ + uint32_t dram_1_nb_bar_low; + /* [0x14] PASW high */ + uint32_t dram_2_nb_bar_high; + /* [0x18] PASW low */ + uint32_t dram_2_nb_bar_low; + /* [0x1c] PASW high */ + uint32_t dram_3_nb_bar_high; + /* [0x20] PASW low */ + uint32_t dram_3_nb_bar_low; + /* [0x24] PASW high */ + uint32_t msix_nb_bar_high; + /* [0x28] PASW low */ + uint32_t msix_nb_bar_low; + /* [0x2c] PASW high */ + uint32_t dram_0_sb_bar_high; + /* [0x30] PASW low */ + uint32_t dram_0_sb_bar_low; + /* [0x34] PASW high */ + uint32_t dram_1_sb_bar_high; + /* [0x38] PASW low */ + uint32_t dram_1_sb_bar_low; + /* [0x3c] PASW high */ + uint32_t dram_2_sb_bar_high; + /* [0x40] PASW low */ + uint32_t dram_2_sb_bar_low; + /* [0x44] PASW high */ + uint32_t dram_3_sb_bar_high; + /* [0x48] PASW low */ + uint32_t dram_3_sb_bar_low; + /* [0x4c] PASW high */ + uint32_t msix_sb_bar_high; + /* [0x50] PASW low */ + uint32_t msix_sb_bar_low; + /* [0x54] PASW high */ + uint32_t pcie_mem0_bar_high; + /* [0x58] PASW low */ + uint32_t pcie_mem0_bar_low; + /* [0x5c] PASW high */ + uint32_t pcie_mem1_bar_high; + /* [0x60] PASW low */ + uint32_t pcie_mem1_bar_low; + /* [0x64] PASW high */ + uint32_t pcie_mem2_bar_high; + /* [0x68] PASW low */ + uint32_t pcie_mem2_bar_low; + /* [0x6c] PASW high */ + uint32_t pcie_ext_ecam0_bar_high; + /* [0x70] PASW low */ + uint32_t pcie_ext_ecam0_bar_low; + /* [0x74] PASW high */ + uint32_t pcie_ext_ecam1_bar_high; + /* [0x78] PASW low */ + uint32_t pcie_ext_ecam1_bar_low; + /* [0x7c] PASW high */ + uint32_t pcie_ext_ecam2_bar_high; + /* [0x80] PASW low */ + uint32_t pcie_ext_ecam2_bar_low; + /* [0x84] PASW high */ + uint32_t pbs_nor_bar_high; + /* [0x88] PASW low */ + uint32_t pbs_nor_bar_low; + /* [0x8c] PASW high */ + uint32_t pbs_spi_bar_high; + /* [0x90] PASW low */ + uint32_t pbs_spi_bar_low; + uint32_t rsrvd_0[3]; + /* [0xa0] PASW high */ + uint32_t pbs_nand_bar_high; + /* [0xa4] PASW low */ + uint32_t pbs_nand_bar_low; + /* [0xa8] PASW high */ + uint32_t pbs_int_mem_bar_high; + /* [0xac] PASW low */ + uint32_t pbs_int_mem_bar_low; + /* [0xb0] PASW high */ + uint32_t pbs_boot_bar_high; + /* [0xb4] PASW low */ + uint32_t pbs_boot_bar_low; + /* [0xb8] PASW high */ + uint32_t nb_int_bar_high; + /* [0xbc] PASW low */ + uint32_t nb_int_bar_low; + /* [0xc0] PASW high */ + uint32_t nb_stm_bar_high; + /* [0xc4] PASW low */ + uint32_t nb_stm_bar_low; + /* [0xc8] PASW high */ + uint32_t pcie_ecam_int_bar_high; + /* [0xcc] PASW low */ + uint32_t pcie_ecam_int_bar_low; + /* [0xd0] PASW high */ + uint32_t pcie_mem_int_bar_high; + /* [0xd4] PASW low */ + uint32_t pcie_mem_int_bar_low; + /* [0xd8] Control */ + uint32_t winit_cntl; + /* [0xdc] Control */ + uint32_t latch_bars; + /* [0xe0] Control */ + uint32_t pcie_conf_0; + /* [0xe4] Control */ + uint32_t pcie_conf_1; + /* [0xe8] Control */ + uint32_t serdes_mux_pipe; + /* [0xec] Control */ + uint32_t dma_io_master_map; + /* [0xf0] Status */ + uint32_t i2c_pld_status_high; + /* [0xf4] Status */ + uint32_t i2c_pld_status_low; + /* [0xf8] Status */ + uint32_t spi_dbg_status_high; + /* [0xfc] Status */ + uint32_t spi_dbg_status_low; + /* [0x100] Status */ + uint32_t spi_mst_status_high; + /* [0x104] Status */ + uint32_t spi_mst_status_low; + /* [0x108] Log */ + uint32_t mem_pbs_parity_err_high; + /* [0x10c] Log */ + uint32_t mem_pbs_parity_err_low; + /* [0x110] Log */ + uint32_t boot_strap; + /* [0x114] Conf */ + uint32_t cfg_axi_conf_0; + /* [0x118] Conf */ + uint32_t cfg_axi_conf_1; + /* [0x11c] Conf */ + uint32_t cfg_axi_conf_2; + /* [0x120] Conf */ + uint32_t cfg_axi_conf_3; + /* [0x124] Conf */ + uint32_t spi_mst_conf_0; + /* [0x128] Conf */ + uint32_t spi_mst_conf_1; + /* [0x12c] Conf */ + uint32_t spi_slv_conf_0; + /* [0x130] Conf */ + uint32_t apb_mem_conf_int; + /* [0x134] PASW remap register */ + uint32_t sb2nb_cfg_dram_remap; + /* [0x138] Control */ + uint32_t pbs_mux_sel_0; + /* [0x13c] Control */ + uint32_t pbs_mux_sel_1; + /* [0x140] Control */ + uint32_t pbs_mux_sel_2; + /* [0x144] Control */ + uint32_t pbs_mux_sel_3; + /* [0x148] PASW high */ + uint32_t sb_int_bar_high; + /* [0x14c] PASW low */ + uint32_t sb_int_bar_low; + /* [0x150] log */ + uint32_t ufc_pbs_parity_err_high; + /* [0x154] log */ + uint32_t ufc_pbs_parity_err_low; + /* [0x158] Cntl - internal */ + uint32_t gen_conf; + /* [0x15c] Device ID and Rev ID */ + uint32_t chip_id; + /* [0x160] Status - internal */ + uint32_t uart0_debug; + /* [0x164] Status - internal */ + uint32_t uart1_debug; + /* [0x168] Status - internal */ + uint32_t uart2_debug; + /* [0x16c] Status - internal */ + uint32_t uart3_debug; + /* [0x170] Control - internal */ + uint32_t uart0_conf_status; + /* [0x174] Control - internal */ + uint32_t uart1_conf_status; + /* [0x178] Control - internal */ + uint32_t uart2_conf_status; + /* [0x17c] Control - internal */ + uint32_t uart3_conf_status; + /* [0x180] Control - internal */ + uint32_t gpio0_conf_status; + /* [0x184] Control - internal */ + uint32_t gpio1_conf_status; + /* [0x188] Control - internal */ + uint32_t gpio2_conf_status; + /* [0x18c] Control - internal */ + uint32_t gpio3_conf_status; + /* [0x190] Control - internal */ + uint32_t gpio4_conf_status; + /* [0x194] Control - internal */ + uint32_t i2c_gen_conf_status; + /* [0x198] Control - internal */ + uint32_t i2c_gen_debug; + /* [0x19c] Cntl */ + uint32_t watch_dog_reset_out; + /* [0x1a0] Cntl */ + uint32_t otp_magic_num; + /* + * [0x1a4] Control - internal + */ + uint32_t otp_cntl; + /* [0x1a8] Cfg - internal */ + uint32_t otp_cfg_0; + /* [0x1ac] Cfg - internal */ + uint32_t otp_cfg_1; + /* [0x1b0] Cfg - internal */ + uint32_t otp_cfg_3; + /* [0x1b4] Cfg */ + uint32_t cfg_nand_0; + /* [0x1b8] Cfg */ + uint32_t cfg_nand_1; + /* [0x1bc] Cfg-- timing parameters internal. */ + uint32_t cfg_nand_2; + /* [0x1c0] Cfg - internal */ + uint32_t cfg_nand_3; + /* [0x1c4] PASW high */ + uint32_t nb_nic_regs_bar_high; + /* [0x1c8] PASW low */ + uint32_t nb_nic_regs_bar_low; + /* [0x1cc] PASW high */ + uint32_t sb_nic_regs_bar_high; + /* [0x1d0] PASW low */ + uint32_t sb_nic_regs_bar_low; + /* [0x1d4] Control */ + uint32_t serdes_mux_multi_0; + /* [0x1d8] Control */ + uint32_t serdes_mux_multi_1; + /* [0x1dc] Control - not in use any more - internal */ + uint32_t pbs_ulpi_mux_conf; + /* [0x1e0] Cntl */ + uint32_t wr_once_dbg_dis_ovrd_reg; + /* [0x1e4] Cntl - internal */ + uint32_t gpio5_conf_status; + /* [0x1e8] PASW high */ + uint32_t pcie_mem3_bar_high; + /* [0x1ec] PASW low */ + uint32_t pcie_mem3_bar_low; + /* [0x1f0] PASW high */ + uint32_t pcie_mem4_bar_high; + /* [0x1f4] PASW low */ + uint32_t pcie_mem4_bar_low; + /* [0x1f8] PASW high */ + uint32_t pcie_mem5_bar_high; + /* [0x1fc] PASW low */ + uint32_t pcie_mem5_bar_low; + /* [0x200] PASW high */ + uint32_t pcie_ext_ecam3_bar_high; + /* [0x204] PASW low */ + uint32_t pcie_ext_ecam3_bar_low; + /* [0x208] PASW high */ + uint32_t pcie_ext_ecam4_bar_high; + /* [0x20c] PASW low */ + uint32_t pcie_ext_ecam4_bar_low; + /* [0x210] PASW high */ + uint32_t pcie_ext_ecam5_bar_high; + /* [0x214] PASW low */ + uint32_t pcie_ext_ecam5_bar_low; + /* [0x218] PASW high */ + uint32_t low_latency_sram_bar_high; + /* [0x21c] PASW low */ + uint32_t low_latency_sram_bar_low; + /* [0x220] Control */ + uint32_t pbs_mux_sel_4; + /* [0x224] Control */ + uint32_t pbs_mux_sel_5; + /* [0x228] Control */ + uint32_t serdes_mux_eth; + /* [0x22c] Control */ + uint32_t serdes_mux_pcie; + /* [0x230] Control */ + uint32_t serdes_mux_sata; + uint32_t rsrvd[7]; +}; +struct al_pbs_low_latency_sram_remap { + /* [0x0] PBS MEM Remap */ + uint32_t bar1_orig; + /* [0x4] PBS MEM Remap */ + uint32_t bar1_remap; + /* [0x8] ETH0 MEM Remap */ + uint32_t bar2_orig; + /* [0xc] ETH0 MEM Remap */ + uint32_t bar2_remap; + /* [0x10] ETH1 MEM Remap */ + uint32_t bar3_orig; + /* [0x14] ETH1 MEM Remap */ + uint32_t bar3_remap; + /* [0x18] ETH2 MEM Remap */ + uint32_t bar4_orig; + /* [0x1c] ETH2 MEM Remap */ + uint32_t bar4_remap; + /* [0x20] ETH3 MEM Remap */ + uint32_t bar5_orig; + /* [0x24] ETH3 MEM Remap */ + uint32_t bar5_remap; + /* [0x28] CRYPTO0 MEM Remap */ + uint32_t bar6_orig; + /* [0x2c] CRYPTO0 MEM Remap */ + uint32_t bar6_remap; + /* [0x30] RAID0 MEM Remap */ + uint32_t bar7_orig; + /* [0x34] RAID0 MEM Remap */ + uint32_t bar7_remap; + /* [0x38] CRYPTO1 MEM Remap */ + uint32_t bar8_orig; + /* [0x3c] CRYPTO1 MEM Remap */ + uint32_t bar8_remap; + /* [0x40] RAID1 MEM Remap */ + uint32_t bar9_orig; + /* [0x44] RAID2 MEM Remap */ + uint32_t bar9_remap; + /* [0x48] RESERVED MEM Remap */ + uint32_t bar10_orig; + /* [0x4c] RESERVED MEM Remap */ + uint32_t bar10_remap; +}; +struct al_pbs_target_id_enforcement { + /* [0x0] target enforcement */ + uint32_t cpu; + /* [0x4] target enforcement mask (bits which are 0 are not compared) */ + uint32_t cpu_mask; + /* [0x8] target enforcement */ + uint32_t debug_nb; + /* [0xc] target enforcement mask (bits which are 0 are not compared) */ + uint32_t debug_nb_mask; + /* [0x10] target enforcement */ + uint32_t debug_sb; + /* [0x14] target enforcement mask (bits which are 0 are not compared) */ + uint32_t debug_sb_mask; + /* [0x18] target enforcement */ + uint32_t eth_0; + /* [0x1c] target enforcement mask (bits which are 0 are not compared) */ + uint32_t eth_0_mask; + /* [0x20] target enforcement */ + uint32_t eth_1; + /* [0x24] target enforcement mask (bits which are 0 are not compared) */ + uint32_t eth_1_mask; + /* [0x28] target enforcement */ + uint32_t eth_2; + /* [0x2c] target enforcement mask (bits which are 0 are not compared) */ + uint32_t eth_2_mask; + /* [0x30] target enforcement */ + uint32_t eth_3; + /* [0x34] target enforcement mask (bits which are 0 are not compared) */ + uint32_t eth_3_mask; + /* [0x38] target enforcement */ + uint32_t sata_0; + /* [0x3c] target enforcement mask (bits which are 0 are not compared) */ + uint32_t sata_0_mask; + /* [0x40] target enforcement */ + uint32_t sata_1; + /* [0x44] target enforcement mask (bits which are 0 are not compared) */ + uint32_t sata_1_mask; + /* [0x48] target enforcement */ + uint32_t crypto_0; + /* [0x4c] target enforcement mask (bits which are 0 are not compared) */ + uint32_t crypto_0_mask; + /* [0x50] target enforcement */ + uint32_t crypto_1; + /* [0x54] target enforcement mask (bits which are 0 are not compared) */ + uint32_t crypto_1_mask; + /* [0x58] target enforcement */ + uint32_t pcie_0; + /* [0x5c] target enforcement mask (bits which are 0 are not compared) */ + uint32_t pcie_0_mask; + /* [0x60] target enforcement */ + uint32_t pcie_1; + /* [0x64] target enforcement mask (bits which are 0 are not compared) */ + uint32_t pcie_1_mask; + /* [0x68] target enforcement */ + uint32_t pcie_2; + /* [0x6c] target enforcement mask (bits which are 0 are not compared) */ + uint32_t pcie_2_mask; + /* [0x70] target enforcement */ + uint32_t pcie_3; + /* [0x74] target enforcement mask (bits which are 0 are not compared) */ + uint32_t pcie_3_mask; + /* [0x78] Control */ + uint32_t latch; + uint32_t rsrvd[9]; +}; + +struct al_pbs_regs { + struct al_pbs_unit unit; /* [0x0] */ +struct al_pbs_low_latency_sram_remap low_latency_sram_remap; +/* [0x250] */ + uint32_t rsrvd_0[88]; + struct al_pbs_target_id_enforcement target_id_enforcement; /* [0x400] */ +}; + + +/* +* Registers Fields +*/ + + +/**** conf_bus register ****/ +/* Read slave error enable */ +#define PBS_UNIT_CONF_BUS_RD_SLVERR_EN (1 << 0) +/* Write slave error enable */ +#define PBS_UNIT_CONF_BUS_WR_SLVERR_EN (1 << 1) +/* Read decode error enable */ +#define PBS_UNIT_CONF_BUS_RD_DECERR_EN (1 << 2) +/* Write decode error enable */ +#define PBS_UNIT_CONF_BUS_WR_DECERR_EN (1 << 3) +/* For debug clear the APB SM */ +#define PBS_UNIT_CONF_BUS_CLR_APB_FSM (1 << 4) +/* For debug clear the WFIFO */ +#define PBS_UNIT_CONF_BUS_CLR_WFIFO_CLEAR (1 << 5) +/* Arbiter between read and write channel */ +#define PBS_UNIT_CONF_BUS_WRR_CNT_MASK 0x000001C0 +#define PBS_UNIT_CONF_BUS_WRR_CNT_SHIFT 6 + + +/* general PASWS */ +/* window size = 2 ^ (15 + win_size), zero value disable the win ... */ +#define PBS_PASW_WIN_SIZE_MASK 0x0000003F +#define PBS_PASW_WIN_SIZE_SHIFT 0 +/* reserved fields */ +#define PBS_PASW_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_PASW_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_PASW_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_PASW_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** dram_0_nb_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_DRAM_0_NB_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_DRAM_0_NB_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_DRAM_0_NB_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_DRAM_0_NB_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_DRAM_0_NB_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_DRAM_0_NB_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** dram_1_nb_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_DRAM_1_NB_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_DRAM_1_NB_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_DRAM_1_NB_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_DRAM_1_NB_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_DRAM_1_NB_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_DRAM_1_NB_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** dram_2_nb_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_DRAM_2_NB_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_DRAM_2_NB_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_DRAM_2_NB_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_DRAM_2_NB_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_DRAM_2_NB_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_DRAM_2_NB_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** dram_3_nb_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_DRAM_3_NB_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_DRAM_3_NB_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_DRAM_3_NB_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_DRAM_3_NB_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_DRAM_3_NB_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_DRAM_3_NB_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** msix_nb_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_MSIX_NB_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_MSIX_NB_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_MSIX_NB_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_MSIX_NB_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_MSIX_NB_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_MSIX_NB_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** dram_0_sb_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_DRAM_0_SB_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_DRAM_0_SB_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_DRAM_0_SB_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_DRAM_0_SB_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_DRAM_0_SB_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_DRAM_0_SB_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** dram_1_sb_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_DRAM_1_SB_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_DRAM_1_SB_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_DRAM_1_SB_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_DRAM_1_SB_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_DRAM_1_SB_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_DRAM_1_SB_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** dram_2_sb_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_DRAM_2_SB_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_DRAM_2_SB_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_DRAM_2_SB_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_DRAM_2_SB_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_DRAM_2_SB_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_DRAM_2_SB_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** dram_3_sb_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_DRAM_3_SB_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_DRAM_3_SB_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_DRAM_3_SB_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_DRAM_3_SB_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_DRAM_3_SB_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_DRAM_3_SB_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** msix_sb_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_MSIX_SB_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_MSIX_SB_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_MSIX_SB_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_MSIX_SB_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_MSIX_SB_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_MSIX_SB_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pcie_mem0_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PCIE_MEM0_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PCIE_MEM0_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PCIE_MEM0_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PCIE_MEM0_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_PCIE_MEM0_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PCIE_MEM0_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pcie_mem1_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PCIE_MEM1_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PCIE_MEM1_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PCIE_MEM1_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PCIE_MEM1_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_PCIE_MEM1_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PCIE_MEM1_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pcie_mem2_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PCIE_MEM2_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PCIE_MEM2_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PCIE_MEM2_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PCIE_MEM2_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_PCIE_MEM2_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PCIE_MEM2_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pcie_ext_ecam0_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PCIE_EXT_ECAM0_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PCIE_EXT_ECAM0_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PCIE_EXT_ECAM0_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PCIE_EXT_ECAM0_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_PCIE_EXT_ECAM0_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PCIE_EXT_ECAM0_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pcie_ext_ecam1_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PCIE_EXT_ECAM1_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PCIE_EXT_ECAM1_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PCIE_EXT_ECAM1_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PCIE_EXT_ECAM1_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_PCIE_EXT_ECAM1_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PCIE_EXT_ECAM1_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pcie_ext_ecam2_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PCIE_EXT_ECAM2_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PCIE_EXT_ECAM2_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PCIE_EXT_ECAM2_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PCIE_EXT_ECAM2_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_PCIE_EXT_ECAM2_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PCIE_EXT_ECAM2_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pbs_nor_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PBS_NOR_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PBS_NOR_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PBS_NOR_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PBS_NOR_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_PBS_NOR_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PBS_NOR_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pbs_spi_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PBS_SPI_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PBS_SPI_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PBS_SPI_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PBS_SPI_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_PBS_SPI_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PBS_SPI_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pbs_nand_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PBS_NAND_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PBS_NAND_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PBS_NAND_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PBS_NAND_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_PBS_NAND_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PBS_NAND_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pbs_int_mem_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PBS_INT_MEM_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PBS_INT_MEM_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PBS_INT_MEM_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PBS_INT_MEM_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_PBS_INT_MEM_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PBS_INT_MEM_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pbs_boot_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PBS_BOOT_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PBS_BOOT_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PBS_BOOT_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PBS_BOOT_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_PBS_BOOT_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PBS_BOOT_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** nb_int_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_NB_INT_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_NB_INT_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_NB_INT_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_NB_INT_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_NB_INT_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_NB_INT_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** nb_stm_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_NB_STM_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_NB_STM_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_NB_STM_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_NB_STM_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_NB_STM_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_NB_STM_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pcie_ecam_int_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PCIE_ECAM_INT_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PCIE_ECAM_INT_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PCIE_ECAM_INT_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PCIE_ECAM_INT_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_PCIE_ECAM_INT_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PCIE_ECAM_INT_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pcie_mem_int_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PCIE_MEM_INT_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PCIE_MEM_INT_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PCIE_MEM_INT_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PCIE_MEM_INT_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_PCIE_MEM_INT_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PCIE_MEM_INT_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** winit_cntl register ****/ +/* When set, enables access to winit regs, in normal mode. */ +#define PBS_UNIT_WINIT_CNTL_ENABLE_WINIT_REGS_ACCESS (1 << 0) +/* Reserved */ +#define PBS_UNIT_WINIT_CNTL_RSRVD_MASK 0xFFFFFFFE +#define PBS_UNIT_WINIT_CNTL_RSRVD_SHIFT 1 + +/**** latch_bars register ****/ +/* + * Software clears this bit before any bar update, and set it after all bars + * updated. + */ +#define PBS_UNIT_LATCH_BARS_ENABLE (1 << 0) +/* Reserved */ +#define PBS_UNIT_LATCH_BARS_RSRVD_MASK 0xFFFFFFFE +#define PBS_UNIT_LATCH_BARS_RSRVD_SHIFT 1 + +/**** pcie_conf_0 register ****/ +/* NOT_use, config internal inside each PCIe core */ +#define PBS_UNIT_PCIE_CONF_0_DEVS_TYPE_MASK 0x00000FFF +#define PBS_UNIT_PCIE_CONF_0_DEVS_TYPE_SHIFT 0 +/* sys_aux_det value */ +#define PBS_UNIT_PCIE_CONF_0_SYS_AUX_PWR_DET_VEC_MASK 0x00007000 +#define PBS_UNIT_PCIE_CONF_0_SYS_AUX_PWR_DET_VEC_SHIFT 12 +/* Reserved */ +#define PBS_UNIT_PCIE_CONF_0_RSRVD_MASK 0xFFFF8000 +#define PBS_UNIT_PCIE_CONF_0_RSRVD_SHIFT 15 + +/**** pcie_conf_1 register ****/ +/* + * Which PCIe exists? The PCIe device is under reset until the corresponding bit + * is set. + */ +#define PBS_UNIT_PCIE_CONF_1_PCIE_EXIST_MASK 0x0000003F +#define PBS_UNIT_PCIE_CONF_1_PCIE_EXIST_SHIFT 0 +/* Reserved */ +#define PBS_UNIT_PCIE_CONF_1_RSRVD_MASK 0xFFFFFFC0 +#define PBS_UNIT_PCIE_CONF_1_RSRVD_SHIFT 6 + +/**** serdes_mux_pipe register ****/ +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_SERDES_2_MASK 0x00000007 +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_SERDES_2_SHIFT 0 +/* Reserved */ +#define PBS_UNIT_SERDES_MUX_PIPE_RSRVD_3 (1 << 3) +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_SERDES_3_MASK 0x00000070 +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_SERDES_3_SHIFT 4 +/* Reserved */ +#define PBS_UNIT_SERDES_MUX_PIPE_RSRVD_7 (1 << 7) +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_PCI_B_0_MASK 0x00000300 +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_PCI_B_0_SHIFT 8 +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_PCI_B_1_MASK 0x00000C00 +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_PCI_B_1_SHIFT 10 +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_PCI_C_0_MASK 0x00003000 +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_PCI_C_0_SHIFT 12 +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_PCI_C_1_MASK 0x0000C000 +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_PCI_C_1_SHIFT 14 +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_USB_A_0_MASK 0x00030000 +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_USB_A_0_SHIFT 16 +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_USB_B_0_MASK 0x000C0000 +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_USB_B_0_SHIFT 18 +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_CLKI_SER_2_MASK 0x00300000 +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_CLKI_SER_2_SHIFT 20 +/* Reserved */ +#define PBS_UNIT_SERDES_MUX_PIPE_RSRVD_23_22_MASK 0x00C00000 +#define PBS_UNIT_SERDES_MUX_PIPE_RSRVD_23_22_SHIFT 22 +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_CLKI_SER_3_MASK 0x07000000 +#define PBS_UNIT_SERDES_MUX_PIPE_SELECT_OH_CLKI_SER_3_SHIFT 24 +/* Reserved */ +#define PBS_UNIT_SERDES_MUX_PIPE_RSRVD_MASK 0xF8000000 +#define PBS_UNIT_SERDES_MUX_PIPE_RSRVD_SHIFT 27 + +/* + * 2'b01 - select pcie_b[0] + * 2'b10 - select pcie_a[2] + */ +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_2_MASK 0x00000003 +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_2_SHIFT 0 +/* + * 2'b01 - select pcie_b[1] + * 2'b10 - select pcie_a[3] + */ +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_3_MASK 0x00000030 +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_3_SHIFT 4 +/* + * 2'b01 - select pcie_b[0] + * 2'b10 - select pcie_a[4] + */ +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_4_MASK 0x00000300 +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_4_SHIFT 8 +/* + * 2'b01 - select pcie_b[1] + * 2'b10 - select pcie_a[5] + */ +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_5_MASK 0x00003000 +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_5_SHIFT 12 +/* + * 2'b01 - select pcie_b[2] + * 2'b10 - select pcie_a[6] + */ +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_6_MASK 0x00030000 +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_6_SHIFT 16 +/* + * 2'b01 - select pcie_b[3] + * 2'b10 - select pcie_a[7] + */ +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_7_MASK 0x00300000 +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_7_SHIFT 20 +/* + * 2'b01 - select pcie_d[0] + * 2'b10 - select pcie_c[2] + */ +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_10_MASK 0x03000000 +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_10_SHIFT 24 +/* + * 2'b01 - select pcie_d[1] + * 2'b10 - select pcie_c[3] + */ +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_11_MASK 0x30000000 +#define PBS_UNIT_SERDES_MUX_PIPE_PKR_SELECT_OH_SERDES_11_SHIFT 28 + +/**** dma_io_master_map register ****/ +/* + * [0]: When set, maps all the io_dma transactions to the NB/DRAM, regardless of + * the window hit. + * [1]: When set, maps all the eth_0 transactions to the NB/DRAM, regardless of + * the window hit. + * [2]: When set, maps all the eth_2 transaction to the NB/DRAM, regardless of + * the window hit. + * [3]: When set, maps all the sata_0 transactions to the NB/DRAM, regardless of + * the window hit. + * [4]: When set, maps all the sata_1 transactions to the NB/DRAM, regardless of + * the window hit. + * [5]: When set, maps all the pcie_0 master transactions to the NB/DRAM, + * regardless of the window hit. + * [6]: When set, maps all the SPI debug port transactions to the NB/DRAM, + * regardless of the window hit. + * [7]: When set, maps all the CPU debug port transactions to the NB/DRAM, + * regardless of the window hit. + * [8] When set, maps all the Crypto transactions to the NB/DRAM, regardless of + * the window hit. + * [15:9] - Reserved + */ +#define PBS_UNIT_DMA_IO_MASTER_MAP_CNTL_MASK 0x0000FFFF +#define PBS_UNIT_DMA_IO_MASTER_MAP_CNTL_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_DMA_IO_MASTER_MAP_RSRVD_MASK 0xFFFF0000 +#define PBS_UNIT_DMA_IO_MASTER_MAP_RSRVD_SHIFT 16 + +/**** i2c_pld_status_high register ****/ +/* I2C pre-load status */ +#define PBS_UNIT_I2C_PLD_STATUS_HIGH_STATUS_MASK 0x000000FF +#define PBS_UNIT_I2C_PLD_STATUS_HIGH_STATUS_SHIFT 0 + +/**** spi_dbg_status_high register ****/ +/* SPI DBG load status */ +#define PBS_UNIT_SPI_DBG_STATUS_HIGH_STATUS_MASK 0x000000FF +#define PBS_UNIT_SPI_DBG_STATUS_HIGH_STATUS_SHIFT 0 + +/**** spi_mst_status_high register ****/ +/* SP IMST load status */ +#define PBS_UNIT_SPI_MST_STATUS_HIGH_STATUS_MASK 0x000000FF +#define PBS_UNIT_SPI_MST_STATUS_HIGH_STATUS_SHIFT 0 + +/**** mem_pbs_parity_err_high register ****/ +/* Address latch in the case of a parity error */ +#define PBS_UNIT_MEM_PBS_PARITY_ERR_HIGH_ADDR_MASK 0x000000FF +#define PBS_UNIT_MEM_PBS_PARITY_ERR_HIGH_ADDR_SHIFT 0 + +/**** cfg_axi_conf_0 register ****/ +/* Sets the AXI field in the I2C preloader interface. */ +#define PBS_UNIT_CFG_AXI_CONF_0_DBG_RD_ID_MASK 0x0000007F +#define PBS_UNIT_CFG_AXI_CONF_0_DBG_RD_ID_SHIFT 0 +/* Sets the AXI field in the I2C preloader interface. */ +#define PBS_UNIT_CFG_AXI_CONF_0_DBG_WR_ID_MASK 0x00003F80 +#define PBS_UNIT_CFG_AXI_CONF_0_DBG_WR_ID_SHIFT 7 +/* Sets the AXI field in the I2C preloader interface. */ +#define PBS_UNIT_CFG_AXI_CONF_0_PLD_WR_ID_MASK 0x001FC000 +#define PBS_UNIT_CFG_AXI_CONF_0_PLD_WR_ID_SHIFT 14 +/* Sets the AXI field in the SPI debug interface. */ +#define PBS_UNIT_CFG_AXI_CONF_0_DBG_AWCACHE_MASK 0x01E00000 +#define PBS_UNIT_CFG_AXI_CONF_0_DBG_AWCACHE_SHIFT 21 +/* Sets the AXI field in the SPI debug interface. */ +#define PBS_UNIT_CFG_AXI_CONF_0_DBG_ARCACHE_MASK 0x1E000000 +#define PBS_UNIT_CFG_AXI_CONF_0_DBG_ARCACHE_SHIFT 25 +/* Sets the AXI field in the SPI debug interface. */ +#define PBS_UNIT_CFG_AXI_CONF_0_DBG_AXPROT_MASK 0xE0000000 +#define PBS_UNIT_CFG_AXI_CONF_0_DBG_AXPROT_SHIFT 29 + +/**** cfg_axi_conf_1 register ****/ +/* Sets the AXI field in the SPI debug interface. */ +#define PBS_UNIT_CFG_AXI_CONF_1_DBG_ARUSER_MASK 0x03FFFFFF +#define PBS_UNIT_CFG_AXI_CONF_1_DBG_ARUSER_SHIFT 0 +/* Sets the AXI field in the SPI debug interface. */ +#define PBS_UNIT_CFG_AXI_CONF_1_DBG_ARQOS_MASK 0x3C000000 +#define PBS_UNIT_CFG_AXI_CONF_1_DBG_ARQOS_SHIFT 26 + +/**** cfg_axi_conf_2 register ****/ +/* Sets the AXI field in the SPI debug interface. */ +#define PBS_UNIT_CFG_AXI_CONF_2_DBG_AWUSER_MASK 0x03FFFFFF +#define PBS_UNIT_CFG_AXI_CONF_2_DBG_AWUSER_SHIFT 0 +/* Sets the AXI field in the SPI debug interface. */ +#define PBS_UNIT_CFG_AXI_CONF_2_DBG_AWQOS_MASK 0x3C000000 +#define PBS_UNIT_CFG_AXI_CONF_2_DBG_AWQOS_SHIFT 26 + +/**** spi_mst_conf_0 register ****/ +/* + * Sets the SPI master Configuration. For details see the SPI section in the + * documentation. + */ +#define PBS_UNIT_SPI_MST_CONF_0_CFG_SPI_MST_SRL (1 << 0) +/* + * Sets the SPI master Configuration. For details see the SPI section in the + * documentation. + */ +#define PBS_UNIT_SPI_MST_CONF_0_CFG_SPI_MST_SCPOL (1 << 1) +/* + * Sets the SPI master Configuration. For details see the SPI section in the + * documentation. + */ +#define PBS_UNIT_SPI_MST_CONF_0_CFG_SPI_MST_SCPH (1 << 2) +/* + * Set the SPI master configuration. For details see the SPI section in the + * documentation. + */ +#define PBS_UNIT_SPI_MST_CONF_0_CFG_SPI_MST_SER_MASK 0x00000078 +#define PBS_UNIT_SPI_MST_CONF_0_CFG_SPI_MST_SER_SHIFT 3 +/* + * Set the SPI master configuration. For details see the SPI section in the + * documentation. + */ +#define PBS_UNIT_SPI_MST_CONF_0_CFG_SPI_MST_BAUD_MASK 0x007FFF80 +#define PBS_UNIT_SPI_MST_CONF_0_CFG_SPI_MST_BAUD_SHIFT 7 +/* + * Sets the SPI master configuration. For details see the SPI section in the + * documentation. + */ +#define PBS_UNIT_SPI_MST_CONF_0_CFG_SPI_MST_RD_CMD_MASK 0x7F800000 +#define PBS_UNIT_SPI_MST_CONF_0_CFG_SPI_MST_RD_CMD_SHIFT 23 + +/**** spi_mst_conf_1 register ****/ +/* + * Sets the SPI master Configuration. For details see the SPI section in the + * documentation. + */ +#define PBS_UNIT_SPI_MST_CONF_1_CFG_SPI_MST_WR_CMD_MASK 0x000000FF +#define PBS_UNIT_SPI_MST_CONF_1_CFG_SPI_MST_WR_CMD_SHIFT 0 +/* + * Sets the SPI master Configuration. For details see the SPI section in the + * documentation. + */ +#define PBS_UNIT_SPI_MST_CONF_1_CFG_SPI_MST_ADDR_BYTES_NUM_MASK 0x00000700 +#define PBS_UNIT_SPI_MST_CONF_1_CFG_SPI_MST_ADDR_BYTES_NUM_SHIFT 8 +/* + * Sets the SPI master Configuration. For details see the SPI section in the + * documentation. + */ +#define PBS_UNIT_SPI_MST_CONF_1_CFG_SPI_MST_TMODE_MASK 0x00001800 +#define PBS_UNIT_SPI_MST_CONF_1_CFG_SPI_MST_TMODE_SHIFT 11 +/* + * Sets the SPI master Configuration. For details see the SPI section in the + * documentation. + */ +#define PBS_UNIT_SPI_MST_CONF_1_CFG_SPI_MST_FAST_RD (1 << 13) + +/**** spi_slv_conf_0 register ****/ +/* + * Sets the SPI slave configuration. For details see the SPI section in the + * documentation. + */ +#define PBS_UNIT_SPI_SLV_CONF_0_CFG_SPI_SLV_BAUD_MASK 0x0000FFFF +#define PBS_UNIT_SPI_SLV_CONF_0_CFG_SPI_SLV_BAUD_SHIFT 0 +/* Value. The reset value is according to bootstrap. */ +#define PBS_UNIT_SPI_SLV_CONF_0_CFG_SPI_SLV_SCPOL (1 << 16) +/* Value. The reset value is according to bootstrap. */ +#define PBS_UNIT_SPI_SLV_CONF_0_CFG_SPI_SLV_SCPH (1 << 17) +/* + * Sets the SPI slave configuration. For details see the SPI section in the + * documentation. + */ +#define PBS_UNIT_SPI_SLV_CONF_0_CFG_SPI_SLV_SER_MASK 0x03FC0000 +#define PBS_UNIT_SPI_SLV_CONF_0_CFG_SPI_SLV_SER_SHIFT 18 +/* + * Sets the SPI slave configuration. For details see the SPI section in the + * documentation. + */ +#define PBS_UNIT_SPI_SLV_CONF_0_CFG_SPI_SLV_SRL (1 << 26) +/* + * Sets the SPI slave configuration. For details see the SPI section in the + * documentation. + */ +#define PBS_UNIT_SPI_SLV_CONF_0_CFG_SPI_SLV_TMODE_MASK 0x18000000 +#define PBS_UNIT_SPI_SLV_CONF_0_CFG_SPI_SLV_TMODE_SHIFT 27 + +/**** apb_mem_conf_int register ****/ +/* Value-- internal */ +#define PBS_UNIT_APB_MEM_CONF_INT_CFG_PBS_WRR_CNT_MASK 0x00000007 +#define PBS_UNIT_APB_MEM_CONF_INT_CFG_PBS_WRR_CNT_SHIFT 0 +/* Value-- internal */ +#define PBS_UNIT_APB_MEM_CONF_INT_CFG_I2C_PLD_APB_MIX_ARB (1 << 3) +/* Value-- internal */ +#define PBS_UNIT_APB_MEM_CONF_INT_CFG_SPI_DBG_APB_MIX_ARB (1 << 4) +/* Value-- internal */ +#define PBS_UNIT_APB_MEM_CONF_INT_CFG_SPI_MST_APB_MIX_ARB (1 << 5) +/* Value-- internal */ +#define PBS_UNIT_APB_MEM_CONF_INT_CFG_I2C_PLD_CLEAR_FSM (1 << 6) +/* Value-- internal */ +#define PBS_UNIT_APB_MEM_CONF_INT_CFG_SPI_DBG_CLEAR_FSM (1 << 7) +/* Value-- internal */ +#define PBS_UNIT_APB_MEM_CONF_INT_CFG_SPI_MST_CLEAR_FSM (1 << 8) +/* Value-- internal */ +#define PBS_UNIT_APB_MEM_CONF_INT_CFG_PBS_AXI_FSM_CLEAR (1 << 9) +/* Value-- internal */ +#define PBS_UNIT_APB_MEM_CONF_INT_CFG_PBS_AXI_FIFOS_CLEAR (1 << 10) +/* Enables parity protection on the integrated SRAM. */ +#define PBS_UNIT_APB_MEM_CONF_INT_CFG_BOOTROM_PARITY_EN (1 << 11) +/* + * When set, reports a slave error whenthe slave returns an AXI slave error, for + * configuration access to the internal configuration space. + */ +#define PBS_UNIT_APB_MEM_CONF_INT_CFG_RD_SLV_ERR_EN (1 << 12) +/* + * When set, reports a decode error when timeout has occurred for configuration + * access to the internal configuration space. + */ +#define PBS_UNIT_APB_MEM_CONF_INT_CFG_RD_DEC_ERR_EN (1 << 13) +/* + * When set, reports a slave error, when the slave returns an AXI slave error, + * for configuration access to the internal configuration space. + */ +#define PBS_UNIT_APB_MEM_CONF_INT_CFG_WR_SLV_ERR_EN (1 << 14) +/* + * When set, reports a decode error when timeout has occurred for configuration + * access to the internal configuration space. + */ +#define PBS_UNIT_APB_MEM_CONF_INT_CFG_WR_DEC_ERR_EN (1 << 15) + +/**** sb_int_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_SB_INT_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_SB_INT_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_SB_INT_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_SB_INT_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_SB_INT_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_SB_INT_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** ufc_pbs_parity_err_high register ****/ +/* + * Address latch in the case of a parity error in the Flash Controller internal + * memories. + */ +#define PBS_UNIT_UFC_PBS_PARITY_ERR_HIGH_ADDR_MASK 0x000000FF +#define PBS_UNIT_UFC_PBS_PARITY_ERR_HIGH_ADDR_SHIFT 0 + +/**** chip_id register ****/ +/* [15:0] : Dev Rev ID */ +#define PBS_UNIT_CHIP_ID_DEV_REV_ID_MASK 0x0000FFFF +#define PBS_UNIT_CHIP_ID_DEV_REV_ID_SHIFT 0 +/* [31:16] : 0x0 - Dev ID */ +#define PBS_UNIT_CHIP_ID_DEV_ID_MASK 0xFFFF0000 +#define PBS_UNIT_CHIP_ID_DEV_ID_SHIFT 16 + +#define PBS_UNIT_CHIP_ID_DEV_ID_ALPINE 0 +#define PBS_UNIT_CHIP_ID_DEV_ID_PEAKROCK 1 +#define PBS_UNIT_CHIP_ID_DEV_ID_COYOTE 2 + +/**** uart0_conf_status register ****/ +/* + * Conf: + * // [0] -- DSR_N RW bit + * // [1] -- DCD_N RW bit + * // [2] -- RI_N bit + * // [3] -- dma_tx_ack_n + * // [4] -- dma_rx_ack_n + */ +#define PBS_UNIT_UART0_CONF_STATUS_CONF_MASK 0x0000FFFF +#define PBS_UNIT_UART0_CONF_STATUS_CONF_SHIFT 0 +/* + * Status: + * // [16] -- dtr_n RO bit + * // [17] -- OUT1_N RO bit + * // [18] -- OUT2_N RO bit + * // [19] -- dma_tx_req_n RO bit + * // [20] -- dma_tx_single_n RO bit + * // [21] -- dma_rx_req_n RO bit + * // [22] -- dma_rx_single_n RO bit + * // [23] -- uart_lp_req_pclk RO bit + * // [24] -- baudout_n RO bit + */ +#define PBS_UNIT_UART0_CONF_STATUS_STATUS_MASK 0xFFFF0000 +#define PBS_UNIT_UART0_CONF_STATUS_STATUS_SHIFT 16 + +/**** uart1_conf_status register ****/ +/* + * Conf: // [0] -- DSR_N RW bit // [1] -- DCD_N RW bit // [2] -- RI_N bit // [3] + * -- dma_tx_ack_n // [4] - dma_rx_ack_n + */ +#define PBS_UNIT_UART1_CONF_STATUS_CONF_MASK 0x0000FFFF +#define PBS_UNIT_UART1_CONF_STATUS_CONF_SHIFT 0 +/* + * Status: // [16] -- dtr_n RO bit // [17] -- OUT1_N RO bit // [18] -- OUT2_N RO + * bit // [19] -- dma_tx_req_n RO bit // [20] -- dma_tx_single_n RO bit // [21] + * -- dma_rx_req_n RO bit // [22] -- dma_rx_single_n RO bit // [23] -- + * uart_lp_req_pclk RO bit // [24] -- baudout_n RO bit + */ +#define PBS_UNIT_UART1_CONF_STATUS_STATUS_MASK 0xFFFF0000 +#define PBS_UNIT_UART1_CONF_STATUS_STATUS_SHIFT 16 + +/**** uart2_conf_status register ****/ +/* + * Conf: // [0] -- DSR_N RW bit // [1] -- DCD_N RW bit // [2] -- RI_N bit // [3] + * -- dma_tx_ack_n // [4] - dma_rx_ack_n + */ +#define PBS_UNIT_UART2_CONF_STATUS_CONF_MASK 0x0000FFFF +#define PBS_UNIT_UART2_CONF_STATUS_CONF_SHIFT 0 +/* + * Status: // [16] -- dtr_n RO bit // [17] -- OUT1_N RO bit // [18] -- OUT2_N RO + * bit // [19] -- dma_tx_req_n RO bit // [20] -- dma_tx_single_n RO bit // [21] + * -- dma_rx_req_n RO bit // [22] -- dma_rx_single_n RO bit // [23] -- + * uart_lp_req_pclk RO bit // [24] -- baudout_n RO bit + */ +#define PBS_UNIT_UART2_CONF_STATUS_STATUS_MASK 0xFFFF0000 +#define PBS_UNIT_UART2_CONF_STATUS_STATUS_SHIFT 16 + +/**** uart3_conf_status register ****/ +/* + * Conf: // [0] -- DSR_N RW bit // [1] -- DCD_N RW bit // [2] -- RI_N bit // [3] + * -- dma_tx_ack_n // [4] - dma_rx_ack_n + */ +#define PBS_UNIT_UART3_CONF_STATUS_CONF_MASK 0x0000FFFF +#define PBS_UNIT_UART3_CONF_STATUS_CONF_SHIFT 0 +/* + * Status: // [16] -- dtr_n RO bit // [17] -- OUT1_N RO bit // [18] -- OUT2_N RO + * bit // [19] -- dma_tx_req_n RO bit // [20] -- dma_tx_single_n RO bit // [21] + * -- dma_rx_req_n RO bit // [22] -- dma_rx_single_n RO bit // [23] -- + * uart_lp_req_pclk RO bit // [24] -- baudout_n RO bit + */ +#define PBS_UNIT_UART3_CONF_STATUS_STATUS_MASK 0xFFFF0000 +#define PBS_UNIT_UART3_CONF_STATUS_STATUS_SHIFT 16 + +/**** gpio0_conf_status register ****/ +/* + * Cntl: + * // [7:0] nGPAFEN; // from regfile + * // [15:8] GPAFOUT; // from regfile + */ +#define PBS_UNIT_GPIO0_CONF_STATUS_CONF_MASK 0x0000FFFF +#define PBS_UNIT_GPIO0_CONF_STATUS_CONF_SHIFT 0 +/* + * Status: + * // [24:16] GPAFIN; // to regfile + */ +#define PBS_UNIT_GPIO0_CONF_STATUS_STATUS_MASK 0xFFFF0000 +#define PBS_UNIT_GPIO0_CONF_STATUS_STATUS_SHIFT 16 + +/**** gpio1_conf_status register ****/ +/* + * Cntl: + * // [7:0] nGPAFEN; // from regfile + * // [15:8] GPAFOUT; // from regfile + */ +#define PBS_UNIT_GPIO1_CONF_STATUS_CONF_MASK 0x0000FFFF +#define PBS_UNIT_GPIO1_CONF_STATUS_CONF_SHIFT 0 +/* + * Status: + * // [24:16] GPAFIN; // to regfile + */ +#define PBS_UNIT_GPIO1_CONF_STATUS_STATUS_MASK 0xFFFF0000 +#define PBS_UNIT_GPIO1_CONF_STATUS_STATUS_SHIFT 16 + +/**** gpio2_conf_status register ****/ +/* + * Cntl: + * // [7:0] nGPAFEN; // from regfile + * // [15:8] GPAFOUT; // from regfile + */ +#define PBS_UNIT_GPIO2_CONF_STATUS_CONF_MASK 0x0000FFFF +#define PBS_UNIT_GPIO2_CONF_STATUS_CONF_SHIFT 0 +/* + * Status: + * // [24:16] GPAFIN; // to regfile + */ +#define PBS_UNIT_GPIO2_CONF_STATUS_STATUS_MASK 0xFFFF0000 +#define PBS_UNIT_GPIO2_CONF_STATUS_STATUS_SHIFT 16 + +/**** gpio3_conf_status register ****/ +/* + * Cntl: + * // [7:0] nGPAFEN; // from regfile + * // [15:8] GPAFOUT; // from regfile + */ +#define PBS_UNIT_GPIO3_CONF_STATUS_CONF_MASK 0x0000FFFF +#define PBS_UNIT_GPIO3_CONF_STATUS_CONF_SHIFT 0 +/* + * Status: + * // [24:16] GPAFIN; // to regfile + */ +#define PBS_UNIT_GPIO3_CONF_STATUS_STATUS_MASK 0xFFFF0000 +#define PBS_UNIT_GPIO3_CONF_STATUS_STATUS_SHIFT 16 + +/**** gpio4_conf_status register ****/ +/* + * Cntl: + * // [7:0] nGPAFEN; // from regfile + * // [15:8] GPAFOUT; // from regfile + */ +#define PBS_UNIT_GPIO4_CONF_STATUS_CONF_MASK 0x0000FFFF +#define PBS_UNIT_GPIO4_CONF_STATUS_CONF_SHIFT 0 +/* + * Status: + * // [24:16] GPAFIN; // to regfile + */ +#define PBS_UNIT_GPIO4_CONF_STATUS_STATUS_MASK 0xFFFF0000 +#define PBS_UNIT_GPIO4_CONF_STATUS_STATUS_SHIFT 16 + +/**** i2c_gen_conf_status register ****/ +/* + * cntl + * // [0] -- dma_tx_ack + * // [1] -- dma_rx_ack + */ +#define PBS_UNIT_I2C_GEN_CONF_STATUS_CONF_MASK 0x0000FFFF +#define PBS_UNIT_I2C_GEN_CONF_STATUS_CONF_SHIFT 0 +/* + * Status + * + * // [16] -- dma_tx_req RO bit + * // [17] -- dma_tx_single RO bit + * // [18] -- dma_rx_req RO bit + * // [19] -- dma_rx_single RO bit + */ +#define PBS_UNIT_I2C_GEN_CONF_STATUS_STATUS_MASK 0xFFFF0000 +#define PBS_UNIT_I2C_GEN_CONF_STATUS_STATUS_SHIFT 16 + +/**** watch_dog_reset_out register ****/ +/* + * [0] If set to 1'b1, WD0 cannot generate reset_out_n + * [1] If set to 1'b1, WD1 cannot generate reset_out_n + * [2] If set to 1'b1, WD2 cannot generate reset_out_n + * [3] If set to 1'b1, WD3 cannot generate reset_out_n + * [4] If set to 1'b1, WD4 cannot generate reset_out_n + * [5] If set to 1'b1, WD5 cannot generate reset_out_n + * [6] If set to 1'b1, WD6 cannot generate reset_out_n + * [7] If set to 1'b1, WD7 cannot generate reset_out_n + */ +#define PBS_UNIT_WATCH_DOG_RESET_OUT_DISABLE_MASK 0x000000FF +#define PBS_UNIT_WATCH_DOG_RESET_OUT_DISABLE_SHIFT 0 + +/**** otp_cntl register ****/ +/* from reg file Config To bypass the copy from OTPW to OTPR */ +#define PBS_UNIT_OTP_CNTL_IGNORE_OTPW (1 << 0) +/* Not in use.Comes from bond. */ +#define PBS_UNIT_OTP_CNTL_IGNORE_PRELOAD (1 << 1) +/* Margin read from the fuse box */ +#define PBS_UNIT_OTP_CNTL_OTPW_MARGIN_READ (1 << 2) +/* Indicates when OTPis busy. */ +#define PBS_UNIT_OTP_CNTL_OTP_BUSY (1 << 3) + +/**** otp_cfg_0 register ****/ +/* Cfg to OTP cntl. */ +#define PBS_UNIT_OTP_CFG_0_CFG_OTPW_PWRDN_CNT_MASK 0x0000FFFF +#define PBS_UNIT_OTP_CFG_0_CFG_OTPW_PWRDN_CNT_SHIFT 0 +/* Cfg to OTP cntl. */ +#define PBS_UNIT_OTP_CFG_0_CFG_OTPW_READ_CNT_MASK 0xFFFF0000 +#define PBS_UNIT_OTP_CFG_0_CFG_OTPW_READ_CNT_SHIFT 16 + +/**** otp_cfg_1 register ****/ +/* Cfg to OTP cntl. */ +#define PBS_UNIT_OTP_CFG_1_CFG_OTPW_PGM_CNT_MASK 0x0000FFFF +#define PBS_UNIT_OTP_CFG_1_CFG_OTPW_PGM_CNT_SHIFT 0 +/* Cfg to OTP cntl. */ +#define PBS_UNIT_OTP_CFG_1_CFG_OTPW_PREP_CNT_MASK 0xFFFF0000 +#define PBS_UNIT_OTP_CFG_1_CFG_OTPW_PREP_CNT_SHIFT 16 + +/**** otp_cfg_3 register ****/ +/* Cfg to OTP cntl. */ +#define PBS_UNIT_OTP_CFG_3_CFG_OTPW_PS18_CNT_MASK 0x0000FFFF +#define PBS_UNIT_OTP_CFG_3_CFG_OTPW_PS18_CNT_SHIFT 0 +/* Cfg to OTP cntl. */ +#define PBS_UNIT_OTP_CFG_3_CFG_OTPW_PWRUP_CNT_MASK 0xFFFF0000 +#define PBS_UNIT_OTP_CFG_3_CFG_OTPW_PWRUP_CNT_SHIFT 16 + +/**** nb_nic_regs_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_NB_NIC_REGS_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_NB_NIC_REGS_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_NB_NIC_REGS_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_NB_NIC_REGS_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_NB_NIC_REGS_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_NB_NIC_REGS_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** sb_nic_regs_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_SB_NIC_REGS_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_SB_NIC_REGS_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_SB_NIC_REGS_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_SB_NIC_REGS_BAR_LOW_RSRVD_SHIFT 6 +/* bar low address 16 MSB bits */ +#define PBS_UNIT_SB_NIC_REGS_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_SB_NIC_REGS_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** serdes_mux_multi_0 register ****/ +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_8_MASK 0x00000007 +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_8_SHIFT 0 +/* Reserved */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_RSRVD_3 (1 << 3) +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_9_MASK 0x00000070 +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_9_SHIFT 4 +/* Reserved */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_RSRVD_7 (1 << 7) +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_10_MASK 0x00000700 +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_10_SHIFT 8 +/* Reserved */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_RSRVD_11 (1 << 11) +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_11_MASK 0x00007000 +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_11_SHIFT 12 +/* Reserved */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_RSRVD_15 (1 << 15) +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_12_MASK 0x00030000 +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_12_SHIFT 16 +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_13_MASK 0x000C0000 +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_13_SHIFT 18 +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_14_MASK 0x00300000 +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_14_SHIFT 20 +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_15_MASK 0x00C00000 +#define PBS_UNIT_SERDES_MUX_MULTI_0_SELECT_OH_SERDES_15_SHIFT 22 +/* Reserved */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_RSRVD_MASK 0xFF000000 +#define PBS_UNIT_SERDES_MUX_MULTI_0_RSRVD_SHIFT 24 + +/* + * 2'b01 - select sata_b[0] + * 2'b10 - select eth_a[0] + */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_8_MASK 0x00000003 +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_8_SHIFT 0 +/* + * 3'b001 - select sata_b[1] + * 3'b010 - select eth_b[0] + * 3'b100 - select eth_a[1] + */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_9_MASK 0x00000070 +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_9_SHIFT 4 +/* + * 3'b001 - select sata_b[2] + * 3'b010 - select eth_c[0] + * 3'b100 - select eth_a[2] + */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_10_MASK 0x00000700 +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_10_SHIFT 8 +/* + * 3'b001 - select sata_b[3] + * 3'b010 - select eth_d[0] + * 3'b100 - select eth_a[3] + */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_11_MASK 0x00007000 +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_11_SHIFT 12 +/* + * 2'b01 - select eth_a[0] + * 2'b10 - select sata_a[0] + */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_12_MASK 0x00030000 +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_12_SHIFT 16 +/* + * 3'b001 - select eth_b[0] + * 3'b010 - select eth_c[1] + * 3'b100 - select sata_a[1] + */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_13_MASK 0x00700000 +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_13_SHIFT 20 +/* + * 3'b001 - select eth_a[0] + * 3'b010 - select eth_c[2] + * 3'b100 - select sata_a[2] + */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_14_MASK 0x07000000 +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_14_SHIFT 24 +/* + * 3'b001 - select eth_d[0] + * 3'b010 - select eth_c[3] + * 3'b100 - select sata_a[3] + */ +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_15_MASK 0x70000000 +#define PBS_UNIT_SERDES_MUX_MULTI_0_PKR_SELECT_OH_SERDES_15_SHIFT 28 + +/**** serdes_mux_multi_1 register ****/ +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_MULTI_1_SELECT_OH_ETH_A_0_MASK 0x00000003 +#define PBS_UNIT_SERDES_MUX_MULTI_1_SELECT_OH_ETH_A_0_SHIFT 0 +/* Reserved */ +#define PBS_UNIT_SERDES_MUX_MULTI_1_RSRVD_3_2_MASK 0x0000000C +#define PBS_UNIT_SERDES_MUX_MULTI_1_RSRVD_3_2_SHIFT 2 +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_MULTI_1_SELECT_OH_ETH_B_0_MASK 0x00000070 +#define PBS_UNIT_SERDES_MUX_MULTI_1_SELECT_OH_ETH_B_0_SHIFT 4 +/* Reserved */ +#define PBS_UNIT_SERDES_MUX_MULTI_1_RSRVD_7 (1 << 7) +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_MULTI_1_SELECT_OH_ETH_C_0_MASK 0x00000300 +#define PBS_UNIT_SERDES_MUX_MULTI_1_SELECT_OH_ETH_C_0_SHIFT 8 +/* Reserved */ +#define PBS_UNIT_SERDES_MUX_MULTI_1_RSRVD_11_10_MASK 0x00000C00 +#define PBS_UNIT_SERDES_MUX_MULTI_1_RSRVD_11_10_SHIFT 10 +/* SerDes one hot mux control. For details see datasheet. */ +#define PBS_UNIT_SERDES_MUX_MULTI_1_SELECT_OH_ETH_D_0_MASK 0x00007000 +#define PBS_UNIT_SERDES_MUX_MULTI_1_SELECT_OH_ETH_D_0_SHIFT 12 +/* Reserved */ +#define PBS_UNIT_SERDES_MUX_MULTI_1_RSRVD_MASK 0xFFFF8000 +#define PBS_UNIT_SERDES_MUX_MULTI_1_RSRVD_SHIFT 15 + +/**** pbs_ulpi_mux_conf register ****/ +/* + * Value 0 - Select dedicated pins for the USB-1 inputs. + * Value 1 - Select PBS mux pins for the USB-1 inputs. + * [0] ULPI_B_CLK + * [1] ULPI_B_DIR + * [2] ULPI_B_NXT + * [10:3] ULPI_B_DATA[7:0] + */ +#define PBS_UNIT_PBS_ULPI_MUX_CONF_SEL_UPLI_IN_PBSMUX_MASK 0x000007FF +#define PBS_UNIT_PBS_ULPI_MUX_CONF_SEL_UPLI_IN_PBSMUX_SHIFT 0 +/* + * [3] - Force to zero + * [2] == 1 - Force register selection + * [1 : 0] -Binary selection of the input in bypass mode + */ +#define PBS_UNIT_PBS_ULPI_MUX_CONF_REG_MDIO_BYPASS_SEL_MASK 0x0000F000 +#define PBS_UNIT_PBS_ULPI_MUX_CONF_REG_MDIO_BYPASS_SEL_SHIFT 12 +/* + * [0] Sets the clk_ulpi OE for USB0, 1'b0 set to input, 1'b1 set to output. + * [1] Sets the clk_ulpi OE for USB01, 1'b0 set to input, 1'b1 set to output. + */ +#define PBS_UNIT_PBS_ULPI_MUX_CONF_RSRVD_MASK 0xFFFF0000 +#define PBS_UNIT_PBS_ULPI_MUX_CONF_RSRVD_SHIFT 16 + +/**** wr_once_dbg_dis_ovrd_reg register ****/ +/* This register can be written only once. Use in the secure boot process. */ +#define PBS_UNIT_WR_ONCE_DBG_DIS_OVRD_REG_WR_ONCE_DBG_DIS_OVRD (1 << 0) + +#define PBS_UNIT_WR_ONCE_DBG_DIS_OVRD_REG_RSRVD_MASK 0xFFFFFFFE +#define PBS_UNIT_WR_ONCE_DBG_DIS_OVRD_REG_RSRVD_SHIFT 1 + +/**** gpio5_conf_status register ****/ +/* + * Cntl: // [7:0] nGPAFEN; // from regfile // [15:8] GPAFOUT; // from regfile + */ +#define PBS_UNIT_GPIO5_CONF_STATUS_CONF_MASK 0x0000FFFF +#define PBS_UNIT_GPIO5_CONF_STATUS_CONF_SHIFT 0 +/* Status: // [24:16] GPAFIN; // to regfile */ +#define PBS_UNIT_GPIO5_CONF_STATUS_STATUS_MASK 0xFFFF0000 +#define PBS_UNIT_GPIO5_CONF_STATUS_STATUS_SHIFT 16 + +/**** pcie_mem3_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PCIE_MEM3_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PCIE_MEM3_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PCIE_MEM3_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PCIE_MEM3_BAR_LOW_RSRVD_SHIFT 6 +/* Reserved */ +#define PBS_UNIT_PCIE_MEM3_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PCIE_MEM3_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pcie_mem4_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PCIE_MEM4_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PCIE_MEM4_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PCIE_MEM4_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PCIE_MEM4_BAR_LOW_RSRVD_SHIFT 6 +/* Reserved */ +#define PBS_UNIT_PCIE_MEM4_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PCIE_MEM4_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pcie_mem5_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PCIE_MEM5_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PCIE_MEM5_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PCIE_MEM5_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PCIE_MEM5_BAR_LOW_RSRVD_SHIFT 6 +/* Reserved */ +#define PBS_UNIT_PCIE_MEM5_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PCIE_MEM5_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pcie_ext_ecam3_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PCIE_EXT_ECAM3_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PCIE_EXT_ECAM3_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PCIE_EXT_ECAM3_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PCIE_EXT_ECAM3_BAR_LOW_RSRVD_SHIFT 6 +/* Reserved */ +#define PBS_UNIT_PCIE_EXT_ECAM3_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PCIE_EXT_ECAM3_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pcie_ext_ecam4_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PCIE_EXT_ECAM4_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PCIE_EXT_ECAM4_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PCIE_EXT_ECAM4_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PCIE_EXT_ECAM4_BAR_LOW_RSRVD_SHIFT 6 +/* Reserved */ +#define PBS_UNIT_PCIE_EXT_ECAM4_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PCIE_EXT_ECAM4_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pcie_ext_ecam5_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_PCIE_EXT_ECAM5_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_PCIE_EXT_ECAM5_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_PCIE_EXT_ECAM5_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_PCIE_EXT_ECAM5_BAR_LOW_RSRVD_SHIFT 6 +/* Reserved */ +#define PBS_UNIT_PCIE_EXT_ECAM5_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_PCIE_EXT_ECAM5_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** low_latency_sram_bar_low register ****/ +/* Window size = 2 ^ (15 + win_size). Zero value: disable the window. */ +#define PBS_UNIT_LOW_LATENCY_SRAM_BAR_LOW_WIN_SIZE_MASK 0x0000003F +#define PBS_UNIT_LOW_LATENCY_SRAM_BAR_LOW_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_UNIT_LOW_LATENCY_SRAM_BAR_LOW_RSRVD_MASK 0x0000FFC0 +#define PBS_UNIT_LOW_LATENCY_SRAM_BAR_LOW_RSRVD_SHIFT 6 +/* Reserved */ +#define PBS_UNIT_LOW_LATENCY_SRAM_BAR_LOW_ADDR_HIGH_MASK 0xFFFF0000 +#define PBS_UNIT_LOW_LATENCY_SRAM_BAR_LOW_ADDR_HIGH_SHIFT 16 + +/**** pbs_sb2nb_cfg_dram_remap register ****/ +#define PBS_UNIT_SB2NB_REMAP_BASE_ADDR_SHIFT 5 +#define PBS_UNIT_SB2NB_REMAP_BASE_ADDR_MASK 0x0000FFE0 +#define PBS_UNIT_SB2NB_REMAP_TRANSL_BASE_ADDR_SHIFT 21 +#define PBS_UNIT_SB2NB_REMAP_TRANSL_BASE_ADDR_MASK 0xFFE00000 + +/* For remapping are used bits [39 - 29] of DRAM 40bit Physical address */ +#define PBS_UNIT_DRAM_SRC_REMAP_BASE_ADDR_SHIFT 29 +#define PBS_UNIT_DRAM_DST_REMAP_BASE_ADDR_SHIFT 29 +#define PBS_UNIT_DRAM_REMAP_BASE_ADDR_MASK 0xFFE0000000UL + + +/**** serdes_mux_eth register ****/ +/* + * 2'b01 - eth_a[0] from serdes_8 + * 2'b10 - eth_a[0] from serdes_14 + */ +#define PBS_UNIT_SERDES_MUX_ETH_PKR_SELECT_OH_ETH_A_0_MASK 0x00000003 +#define PBS_UNIT_SERDES_MUX_ETH_PKR_SELECT_OH_ETH_A_0_SHIFT 0 +/* + * 2'b01 - eth_b[0] from serdes_9 + * 2'b10 - eth_b[0] from serdes_13 + */ +#define PBS_UNIT_SERDES_MUX_ETH_PKR_SELECT_OH_ETH_B_0_MASK 0x00000030 +#define PBS_UNIT_SERDES_MUX_ETH_PKR_SELECT_OH_ETH_B_0_SHIFT 4 +/* + * 2'b01 - eth_c[0] from serdes_10 + * 2'b10 - eth_c[0] from serdes_12 + */ +#define PBS_UNIT_SERDES_MUX_ETH_PKR_SELECT_OH_ETH_C_0_MASK 0x00000300 +#define PBS_UNIT_SERDES_MUX_ETH_PKR_SELECT_OH_ETH_C_0_SHIFT 8 +/* + * 2'b01 - eth_d[0] from serdes_11 + * 2'b10 - eth_d[0] from serdes_15 + */ +#define PBS_UNIT_SERDES_MUX_ETH_PKR_SELECT_OH_ETH_D_0_MASK 0x00003000 +#define PBS_UNIT_SERDES_MUX_ETH_PKR_SELECT_OH_ETH_D_0_SHIFT 12 +/* which lane's is master clk */ +#define PBS_UNIT_SERDES_MUX_ETH_PKR_SELECT_OH_ETH_A_ICK_MASTER_MASK 0x00030000 +#define PBS_UNIT_SERDES_MUX_ETH_PKR_SELECT_OH_ETH_A_ICK_MASTER_SHIFT 16 +/* which lane's is master clk */ +#define PBS_UNIT_SERDES_MUX_ETH_PKR_SELECT_OH_ETH_C_ICK_MASTER_MASK 0x00300000 +#define PBS_UNIT_SERDES_MUX_ETH_PKR_SELECT_OH_ETH_C_ICK_MASTER_SHIFT 20 +/* enable xlaui on eth a */ +#define PBS_UNIT_SERDES_MUX_ETH_PKR_SELECT_OH_ETH_A_XLAUI_ENABLE (1 << 24) +/* enable xlaui on eth c */ +#define PBS_UNIT_SERDES_MUX_ETH_PKR_SELECT_OH_ETH_C_XLAUI_ENABLE (1 << 28) + +/**** serdes_mux_pcie register ****/ +/* + * 2'b01 - select pcie_b[0] from serdes 2 + * 2'b10 - select pcie_b[0] from serdes 4 + */ +#define PBS_UNIT_SERDES_MUX_PCIE_PKR_SELECT_OH_PCIE_B_0_MASK 0x00000003 +#define PBS_UNIT_SERDES_MUX_PCIE_PKR_SELECT_OH_PCIE_B_0_SHIFT 0 +/* + * 2'b01 - select pcie_b[1] from serdes 3 + * 2'b10 - select pcie_b[1] from serdes 5 + */ +#define PBS_UNIT_SERDES_MUX_PCIE_PKR_SELECT_OH_PCIE_B_1_MASK 0x00000030 +#define PBS_UNIT_SERDES_MUX_PCIE_PKR_SELECT_OH_PCIE_B_1_SHIFT 4 +/* + * 2'b01 - select pcie_d[0] from serdes 10 + * 2'b10 - select pcie_d[0] from serdes 12 + */ +#define PBS_UNIT_SERDES_MUX_PCIE_PKR_SELECT_OH_PCIE_D_0_MASK 0x00000300 +#define PBS_UNIT_SERDES_MUX_PCIE_PKR_SELECT_OH_PCIE_D_0_SHIFT 8 +/* + * 2'b01 - select pcie_d[1] from serdes 11 + * 2'b10 - select pcie_d[1] from serdes 13 + */ +#define PBS_UNIT_SERDES_MUX_PCIE_PKR_SELECT_OH_PCIE_D_1_MASK 0x00003000 +#define PBS_UNIT_SERDES_MUX_PCIE_PKR_SELECT_OH_PCIE_D_1_SHIFT 12 + +/**** serdes_mux_sata register ****/ +/* + * 2'b01 - select sata_a from serdes group 1 + * 2'b10 - select sata_a from serdes group 3 + */ +#define PBS_UNIT_SERDES_MUX_SATA_SELECT_OH_SATA_A_MASK 0x00000003 +#define PBS_UNIT_SERDES_MUX_SATA_SELECT_OH_SATA_A_SHIFT 0 +/* Reserved */ +#define PBS_UNIT_SERDES_MUX_SATA_RESERVED_3_2_MASK 0x0000000C +#define PBS_UNIT_SERDES_MUX_SATA_RESERVED_3_2_SHIFT 2 +/* Reserved */ +#define PBS_UNIT_SERDES_MUX_SATA_RESERVED_MASK 0xFFFFFFF0 +#define PBS_UNIT_SERDES_MUX_SATA_RESERVED_SHIFT 4 + +/**** bar1_orig register ****/ +/* + * Window size = 2 ^ (11 + win_size). + * Zero value: disable the window. + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR1_ORIG_WIN_SIZE_MASK 0x00000007 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR1_ORIG_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR1_ORIG_RSRVD_MASK 0x00000FF8 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR1_ORIG_RSRVD_SHIFT 3 +/* + * offset within the SRAM, in resolution of 4KB. + * Only offsets which are inside the boundaries of the SRAM bar are allowed + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR1_ORIG_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR1_ORIG_ADDR_HIGH_SHIFT 12 + +/**** bar1_remap register ****/ +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR1_REMAP_RSRVD_MASK 0x00000FFF +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR1_REMAP_RSRVD_SHIFT 0 +/* remapped address */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR1_REMAP_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR1_REMAP_ADDR_HIGH_SHIFT 12 + +/**** bar2_orig register ****/ +/* + * Window size = 2 ^ (11 + win_size). + * Zero value: disable the window. + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR2_ORIG_WIN_SIZE_MASK 0x00000007 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR2_ORIG_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR2_ORIG_RSRVD_MASK 0x00000FF8 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR2_ORIG_RSRVD_SHIFT 3 +/* + * offset within the SRAM, in resolution of 4KB. + * Only offsets which are inside the boundaries of the SRAM bar are allowed + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR2_ORIG_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR2_ORIG_ADDR_HIGH_SHIFT 12 + +/**** bar2_remap register ****/ +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR2_REMAP_RSRVD_MASK 0x00000FFF +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR2_REMAP_RSRVD_SHIFT 0 +/* remapped address */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR2_REMAP_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR2_REMAP_ADDR_HIGH_SHIFT 12 + +/**** bar3_orig register ****/ +/* + * Window size = 2 ^ (11 + win_size). + * Zero value: disable the window. + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR3_ORIG_WIN_SIZE_MASK 0x00000007 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR3_ORIG_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR3_ORIG_RSRVD_MASK 0x00000FF8 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR3_ORIG_RSRVD_SHIFT 3 +/* + * offset within the SRAM, in resolution of 4KB. + * Only offsets which are inside the boundaries of the SRAM bar are allowed + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR3_ORIG_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR3_ORIG_ADDR_HIGH_SHIFT 12 + +/**** bar3_remap register ****/ +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR3_REMAP_RSRVD_MASK 0x00000FFF +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR3_REMAP_RSRVD_SHIFT 0 +/* remapped address */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR3_REMAP_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR3_REMAP_ADDR_HIGH_SHIFT 12 + +/**** bar4_orig register ****/ +/* + * Window size = 2 ^ (11 + win_size). + * Zero value: disable the window. + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR4_ORIG_WIN_SIZE_MASK 0x00000007 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR4_ORIG_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR4_ORIG_RSRVD_MASK 0x00000FF8 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR4_ORIG_RSRVD_SHIFT 3 +/* + * offset within the SRAM, in resolution of 4KB. + * Only offsets which are inside the boundaries of the SRAM bar are allowed + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR4_ORIG_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR4_ORIG_ADDR_HIGH_SHIFT 12 + +/**** bar4_remap register ****/ +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR4_REMAP_RSRVD_MASK 0x00000FFF +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR4_REMAP_RSRVD_SHIFT 0 +/* remapped address */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR4_REMAP_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR4_REMAP_ADDR_HIGH_SHIFT 12 + +/**** bar5_orig register ****/ +/* + * Window size = 2 ^ (11 + win_size). + * Zero value: disable the window. + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR5_ORIG_WIN_SIZE_MASK 0x00000007 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR5_ORIG_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR5_ORIG_RSRVD_MASK 0x00000FF8 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR5_ORIG_RSRVD_SHIFT 3 +/* + * offset within the SRAM, in resolution of 4KB. + * Only offsets which are inside the boundaries of the SRAM bar are allowed + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR5_ORIG_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR5_ORIG_ADDR_HIGH_SHIFT 12 + +/**** bar5_remap register ****/ +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR5_REMAP_RSRVD_MASK 0x00000FFF +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR5_REMAP_RSRVD_SHIFT 0 +/* remapped address */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR5_REMAP_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR5_REMAP_ADDR_HIGH_SHIFT 12 + +/**** bar6_orig register ****/ +/* + * Window size = 2 ^ (11 + win_size). + * Zero value: disable the window. + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR6_ORIG_WIN_SIZE_MASK 0x00000007 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR6_ORIG_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR6_ORIG_RSRVD_MASK 0x00000FF8 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR6_ORIG_RSRVD_SHIFT 3 +/* + * offset within the SRAM, in resolution of 4KB. + * Only offsets which are inside the boundaries of the SRAM bar are allowed + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR6_ORIG_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR6_ORIG_ADDR_HIGH_SHIFT 12 + +/**** bar6_remap register ****/ +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR6_REMAP_RSRVD_MASK 0x00000FFF +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR6_REMAP_RSRVD_SHIFT 0 +/* remapped address */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR6_REMAP_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR6_REMAP_ADDR_HIGH_SHIFT 12 + +/**** bar7_orig register ****/ +/* + * Window size = 2 ^ (11 + win_size). + * Zero value: disable the window. + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR7_ORIG_WIN_SIZE_MASK 0x00000007 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR7_ORIG_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR7_ORIG_RSRVD_MASK 0x00000FF8 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR7_ORIG_RSRVD_SHIFT 3 +/* + * offset within the SRAM, in resolution of 4KB. + * Only offsets which are inside the boundaries of the SRAM bar are allowed + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR7_ORIG_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR7_ORIG_ADDR_HIGH_SHIFT 12 + +/**** bar7_remap register ****/ +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR7_REMAP_RSRVD_MASK 0x00000FFF +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR7_REMAP_RSRVD_SHIFT 0 +/* remapped address */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR7_REMAP_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR7_REMAP_ADDR_HIGH_SHIFT 12 + +/**** bar8_orig register ****/ +/* + * Window size = 2 ^ (11 + win_size). + * Zero value: disable the window. + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR8_ORIG_WIN_SIZE_MASK 0x00000007 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR8_ORIG_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR8_ORIG_RSRVD_MASK 0x00000FF8 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR8_ORIG_RSRVD_SHIFT 3 +/* + * offset within the SRAM, in resolution of 4KB. + * Only offsets which are inside the boundaries of the SRAM bar are allowed + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR8_ORIG_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR8_ORIG_ADDR_HIGH_SHIFT 12 + +/**** bar8_remap register ****/ +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR8_REMAP_RSRVD_MASK 0x00000FFF +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR8_REMAP_RSRVD_SHIFT 0 +/* remapped address */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR8_REMAP_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR8_REMAP_ADDR_HIGH_SHIFT 12 + +/**** bar9_orig register ****/ +/* + * Window size = 2 ^ (11 + win_size). + * Zero value: disable the window. + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR9_ORIG_WIN_SIZE_MASK 0x00000007 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR9_ORIG_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR9_ORIG_RSRVD_MASK 0x00000FF8 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR9_ORIG_RSRVD_SHIFT 3 +/* + * offset within the SRAM, in resolution of 4KB. + * Only offsets which are inside the boundaries of the SRAM bar are allowed + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR9_ORIG_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR9_ORIG_ADDR_HIGH_SHIFT 12 + +/**** bar9_remap register ****/ +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR9_REMAP_RSRVD_MASK 0x00000FFF +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR9_REMAP_RSRVD_SHIFT 0 +/* remapped address */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR9_REMAP_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR9_REMAP_ADDR_HIGH_SHIFT 12 + +/**** bar10_orig register ****/ +/* + * Window size = 2 ^ (11 + win_size). + * Zero value: disable the window. + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR10_ORIG_WIN_SIZE_MASK 0x00000007 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR10_ORIG_WIN_SIZE_SHIFT 0 +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR10_ORIG_RSRVD_MASK 0x00000FF8 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR10_ORIG_RSRVD_SHIFT 3 +/* + * offset within the SRAM, in resolution of 4KB. + * Only offsets which are inside the boundaries of the SRAM bar are allowed + */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR10_ORIG_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR10_ORIG_ADDR_HIGH_SHIFT 12 + +/**** bar10_remap register ****/ +/* Reserved fields */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR10_REMAP_RSRVD_MASK 0x00000FFF +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR10_REMAP_RSRVD_SHIFT 0 +/* remapped address */ +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR10_REMAP_ADDR_HIGH_MASK 0xFFFFF000 +#define PBS_LOW_LATENCY_SRAM_REMAP_BAR10_REMAP_ADDR_HIGH_SHIFT 12 + +/**** cpu register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_CPU_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_CPU_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_CPU_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_CPU_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_CPU_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_CPU_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_CPU_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_CPU_DRAM_SHIFT 28 + +/**** cpu_mask register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_CPU_MASK_DRAM_SHIFT 28 + +/**** debug_nb register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_DRAM_SHIFT 28 + +/**** debug_nb_mask register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_NB_MASK_DRAM_SHIFT 28 + +/**** debug_sb register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_DRAM_SHIFT 28 + +/**** debug_sb_mask register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_DEBUG_SB_MASK_DRAM_SHIFT 28 + +/**** eth_0 register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_DRAM_SHIFT 28 + +/**** eth_0_mask register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_0_MASK_DRAM_SHIFT 28 + +/**** eth_1 register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_DRAM_SHIFT 28 + +/**** eth_1_mask register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_1_MASK_DRAM_SHIFT 28 + +/**** eth_2 register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_DRAM_SHIFT 28 + +/**** eth_2_mask register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_2_MASK_DRAM_SHIFT 28 + +/**** eth_3 register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_DRAM_SHIFT 28 + +/**** eth_3_mask register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_ETH_3_MASK_DRAM_SHIFT 28 + +/**** sata_0 register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_DRAM_SHIFT 28 + +/**** sata_0_mask register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_0_MASK_DRAM_SHIFT 28 + +/**** sata_1 register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_DRAM_SHIFT 28 + +/**** sata_1_mask register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_SATA_1_MASK_DRAM_SHIFT 28 + +/**** crypto_0 register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_DRAM_SHIFT 28 + +/**** crypto_0_mask register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_0_MASK_DRAM_SHIFT 28 + +/**** crypto_1 register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_DRAM_SHIFT 28 + +/**** crypto_1_mask register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_CRYPTO_1_MASK_DRAM_SHIFT 28 + +/**** pcie_0 register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_DRAM_SHIFT 28 + +/**** pcie_0_mask register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_0_MASK_DRAM_SHIFT 28 + +/**** pcie_1 register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_DRAM_SHIFT 28 + +/**** pcie_1_mask register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_1_MASK_DRAM_SHIFT 28 + +/**** pcie_2 register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_DRAM_SHIFT 28 + +/**** pcie_2_mask register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_2_MASK_DRAM_SHIFT 28 + +/**** pcie_3 register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_DRAM_SHIFT 28 + +/**** pcie_3_mask register ****/ +/* map transactions according to address decoding */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_NO_ENFORCEMENT_MASK 0x0000000F +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_NO_ENFORCEMENT_SHIFT 0 +/* map transactions to pcie_0 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_PCIE_0_MASK 0x000000F0 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_PCIE_0_SHIFT 4 +/* map transactions to pcie_1 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_PCIE_1_MASK 0x00000F00 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_PCIE_1_SHIFT 8 +/* map transactions to pcie_2 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_PCIE_2_MASK 0x0000F000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_PCIE_2_SHIFT 12 +/* map transactions to pcie_3 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_PCIE_3_MASK 0x000F0000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_PCIE_3_SHIFT 16 +/* map transactions to pcie_4 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_PCIE_4_MASK 0x00F00000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_PCIE_4_SHIFT 20 +/* map transactions to pcie_5 */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_PCIE_5_MASK 0x0F000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_PCIE_5_SHIFT 24 +/* map transactions to dram */ +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_DRAM_MASK 0xF0000000 +#define PBS_TARGET_ID_ENFORCEMENT_PCIE_3_MASK_DRAM_SHIFT 28 + +/**** latch register ****/ +/* + * Software clears this bit before any bar update, and set it after all bars + * updated. + */ +#define PBS_TARGET_ID_ENFORCEMENT_LATCH_ENABLE (1 << 0) + +#ifdef __cplusplus +} +#endif + +#endif /* __AL_HAL_PBS_REGS_H__ */ + +/** @} end of ... group */ + + Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pbs_regs.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie.c =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie.c (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie.c (revision 283031) @@ -0,0 +1,2788 @@ +/*- +******************************************************************************** +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include "al_hal_pcie.h" +#include "al_hal_pbs_regs.h" +#include "al_hal_unit_adapter_regs.h" + +/** + * Parameter definitions + */ +#define AL_PCIE_AXI_REGS_OFFSET 0x0 + +#define AL_PCIE_LTSSM_STATE_L0 0x11 +#define AL_PCIE_LTSSM_STATE_L0S 0x12 +#define AL_PCIE_DEVCTL_PAYLOAD_128B 0x00 +#define AL_PCIE_DEVCTL_PAYLOAD_256B 0x20 + +#define AL_PCIE_SECBUS_DEFAULT 0x1 +#define AL_PCIE_SUBBUS_DEFAULT 0x1 +#define AL_PCIE_LINKUP_WAIT_INTERVAL 50 /* measured in usec */ +#define AL_PCIE_LINKUP_WAIT_INTERVALS_PER_SEC 20 + +#define AL_PCIE_LINKUP_RETRIES 8 + +#define AL_PCIE_MAX_32_MEMORY_BAR_SIZE (0x100000000ULL) +#define AL_PCIE_MIN_MEMORY_BAR_SIZE (1 << 12) +#define AL_PCIE_MIN_IO_BAR_SIZE (1 << 8) + +/** + * inbound header credits and outstanding outbound reads defaults + */ +/** RC - Revisions 1/2 */ +#define AL_PCIE_REV_1_2_RC_OB_OS_READS_DEFAULT (8) +#define AL_PCIE_REV_1_2_RC_NOF_CPL_HDR_DEFAULT (41) +#define AL_PCIE_REV_1_2_RC_NOF_NP_HDR_DEFAULT (25) +#define AL_PCIE_REV_1_2_RC_NOF_P_HDR_DEFAULT (31) +/** EP - Revisions 1/2 */ +#define AL_PCIE_REV_1_2_EP_OB_OS_READS_DEFAULT (15) +#define AL_PCIE_REV_1_2_EP_NOF_CPL_HDR_DEFAULT (76) +#define AL_PCIE_REV_1_2_EP_NOF_NP_HDR_DEFAULT (6) +#define AL_PCIE_REV_1_2_EP_NOF_P_HDR_DEFAULT (15) +/** RC - Revision 3 */ +#define AL_PCIE_REV_3_RC_OB_OS_READS_DEFAULT (32) +#define AL_PCIE_REV_3_RC_NOF_CPL_HDR_DEFAULT (161) +#define AL_PCIE_REV_3_RC_NOF_NP_HDR_DEFAULT (38) +#define AL_PCIE_REV_3_RC_NOF_P_HDR_DEFAULT (60) +/** EP - Revision 3 */ +#define AL_PCIE_REV_3_EP_OB_OS_READS_DEFAULT (32) +#define AL_PCIE_REV_3_EP_NOF_CPL_HDR_DEFAULT (161) +#define AL_PCIE_REV_3_EP_NOF_NP_HDR_DEFAULT (38) +#define AL_PCIE_REV_3_EP_NOF_P_HDR_DEFAULT (60) + +/** + * MACROS + */ +#define AL_PCIE_PARSE_LANES(v) (((1 << v) - 1) << \ + PCIE_REVX_AXI_MISC_PCIE_GLOBAL_CONF_NOF_ACT_LANES_SHIFT) + +/** + * Static functions + */ +static void +al_pcie_port_wr_to_ro_set(struct al_pcie_port *pcie_port, al_bool enable) +{ + /* when disabling writes to RO, make sure any previous writes to + * config space were committed + */ + if (enable == AL_FALSE) + al_local_data_memory_barrier(); + + al_reg_write32(&pcie_port->regs->port_regs->rd_only_wr_en, + (enable == AL_TRUE) ? 1 : 0); + + /* when enabling writes to RO, make sure it is committed before trying + * to write to RO config space + */ + if (enable == AL_TRUE) + al_local_data_memory_barrier(); +} + +/** helper function to access dbi_cs2 registers */ +static void +al_reg_write32_dbi_cs2( + struct al_pcie_port *pcie_port, + uint32_t *offset, + uint32_t val) +{ + uintptr_t cs2_bit = + (pcie_port->rev_id == AL_PCIE_REV_ID_3) ? 0x4000 : 0x1000; + + al_reg_write32((uint32_t *)((uintptr_t)offset | cs2_bit), val); +} + +static unsigned int +al_pcie_speed_gen_code(enum al_pcie_link_speed speed) +{ + if (speed == AL_PCIE_LINK_SPEED_GEN1) + return 1; + if (speed == AL_PCIE_LINK_SPEED_GEN2) + return 2; + if (speed == AL_PCIE_LINK_SPEED_GEN3) + return 3; + /* must not be reached */ + return 0; +} + +static inline void +al_pcie_port_link_speed_ctrl_set( + struct al_pcie_port *pcie_port, + enum al_pcie_link_speed max_speed) +{ + struct al_pcie_regs *regs = pcie_port->regs; + + al_pcie_port_wr_to_ro_set(pcie_port, AL_TRUE); + + if (max_speed != AL_PCIE_LINK_SPEED_DEFAULT) { + uint16_t max_speed_val = (uint16_t)al_pcie_speed_gen_code(max_speed); + al_reg_write32_masked( + (uint32_t __iomem *)(regs->core_space[0].pcie_link_cap_base), + 0xF, max_speed_val); + al_reg_write32_masked( + (uint32_t __iomem *)(regs->core_space[0].pcie_cap_base + + (AL_PCI_EXP_LNKCTL2 >> 2)), + 0xF, max_speed_val); + } + + al_pcie_port_wr_to_ro_set(pcie_port, AL_FALSE); +} + +static int +al_pcie_port_link_config( + struct al_pcie_port *pcie_port, + const struct al_pcie_link_params *link_params) +{ + struct al_pcie_regs *regs = pcie_port->regs; + uint8_t max_lanes = pcie_port->max_lanes; + + if ((link_params->max_payload_size != AL_PCIE_MPS_DEFAULT) && + (link_params->max_payload_size != AL_PCIE_MPS_128) && + (link_params->max_payload_size != AL_PCIE_MPS_256)) { + al_err("PCIe %d: unsupported Max Payload Size (%u)\n", + pcie_port->port_id, link_params->max_payload_size); + return -EINVAL; + } + + al_dbg("PCIe %d: link config: max speed gen %d, max lanes %d, reversal %s\n", + pcie_port->port_id, link_params->max_speed, + pcie_port->max_lanes, link_params->enable_reversal? "enable" : "disable"); + + al_pcie_port_link_speed_ctrl_set(pcie_port, link_params->max_speed); + + /* Change Max Payload Size, if needed. + * The Max Payload Size is only valid for PF0. + */ + if (link_params->max_payload_size != AL_PCIE_MPS_DEFAULT) + al_reg_write32_masked(regs->core_space[0].pcie_dev_ctrl_status, + PCIE_PORT_DEV_CTRL_STATUS_MPS_MASK, + link_params->max_payload_size << + PCIE_PORT_DEV_CTRL_STATUS_MPS_SHIFT); + + /** Snap from PCIe core spec: + * Link Mode Enable. Sets the number of lanes in the link that you want + * to connect to the link partner. When you have unused lanes in your + * system, then you must change the value in this register to reflect + * the number of lanes. You must also change the value in the + * "Predetermined Number of Lanes" field of the "Link Width and Speed + * Change Control Register". + * 000001: x1 + * 000011: x2 + * 000111: x4 + * 001111: x8 + * 011111: x16 + * 111111: x32 (not supported) + */ + al_reg_write32_masked(®s->port_regs->gen2_ctrl, + PCIE_PORT_GEN2_CTRL_NUM_OF_LANES_MASK, + max_lanes << PCIE_PORT_GEN2_CTRL_NUM_OF_LANES_SHIFT); + al_reg_write32_masked(®s->port_regs->port_link_ctrl, + PCIE_PORT_LINK_CTRL_LINK_CAPABLE_MASK, + (max_lanes + (max_lanes-1)) + << PCIE_PORT_LINK_CTRL_LINK_CAPABLE_SHIFT); + + /* TODO: add support for reversal mode */ + if (link_params->enable_reversal) { + al_err("PCIe %d: enabling reversal mode not implemented\n", + pcie_port->port_id); + return -ENOSYS; + } + return 0; +} + +static void +al_pcie_port_ram_parity_int_config( + struct al_pcie_port *pcie_port, + al_bool enable) +{ + struct al_pcie_regs *regs = pcie_port->regs; + + al_reg_write32(®s->app.parity->en_core, + (enable == AL_TRUE) ? 0xffffffff : 0x0); + + al_reg_write32_masked(®s->app.int_grp_b->mask, + PCIE_W_INT_GRP_B_CAUSE_B_PARITY_ERROR_CORE, + (enable != AL_TRUE) ? + PCIE_W_INT_GRP_B_CAUSE_B_PARITY_ERROR_CORE : 0); + +} + +static void +al_pcie_port_axi_parity_int_config( + struct al_pcie_port *pcie_port, + al_bool enable) +{ + struct al_pcie_regs *regs = pcie_port->regs; + uint32_t parity_enable_mask = 0xffffffff; + + /** + * Addressing RMN: 5603 + * + * RMN description: + * u4_ram2p signal false parity error + * + * Software flow: + * Disable parity check for this memory + */ + if (pcie_port->rev_id >= AL_PCIE_REV_ID_3) + parity_enable_mask &= ~PCIE_AXI_PARITY_EN_AXI_U4_RAM2P; + + al_reg_write32(regs->axi.parity.en_axi, + (enable == AL_TRUE) ? parity_enable_mask : 0x0); + + if (pcie_port->rev_id == AL_PCIE_REV_ID_3) { + al_reg_write32_masked(regs->axi.ctrl.global, + PCIE_REV3_AXI_CTRL_GLOBAL_PARITY_CALC_EN_MSTR | + PCIE_REV3_AXI_CTRL_GLOBAL_PARITY_ERR_EN_RD | + PCIE_REV3_AXI_CTRL_GLOBAL_PARITY_CALC_EN_SLV | + PCIE_REV3_AXI_CTRL_GLOBAL_PARITY_ERR_EN_WR, + (enable == AL_TRUE) ? + PCIE_REV3_AXI_CTRL_GLOBAL_PARITY_CALC_EN_MSTR | + PCIE_REV3_AXI_CTRL_GLOBAL_PARITY_ERR_EN_RD | + PCIE_REV3_AXI_CTRL_GLOBAL_PARITY_CALC_EN_SLV | + PCIE_REV3_AXI_CTRL_GLOBAL_PARITY_ERR_EN_WR : + PCIE_REV3_AXI_CTRL_GLOBAL_PARITY_CALC_EN_SLV); + } else { + al_reg_write32_masked(regs->axi.ctrl.global, + PCIE_REV1_2_AXI_CTRL_GLOBAL_PARITY_CALC_EN_MSTR | + PCIE_REV1_2_AXI_CTRL_GLOBAL_PARITY_ERR_EN_RD | + PCIE_REV1_2_AXI_CTRL_GLOBAL_PARITY_CALC_EN_SLV | + PCIE_REV1_2_AXI_CTRL_GLOBAL_PARITY_ERR_EN_WR, + (enable == AL_TRUE) ? + PCIE_REV1_2_AXI_CTRL_GLOBAL_PARITY_CALC_EN_MSTR | + PCIE_REV1_2_AXI_CTRL_GLOBAL_PARITY_ERR_EN_RD | + PCIE_REV1_2_AXI_CTRL_GLOBAL_PARITY_CALC_EN_SLV | + PCIE_REV1_2_AXI_CTRL_GLOBAL_PARITY_ERR_EN_WR : + PCIE_REV1_2_AXI_CTRL_GLOBAL_PARITY_CALC_EN_SLV); + } + + al_reg_write32_masked(®s->axi.int_grp_a->mask, + PCIE_AXI_INT_GRP_A_CAUSE_PARITY_ERR_DATA_PATH_RD | + PCIE_AXI_INT_GRP_A_CAUSE_PARITY_ERR_OUT_ADDR_RD | + PCIE_AXI_INT_GRP_A_CAUSE_PARITY_ERR_OUT_ADDR_WR | + PCIE_AXI_INT_GRP_A_CAUSE_PARITY_ERR_OUT_DATA_WR | + PCIE_AXI_INT_GRP_A_CAUSE_PARITY_ERROR_AXI, + (enable != AL_TRUE) ? + (PCIE_AXI_INT_GRP_A_CAUSE_PARITY_ERR_DATA_PATH_RD | + PCIE_AXI_INT_GRP_A_CAUSE_PARITY_ERR_OUT_ADDR_RD | + PCIE_AXI_INT_GRP_A_CAUSE_PARITY_ERR_OUT_ADDR_WR | + PCIE_AXI_INT_GRP_A_CAUSE_PARITY_ERR_OUT_DATA_WR | + PCIE_AXI_INT_GRP_A_CAUSE_PARITY_ERROR_AXI) : 0); +} + +static void +al_pcie_port_relaxed_pcie_ordering_config( + struct al_pcie_port *pcie_port, + struct al_pcie_relaxed_ordering_params *relaxed_ordering_params) +{ + struct al_pcie_regs *regs = pcie_port->regs; + enum al_pcie_operating_mode op_mode = al_pcie_operating_mode_get(pcie_port); + /** + * Default: + * - RC: Rx relaxed ordering only + * - EP: TX relaxed ordering only + */ + al_bool tx_relaxed_ordering = (op_mode == AL_PCIE_OPERATING_MODE_RC ? AL_FALSE : AL_TRUE); + al_bool rx_relaxed_ordering = (op_mode == AL_PCIE_OPERATING_MODE_RC ? AL_TRUE : AL_FALSE); + + if (relaxed_ordering_params) { + tx_relaxed_ordering = relaxed_ordering_params->enable_tx_relaxed_ordering; + rx_relaxed_ordering = relaxed_ordering_params->enable_rx_relaxed_ordering; + } + + /** PCIe ordering: + * - disable outbound completion must be stalled behind outbound write + * ordering rule enforcement is disabled for root-port + * - disables read completion on the master port push slave writes for end-point + */ + al_reg_write32_masked( + regs->axi.ordering.pos_cntl, + PCIE_AXI_POS_ORDER_BYPASS_CMPL_AFTER_WR_FIX | + PCIE_AXI_POS_ORDER_EP_CMPL_AFTER_WR_DIS | + PCIE_AXI_POS_ORDER_EP_CMPL_AFTER_WR_SUPPORT_INTERLV_DIS | + PCIE_AXI_POS_ORDER_SEGMENT_BUFFER_DONT_WAIT_FOR_P_WRITES, + (tx_relaxed_ordering ? + (PCIE_AXI_POS_ORDER_BYPASS_CMPL_AFTER_WR_FIX | + PCIE_AXI_POS_ORDER_SEGMENT_BUFFER_DONT_WAIT_FOR_P_WRITES) : 0) | + (rx_relaxed_ordering ? + (PCIE_AXI_POS_ORDER_EP_CMPL_AFTER_WR_DIS | + PCIE_AXI_POS_ORDER_EP_CMPL_AFTER_WR_SUPPORT_INTERLV_DIS) : 0)); +} + +static int +al_pcie_rev_id_get( + void __iomem *pbs_reg_base, + void __iomem *pcie_reg_base) +{ + uint32_t chip_id; + uint16_t chip_id_dev; + uint8_t rev_id; + struct al_pbs_regs *pbs_regs = pbs_reg_base; + + /* get revision ID from PBS' chip_id register */ + chip_id = al_reg_read32(&pbs_regs->unit.chip_id); + chip_id_dev = AL_REG_FIELD_GET(chip_id, + PBS_UNIT_CHIP_ID_DEV_ID_MASK, + PBS_UNIT_CHIP_ID_DEV_ID_SHIFT); + + if (chip_id_dev == PBS_UNIT_CHIP_ID_DEV_ID_ALPINE) { + rev_id = AL_REG_FIELD_GET( + chip_id, + PBS_UNIT_CHIP_ID_DEV_REV_ID_MASK, + PBS_UNIT_CHIP_ID_DEV_REV_ID_SHIFT); + } else if (chip_id_dev == PBS_UNIT_CHIP_ID_DEV_ID_PEAKROCK) { + struct al_pcie_revx_regs __iomem *regs = + (struct al_pcie_revx_regs __iomem *)pcie_reg_base; + uint32_t dev_id; + + dev_id = al_reg_read32(®s->axi.device_id.device_rev_id) & + PCIE_AXI_DEVICE_ID_REG_DEV_ID_MASK; + if (dev_id == PCIE_AXI_DEVICE_ID_REG_DEV_ID_X4) { + rev_id = AL_PCIE_REV_ID_2; + } else if (dev_id == PCIE_AXI_DEVICE_ID_REG_DEV_ID_X8) { + rev_id = AL_PCIE_REV_ID_3; + } else { + al_warn("%s: Revision ID is unknown\n", + __func__); + return -EINVAL; + } + } else { + al_warn("%s: Revision ID is unknown\n", + __func__); + return -EINVAL; + } + return rev_id; +} + +static int +al_pcie_port_lat_rply_timers_config( + struct al_pcie_port *pcie_port, + const struct al_pcie_latency_replay_timers *lat_rply_timers) +{ + struct al_pcie_regs *regs = pcie_port->regs; + uint32_t reg = 0; + + AL_REG_FIELD_SET(reg, 0xFFFF, 0, lat_rply_timers->round_trip_lat_limit); + AL_REG_FIELD_SET(reg, 0xFFFF0000, 16, lat_rply_timers->replay_timer_limit); + + al_reg_write32(®s->port_regs->ack_lat_rply_timer, reg); + return 0; +} + +static void +al_pcie_ib_hcrd_os_ob_reads_config_default( + struct al_pcie_port *pcie_port) +{ + + struct al_pcie_ib_hcrd_os_ob_reads_config ib_hcrd_os_ob_reads_config; + + switch (al_pcie_operating_mode_get(pcie_port)) { + case AL_PCIE_OPERATING_MODE_RC: + if (pcie_port->rev_id == AL_PCIE_REV_ID_3) { + ib_hcrd_os_ob_reads_config.nof_outstanding_ob_reads = + AL_PCIE_REV_3_RC_OB_OS_READS_DEFAULT; + ib_hcrd_os_ob_reads_config.nof_cpl_hdr = + AL_PCIE_REV_3_RC_NOF_CPL_HDR_DEFAULT; + ib_hcrd_os_ob_reads_config.nof_np_hdr = + AL_PCIE_REV_3_RC_NOF_NP_HDR_DEFAULT; + ib_hcrd_os_ob_reads_config.nof_p_hdr = + AL_PCIE_REV_3_RC_NOF_P_HDR_DEFAULT; + } else { + ib_hcrd_os_ob_reads_config.nof_outstanding_ob_reads = + AL_PCIE_REV_1_2_RC_OB_OS_READS_DEFAULT; + ib_hcrd_os_ob_reads_config.nof_cpl_hdr = + AL_PCIE_REV_1_2_RC_NOF_CPL_HDR_DEFAULT; + ib_hcrd_os_ob_reads_config.nof_np_hdr = + AL_PCIE_REV_1_2_RC_NOF_NP_HDR_DEFAULT; + ib_hcrd_os_ob_reads_config.nof_p_hdr = + AL_PCIE_REV_1_2_RC_NOF_P_HDR_DEFAULT; + } + break; + + case AL_PCIE_OPERATING_MODE_EP: + if (pcie_port->rev_id == AL_PCIE_REV_ID_3) { + ib_hcrd_os_ob_reads_config.nof_outstanding_ob_reads = + AL_PCIE_REV_3_EP_OB_OS_READS_DEFAULT; + ib_hcrd_os_ob_reads_config.nof_cpl_hdr = + AL_PCIE_REV_3_EP_NOF_CPL_HDR_DEFAULT; + ib_hcrd_os_ob_reads_config.nof_np_hdr = + AL_PCIE_REV_3_EP_NOF_NP_HDR_DEFAULT; + ib_hcrd_os_ob_reads_config.nof_p_hdr = + AL_PCIE_REV_3_EP_NOF_P_HDR_DEFAULT; + } else { + ib_hcrd_os_ob_reads_config.nof_outstanding_ob_reads = + AL_PCIE_REV_1_2_EP_OB_OS_READS_DEFAULT; + ib_hcrd_os_ob_reads_config.nof_cpl_hdr = + AL_PCIE_REV_1_2_EP_NOF_CPL_HDR_DEFAULT; + ib_hcrd_os_ob_reads_config.nof_np_hdr = + AL_PCIE_REV_1_2_EP_NOF_NP_HDR_DEFAULT; + ib_hcrd_os_ob_reads_config.nof_p_hdr = + AL_PCIE_REV_1_2_EP_NOF_P_HDR_DEFAULT; + } + break; + + default: + al_err("PCIe %d: outstanding outbound transactions could not be configured - unknown operating mode\n", + pcie_port->port_id); + al_assert(0); + } + + al_pcie_port_ib_hcrd_os_ob_reads_config(pcie_port, &ib_hcrd_os_ob_reads_config); +}; + +/** return AL_TRUE is link started (LTSSM enabled) and AL_FALSE otherwise */ +static al_bool +al_pcie_is_link_started(struct al_pcie_port *pcie_port) +{ + struct al_pcie_regs *regs = (struct al_pcie_regs *)pcie_port->regs; + + uint32_t port_init = al_reg_read32(regs->app.global_ctrl.port_init); + uint8_t ltssm_en = AL_REG_FIELD_GET(port_init, + PCIE_W_GLOBAL_CTRL_PORT_INIT_APP_LTSSM_EN_MASK, + PCIE_W_GLOBAL_CTRL_PORT_INIT_APP_LTSSM_EN_SHIFT); + + return ltssm_en; +} + +/** return AL_TRUE if link is up, AL_FALSE otherwise */ +static al_bool +al_pcie_check_link( + struct al_pcie_port *pcie_port, + uint8_t *ltssm_ret) +{ + struct al_pcie_regs *regs = (struct al_pcie_regs *)pcie_port->regs; + uint32_t info_0; + uint8_t ltssm_state; + + info_0 = al_reg_read32(®s->app.debug->info_0); + + ltssm_state = AL_REG_FIELD_GET(info_0, + PCIE_W_DEBUG_INFO_0_LTSSM_STATE_MASK, + PCIE_W_DEBUG_INFO_0_LTSSM_STATE_SHIFT); + + al_dbg("PCIe %d: Port Debug 0: 0x%08x. LTSSM state :0x%x\n", + pcie_port->port_id, info_0, ltssm_state); + + if (ltssm_ret) + *ltssm_ret = ltssm_state; + + if ((ltssm_state == AL_PCIE_LTSSM_STATE_L0) || + (ltssm_state == AL_PCIE_LTSSM_STATE_L0S)) + return AL_TRUE; + return AL_FALSE; +} + +static int +al_pcie_port_gen2_params_config(struct al_pcie_port *pcie_port, + const struct al_pcie_gen2_params *gen2_params) +{ + struct al_pcie_regs *regs = pcie_port->regs; + uint32_t gen2_ctrl; + + al_dbg("PCIe %d: Gen2 params config: Tx Swing %s, interrupt on link Eq %s, set Deemphasis %s\n", + pcie_port->port_id, + gen2_params->tx_swing_low ? "Low" : "Full", + gen2_params->tx_compliance_receive_enable? "enable" : "disable", + gen2_params->set_deemphasis? "enable" : "disable"); + + gen2_ctrl = al_reg_read32(®s->port_regs->gen2_ctrl); + + if (gen2_params->tx_swing_low) + AL_REG_BIT_SET(gen2_ctrl, PCIE_PORT_GEN2_CTRL_TX_SWING_LOW_SHIFT); + else + AL_REG_BIT_CLEAR(gen2_ctrl, PCIE_PORT_GEN2_CTRL_TX_SWING_LOW_SHIFT); + + if (gen2_params->tx_compliance_receive_enable) + AL_REG_BIT_SET(gen2_ctrl, PCIE_PORT_GEN2_CTRL_TX_COMPLIANCE_RCV_SHIFT); + else + AL_REG_BIT_CLEAR(gen2_ctrl, PCIE_PORT_GEN2_CTRL_TX_COMPLIANCE_RCV_SHIFT); + + if (gen2_params->set_deemphasis) + AL_REG_BIT_SET(gen2_ctrl, PCIE_PORT_GEN2_CTRL_DEEMPHASIS_SET_SHIFT); + else + AL_REG_BIT_CLEAR(gen2_ctrl, PCIE_PORT_GEN2_CTRL_DEEMPHASIS_SET_SHIFT); + + al_reg_write32(®s->port_regs->gen2_ctrl, gen2_ctrl); + + return 0; +} + + +static uint16_t +gen3_lane_eq_param_to_val(const struct al_pcie_gen3_lane_eq_params *eq_params) +{ + uint16_t eq_control = 0; + + eq_control = eq_params->downstream_port_transmitter_preset & 0xF; + eq_control |= (eq_params->downstream_port_receiver_preset_hint & 0x7) << 4; + eq_control |= (eq_params->upstream_port_transmitter_preset & 0xF) << 8; + eq_control |= (eq_params->upstream_port_receiver_preset_hint & 0x7) << 12; + + return eq_control; +} + +static int +al_pcie_port_gen3_params_config(struct al_pcie_port *pcie_port, + const struct al_pcie_gen3_params *gen3_params) +{ + struct al_pcie_regs *regs = pcie_port->regs; + uint32_t reg = 0; + uint16_t __iomem *lanes_eq_base = (uint16_t __iomem *)(regs->core_space[0].pcie_sec_ext_cap_base + (0xC >> 2)); + int i; + + al_dbg("PCIe %d: Gen3 params config: Equalization %s, interrupt on link Eq %s\n", + pcie_port->port_id, + gen3_params->perform_eq ? "enable" : "disable", + gen3_params->interrupt_enable_on_link_eq_request? "enable" : "disable"); + + if (gen3_params->perform_eq) + AL_REG_BIT_SET(reg, 0); + if (gen3_params->interrupt_enable_on_link_eq_request) + AL_REG_BIT_SET(reg, 1); + + al_reg_write32(regs->core_space[0].pcie_sec_ext_cap_base + (4 >> 2), + reg); + + al_pcie_port_wr_to_ro_set(pcie_port, AL_TRUE); + + for (i = 0; i < gen3_params->eq_params_elements; i += 2) { + uint32_t eq_control = + (uint32_t)gen3_lane_eq_param_to_val(gen3_params->eq_params + i) | + (uint32_t)gen3_lane_eq_param_to_val(gen3_params->eq_params + i + 1) << 16; + + al_dbg("PCIe %d: Set EQ (0x%08x) for lane %d, %d\n", pcie_port->port_id, eq_control, i, i + 1); + al_reg_write32((uint32_t *)(lanes_eq_base + i), eq_control); + } + + al_pcie_port_wr_to_ro_set(pcie_port, AL_FALSE); + + reg = al_reg_read32(®s->port_regs->gen3_ctrl); + if (gen3_params->eq_disable) + AL_REG_BIT_SET(reg, PCIE_PORT_GEN3_CTRL_EQ_DISABLE_SHIFT); + else + AL_REG_BIT_CLEAR(reg, PCIE_PORT_GEN3_CTRL_EQ_DISABLE_SHIFT); + + if (gen3_params->eq_phase2_3_disable) + AL_REG_BIT_SET(reg, PCIE_PORT_GEN3_CTRL_EQ_PHASE_2_3_DISABLE_SHIFT); + else + AL_REG_BIT_CLEAR(reg, PCIE_PORT_GEN3_CTRL_EQ_PHASE_2_3_DISABLE_SHIFT); + + al_reg_write32(®s->port_regs->gen3_ctrl, reg); + + reg = 0; + AL_REG_FIELD_SET(reg, PCIE_PORT_GEN3_EQ_LF_MASK, + PCIE_PORT_GEN3_EQ_LF_SHIFT, + gen3_params->local_lf); + AL_REG_FIELD_SET(reg, PCIE_PORT_GEN3_EQ_FS_MASK, + PCIE_PORT_GEN3_EQ_FS_SHIFT, + gen3_params->local_fs); + + al_reg_write32(®s->port_regs->gen3_eq_fs_lf, reg); + + reg = 0; + AL_REG_FIELD_SET(reg, PCIE_AXI_MISC_ZERO_LANEX_PHY_MAC_LOCAL_LF_MASK, + PCIE_AXI_MISC_ZERO_LANEX_PHY_MAC_LOCAL_LF_SHIFT, + gen3_params->local_lf); + AL_REG_FIELD_SET(reg, PCIE_AXI_MISC_ZERO_LANEX_PHY_MAC_LOCAL_FS_MASK, + PCIE_AXI_MISC_ZERO_LANEX_PHY_MAC_LOCAL_FS_SHIFT, + gen3_params->local_fs); + al_reg_write32(regs->axi.conf.zero_lane0, reg); + al_reg_write32(regs->axi.conf.zero_lane1, reg); + al_reg_write32(regs->axi.conf.zero_lane2, reg); + al_reg_write32(regs->axi.conf.zero_lane3, reg); + if (pcie_port->rev_id == AL_PCIE_REV_ID_3) { + al_reg_write32(regs->axi.conf.zero_lane4, reg); + al_reg_write32(regs->axi.conf.zero_lane5, reg); + al_reg_write32(regs->axi.conf.zero_lane6, reg); + al_reg_write32(regs->axi.conf.zero_lane7, reg); + } + + /* + * Gen3 EQ Control Register: + * - Preset Request Vector - request 9 + * - Behavior After 24 ms Timeout (when optimal settings are not + * found): Recovery.Equalization.RcvrLock + * - Phase2_3 2 ms Timeout Disable + * - Feedback Mode - Figure Of Merit + */ + reg = 0x00020031; + al_reg_write32(®s->port_regs->gen3_eq_ctrl, reg); + + return 0; +} + +static int +al_pcie_port_tl_credits_config( + struct al_pcie_port *pcie_port, + const struct al_pcie_tl_credits_params *tl_credits __attribute__((__unused__))) +{ + al_err("PCIe %d: transport layer credits config not implemented\n", + pcie_port->port_id); + + return -ENOSYS; + +} + +static int +al_pcie_port_pf_params_config(struct al_pcie_pf *pcie_pf, + const struct al_pcie_pf_config_params *pf_params) +{ + struct al_pcie_port *pcie_port = pcie_pf->pcie_port; + struct al_pcie_regs *regs = pcie_port->regs; + unsigned int pf_num = pcie_pf->pf_num; + int bar_idx; + int ret; + + al_pcie_port_wr_to_ro_set(pcie_port, AL_TRUE); + + /* Disable D1 and D3hot capabilities */ + if (pf_params->cap_d1_d3hot_dis) + al_reg_write32_masked( + regs->core_space[pf_num].pcie_pm_cap_base, + AL_FIELD_MASK(26, 25) | AL_FIELD_MASK(31, 28), 0); + + /* Disable FLR capability */ + if (pf_params->cap_flr_dis) + al_reg_write32_masked( + regs->core_space[pf_num].pcie_dev_cap_base, + AL_BIT(28), 0); + + /* Disable ASPM capability */ + if (pf_params->cap_aspm_dis) { + al_reg_write32_masked( + regs->core_space[pf_num].pcie_cap_base + (AL_PCI_EXP_LNKCAP >> 2), + AL_PCI_EXP_LNKCAP_ASPMS, 0); + } else if (pcie_port->rev_id == AL_PCIE_REV_ID_0) { + al_warn("%s: ASPM support is enabled, please disable it\n", + __func__); + ret = -EINVAL; + goto done; + } + + if (!pf_params->bar_params_valid) { + ret = 0; + goto done; + } + + for (bar_idx = 0; bar_idx < 6;){ /* bar_idx will be incremented depending on bar type */ + const struct al_pcie_ep_bar_params *params = pf_params->bar_params + bar_idx; + uint32_t mask = 0; + uint32_t ctrl = 0; + uint32_t __iomem *bar_addr = ®s->core_space[pf_num].config_header[(AL_PCI_BASE_ADDRESS_0 >> 2) + bar_idx]; + + if (params->enable) { + uint64_t size = params->size; + + if (params->memory_64_bit) { + const struct al_pcie_ep_bar_params *next_params = params + 1; + /* 64 bars start at even index (BAR0, BAR 2 or BAR 4) */ + if (bar_idx & 1) { + ret = -EINVAL; + goto done; + } + + /* next BAR must be disabled */ + if (next_params->enable) { + ret = -EINVAL; + goto done; + } + + /* 64 bar must be memory bar */ + if (!params->memory_space) { + ret = -EINVAL; + goto done; + } + } else { + if (size > AL_PCIE_MAX_32_MEMORY_BAR_SIZE) + return -EINVAL; + /* 32 bit space can't be prefetchable */ + if (params->memory_is_prefetchable) { + ret = -EINVAL; + goto done; + } + } + + if (params->memory_space) { + if (size < AL_PCIE_MIN_MEMORY_BAR_SIZE) { + al_err("PCIe %d: memory BAR %d: size (0x%llx) less that minimal allowed value\n", + pcie_port->port_id, bar_idx, size); + ret = -EINVAL; + goto done; + } + } else { + /* IO can't be prefetchable */ + if (params->memory_is_prefetchable) { + ret = -EINVAL; + goto done; + } + + if (size < AL_PCIE_MIN_IO_BAR_SIZE) { + al_err("PCIe %d: IO BAR %d: size (0x%llx) less that minimal allowed value\n", + pcie_port->port_id, bar_idx, size); + ret = -EINVAL; + goto done; + } + } + + /* size must be power of 2 */ + if (size & (size - 1)) { + al_err("PCIe %d: BAR %d:size (0x%llx) must be " + "power of 2\n", + pcie_port->port_id, bar_idx, size); + ret = -EINVAL; + goto done; + } + + /* If BAR is 64-bit, disable the next BAR before + * configuring this one + */ + if (params->memory_64_bit) + al_reg_write32_dbi_cs2(pcie_port, bar_addr + 1, 0); + + mask = 1; /* enable bit*/ + mask |= (params->size - 1) & 0xFFFFFFFF; + + al_reg_write32_dbi_cs2(pcie_port, bar_addr , mask); + + if (params->memory_space == AL_FALSE) + ctrl = AL_PCI_BASE_ADDRESS_SPACE_IO; + if (params->memory_64_bit) + ctrl |= AL_PCI_BASE_ADDRESS_MEM_TYPE_64; + if (params->memory_is_prefetchable) + ctrl |= AL_PCI_BASE_ADDRESS_MEM_PREFETCH; + al_reg_write32(bar_addr, ctrl); + + if (params->memory_64_bit) { + mask = ((params->size - 1) >> 32) & 0xFFFFFFFF; + al_reg_write32_dbi_cs2(pcie_port, bar_addr + 1, mask); + } + + } else { + al_reg_write32_dbi_cs2(pcie_port, bar_addr , mask); + } + if (params->enable && params->memory_64_bit) + bar_idx += 2; + else + bar_idx += 1; + } + + if (pf_params->exp_bar_params.enable) { + if (pcie_port->rev_id != AL_PCIE_REV_ID_3) { + al_err("PCIe %d: Expansion BAR enable not supported\n", pcie_port->port_id); + ret = -ENOSYS; + goto done; + } else { + /* Enable exp ROM */ + uint32_t __iomem *exp_rom_bar_addr = + ®s->core_space[pf_num].config_header[AL_PCI_EXP_ROM_BASE_ADDRESS >> 2]; + uint32_t mask = 1; /* enable bit*/ + mask |= (pf_params->exp_bar_params.size - 1) & 0xFFFFFFFF; + al_reg_write32_dbi_cs2(pcie_port, exp_rom_bar_addr , mask); + } + } else if (pcie_port->rev_id == AL_PCIE_REV_ID_3) { + /* Disable exp ROM */ + uint32_t __iomem *exp_rom_bar_addr = + ®s->core_space[pf_num].config_header[AL_PCI_EXP_ROM_BASE_ADDRESS >> 2]; + al_reg_write32_dbi_cs2(pcie_port, exp_rom_bar_addr , 0); + } + + /* Open CPU generated msi and legacy interrupts in pcie wrapper logic */ + if ((pcie_port->rev_id == AL_PCIE_REV_ID_0) || + (pcie_port->rev_id == AL_PCIE_REV_ID_1)) { + al_reg_write32(regs->app.soc_int[pf_num].mask_inta_leg_0, (1 << 21)); + } else if ((pcie_port->rev_id == AL_PCIE_REV_ID_2) || + (pcie_port->rev_id == AL_PCIE_REV_ID_3)) { + al_reg_write32(regs->app.soc_int[pf_num].mask_inta_leg_3, (1 << 18)); + } else { + al_assert(0); + ret = -ENOSYS; + goto done; + } + + /** + * Addressing RMN: 1547 + * + * RMN description: + * 1. Whenever writing to 0x2xx offset, the write also happens to + * 0x3xx address, meaning two registers are written instead of one. + * 2. Read and write from 0x3xx work ok. + * + * Software flow: + * Backup the value of the app.int_grp_a.mask_a register, because + * app.int_grp_a.mask_clear_a gets overwritten during the write to + * app.soc.mask_msi_leg_0 register. + * Restore the original value after the write to app.soc.mask_msi_leg_0 + * register. + */ + if (pcie_port->rev_id == AL_PCIE_REV_ID_0) { + uint32_t backup; + + backup = al_reg_read32(®s->app.int_grp_a->mask); + al_reg_write32(regs->app.soc_int[pf_num].mask_msi_leg_0, (1 << 22)); + al_reg_write32(®s->app.int_grp_a->mask, backup); + } else if (pcie_port->rev_id == AL_PCIE_REV_ID_1) { + al_reg_write32(regs->app.soc_int[pf_num].mask_msi_leg_0, (1 << 22)); + } else if ((pcie_port->rev_id == AL_PCIE_REV_ID_2) || + (pcie_port->rev_id == AL_PCIE_REV_ID_3)) { + al_reg_write32(regs->app.soc_int[pf_num].mask_msi_leg_3, (1 << 19)); + } else { + al_assert(0); + ret = -ENOSYS; + goto done; + } + + ret = 0; + +done: + al_pcie_port_wr_to_ro_set(pcie_port, AL_FALSE); + + return ret; +} + +static void +al_pcie_port_features_config( + struct al_pcie_port *pcie_port, + const struct al_pcie_features *features) +{ + struct al_pcie_regs *regs = pcie_port->regs; + + al_assert(pcie_port->rev_id > AL_PCIE_REV_ID_0); + + al_reg_write32_masked( + ®s->app.ctrl_gen->features, + PCIE_W_CTRL_GEN_FEATURES_SATA_EP_MSI_FIX, + features->sata_ep_msi_fix ? + PCIE_W_CTRL_GEN_FEATURES_SATA_EP_MSI_FIX : 0); +} + +static int +al_pcie_port_sris_config( + struct al_pcie_port *pcie_port, + struct al_pcie_sris_params *sris_params, + enum al_pcie_link_speed link_speed) +{ + int rc = 0; + struct al_pcie_regs *regs = pcie_port->regs; + + if (sris_params->use_defaults) { + sris_params->kp_counter_gen3 = (pcie_port->rev_id > AL_PCIE_REV_ID_1) ? + PCIE_SRIS_KP_COUNTER_GEN3_DEFAULT_VAL : 0; + sris_params->kp_counter_gen21 = PCIE_SRIS_KP_COUNTER_GEN21_DEFAULT_VAL; + + al_dbg("PCIe %d: configuring SRIS with default values kp_gen3[%d] kp_gen21[%d]\n", + pcie_port->port_id, + sris_params->kp_counter_gen3, + sris_params->kp_counter_gen21); + } + + switch (pcie_port->rev_id) { + case AL_PCIE_REV_ID_3: + case AL_PCIE_REV_ID_2: + al_reg_write32_masked(regs->app.global_ctrl.sris_kp_counter, + PCIE_W_GLOBAL_CTRL_SRIS_KP_COUNTER_VALUE_GEN3_SRIS_MASK | + PCIE_W_GLOBAL_CTRL_SRIS_KP_COUNTER_VALUE_GEN21_SRIS_MASK | + PCIE_W_GLOBAL_CTRL_SRIS_KP_COUNTER_VALUE_PCIE_X4_SRIS_EN, + (sris_params->kp_counter_gen3 << + PCIE_W_GLOBAL_CTRL_SRIS_KP_COUNTER_VALUE_GEN3_SRIS_SHIFT) | + (sris_params->kp_counter_gen21 << + PCIE_W_GLOBAL_CTRL_SRIS_KP_COUNTER_VALUE_GEN21_SRIS_SHIFT) | + PCIE_W_GLOBAL_CTRL_SRIS_KP_COUNTER_VALUE_PCIE_X4_SRIS_EN); + break; + + case AL_PCIE_REV_ID_1: + if ((link_speed == AL_PCIE_LINK_SPEED_GEN3) && (sris_params->kp_counter_gen3)) { + al_err("PCIe %d: cannot config Gen%d SRIS with rev_id[%d]\n", + pcie_port->port_id, al_pcie_speed_gen_code(link_speed), + pcie_port->rev_id); + return -EINVAL; + } + + al_reg_write32_masked(®s->port_regs->filter_mask_reg_1, + PCIE_FLT_MASK_SKP_INT_VAL_MASK, + sris_params->kp_counter_gen21); + break; + + default: + al_err("PCIe %d: SRIS config is not supported in rev_id[%d]\n", + pcie_port->port_id, pcie_port->rev_id); + al_assert(0); + return -EINVAL; + } + + return rc; +} + +static void +al_pcie_port_ib_hcrd_config(struct al_pcie_port *pcie_port) +{ + struct al_pcie_regs *regs = pcie_port->regs; + + al_reg_write32_masked( + ®s->port_regs->vc0_posted_rcv_q_ctrl, + RADM_PQ_HCRD_VC0_MASK, + (pcie_port->ib_hcrd_config.nof_p_hdr - 1) + << RADM_PQ_HCRD_VC0_SHIFT); + + al_reg_write32_masked( + ®s->port_regs->vc0_non_posted_rcv_q_ctrl, + RADM_NPQ_HCRD_VC0_MASK, + (pcie_port->ib_hcrd_config.nof_np_hdr - 1) + << RADM_NPQ_HCRD_VC0_SHIFT); +} + +static unsigned int +al_pcie_port_max_num_of_pfs_get(struct al_pcie_port *pcie_port) +{ + struct al_pcie_regs *regs = pcie_port->regs; + uint32_t max_func_num; + uint32_t max_num_of_pfs; + + /** + * Only in REV3, when port is already enabled, max_num_of_pfs is already + * initialized, return it. Otherwise, return default: 1 PF + */ + if ((pcie_port->rev_id == AL_PCIE_REV_ID_3) + && al_pcie_port_is_enabled(pcie_port)) { + max_func_num = al_reg_read32(®s->port_regs->timer_ctrl_max_func_num); + max_num_of_pfs = AL_REG_FIELD_GET(max_func_num, PCIE_PORT_GEN3_MAX_FUNC_NUM, 0) + 1; + return max_num_of_pfs; + } + return 1; +} + +/******************************************************************************/ +/***************************** API Implementation *****************************/ +/******************************************************************************/ + +/*************************** PCIe Initialization API **************************/ + +/** + * Initializes a PCIe port handle structure + * Caution: this function should not read/write to any register except for + * reading RO register (REV_ID for example) + */ +int +al_pcie_port_handle_init( + struct al_pcie_port *pcie_port, + void __iomem *pcie_reg_base, + void __iomem *pbs_reg_base, + unsigned int port_id) +{ + int i, ret; + + pcie_port->pcie_reg_base = pcie_reg_base; + pcie_port->regs = &pcie_port->regs_ptrs; + pcie_port->ex_regs = NULL; + pcie_port->pbs_regs = pbs_reg_base; + pcie_port->port_id = port_id; + pcie_port->max_lanes = 0; + + ret = al_pcie_rev_id_get(pbs_reg_base, pcie_reg_base); + if (ret < 0) + return ret; + + pcie_port->rev_id = ret; + + /* Zero all regs */ + al_memset(pcie_port->regs, 0, sizeof(struct al_pcie_regs)); + + if ((pcie_port->rev_id == AL_PCIE_REV_ID_0) || + (pcie_port->rev_id == AL_PCIE_REV_ID_1)) { + struct al_pcie_rev1_regs __iomem *regs = + (struct al_pcie_rev1_regs __iomem *)pcie_reg_base; + + pcie_port->regs->axi.ctrl.global = ®s->axi.ctrl.global; + pcie_port->regs->axi.ctrl.master_arctl = ®s->axi.ctrl.master_arctl; + pcie_port->regs->axi.ctrl.master_awctl = ®s->axi.ctrl.master_awctl; + pcie_port->regs->axi.ctrl.slv_ctl = ®s->axi.ctrl.slv_ctl; + pcie_port->regs->axi.ob_ctrl.cfg_target_bus = ®s->axi.ob_ctrl.cfg_target_bus; + pcie_port->regs->axi.ob_ctrl.cfg_control = ®s->axi.ob_ctrl.cfg_control; + pcie_port->regs->axi.ob_ctrl.io_start_l = ®s->axi.ob_ctrl.io_start_l; + pcie_port->regs->axi.ob_ctrl.io_start_h = ®s->axi.ob_ctrl.io_start_h; + pcie_port->regs->axi.ob_ctrl.io_limit_l = ®s->axi.ob_ctrl.io_limit_l; + pcie_port->regs->axi.ob_ctrl.io_limit_h = ®s->axi.ob_ctrl.io_limit_h; + pcie_port->regs->axi.pcie_global.conf = ®s->axi.pcie_global.conf; + pcie_port->regs->axi.conf.zero_lane0 = ®s->axi.conf.zero_lane0; + pcie_port->regs->axi.conf.zero_lane1 = ®s->axi.conf.zero_lane1; + pcie_port->regs->axi.conf.zero_lane2 = ®s->axi.conf.zero_lane2; + pcie_port->regs->axi.conf.zero_lane3 = ®s->axi.conf.zero_lane3; + pcie_port->regs->axi.status.lane[0] = ®s->axi.status.lane0; + pcie_port->regs->axi.status.lane[1] = ®s->axi.status.lane1; + pcie_port->regs->axi.status.lane[2] = ®s->axi.status.lane2; + pcie_port->regs->axi.status.lane[3] = ®s->axi.status.lane3; + pcie_port->regs->axi.parity.en_axi = ®s->axi.parity.en_axi; + pcie_port->regs->axi.ordering.pos_cntl = ®s->axi.ordering.pos_cntl; + pcie_port->regs->axi.pre_configuration.pcie_core_setup = ®s->axi.pre_configuration.pcie_core_setup; + pcie_port->regs->axi.init_fc.cfg = ®s->axi.init_fc.cfg; + pcie_port->regs->axi.int_grp_a = ®s->axi.int_grp_a; + + pcie_port->regs->app.global_ctrl.port_init = ®s->app.global_ctrl.port_init; + pcie_port->regs->app.global_ctrl.pm_control = ®s->app.global_ctrl.pm_control; + pcie_port->regs->app.global_ctrl.events_gen[0] = ®s->app.global_ctrl.events_gen; + pcie_port->regs->app.debug = ®s->app.debug; + pcie_port->regs->app.soc_int[0].mask_inta_leg_0 = ®s->app.soc_int.mask_inta_leg_0; + pcie_port->regs->app.soc_int[0].mask_msi_leg_0 = ®s->app.soc_int.mask_msi_leg_0; + pcie_port->regs->app.ctrl_gen = ®s->app.ctrl_gen; + pcie_port->regs->app.parity = ®s->app.parity; + pcie_port->regs->app.atu.in_mask_pair = regs->app.atu.in_mask_pair; + pcie_port->regs->app.atu.out_mask_pair = regs->app.atu.out_mask_pair; + + if (pcie_port->rev_id == AL_PCIE_REV_ID_0) { + pcie_port->regs->app.int_grp_a = ®s->app.int_grp_a_m0; + pcie_port->regs->app.int_grp_b = ®s->app.int_grp_b_m0; + } else { + pcie_port->regs->app.int_grp_a = ®s->app.int_grp_a; + pcie_port->regs->app.int_grp_b = ®s->app.int_grp_b; + } + + pcie_port->regs->core_space[0].config_header = regs->core_space.config_header; + pcie_port->regs->core_space[0].pcie_pm_cap_base = ®s->core_space.pcie_pm_cap_base; + pcie_port->regs->core_space[0].pcie_cap_base = ®s->core_space.pcie_cap_base; + pcie_port->regs->core_space[0].pcie_dev_cap_base = ®s->core_space.pcie_dev_cap_base; + pcie_port->regs->core_space[0].pcie_dev_ctrl_status = ®s->core_space.pcie_dev_ctrl_status; + pcie_port->regs->core_space[0].pcie_link_cap_base = ®s->core_space.pcie_link_cap_base; + pcie_port->regs->core_space[0].msix_cap_base = ®s->core_space.msix_cap_base; + pcie_port->regs->core_space[0].aer = ®s->core_space.aer; + pcie_port->regs->core_space[0].pcie_sec_ext_cap_base = ®s->core_space.pcie_sec_ext_cap_base; + + pcie_port->regs->port_regs = ®s->core_space.port_regs; + + } else if (pcie_port->rev_id == AL_PCIE_REV_ID_2) { + struct al_pcie_rev2_regs __iomem *regs = + (struct al_pcie_rev2_regs __iomem *)pcie_reg_base; + + pcie_port->regs->axi.ctrl.global = ®s->axi.ctrl.global; + pcie_port->regs->axi.ctrl.master_arctl = ®s->axi.ctrl.master_arctl; + pcie_port->regs->axi.ctrl.master_awctl = ®s->axi.ctrl.master_awctl; + pcie_port->regs->axi.ctrl.slv_ctl = ®s->axi.ctrl.slv_ctl; + pcie_port->regs->axi.ob_ctrl.cfg_target_bus = ®s->axi.ob_ctrl.cfg_target_bus; + pcie_port->regs->axi.ob_ctrl.cfg_control = ®s->axi.ob_ctrl.cfg_control; + pcie_port->regs->axi.ob_ctrl.io_start_l = ®s->axi.ob_ctrl.io_start_l; + pcie_port->regs->axi.ob_ctrl.io_start_h = ®s->axi.ob_ctrl.io_start_h; + pcie_port->regs->axi.ob_ctrl.io_limit_l = ®s->axi.ob_ctrl.io_limit_l; + pcie_port->regs->axi.ob_ctrl.io_limit_h = ®s->axi.ob_ctrl.io_limit_h; + pcie_port->regs->axi.pcie_global.conf = ®s->axi.pcie_global.conf; + pcie_port->regs->axi.conf.zero_lane0 = ®s->axi.conf.zero_lane0; + pcie_port->regs->axi.conf.zero_lane1 = ®s->axi.conf.zero_lane1; + pcie_port->regs->axi.conf.zero_lane2 = ®s->axi.conf.zero_lane2; + pcie_port->regs->axi.conf.zero_lane3 = ®s->axi.conf.zero_lane3; + pcie_port->regs->axi.status.lane[0] = ®s->axi.status.lane0; + pcie_port->regs->axi.status.lane[1] = ®s->axi.status.lane1; + pcie_port->regs->axi.status.lane[2] = ®s->axi.status.lane2; + pcie_port->regs->axi.status.lane[3] = ®s->axi.status.lane3; + pcie_port->regs->axi.parity.en_axi = ®s->axi.parity.en_axi; + pcie_port->regs->axi.ordering.pos_cntl = ®s->axi.ordering.pos_cntl; + pcie_port->regs->axi.pre_configuration.pcie_core_setup = ®s->axi.pre_configuration.pcie_core_setup; + pcie_port->regs->axi.init_fc.cfg = ®s->axi.init_fc.cfg; + pcie_port->regs->axi.int_grp_a = ®s->axi.int_grp_a; + + pcie_port->regs->app.global_ctrl.port_init = ®s->app.global_ctrl.port_init; + pcie_port->regs->app.global_ctrl.pm_control = ®s->app.global_ctrl.pm_control; + pcie_port->regs->app.global_ctrl.events_gen[0] = ®s->app.global_ctrl.events_gen; + pcie_port->regs->app.global_ctrl.corr_err_sts_int = ®s->app.global_ctrl.pended_corr_err_sts_int; + pcie_port->regs->app.global_ctrl.uncorr_err_sts_int = ®s->app.global_ctrl.pended_uncorr_err_sts_int; + pcie_port->regs->app.debug = ®s->app.debug; + pcie_port->regs->app.ap_user_send_msg = ®s->app.ap_user_send_msg; + pcie_port->regs->app.soc_int[0].mask_inta_leg_0 = ®s->app.soc_int.mask_inta_leg_0; + pcie_port->regs->app.soc_int[0].mask_inta_leg_3 = ®s->app.soc_int.mask_inta_leg_3; + pcie_port->regs->app.soc_int[0].mask_msi_leg_0 = ®s->app.soc_int.mask_msi_leg_0; + pcie_port->regs->app.soc_int[0].mask_msi_leg_3 = ®s->app.soc_int.mask_msi_leg_3; + pcie_port->regs->app.ctrl_gen = ®s->app.ctrl_gen; + pcie_port->regs->app.parity = ®s->app.parity; + pcie_port->regs->app.atu.in_mask_pair = regs->app.atu.in_mask_pair; + pcie_port->regs->app.atu.out_mask_pair = regs->app.atu.out_mask_pair; + pcie_port->regs->app.status_per_func[0] = ®s->app.status_per_func; + pcie_port->regs->app.int_grp_a = ®s->app.int_grp_a; + pcie_port->regs->app.int_grp_b = ®s->app.int_grp_b; + + pcie_port->regs->core_space[0].config_header = regs->core_space.config_header; + pcie_port->regs->core_space[0].pcie_pm_cap_base = ®s->core_space.pcie_pm_cap_base; + pcie_port->regs->core_space[0].pcie_cap_base = ®s->core_space.pcie_cap_base; + pcie_port->regs->core_space[0].pcie_dev_cap_base = ®s->core_space.pcie_dev_cap_base; + pcie_port->regs->core_space[0].pcie_dev_ctrl_status = ®s->core_space.pcie_dev_ctrl_status; + pcie_port->regs->core_space[0].pcie_link_cap_base = ®s->core_space.pcie_link_cap_base; + pcie_port->regs->core_space[0].msix_cap_base = ®s->core_space.msix_cap_base; + pcie_port->regs->core_space[0].aer = ®s->core_space.aer; + pcie_port->regs->core_space[0].pcie_sec_ext_cap_base = ®s->core_space.pcie_sec_ext_cap_base; + + pcie_port->regs->port_regs = ®s->core_space.port_regs; + + } else if (pcie_port->rev_id == AL_PCIE_REV_ID_3) { + struct al_pcie_rev3_regs __iomem *regs = + (struct al_pcie_rev3_regs __iomem *)pcie_reg_base; + pcie_port->regs->axi.ctrl.global = ®s->axi.ctrl.global; + pcie_port->regs->axi.ctrl.master_arctl = ®s->axi.ctrl.master_arctl; + pcie_port->regs->axi.ctrl.master_awctl = ®s->axi.ctrl.master_awctl; + pcie_port->regs->axi.ctrl.slv_ctl = ®s->axi.ctrl.slv_ctl; + pcie_port->regs->axi.ob_ctrl.cfg_target_bus = ®s->axi.ob_ctrl.cfg_target_bus; + pcie_port->regs->axi.ob_ctrl.cfg_control = ®s->axi.ob_ctrl.cfg_control; + pcie_port->regs->axi.ob_ctrl.io_start_l = ®s->axi.ob_ctrl.io_start_l; + pcie_port->regs->axi.ob_ctrl.io_start_h = ®s->axi.ob_ctrl.io_start_h; + pcie_port->regs->axi.ob_ctrl.io_limit_l = ®s->axi.ob_ctrl.io_limit_l; + pcie_port->regs->axi.ob_ctrl.io_limit_h = ®s->axi.ob_ctrl.io_limit_h; + pcie_port->regs->axi.pcie_global.conf = ®s->axi.pcie_global.conf; + pcie_port->regs->axi.conf.zero_lane0 = ®s->axi.conf.zero_lane0; + pcie_port->regs->axi.conf.zero_lane1 = ®s->axi.conf.zero_lane1; + pcie_port->regs->axi.conf.zero_lane2 = ®s->axi.conf.zero_lane2; + pcie_port->regs->axi.conf.zero_lane3 = ®s->axi.conf.zero_lane3; + pcie_port->regs->axi.conf.zero_lane4 = ®s->axi.conf.zero_lane4; + pcie_port->regs->axi.conf.zero_lane5 = ®s->axi.conf.zero_lane5; + pcie_port->regs->axi.conf.zero_lane6 = ®s->axi.conf.zero_lane6; + pcie_port->regs->axi.conf.zero_lane7 = ®s->axi.conf.zero_lane7; + pcie_port->regs->axi.status.lane[0] = ®s->axi.status.lane0; + pcie_port->regs->axi.status.lane[1] = ®s->axi.status.lane1; + pcie_port->regs->axi.status.lane[2] = ®s->axi.status.lane2; + pcie_port->regs->axi.status.lane[3] = ®s->axi.status.lane3; + pcie_port->regs->axi.status.lane[4] = ®s->axi.status.lane4; + pcie_port->regs->axi.status.lane[5] = ®s->axi.status.lane5; + pcie_port->regs->axi.status.lane[6] = ®s->axi.status.lane6; + pcie_port->regs->axi.status.lane[7] = ®s->axi.status.lane7; + pcie_port->regs->axi.parity.en_axi = ®s->axi.parity.en_axi; + pcie_port->regs->axi.ordering.pos_cntl = ®s->axi.ordering.pos_cntl; + pcie_port->regs->axi.pre_configuration.pcie_core_setup = ®s->axi.pre_configuration.pcie_core_setup; + pcie_port->regs->axi.init_fc.cfg = ®s->axi.init_fc.cfg; + pcie_port->regs->axi.int_grp_a = ®s->axi.int_grp_a; + pcie_port->regs->axi.axi_attr_ovrd.write_msg_ctrl_0 = ®s->axi.axi_attr_ovrd.write_msg_ctrl_0; + pcie_port->regs->axi.axi_attr_ovrd.write_msg_ctrl_1 = ®s->axi.axi_attr_ovrd.write_msg_ctrl_1; + pcie_port->regs->axi.axi_attr_ovrd.pf_sel = ®s->axi.axi_attr_ovrd.pf_sel; + + for (i = 0; i < AL_MAX_NUM_OF_PFS; i++) { + pcie_port->regs->axi.pf_axi_attr_ovrd[i].func_ctrl_0 = ®s->axi.pf_axi_attr_ovrd[i].func_ctrl_0; + pcie_port->regs->axi.pf_axi_attr_ovrd[i].func_ctrl_1 = ®s->axi.pf_axi_attr_ovrd[i].func_ctrl_1; + pcie_port->regs->axi.pf_axi_attr_ovrd[i].func_ctrl_2 = ®s->axi.pf_axi_attr_ovrd[i].func_ctrl_2; + pcie_port->regs->axi.pf_axi_attr_ovrd[i].func_ctrl_3 = ®s->axi.pf_axi_attr_ovrd[i].func_ctrl_3; + pcie_port->regs->axi.pf_axi_attr_ovrd[i].func_ctrl_4 = ®s->axi.pf_axi_attr_ovrd[i].func_ctrl_4; + pcie_port->regs->axi.pf_axi_attr_ovrd[i].func_ctrl_5 = ®s->axi.pf_axi_attr_ovrd[i].func_ctrl_5; + pcie_port->regs->axi.pf_axi_attr_ovrd[i].func_ctrl_6 = ®s->axi.pf_axi_attr_ovrd[i].func_ctrl_6; + pcie_port->regs->axi.pf_axi_attr_ovrd[i].func_ctrl_7 = ®s->axi.pf_axi_attr_ovrd[i].func_ctrl_7; + pcie_port->regs->axi.pf_axi_attr_ovrd[i].func_ctrl_8 = ®s->axi.pf_axi_attr_ovrd[i].func_ctrl_8; + pcie_port->regs->axi.pf_axi_attr_ovrd[i].func_ctrl_9 = ®s->axi.pf_axi_attr_ovrd[i].func_ctrl_9; + } + + pcie_port->regs->axi.msg_attr_axuser_table.entry_vec = ®s->axi.msg_attr_axuser_table.entry_vec; + + pcie_port->regs->app.global_ctrl.port_init = ®s->app.global_ctrl.port_init; + pcie_port->regs->app.global_ctrl.pm_control = ®s->app.global_ctrl.pm_control; + pcie_port->regs->app.global_ctrl.corr_err_sts_int = ®s->app.global_ctrl.pended_corr_err_sts_int; + pcie_port->regs->app.global_ctrl.uncorr_err_sts_int = ®s->app.global_ctrl.pended_uncorr_err_sts_int; + + for (i = 0; i < AL_MAX_NUM_OF_PFS; i++) { + pcie_port->regs->app.global_ctrl.events_gen[i] = ®s->app.events_gen_per_func[i].events_gen; + } + + pcie_port->regs->app.global_ctrl.sris_kp_counter = ®s->app.global_ctrl.sris_kp_counter_value; + pcie_port->regs->app.debug = ®s->app.debug; + + for (i = 0; i < AL_MAX_NUM_OF_PFS; i++) { + pcie_port->regs->app.soc_int[i].mask_inta_leg_0 = ®s->app.soc_int_per_func[i].mask_inta_leg_0; + pcie_port->regs->app.soc_int[i].mask_inta_leg_3 = ®s->app.soc_int_per_func[i].mask_inta_leg_3; + pcie_port->regs->app.soc_int[i].mask_msi_leg_0 = ®s->app.soc_int_per_func[i].mask_msi_leg_0; + pcie_port->regs->app.soc_int[i].mask_msi_leg_3 = ®s->app.soc_int_per_func[i].mask_msi_leg_3; + } + + pcie_port->regs->app.ap_user_send_msg = ®s->app.ap_user_send_msg; + pcie_port->regs->app.ctrl_gen = ®s->app.ctrl_gen; + pcie_port->regs->app.parity = ®s->app.parity; + pcie_port->regs->app.atu.in_mask_pair = regs->app.atu.in_mask_pair; + pcie_port->regs->app.atu.out_mask_pair = regs->app.atu.out_mask_pair; + + for (i = 0; i < AL_MAX_NUM_OF_PFS; i++) + pcie_port->regs->app.status_per_func[i] = ®s->app.status_per_func[i]; + + pcie_port->regs->app.int_grp_a = ®s->app.int_grp_a; + pcie_port->regs->app.int_grp_b = ®s->app.int_grp_b; + pcie_port->regs->app.int_grp_c = ®s->app.int_grp_c; + pcie_port->regs->app.int_grp_d = ®s->app.int_grp_d; + + for (i = 0; i < AL_MAX_NUM_OF_PFS; i++) { + pcie_port->regs->core_space[i].config_header = regs->core_space.func[i].config_header; + pcie_port->regs->core_space[i].pcie_pm_cap_base = ®s->core_space.func[i].pcie_pm_cap_base; + pcie_port->regs->core_space[i].pcie_cap_base = ®s->core_space.func[i].pcie_cap_base; + pcie_port->regs->core_space[i].pcie_dev_cap_base = ®s->core_space.func[i].pcie_dev_cap_base; + pcie_port->regs->core_space[i].pcie_dev_ctrl_status = ®s->core_space.func[i].pcie_dev_ctrl_status; + pcie_port->regs->core_space[i].pcie_link_cap_base = ®s->core_space.func[i].pcie_link_cap_base; + pcie_port->regs->core_space[i].msix_cap_base = ®s->core_space.func[i].msix_cap_base; + pcie_port->regs->core_space[i].aer = ®s->core_space.func[i].aer; + pcie_port->regs->core_space[i].tph_cap_base = ®s->core_space.func[i].tph_cap_base; + + } + + /* secondary extension capability only for PF0 */ + pcie_port->regs->core_space[0].pcie_sec_ext_cap_base = ®s->core_space.func[0].pcie_sec_ext_cap_base; + + pcie_port->regs->port_regs = ®s->core_space.func[0].port_regs; + + } else { + al_warn("%s: Revision ID is unknown\n", + __func__); + return -EINVAL; + } + + /* set maximum number of physical functions */ + pcie_port->max_num_of_pfs = al_pcie_port_max_num_of_pfs_get(pcie_port); + + al_dbg("pcie port handle initialized. port id: %d, rev_id %d, regs base %p\n", + port_id, pcie_port->rev_id, pcie_reg_base); + return 0; +} + +/** + * Initializes a PCIe Physical function handle structure + * Caution: this function should not read/write to any register except for + * reading RO register (REV_ID for example) + */ +int +al_pcie_pf_handle_init( + struct al_pcie_pf *pcie_pf, + struct al_pcie_port *pcie_port, + unsigned int pf_num) +{ + enum al_pcie_operating_mode op_mode = al_pcie_operating_mode_get(pcie_port); + al_assert(pf_num < pcie_port->max_num_of_pfs); + + if (op_mode != AL_PCIE_OPERATING_MODE_EP) { + al_err("PCIe %d: can't init PF handle with operating mode [%d]\n", + pcie_port->port_id, op_mode); + return -EINVAL; + } + + pcie_pf->pf_num = pf_num; + pcie_pf->pcie_port = pcie_port; + + al_dbg("PCIe %d: pf handle initialized. pf number: %d, rev_id %d, regs %p\n", + pcie_port->port_id, pcie_pf->pf_num, pcie_port->rev_id, + pcie_port->regs); + return 0; +} + +/************************** Pre PCIe Port Enable API **************************/ + +/** configure pcie operating mode (root complex or endpoint) */ +int +al_pcie_port_operating_mode_config( + struct al_pcie_port *pcie_port, + enum al_pcie_operating_mode mode) +{ + struct al_pcie_regs *regs = pcie_port->regs; + uint32_t reg, device_type, new_device_type; + + if (al_pcie_port_is_enabled(pcie_port)) { + al_err("PCIe %d: already enabled, cannot set operating mode\n", + pcie_port->port_id); + return -EINVAL; + } + + reg = al_reg_read32(regs->axi.pcie_global.conf); + + device_type = AL_REG_FIELD_GET(reg, + PCIE_AXI_MISC_PCIE_GLOBAL_CONF_DEV_TYPE_MASK, + PCIE_AXI_MISC_PCIE_GLOBAL_CONF_DEV_TYPE_SHIFT); + if (mode == AL_PCIE_OPERATING_MODE_EP) { + new_device_type = PCIE_AXI_MISC_PCIE_GLOBAL_CONF_DEV_TYPE_EP; + } else if (mode == AL_PCIE_OPERATING_MODE_RC) { + new_device_type = PCIE_AXI_MISC_PCIE_GLOBAL_CONF_DEV_TYPE_RC; + + if (pcie_port->rev_id == AL_PCIE_REV_ID_3) { + /* config 1 PF in RC mode */ + al_reg_write32_masked(regs->axi.axi_attr_ovrd.pf_sel, + PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT0_OVRD_FROM_AXUSER | + PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT0_OVRD_FROM_REG | + PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT0_ADDR_OFFSET_MASK | + PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_CFG_PF_BIT0_OVRD | + PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT1_OVRD_FROM_AXUSER | + PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT1_OVRD_FROM_REG | + PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT1_ADDR_OFFSET_MASK | + PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_CFG_PF_BIT1_OVRD, + PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT0_OVRD_FROM_REG | + PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT1_OVRD_FROM_REG); + } + } else { + al_err("PCIe %d: unknown operating mode: %d\n", pcie_port->port_id, mode); + return -EINVAL; + } + + if (new_device_type == device_type) { + al_dbg("PCIe %d: operating mode already set to %s\n", + pcie_port->port_id, (mode == AL_PCIE_OPERATING_MODE_EP) ? + "EndPoint" : "Root Complex"); + return 0; + } + al_info("PCIe %d: set operating mode to %s\n", + pcie_port->port_id, (mode == AL_PCIE_OPERATING_MODE_EP) ? + "EndPoint" : "Root Complex"); + AL_REG_FIELD_SET(reg, PCIE_AXI_MISC_PCIE_GLOBAL_CONF_DEV_TYPE_MASK, + PCIE_AXI_MISC_PCIE_GLOBAL_CONF_DEV_TYPE_SHIFT, + new_device_type); + + al_reg_write32(regs->axi.pcie_global.conf, reg); + + return 0; +} + +int +al_pcie_port_max_lanes_set(struct al_pcie_port *pcie_port, uint8_t lanes) +{ + struct al_pcie_regs *regs = pcie_port->regs; + + if (al_pcie_port_is_enabled(pcie_port)) { + al_err("PCIe %d: already enabled, cannot set max lanes\n", + pcie_port->port_id); + return -EINVAL; + } + + /* convert to bitmask format (4 ->'b1111, 2 ->'b11, 1 -> 'b1) */ + uint32_t active_lanes_val = AL_PCIE_PARSE_LANES(lanes); + + al_reg_write32_masked(regs->axi.pcie_global.conf, + (pcie_port->rev_id == AL_PCIE_REV_ID_3) ? + PCIE_REV3_AXI_MISC_PCIE_GLOBAL_CONF_NOF_ACT_LANES_MASK : + PCIE_REV1_2_AXI_MISC_PCIE_GLOBAL_CONF_NOF_ACT_LANES_MASK, + active_lanes_val); + + pcie_port->max_lanes = lanes; + return 0; +} + +int +al_pcie_port_max_num_of_pfs_set( + struct al_pcie_port *pcie_port, + uint8_t max_num_of_pfs) +{ + if (al_pcie_port_is_enabled(pcie_port)) { + al_err("PCIe %d: already enabled, cannot set max num of PFs\n", + pcie_port->port_id); + return -EINVAL; + } + + if (pcie_port->rev_id == AL_PCIE_REV_ID_3) + al_assert(max_num_of_pfs <= REV3_MAX_NUM_OF_PFS); + else + al_assert(max_num_of_pfs == REV1_2_MAX_NUM_OF_PFS); + + pcie_port->max_num_of_pfs = max_num_of_pfs; + + return 0; +} + +/* Inbound header credits and outstanding outbound reads configuration */ +int +al_pcie_port_ib_hcrd_os_ob_reads_config( + struct al_pcie_port *pcie_port, + struct al_pcie_ib_hcrd_os_ob_reads_config *ib_hcrd_os_ob_reads_config) +{ + struct al_pcie_regs *regs = pcie_port->regs; + + if (al_pcie_port_is_enabled(pcie_port)) { + al_err("PCIe %d: already enabled, cannot configure IB credits and OB OS reads\n", + pcie_port->port_id); + return -EINVAL; + } + + al_assert(ib_hcrd_os_ob_reads_config->nof_np_hdr > 0); + + al_assert(ib_hcrd_os_ob_reads_config->nof_p_hdr > 0); + + al_assert(ib_hcrd_os_ob_reads_config->nof_cpl_hdr > 0); + + if (pcie_port->rev_id == AL_PCIE_REV_ID_3) { + al_assert( + (ib_hcrd_os_ob_reads_config->nof_cpl_hdr + + ib_hcrd_os_ob_reads_config->nof_np_hdr + + ib_hcrd_os_ob_reads_config->nof_p_hdr) == + AL_PCIE_REV3_IB_HCRD_SUM); + + al_reg_write32_masked( + regs->axi.init_fc.cfg, + PCIE_AXI_REV3_INIT_FC_CFG_NOF_P_HDR_MASK | + PCIE_AXI_REV3_INIT_FC_CFG_NOF_NP_HDR_MASK | + PCIE_AXI_REV3_INIT_FC_CFG_NOF_CPL_HDR_MASK, + (ib_hcrd_os_ob_reads_config->nof_p_hdr << + PCIE_AXI_REV3_INIT_FC_CFG_NOF_P_HDR_SHIFT) | + (ib_hcrd_os_ob_reads_config->nof_np_hdr << + PCIE_AXI_REV3_INIT_FC_CFG_NOF_NP_HDR_SHIFT) | + (ib_hcrd_os_ob_reads_config->nof_cpl_hdr << + PCIE_AXI_REV3_INIT_FC_CFG_NOF_CPL_HDR_SHIFT)); + } else { + al_assert( + (ib_hcrd_os_ob_reads_config->nof_cpl_hdr + + ib_hcrd_os_ob_reads_config->nof_np_hdr + + ib_hcrd_os_ob_reads_config->nof_p_hdr) == + AL_PCIE_REV_1_2_IB_HCRD_SUM); + + al_reg_write32_masked( + regs->axi.init_fc.cfg, + PCIE_AXI_REV1_2_INIT_FC_CFG_NOF_P_HDR_MASK | + PCIE_AXI_REV1_2_INIT_FC_CFG_NOF_NP_HDR_MASK | + PCIE_AXI_REV1_2_INIT_FC_CFG_NOF_CPL_HDR_MASK, + (ib_hcrd_os_ob_reads_config->nof_p_hdr << + PCIE_AXI_REV1_2_INIT_FC_CFG_NOF_P_HDR_SHIFT) | + (ib_hcrd_os_ob_reads_config->nof_np_hdr << + PCIE_AXI_REV1_2_INIT_FC_CFG_NOF_NP_HDR_SHIFT) | + (ib_hcrd_os_ob_reads_config->nof_cpl_hdr << + PCIE_AXI_REV1_2_INIT_FC_CFG_NOF_CPL_HDR_SHIFT)); + } + + al_reg_write32_masked( + regs->axi.pre_configuration.pcie_core_setup, + PCIE_AXI_CORE_SETUP_NOF_READS_ONSLAVE_INTRF_PCIE_CORE_MASK, + ib_hcrd_os_ob_reads_config->nof_outstanding_ob_reads << + PCIE_AXI_CORE_SETUP_NOF_READS_ONSLAVE_INTRF_PCIE_CORE_SHIFT); + + /* Store 'nof_p_hdr' and 'nof_np_hdr' to be set in the core later */ + pcie_port->ib_hcrd_config.nof_np_hdr = + ib_hcrd_os_ob_reads_config->nof_np_hdr; + pcie_port->ib_hcrd_config.nof_p_hdr = + ib_hcrd_os_ob_reads_config->nof_p_hdr; + + return 0; +} + +enum al_pcie_operating_mode +al_pcie_operating_mode_get( + struct al_pcie_port *pcie_port) +{ + struct al_pcie_regs *regs = pcie_port->regs; + uint32_t reg, device_type; + + al_assert(pcie_port); + + reg = al_reg_read32(regs->axi.pcie_global.conf); + + device_type = AL_REG_FIELD_GET(reg, + PCIE_AXI_MISC_PCIE_GLOBAL_CONF_DEV_TYPE_MASK, + PCIE_AXI_MISC_PCIE_GLOBAL_CONF_DEV_TYPE_SHIFT); + + switch (device_type) { + case PCIE_AXI_MISC_PCIE_GLOBAL_CONF_DEV_TYPE_EP: + return AL_PCIE_OPERATING_MODE_EP; + case PCIE_AXI_MISC_PCIE_GLOBAL_CONF_DEV_TYPE_RC: + return AL_PCIE_OPERATING_MODE_RC; + default: + al_err("PCIe %d: unknown device type (%d) in global conf register.\n", + pcie_port->port_id, device_type); + } + return AL_PCIE_OPERATING_MODE_UNKNOWN; +} + +/**************************** PCIe Port Enable API ****************************/ + +/** Enable PCIe port (deassert reset) */ +int +al_pcie_port_enable(struct al_pcie_port *pcie_port) +{ + struct al_pbs_regs *pbs_reg_base = + (struct al_pbs_regs *)pcie_port->pbs_regs; + struct al_pcie_regs *regs = pcie_port->regs; + unsigned int port_id = pcie_port->port_id; + + /* pre-port-enable default functionality should be here */ + + /** + * Set inbound header credit and outstanding outbound reads defaults + * Must be called before port enable (PCIE_EXIST) + */ + al_pcie_ib_hcrd_os_ob_reads_config_default(pcie_port); + + /* + * Disable ATS capability + * - must be done before core reset deasserted + * - rev_id 0 - no effect, but no harm + */ + if ((pcie_port->rev_id == AL_PCIE_REV_ID_0) || + (pcie_port->rev_id == AL_PCIE_REV_ID_1) || + (pcie_port->rev_id == AL_PCIE_REV_ID_2)) { + al_reg_write32_masked( + regs->axi.ordering.pos_cntl, + PCIE_AXI_CORE_SETUP_ATS_CAP_DIS, + PCIE_AXI_CORE_SETUP_ATS_CAP_DIS); + } + + /* Deassert core reset */ + al_reg_write32_masked( + &pbs_reg_base->unit.pcie_conf_1, + 1 << (port_id + PBS_UNIT_PCIE_CONF_1_PCIE_EXIST_SHIFT), + 1 << (port_id + PBS_UNIT_PCIE_CONF_1_PCIE_EXIST_SHIFT)); + + return 0; +} + +/** Disable PCIe port (assert reset) */ +void +al_pcie_port_disable(struct al_pcie_port *pcie_port) +{ + struct al_pbs_regs *pbs_reg_base = + (struct al_pbs_regs *)pcie_port->pbs_regs; + unsigned int port_id = pcie_port->port_id; + + if (!al_pcie_port_is_enabled(pcie_port)) { + al_warn("PCIe %d: trying to disable a non-enabled port\n", + pcie_port->port_id); + } + + /* Assert core reset */ + al_reg_write32_masked( + &pbs_reg_base->unit.pcie_conf_1, + 1 << (port_id + PBS_UNIT_PCIE_CONF_1_PCIE_EXIST_SHIFT), + 0); +} + +int +al_pcie_port_memory_shutdown_set( + struct al_pcie_port *pcie_port, + al_bool enable) +{ + struct al_pcie_regs *regs = pcie_port->regs; + uint32_t mask = (pcie_port->rev_id == AL_PCIE_REV_ID_3) ? + PCIE_REV3_AXI_MISC_PCIE_GLOBAL_CONF_MEM_SHUTDOWN : + PCIE_REV1_2_AXI_MISC_PCIE_GLOBAL_CONF_MEM_SHUTDOWN; + + if (!al_pcie_port_is_enabled(pcie_port)) { + al_err("PCIe %d: not enabled, cannot shutdown memory\n", + pcie_port->port_id); + return -EINVAL; + } + + al_reg_write32_masked(regs->axi.pcie_global.conf, + mask, enable == AL_TRUE ? mask : 0); + + return 0; +} + +al_bool +al_pcie_port_is_enabled(struct al_pcie_port *pcie_port) +{ + struct al_pbs_regs *pbs_reg_base = (struct al_pbs_regs *)pcie_port->pbs_regs; + uint32_t pcie_exist = al_reg_read32(&pbs_reg_base->unit.pcie_conf_1); + + uint32_t ports_enabled = AL_REG_FIELD_GET(pcie_exist, + PBS_UNIT_PCIE_CONF_1_PCIE_EXIST_MASK, + PBS_UNIT_PCIE_CONF_1_PCIE_EXIST_SHIFT); + + return (AL_REG_FIELD_GET(ports_enabled, AL_BIT(pcie_port->port_id), + pcie_port->port_id) == 1); +} + +/*************************** PCIe Configuration API ***************************/ + +/** configure pcie port (link params, etc..) */ +int +al_pcie_port_config(struct al_pcie_port *pcie_port, + const struct al_pcie_port_config_params *params) +{ + struct al_pcie_regs *regs = pcie_port->regs; + enum al_pcie_operating_mode op_mode; + int status = 0; + int i; + + if (!al_pcie_port_is_enabled(pcie_port)) { + al_err("PCIe %d: port not enabled, cannot configure port\n", + pcie_port->port_id); + return -EINVAL; + } + + if (al_pcie_is_link_started(pcie_port)) { + al_err("PCIe %d: link already started, cannot configure port\n", + pcie_port->port_id); + return -EINVAL; + } + + al_assert(pcie_port); + al_assert(params); + + al_dbg("PCIe %d: port config\n", pcie_port->port_id); + + op_mode = al_pcie_operating_mode_get(pcie_port); + + /* if max lanes not specifies, read it from register */ + if (pcie_port->max_lanes == 0) { + uint32_t global_conf = al_reg_read32(regs->axi.pcie_global.conf); + uint32_t act_lanes = AL_REG_FIELD_GET(global_conf, + (pcie_port->rev_id == AL_PCIE_REV_ID_3) ? + PCIE_REV3_AXI_MISC_PCIE_GLOBAL_CONF_NOF_ACT_LANES_MASK : + PCIE_REV1_2_AXI_MISC_PCIE_GLOBAL_CONF_NOF_ACT_LANES_MASK, + PCIE_REVX_AXI_MISC_PCIE_GLOBAL_CONF_NOF_ACT_LANES_SHIFT); + + switch(act_lanes) { + case 0x1: + pcie_port->max_lanes = 1; + break; + case 0x3: + pcie_port->max_lanes = 2; + break; + case 0xf: + pcie_port->max_lanes = 4; + break; + case 0xff: + pcie_port->max_lanes = 8; + break; + default: + pcie_port->max_lanes = 0; + al_err("PCIe %d: invalid max lanes val (0x%x)\n", pcie_port->port_id, act_lanes); + break; + } + } + + if (params->link_params) + status = al_pcie_port_link_config(pcie_port, params->link_params); + if (status) + goto done; + + /* Change max read request size to 256 bytes + * Max Payload Size is remained untouched- it is the responsibility of + * the host to change the MPS, if needed. + */ + for (i = 0; i < AL_MAX_NUM_OF_PFS; i++) { + al_reg_write32_masked(regs->core_space[i].pcie_dev_ctrl_status, + PCIE_PORT_DEV_CTRL_STATUS_MRRS_MASK, + PCIE_PORT_DEV_CTRL_STATUS_MRRS_VAL_256); + if (pcie_port->rev_id != AL_PCIE_REV_ID_3) + break; + } + + if (pcie_port->rev_id == AL_PCIE_REV_ID_3) { + /* Set maximum physical function numbers */ + al_reg_write32_masked( + ®s->port_regs->timer_ctrl_max_func_num, + PCIE_PORT_GEN3_MAX_FUNC_NUM, + pcie_port->max_num_of_pfs - 1); + + al_pcie_port_wr_to_ro_set(pcie_port, AL_TRUE); + + /** + * in EP mode, when we have more than 1 PF we need to assert + * multi-pf support so the host scan all PFs + */ + if ((op_mode == AL_PCIE_OPERATING_MODE_EP) && (pcie_port->max_num_of_pfs > 1)) { + al_reg_write32_masked((uint32_t __iomem *) + (®s->core_space[0].config_header[0] + + (PCIE_BIST_HEADER_TYPE_BASE >> 2)), + PCIE_BIST_HEADER_TYPE_MULTI_FUNC_MASK, + PCIE_BIST_HEADER_TYPE_MULTI_FUNC_MASK); + } + + /* Disable TPH next pointer */ + for (i = 0; i < AL_MAX_NUM_OF_PFS; i++) { + al_reg_write32_masked(regs->core_space[i].tph_cap_base, + PCIE_TPH_NEXT_POINTER, 0); + } + + al_pcie_port_wr_to_ro_set(pcie_port, AL_FALSE); + } + + + status = al_pcie_port_snoop_config(pcie_port, params->enable_axi_snoop); + if (status) + goto done; + + al_pcie_port_ram_parity_int_config(pcie_port, params->enable_ram_parity_int); + + al_pcie_port_axi_parity_int_config(pcie_port, params->enable_axi_parity_int); + + al_pcie_port_relaxed_pcie_ordering_config(pcie_port, params->relaxed_ordering_params); + + if (params->lat_rply_timers) + status = al_pcie_port_lat_rply_timers_config(pcie_port, params->lat_rply_timers); + if (status) + goto done; + + if (params->gen2_params) + status = al_pcie_port_gen2_params_config(pcie_port, params->gen2_params); + if (status) + goto done; + + if (params->gen3_params) + status = al_pcie_port_gen3_params_config(pcie_port, params->gen3_params); + if (status) + goto done; + + if (params->tl_credits) + status = al_pcie_port_tl_credits_config(pcie_port, params->tl_credits); + if (status) + goto done; + + if (params->features) + al_pcie_port_features_config(pcie_port, params->features); + + if (params->sris_params) + status = al_pcie_port_sris_config(pcie_port, params->sris_params, + params->link_params->max_speed); + if (status) + goto done; + + al_pcie_port_ib_hcrd_config(pcie_port); + + if (params->fast_link_mode) { + al_reg_write32_masked(®s->port_regs->port_link_ctrl, + 1 << PCIE_PORT_LINK_CTRL_FAST_LINK_EN_SHIFT, + 1 << PCIE_PORT_LINK_CTRL_FAST_LINK_EN_SHIFT); + } + + if (params->enable_axi_slave_err_resp) + al_reg_write32_masked(®s->port_regs->axi_slave_err_resp, + 1 << PCIE_PORT_AXI_SLAVE_ERR_RESP_ALL_MAPPING_SHIFT, + 1 << PCIE_PORT_AXI_SLAVE_ERR_RESP_ALL_MAPPING_SHIFT); + + /** + * Addressing RMN: 5477 + * + * RMN description: + * address-decoder logic performs sub-target decoding even for transactions + * which undergo target enforcement. thus, in case transaction's address is + * inside any ECAM bar, the sub-target decoding will be set to ECAM, which + * causes wrong handling by PCIe unit + * + * Software flow: + * on EP mode only, turning on the iATU-enable bit (with the relevant mask + * below) allows the PCIe unit to discard the ECAM bit which was asserted + * by-mistake in the address-decoder + */ + if (op_mode == AL_PCIE_OPERATING_MODE_EP) { + al_reg_write32_masked(regs->axi.ob_ctrl.cfg_target_bus, + PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_MASK_MASK, + (0) << PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_MASK_SHIFT); + al_reg_write32_masked(regs->axi.ob_ctrl.cfg_control, + PCIE_AXI_MISC_OB_CTRL_CFG_CONTROL_IATU_EN, + PCIE_AXI_MISC_OB_CTRL_CFG_CONTROL_IATU_EN); + } + + if (op_mode == AL_PCIE_OPERATING_MODE_RC) { + /** + * enable memory and I/O access from port when in RC mode + * in RC mode, only core_space[0] is valid. + */ + al_reg_write16_masked( + (uint16_t __iomem *)(®s->core_space[0].config_header[0] + (0x4 >> 2)), + 0x7, /* Mem, MSE, IO */ + 0x7); + + /* change the class code to match pci bridge */ + al_pcie_port_wr_to_ro_set(pcie_port, AL_TRUE); + + al_reg_write32_masked( + (uint32_t __iomem *)(®s->core_space[0].config_header[0] + + (PCI_CLASS_REVISION >> 2)), + 0xFFFFFF00, + 0x06040000); + + al_pcie_port_wr_to_ro_set(pcie_port, AL_FALSE); + + /** + * Addressing RMN: 5702 + * + * RMN description: + * target bus mask default value in HW is: 0xFE, this enforces + * setting the target bus for ports 1 and 3 when running on RC + * mode since bit[20] in ECAM address in these cases is set + * + * Software flow: + * on RC mode only, set target-bus value to 0xFF to prevent this + * enforcement + */ + al_reg_write32_masked(regs->axi.ob_ctrl.cfg_target_bus, + PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_MASK_MASK, + PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_MASK_MASK); + } +done: + al_dbg("PCIe %d: port config %s\n", pcie_port->port_id, status? "failed": "done"); + + return status; +} + +int +al_pcie_pf_config( + struct al_pcie_pf *pcie_pf, + const struct al_pcie_pf_config_params *params) +{ + struct al_pcie_port *pcie_port; + int status = 0; + + al_assert(pcie_pf); + al_assert(params); + + pcie_port = pcie_pf->pcie_port; + + if (!al_pcie_port_is_enabled(pcie_port)) { + al_err("PCIe %d: port not enabled, cannot configure port\n", pcie_port->port_id); + return -EINVAL; + } + + al_dbg("PCIe %d: pf %d config\n", pcie_port->port_id, pcie_pf->pf_num); + + if (params) + status = al_pcie_port_pf_params_config(pcie_pf, params); + if (status) + goto done; + +done: + al_dbg("PCIe %d: pf %d config %s\n", + pcie_port->port_id, pcie_pf->pf_num, status ? "failed" : "done"); + + return status; +} + +/************************** PCIe Link Operations API **************************/ + +/* start pcie link */ +int +al_pcie_link_start(struct al_pcie_port *pcie_port) +{ + struct al_pcie_regs *regs = (struct al_pcie_regs *)pcie_port->regs; + + if (!al_pcie_port_is_enabled(pcie_port)) { + al_err("PCIe %d: port not enabled, cannot start link\n", + pcie_port->port_id); + return -EINVAL; + } + + al_dbg("PCIe_%d: start port link.\n", pcie_port->port_id); + + al_reg_write32_masked( + regs->app.global_ctrl.port_init, + PCIE_W_GLOBAL_CTRL_PORT_INIT_APP_LTSSM_EN_MASK, + PCIE_W_GLOBAL_CTRL_PORT_INIT_APP_LTSSM_EN_MASK); + + return 0; +} + +/* stop pcie link */ +int +al_pcie_link_stop(struct al_pcie_port *pcie_port) +{ + struct al_pcie_regs *regs = (struct al_pcie_regs *)pcie_port->regs; + + if (!al_pcie_is_link_started(pcie_port)) { + al_warn("PCIe %d: trying to stop a non-started link\n", + pcie_port->port_id); + } + + al_dbg("PCIe_%d: stop port link.\n", pcie_port->port_id); + + al_reg_write32_masked( + regs->app.global_ctrl.port_init, + PCIE_W_GLOBAL_CTRL_PORT_INIT_APP_LTSSM_EN_MASK, + ~PCIE_W_GLOBAL_CTRL_PORT_INIT_APP_LTSSM_EN_MASK); + + return 0; +} + +/* wait for link up indication */ +int +al_pcie_link_up_wait(struct al_pcie_port *pcie_port, uint32_t timeout_ms) +{ + int wait_count = timeout_ms * AL_PCIE_LINKUP_WAIT_INTERVALS_PER_SEC; + + while (wait_count-- > 0) { + if (al_pcie_check_link(pcie_port, NULL)) { + al_info("PCIe_%d: <<<<<<<<< Link up >>>>>>>>>\n", pcie_port->port_id); + return 0; + } else + al_dbg("PCIe_%d: No link up, %d attempts remaining\n", + pcie_port->port_id, wait_count); + + al_udelay(AL_PCIE_LINKUP_WAIT_INTERVAL); + } + al_info("PCIE_%d: link is not established in time\n", + pcie_port->port_id); + + return ETIMEDOUT; +} + +/** get link status */ +int +al_pcie_link_status(struct al_pcie_port *pcie_port, + struct al_pcie_link_status *status) +{ + struct al_pcie_regs *regs = pcie_port->regs; + uint16_t pcie_lnksta; + + al_assert(status); + + status->link_up = al_pcie_check_link(pcie_port, &status->ltssm_state); + + if (!status->link_up) { + status->speed = AL_PCIE_LINK_SPEED_DEFAULT; + status->lanes = 0; + return 0; + } + + pcie_lnksta = al_reg_read16((uint16_t __iomem *)regs->core_space[0].pcie_cap_base + (AL_PCI_EXP_LNKSTA >> 1)); + + switch(pcie_lnksta & AL_PCI_EXP_LNKSTA_CLS) { + case AL_PCI_EXP_LNKSTA_CLS_2_5GB: + status->speed = AL_PCIE_LINK_SPEED_GEN1; + break; + case AL_PCI_EXP_LNKSTA_CLS_5_0GB: + status->speed = AL_PCIE_LINK_SPEED_GEN2; + break; + case AL_PCI_EXP_LNKSTA_CLS_8_0GB: + status->speed = AL_PCIE_LINK_SPEED_GEN3; + break; + default: + status->speed = AL_PCIE_LINK_SPEED_DEFAULT; + al_err("PCIe %d: unknown link speed indication. PCIE LINK STATUS %x\n", + pcie_port->port_id, pcie_lnksta); + } + status->lanes = (pcie_lnksta & AL_PCI_EXP_LNKSTA_NLW) >> AL_PCI_EXP_LNKSTA_NLW_SHIFT; + al_info("PCIe %d: Link up. speed gen%d negotiated width %d\n", + pcie_port->port_id, status->speed, status->lanes); + + return 0; +} + +/** get lane status */ +void +al_pcie_lane_status_get( + struct al_pcie_port *pcie_port, + unsigned int lane, + struct al_pcie_lane_status *status) +{ + struct al_pcie_regs *regs = pcie_port->regs; + uint32_t lane_status; + uint32_t *reg_ptr; + + al_assert(pcie_port); + al_assert(status); + al_assert((pcie_port->rev_id != AL_PCIE_REV_ID_1) || (lane < REV1_2_MAX_NUM_LANES)); + al_assert((pcie_port->rev_id != AL_PCIE_REV_ID_2) || (lane < REV1_2_MAX_NUM_LANES)); + al_assert((pcie_port->rev_id != AL_PCIE_REV_ID_3) || (lane < REV3_MAX_NUM_LANES)); + + reg_ptr = regs->axi.status.lane[lane]; + + /* Reset field is valid only when same value is read twice */ + do { + lane_status = al_reg_read32(reg_ptr); + status->is_reset = !!(lane_status & PCIE_AXI_STATUS_LANE_IS_RESET); + } while (status->is_reset != (!!(al_reg_read32(reg_ptr) & PCIE_AXI_STATUS_LANE_IS_RESET))); + + status->requested_speed = + (lane_status & PCIE_AXI_STATUS_LANE_REQUESTED_SPEED_MASK) >> + PCIE_AXI_STATUS_LANE_REQUESTED_SPEED_SHIFT; +} + +/** trigger hot reset */ +int +al_pcie_link_hot_reset(struct al_pcie_port *pcie_port, al_bool enable) +{ + struct al_pcie_regs *regs = pcie_port->regs; + uint32_t events_gen; + al_bool app_reset_state; + enum al_pcie_operating_mode op_mode = al_pcie_operating_mode_get(pcie_port); + + if (op_mode != AL_PCIE_OPERATING_MODE_RC) { + al_err("PCIe %d: hot-reset is applicable only for RC mode\n", pcie_port->port_id); + return -EINVAL; + } + + if (!al_pcie_is_link_started(pcie_port)) { + al_err("PCIe %d: link not started, cannot trigger hot-reset\n", pcie_port->port_id); + return -EINVAL; + } + + events_gen = al_reg_read32(regs->app.global_ctrl.events_gen[0]); + app_reset_state = events_gen & PCIE_W_GLOBAL_CTRL_EVENTS_GEN_APP_RST_INIT; + + if (enable && app_reset_state) { + al_err("PCIe %d: link is already in hot-reset state\n", pcie_port->port_id); + return -EINVAL; + } else if ((!enable) && (!(app_reset_state))) { + al_err("PCIe %d: link is already in non-hot-reset state\n", pcie_port->port_id); + return -EINVAL; + } else { + al_dbg("PCIe %d: %s hot-reset\n", pcie_port->port_id, + (enable ? "enabling" : "disabling")); + /* hot-reset functionality is implemented only for function 0 */ + al_reg_write32_masked(regs->app.global_ctrl.events_gen[0], + PCIE_W_GLOBAL_CTRL_EVENTS_GEN_APP_RST_INIT, + (enable ? PCIE_W_GLOBAL_CTRL_EVENTS_GEN_APP_RST_INIT + : ~PCIE_W_GLOBAL_CTRL_EVENTS_GEN_APP_RST_INIT)); + return 0; + } +} + +/** disable port link */ +int +al_pcie_link_disable(struct al_pcie_port *pcie_port, al_bool disable) +{ + struct al_pcie_regs *regs = pcie_port->regs; + uint32_t pcie_lnkctl; + al_bool link_disable_state; + enum al_pcie_operating_mode op_mode = al_pcie_operating_mode_get(pcie_port); + + if (op_mode != AL_PCIE_OPERATING_MODE_RC) { + al_err("PCIe %d: hot-reset is applicable only for RC mode\n", pcie_port->port_id); + return -EINVAL; + } + + if (!al_pcie_is_link_started(pcie_port)) { + al_err("PCIe %d: link not started, cannot disable link\n", pcie_port->port_id); + return -EINVAL; + } + + pcie_lnkctl = al_reg_read32(regs->core_space[0].pcie_cap_base + (AL_PCI_EXP_LNKCTL >> 1)); + link_disable_state = pcie_lnkctl & AL_PCI_EXP_LNKCTL_LNK_DIS; + + if (disable && link_disable_state) { + al_err("PCIe %d: link is already in disable state\n", pcie_port->port_id); + return -EINVAL; + } else if ((!disable) && (!(link_disable_state))) { + al_err("PCIe %d: link is already in enable state\n", pcie_port->port_id); + return -EINVAL; + } + + al_dbg("PCIe %d: %s port\n", pcie_port->port_id, (disable ? "disabling" : "enabling")); + al_reg_write32_masked(regs->core_space[0].pcie_cap_base + (AL_PCI_EXP_LNKCTL >> 1), + AL_PCI_EXP_LNKCTL_LNK_DIS, + (disable ? AL_PCI_EXP_LNKCTL_LNK_DIS : ~AL_PCI_EXP_LNKCTL_LNK_DIS)); + return 0; +} + +/** retrain link */ +int +al_pcie_link_retrain(struct al_pcie_port *pcie_port) +{ + struct al_pcie_regs *regs = pcie_port->regs; + enum al_pcie_operating_mode op_mode = al_pcie_operating_mode_get(pcie_port); + + if (op_mode != AL_PCIE_OPERATING_MODE_RC) { + al_err("PCIe %d: link-retrain is applicable only for RC mode\n", + pcie_port->port_id); + return -EINVAL; + } + + if (!al_pcie_is_link_started(pcie_port)) { + al_err("PCIe %d: link not started, cannot link-retrain\n", pcie_port->port_id); + return -EINVAL; + } + + al_reg_write32_masked(regs->core_space[0].pcie_cap_base + (AL_PCI_EXP_LNKCTL >> 1), + AL_PCI_EXP_LNKCTL_LNK_RTRN, AL_PCI_EXP_LNKCTL_LNK_RTRN); + + return 0; +} + +/* trigger speed change */ +int +al_pcie_link_change_speed(struct al_pcie_port *pcie_port, + enum al_pcie_link_speed new_speed) +{ + struct al_pcie_regs *regs = pcie_port->regs; + + if (!al_pcie_is_link_started(pcie_port)) { + al_err("PCIe %d: link not started, cannot change speed\n", pcie_port->port_id); + return -EINVAL; + } + + al_dbg("PCIe %d: changing speed to %d\n", pcie_port->port_id, new_speed); + + al_pcie_port_link_speed_ctrl_set(pcie_port, new_speed); + + al_reg_write32_masked(®s->port_regs->gen2_ctrl, + PCIE_PORT_GEN2_CTRL_DIRECT_SPEED_CHANGE, + PCIE_PORT_GEN2_CTRL_DIRECT_SPEED_CHANGE); + + return 0; +} + +/* TODO: check if this function needed */ +int +al_pcie_link_change_width(struct al_pcie_port *pcie_port, + uint8_t width __attribute__((__unused__))) +{ + al_err("PCIe %d: link change width not implemented\n", + pcie_port->port_id); + + return -ENOSYS; +} + +/**************************** Post Link Start API *****************************/ + +/************************** Snoop Configuration API ***************************/ + +int +al_pcie_port_snoop_config(struct al_pcie_port *pcie_port, al_bool enable_axi_snoop) +{ + struct al_pcie_regs *regs = pcie_port->regs; + + /* Set snoop mode */ + al_info("PCIE_%d: snoop mode %s\n", + pcie_port->port_id, enable_axi_snoop ? "enable" : "disable"); + + if (enable_axi_snoop) { + al_reg_write32_masked(regs->axi.ctrl.master_arctl, + PCIE_AXI_CTRL_MASTER_ARCTL_OVR_SNOOP | PCIE_AXI_CTRL_MASTER_ARCTL_SNOOP, + PCIE_AXI_CTRL_MASTER_ARCTL_OVR_SNOOP | PCIE_AXI_CTRL_MASTER_ARCTL_SNOOP); + + al_reg_write32_masked(regs->axi.ctrl.master_awctl, + PCIE_AXI_CTRL_MASTER_AWCTL_OVR_SNOOP | PCIE_AXI_CTRL_MASTER_AWCTL_SNOOP, + PCIE_AXI_CTRL_MASTER_AWCTL_OVR_SNOOP | PCIE_AXI_CTRL_MASTER_AWCTL_SNOOP); + } else { + al_reg_write32_masked(regs->axi.ctrl.master_arctl, + PCIE_AXI_CTRL_MASTER_ARCTL_OVR_SNOOP | PCIE_AXI_CTRL_MASTER_ARCTL_SNOOP, + PCIE_AXI_CTRL_MASTER_ARCTL_OVR_SNOOP); + + al_reg_write32_masked(regs->axi.ctrl.master_awctl, + PCIE_AXI_CTRL_MASTER_AWCTL_OVR_SNOOP | PCIE_AXI_CTRL_MASTER_AWCTL_SNOOP, + PCIE_AXI_CTRL_MASTER_AWCTL_OVR_SNOOP); + } + return 0; +} + +/************************** Configuration Space API ***************************/ + +/** get base address of pci configuration space header */ +int +al_pcie_config_space_get(struct al_pcie_pf *pcie_pf, + uint8_t __iomem **addr) +{ + struct al_pcie_regs *regs = pcie_pf->pcie_port->regs; + + *addr = (uint8_t __iomem *)®s->core_space[pcie_pf->pf_num].config_header[0]; + return 0; +} + +/* Read data from the local configuration space */ +uint32_t +al_pcie_local_cfg_space_read( + struct al_pcie_pf *pcie_pf, + unsigned int reg_offset) +{ + struct al_pcie_regs *regs = pcie_pf->pcie_port->regs; + uint32_t data; + + data = al_reg_read32(®s->core_space[pcie_pf->pf_num].config_header[reg_offset]); + + return data; +} + +/* Write data to the local configuration space */ +void +al_pcie_local_cfg_space_write( + struct al_pcie_pf *pcie_pf, + unsigned int reg_offset, + uint32_t data, + al_bool cs2, + al_bool allow_ro_wr) +{ + struct al_pcie_port *pcie_port = pcie_pf->pcie_port; + struct al_pcie_regs *regs = pcie_port->regs; + unsigned int pf_num = pcie_pf->pf_num; + uint32_t *offset = ®s->core_space[pf_num].config_header[reg_offset]; + + if (allow_ro_wr) + al_pcie_port_wr_to_ro_set(pcie_port, AL_TRUE); + + if (cs2 == AL_FALSE) + al_reg_write32(offset, data); + else + al_reg_write32_dbi_cs2(pcie_port, offset, data); + + if (allow_ro_wr) + al_pcie_port_wr_to_ro_set(pcie_port, AL_FALSE); +} + +/** set target_bus and mask_target_bus */ +int +al_pcie_target_bus_set( + struct al_pcie_port *pcie_port, + uint8_t target_bus, + uint8_t mask_target_bus) +{ + struct al_pcie_regs *regs = (struct al_pcie_regs *)pcie_port->regs; + uint32_t reg; + + reg = al_reg_read32(regs->axi.ob_ctrl.cfg_target_bus); + AL_REG_FIELD_SET(reg, PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_MASK_MASK, + PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_MASK_SHIFT, + mask_target_bus); + AL_REG_FIELD_SET(reg, PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_BUSNUM_MASK, + PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_BUSNUM_SHIFT, + target_bus); + al_reg_write32(regs->axi.ob_ctrl.cfg_target_bus, reg); + return 0; +} + +/** get target_bus and mask_target_bus */ +int +al_pcie_target_bus_get( + struct al_pcie_port *pcie_port, + uint8_t *target_bus, + uint8_t *mask_target_bus) +{ + struct al_pcie_regs *regs = (struct al_pcie_regs *)pcie_port->regs; + uint32_t reg; + + al_assert(target_bus); + al_assert(mask_target_bus); + + reg = al_reg_read32(regs->axi.ob_ctrl.cfg_target_bus); + + *mask_target_bus = AL_REG_FIELD_GET(reg, + PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_MASK_MASK, + PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_MASK_SHIFT); + *target_bus = AL_REG_FIELD_GET(reg, + PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_BUSNUM_MASK, + PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_BUSNUM_SHIFT); + return 0; +} + +/** Set secondary bus number */ +int +al_pcie_secondary_bus_set(struct al_pcie_port *pcie_port, uint8_t secbus) +{ + struct al_pcie_regs *regs = pcie_port->regs; + + uint32_t secbus_val = (secbus << + PCIE_AXI_MISC_OB_CTRL_CFG_CONTROL_SEC_BUS_SHIFT); + + al_reg_write32_masked( + regs->axi.ob_ctrl.cfg_control, + PCIE_AXI_MISC_OB_CTRL_CFG_CONTROL_SEC_BUS_MASK, + secbus_val); + return 0; +} + +/** Set sub-ordinary bus number */ +int +al_pcie_subordinary_bus_set(struct al_pcie_port *pcie_port, uint8_t subbus) +{ + struct al_pcie_regs *regs = pcie_port->regs; + + uint32_t subbus_val = (subbus << + PCIE_AXI_MISC_OB_CTRL_CFG_CONTROL_SUBBUS_SHIFT); + + al_reg_write32_masked( + regs->axi.ob_ctrl.cfg_control, + PCIE_AXI_MISC_OB_CTRL_CFG_CONTROL_SUBBUS_MASK, + subbus_val); + return 0; +} + +/* Enable/disable deferring incoming configuration requests */ +void +al_pcie_app_req_retry_set( + struct al_pcie_port *pcie_port, + al_bool en) +{ + struct al_pcie_regs *regs = pcie_port->regs; + uint32_t mask = (pcie_port->rev_id == AL_PCIE_REV_ID_3) ? + PCIE_W_REV3_GLOBAL_CTRL_PM_CONTROL_APP_REQ_RETRY_EN : + PCIE_W_REV1_2_GLOBAL_CTRL_PM_CONTROL_APP_REQ_RETRY_EN; + + al_reg_write32_masked(regs->app.global_ctrl.pm_control, + mask, (en == AL_TRUE) ? mask : 0); +} + +/*************** Internal Address Translation Unit (ATU) API ******************/ + +/** program internal ATU region entry */ +int +al_pcie_atu_region_set( + struct al_pcie_port *pcie_port, + struct al_pcie_atu_region *atu_region) +{ + struct al_pcie_regs *regs = pcie_port->regs; + enum al_pcie_operating_mode op_mode = al_pcie_operating_mode_get(pcie_port); + uint32_t reg = 0; + + /** + * Addressing RMN: 5384 + * + * RMN description: + * From SNPS (also included in the data book) Dynamic iATU Programming + * With AHB/AXI Bridge Module When the bridge slave interface clock + * (hresetn or slv_aclk) is asynchronous to the PCIe native core clock + * (core_clk), you must not update the iATU registers while operations + * are in progress on the AHB/AXI bridge slave interface. The iATU + * registers are in the core_clk clock domain. The register outputs are + * used in the AHB/AXI bridge slave interface clock domain. There is no + * synchronization logic between these registers and the AHB/AXI bridge + * slave interface. + * + * Software flow: + * Do not allow configuring Outbound iATU after link is started + */ + if ((atu_region->direction == AL_PCIE_ATU_DIR_OUTBOUND) + && (al_pcie_is_link_started(pcie_port))) { + if (!atu_region->enforce_ob_atu_region_set) { + al_err("PCIe %d: setting OB iATU after link is started is not allowed\n", + pcie_port->port_id); + return -EINVAL; + } else { + al_info("PCIe %d: setting OB iATU even after link is started\n", + pcie_port->port_id); + } + } + + /*TODO : add sanity check */ + AL_REG_FIELD_SET(reg, 0xF, 0, atu_region->index); + AL_REG_BIT_VAL_SET(reg, 31, atu_region->direction); + al_reg_write32(®s->port_regs->iatu.index, reg); + + al_reg_write32(®s->port_regs->iatu.lower_base_addr, + (uint32_t)(atu_region->base_addr & 0xFFFFFFFF)); + al_reg_write32(®s->port_regs->iatu.upper_base_addr, + (uint32_t)((atu_region->base_addr >> 32)& 0xFFFFFFFF)); + al_reg_write32(®s->port_regs->iatu.lower_target_addr, + (uint32_t)(atu_region->target_addr & 0xFFFFFFFF)); + al_reg_write32(®s->port_regs->iatu.upper_target_addr, + (uint32_t)((atu_region->target_addr >> 32)& 0xFFFFFFFF)); + + /* configure the limit, not needed when working in BAR match mode */ + if (atu_region->match_mode == 0) { + uint32_t limit_reg_val; + if (pcie_port->rev_id > AL_PCIE_REV_ID_0) { + uint32_t *limit_ext_reg = + (atu_region->direction == AL_PCIE_ATU_DIR_OUTBOUND) ? + ®s->app.atu.out_mask_pair[atu_region->index / 2] : + ®s->app.atu.in_mask_pair[atu_region->index / 2]; + uint32_t limit_ext_reg_mask = + (atu_region->index % 2) ? + PCIE_W_ATU_MASK_EVEN_ODD_ATU_MASK_40_32_ODD_MASK : + PCIE_W_ATU_MASK_EVEN_ODD_ATU_MASK_40_32_EVEN_MASK; + unsigned int limit_ext_reg_shift = + (atu_region->index % 2) ? + PCIE_W_ATU_MASK_EVEN_ODD_ATU_MASK_40_32_ODD_SHIFT : + PCIE_W_ATU_MASK_EVEN_ODD_ATU_MASK_40_32_EVEN_SHIFT; + uint64_t limit_sz_msk = + atu_region->limit - atu_region->base_addr; + uint32_t limit_ext_reg_val = (uint32_t)(((limit_sz_msk) >> + 32) & 0xFFFFFFFF); + + if (limit_ext_reg_val) { + limit_reg_val = (uint32_t)((limit_sz_msk) & 0xFFFFFFFF); + al_assert(limit_reg_val == 0xFFFFFFFF); + } else { + limit_reg_val = (uint32_t)(atu_region->limit & + 0xFFFFFFFF); + } + + al_reg_write32_masked( + limit_ext_reg, + limit_ext_reg_mask, + limit_ext_reg_val << limit_ext_reg_shift); + } else { + limit_reg_val = (uint32_t)(atu_region->limit & 0xFFFFFFFF); + } + + al_reg_write32(®s->port_regs->iatu.limit_addr, + limit_reg_val); + } + + reg = 0; + AL_REG_FIELD_SET(reg, 0x1F, 0, atu_region->tlp_type); + AL_REG_FIELD_SET(reg, 0x3 << 9, 9, atu_region->attr); + + + if ((pcie_port->rev_id == AL_PCIE_REV_ID_3) + && (op_mode == AL_PCIE_OPERATING_MODE_EP) + && (atu_region->function_match_bypass_mode)) { + AL_REG_FIELD_SET(reg, + PCIE_IATU_CR1_FUNC_NUM_MASK, + PCIE_IATU_CR1_FUNC_NUM_SHIFT, + atu_region->function_match_bypass_mode_number); + } + + al_reg_write32(®s->port_regs->iatu.cr1, reg); + + /* Enable/disable the region. */ + reg = 0; + AL_REG_FIELD_SET(reg, 0xFF, 0, atu_region->msg_code); + AL_REG_FIELD_SET(reg, 0x700, 8, atu_region->bar_number); + AL_REG_FIELD_SET(reg, 0x3 << 24, 24, atu_region->response); + AL_REG_BIT_VAL_SET(reg, 16, atu_region->enable_attr_match_mode == AL_TRUE); + AL_REG_BIT_VAL_SET(reg, 21, atu_region->enable_msg_match_mode == AL_TRUE); + AL_REG_BIT_VAL_SET(reg, 28, atu_region->cfg_shift_mode == AL_TRUE); + AL_REG_BIT_VAL_SET(reg, 29, atu_region->invert_matching == AL_TRUE); + if (atu_region->tlp_type == AL_PCIE_TLP_TYPE_MEM || atu_region->tlp_type == AL_PCIE_TLP_TYPE_IO) + AL_REG_BIT_VAL_SET(reg, 30, !!atu_region->match_mode); + AL_REG_BIT_VAL_SET(reg, 31, !!atu_region->enable); + + /* In outbound, enable function bypass + * In inbound, enable function match mode + * Note: this is the same bit, has different meanings in ob/ib ATUs + */ + if (op_mode == AL_PCIE_OPERATING_MODE_EP) + AL_REG_FIELD_SET(reg, + PCIE_IATU_CR2_FUNC_NUM_TRANS_BYPASS_FUNC_MATCH_ENABLE_MASK, + PCIE_IATU_CR2_FUNC_NUM_TRANS_BYPASS_FUNC_MATCH_ENABLE_SHIFT, + atu_region->function_match_bypass_mode ? 0x1 : 0x0); + + al_reg_write32(®s->port_regs->iatu.cr2, reg); + + return 0; +} + +/** obtains internal ATU region base/target addresses */ +void +al_pcie_atu_region_get_fields( + struct al_pcie_port *pcie_port, + enum al_pcie_atu_dir direction, uint8_t index, + al_bool *enable, uint64_t *base_addr, uint64_t *target_addr) +{ + struct al_pcie_regs *regs = pcie_port->regs; + uint64_t high_addr; + uint32_t reg = 0; + + AL_REG_FIELD_SET(reg, 0xF, 0, index); + AL_REG_BIT_VAL_SET(reg, 31, direction); + al_reg_write32(®s->port_regs->iatu.index, reg); + + *base_addr = al_reg_read32(®s->port_regs->iatu.lower_base_addr); + high_addr = al_reg_read32(®s->port_regs->iatu.upper_base_addr); + high_addr <<= 32; + *base_addr |= high_addr; + + *target_addr = al_reg_read32(®s->port_regs->iatu.lower_target_addr); + high_addr = al_reg_read32(®s->port_regs->iatu.upper_target_addr); + high_addr <<= 32; + *target_addr |= high_addr; + + reg = al_reg_read32(®s->port_regs->iatu.cr1); + *enable = AL_REG_BIT_GET(reg, 31) ? AL_TRUE : AL_FALSE; +} + +void +al_pcie_axi_io_config( + struct al_pcie_port *pcie_port, + al_phys_addr_t start, + al_phys_addr_t end) +{ + struct al_pcie_regs *regs = pcie_port->regs; + + al_reg_write32(regs->axi.ob_ctrl.io_start_h, + (uint32_t)((start >> 32) & 0xFFFFFFFF)); + + al_reg_write32(regs->axi.ob_ctrl.io_start_l, + (uint32_t)(start & 0xFFFFFFFF)); + + al_reg_write32(regs->axi.ob_ctrl.io_limit_h, + (uint32_t)((end >> 32) & 0xFFFFFFFF)); + + al_reg_write32(regs->axi.ob_ctrl.io_limit_l, + (uint32_t)(end & 0xFFFFFFFF)); + + al_reg_write32_masked(regs->axi.ctrl.slv_ctl, + PCIE_AXI_CTRL_SLV_CTRL_IO_BAR_EN, + PCIE_AXI_CTRL_SLV_CTRL_IO_BAR_EN); +} + +/************** Interrupt generation (Endpoint mode Only) API *****************/ + +/** generate INTx Assert/DeAssert Message */ +int +al_pcie_legacy_int_gen( + struct al_pcie_pf *pcie_pf, + al_bool assert, + enum al_pcie_legacy_int_type type) +{ + struct al_pcie_regs *regs = pcie_pf->pcie_port->regs; + unsigned int pf_num = pcie_pf->pf_num; + uint32_t reg; + + al_assert(type == AL_PCIE_LEGACY_INTA); /* only INTA supported */ + reg = al_reg_read32(regs->app.global_ctrl.events_gen[pf_num]); + AL_REG_BIT_VAL_SET(reg, 3, !!assert); + al_reg_write32(regs->app.global_ctrl.events_gen[pf_num], reg); + + return 0; +} + +/** generate MSI interrupt */ +int +al_pcie_msi_int_gen(struct al_pcie_pf *pcie_pf, uint8_t vector) +{ + struct al_pcie_regs *regs = pcie_pf->pcie_port->regs; + unsigned int pf_num = pcie_pf->pf_num; + uint32_t reg; + + /* set msi vector and clear MSI request */ + reg = al_reg_read32(regs->app.global_ctrl.events_gen[pf_num]); + AL_REG_BIT_CLEAR(reg, 4); + AL_REG_FIELD_SET(reg, + PCIE_W_GLOBAL_CTRL_EVENTS_GEN_MSI_VECTOR_MASK, + PCIE_W_GLOBAL_CTRL_EVENTS_GEN_MSI_VECTOR_SHIFT, + vector); + al_reg_write32(regs->app.global_ctrl.events_gen[pf_num], reg); + /* set MSI request */ + AL_REG_BIT_SET(reg, 4); + al_reg_write32(regs->app.global_ctrl.events_gen[pf_num], reg); + + return 0; +} + +/** configure MSIX capability */ +int +al_pcie_msix_config( + struct al_pcie_pf *pcie_pf, + struct al_pcie_msix_params *msix_params) +{ + struct al_pcie_regs *regs = pcie_pf->pcie_port->regs; + unsigned int pf_num = pcie_pf->pf_num; + uint32_t msix_reg0; + + al_pcie_port_wr_to_ro_set(pcie_pf->pcie_port, AL_TRUE); + + msix_reg0 = al_reg_read32(regs->core_space[pf_num].msix_cap_base); + + msix_reg0 &= ~(AL_PCI_MSIX_MSGCTRL_TBL_SIZE << AL_PCI_MSIX_MSGCTRL_TBL_SIZE_SHIFT); + msix_reg0 |= ((msix_params->table_size - 1) & AL_PCI_MSIX_MSGCTRL_TBL_SIZE) << + AL_PCI_MSIX_MSGCTRL_TBL_SIZE_SHIFT; + al_reg_write32(regs->core_space[pf_num].msix_cap_base, msix_reg0); + + /* Table offset & BAR */ + al_reg_write32(regs->core_space[pf_num].msix_cap_base + (AL_PCI_MSIX_TABLE >> 2), + (msix_params->table_offset & AL_PCI_MSIX_TABLE_OFFSET) | + (msix_params->table_bar & AL_PCI_MSIX_TABLE_BAR)); + /* PBA offset & BAR */ + al_reg_write32(regs->core_space[pf_num].msix_cap_base + (AL_PCI_MSIX_PBA >> 2), + (msix_params->pba_offset & AL_PCI_MSIX_PBA_OFFSET) | + (msix_params->pba_bar & AL_PCI_MSIX_PBA_BAR)); + + al_pcie_port_wr_to_ro_set(pcie_pf->pcie_port, AL_FALSE); + + return 0; +} + +/** check whether MSIX is enabled */ +al_bool +al_pcie_msix_enabled(struct al_pcie_pf *pcie_pf) +{ + struct al_pcie_regs *regs = pcie_pf->pcie_port->regs; + uint32_t msix_reg0 = al_reg_read32(regs->core_space[pcie_pf->pf_num].msix_cap_base); + + if (msix_reg0 & AL_PCI_MSIX_MSGCTRL_EN) + return AL_TRUE; + return AL_FALSE; +} + +/** check whether MSIX is masked */ +al_bool +al_pcie_msix_masked(struct al_pcie_pf *pcie_pf) +{ + struct al_pcie_regs *regs = pcie_pf->pcie_port->regs; + uint32_t msix_reg0 = al_reg_read32(regs->core_space[pcie_pf->pf_num].msix_cap_base); + + if (msix_reg0 & AL_PCI_MSIX_MSGCTRL_MASK) + return AL_TRUE; + return AL_FALSE; +} + +/******************** Advanced Error Reporting (AER) API **********************/ + +/** configure AER capability */ +int +al_pcie_aer_config( + struct al_pcie_pf *pcie_pf, + struct al_pcie_aer_params *params) +{ + struct al_pcie_regs *regs = pcie_pf->pcie_port->regs; + struct al_pcie_core_aer_regs *aer_regs = regs->core_space[pcie_pf->pf_num].aer; + uint32_t reg_val; + + reg_val = al_reg_read32(&aer_regs->header); + + if (((reg_val & PCIE_AER_CAP_ID_MASK) >> PCIE_AER_CAP_ID_SHIFT) != + PCIE_AER_CAP_ID_VAL) + return -EIO; + + if (((reg_val & PCIE_AER_CAP_VER_MASK) >> PCIE_AER_CAP_VER_SHIFT) != + PCIE_AER_CAP_VER_VAL) + return -EIO; + + al_reg_write32(&aer_regs->corr_err_mask, ~params->enabled_corr_err); + + al_reg_write32(&aer_regs->uncorr_err_mask, + (~params->enabled_uncorr_non_fatal_err) | + (~params->enabled_uncorr_fatal_err)); + + al_reg_write32(&aer_regs->uncorr_err_severity, + params->enabled_uncorr_fatal_err); + + al_reg_write32(&aer_regs->cap_and_ctrl, + (params->ecrc_gen_en ? PCIE_AER_CTRL_STAT_ECRC_GEN_EN : 0) | + (params->ecrc_chk_en ? PCIE_AER_CTRL_STAT_ECRC_CHK_EN : 0)); + + al_reg_write32_masked( + regs->core_space[pcie_pf->pf_num].pcie_dev_ctrl_status, + PCIE_PORT_DEV_CTRL_STATUS_CORR_ERR_REPORT_EN | + PCIE_PORT_DEV_CTRL_STATUS_NON_FTL_ERR_REPORT_EN | + PCIE_PORT_DEV_CTRL_STATUS_FTL_ERR_REPORT_EN | + PCIE_PORT_DEV_CTRL_STATUS_UNSUP_REQ_REPORT_EN, + (params->enabled_corr_err ? + PCIE_PORT_DEV_CTRL_STATUS_CORR_ERR_REPORT_EN : 0) | + (params->enabled_uncorr_non_fatal_err ? + PCIE_PORT_DEV_CTRL_STATUS_NON_FTL_ERR_REPORT_EN : 0) | + (params->enabled_uncorr_fatal_err ? + PCIE_PORT_DEV_CTRL_STATUS_FTL_ERR_REPORT_EN : 0) | + ((params->enabled_uncorr_non_fatal_err & + AL_PCIE_AER_UNCORR_UNSUPRT_REQ_ERR) ? + PCIE_PORT_DEV_CTRL_STATUS_UNSUP_REQ_REPORT_EN : 0) | + ((params->enabled_uncorr_fatal_err & + AL_PCIE_AER_UNCORR_UNSUPRT_REQ_ERR) ? + PCIE_PORT_DEV_CTRL_STATUS_UNSUP_REQ_REPORT_EN : 0)); + + return 0; +} + +/** AER uncorretable errors get and clear */ +unsigned int +al_pcie_aer_uncorr_get_and_clear(struct al_pcie_pf *pcie_pf) +{ + struct al_pcie_regs *regs = pcie_pf->pcie_port->regs; + struct al_pcie_core_aer_regs *aer_regs = regs->core_space[pcie_pf->pf_num].aer; + uint32_t reg_val; + + reg_val = al_reg_read32(&aer_regs->uncorr_err_stat); + al_reg_write32(&aer_regs->uncorr_err_stat, reg_val); + + return reg_val; +} + +/** AER corretable errors get and clear */ +unsigned int +al_pcie_aer_corr_get_and_clear(struct al_pcie_pf *pcie_pf) +{ + struct al_pcie_regs *regs = pcie_pf->pcie_port->regs; + struct al_pcie_core_aer_regs *aer_regs = regs->core_space[pcie_pf->pf_num].aer; + uint32_t reg_val; + + reg_val = al_reg_read32(&aer_regs->corr_err_stat); + al_reg_write32(&aer_regs->corr_err_stat, reg_val); + + return reg_val; +} + +#if (AL_PCIE_AER_ERR_TLP_HDR_NUM_DWORDS != 4) +#error Wrong assumption! +#endif + +/** AER get the header for the TLP corresponding to a detected error */ +void +al_pcie_aer_err_tlp_hdr_get( + struct al_pcie_pf *pcie_pf, + uint32_t hdr[AL_PCIE_AER_ERR_TLP_HDR_NUM_DWORDS]) +{ + struct al_pcie_regs *regs = pcie_pf->pcie_port->regs; + struct al_pcie_core_aer_regs *aer_regs = regs->core_space[pcie_pf->pf_num].aer; + int i; + + for (i = 0; i < AL_PCIE_AER_ERR_TLP_HDR_NUM_DWORDS; i++) + hdr[i] = al_reg_read32(&aer_regs->header_log[i]); +} + +/********************** Loopback mode (RC and Endpoint modes) ************/ + +/** enter local pipe loopback mode */ +int +al_pcie_local_pipe_loopback_enter(struct al_pcie_port *pcie_port) +{ + struct al_pcie_regs *regs = pcie_port->regs; + + al_dbg("PCIe %d: Enter LOCAL PIPE Loopback mode", pcie_port->port_id); + + al_reg_write32_masked(®s->port_regs->pipe_loopback_ctrl, + 1 << PCIE_PORT_PIPE_LOOPBACK_CTRL_PIPE_LB_EN_SHIFT, + 1 << PCIE_PORT_PIPE_LOOPBACK_CTRL_PIPE_LB_EN_SHIFT); + + al_reg_write32_masked(®s->port_regs->port_link_ctrl, + 1 << PCIE_PORT_LINK_CTRL_LB_EN_SHIFT, + 1 << PCIE_PORT_LINK_CTRL_LB_EN_SHIFT); + + return 0; +} + +/** + * @brief exit local pipe loopback mode + * + * @param pcie_port pcie port handle + * @return 0 if no error found + */ +int +al_pcie_local_pipe_loopback_exit(struct al_pcie_port *pcie_port) +{ + struct al_pcie_regs *regs = pcie_port->regs; + + al_dbg("PCIe %d: Exit LOCAL PIPE Loopback mode", pcie_port->port_id); + + al_reg_write32_masked(®s->port_regs->pipe_loopback_ctrl, + 1 << PCIE_PORT_PIPE_LOOPBACK_CTRL_PIPE_LB_EN_SHIFT, + 0); + + al_reg_write32_masked(®s->port_regs->port_link_ctrl, + 1 << PCIE_PORT_LINK_CTRL_LB_EN_SHIFT, + 0); + return 0; +} + +/** enter remote loopback mode */ +int +al_pcie_remote_loopback_enter(struct al_pcie_port *pcie_port) +{ + struct al_pcie_regs *regs = pcie_port->regs; + + al_dbg("PCIe %d: Enter REMOTE Loopback mode", pcie_port->port_id); + + al_reg_write32_masked(®s->port_regs->port_link_ctrl, + 1 << PCIE_PORT_PIPE_LOOPBACK_CTRL_PIPE_LB_EN_SHIFT, + 1 << PCIE_PORT_PIPE_LOOPBACK_CTRL_PIPE_LB_EN_SHIFT); + + return 0; +} + +/** + * @brief exit remote loopback mode + * + * @param pcie_port pcie port handle + * @return 0 if no error found + */ +int +al_pcie_remote_loopback_exit(struct al_pcie_port *pcie_port) +{ + struct al_pcie_regs *regs = pcie_port->regs; + + al_dbg("PCIe %d: Exit REMOTE Loopback mode", pcie_port->port_id); + + al_reg_write32_masked(®s->port_regs->port_link_ctrl, + 1 << PCIE_PORT_LINK_CTRL_LB_EN_SHIFT, + 0); + return 0; +} Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie.h =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie.h (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie.h (revision 283031) @@ -0,0 +1,1157 @@ +/*- +******************************************************************************** +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/** + * @defgroup grouppcie PCI Express Controller + * @{ + * @section overview Overview + * This header file provide API for the HAL driver of the pcie port, the driver + * provides the following functionalities: + * - Port initialization + * - Link operation + * - Interrupts transactions generation (Endpoint mode). + * - Configuration Access management functions + * - Internal Translation Unit programming + * + * This API does not provide the following: + * - PCIe transactions generation and reception (except interrupts as mentioned + * above) as this functionality is done by the port without need for sw + * intervention. + * - Configuration Access: those transactions are generated automatically by + * the port (ECAM or ATU mode) when the CPU issues memory transaction + * through the fabric toward the PCIe port. This API provides management + * function for controlling the Configuration Access type and bus destination + * - Interrupt Handling. + * - Message Generation: common used messages are automatically generated, also, + * the ATU generic mechanism for generating various kind of messages. + * - PCIe Port Management: both link and port power management features can be + * managed using the PCI/PCIe standard power management and PCIe capabilities + * registers. + * - PCIe link and protocol error handling: the feature can be managed using + * the Advanced Error Handling PCIe capability registers. + * + * @section flows Software Flows + * @subsection init Initialization + * - allocation and set zeros al_pcie_port and al_pcie_pf structures handles + * - call al_pcie_port_handle_init() with pointer to the allocated + * al_pcie_port handle, address of the port internal registers space, and + * port id. + * - call al_pcie_pf_handle_init() with pointer to the al_pcie_port handle + * and pf_number. + * - set the port mode, End-Point or Root-Compex (default). + * - set number of lanes connected to the controller. + * - enable the controller using the al_pcie_port_enable(). note that this + * function expect the virtual address of the PBS Functional Registers. + * - wait for 2000 South-bridge cycles. + * - prepare al_pcie_port_config_params and al_pcie_pf_config_params + * structures depending on chip, board and system configuration. + * for example, when using the port as root complex, the operating_mode + * field should be set to AL_PCIE_OPERATING_MODE_RC. In this example we + * prepare the following configuration: + * For port configuration + * - Root Complex mode + * - Set the Max Link Speed to Gen2 + * - Set the max lanes width to 2 (x2) + * - Disable reversal mode + * - Enable Snoops to support I/O Hardware cache coherency + * - Enable pcie core RAM parity + * - Enable pcie core AXI parity + * - Keep transaction layer default credits + * For pf configuration + * - No EP parameters + * - No SR-IOV parameters + * so the structures we prepare: + * @code + * - struct al_pcie_link_params link_params = { + * AL_PCIE_LINK_SPEED_GEN2, + * AL_FALSE, // disable reversal mode + * AL_PCIE_MPS_DEFAULT}; + * + * - struct al_pcie_port_config_params config_params = { + * &link_params, + * AL_TRUE, // enable Snoop for inbound memory transactions + * AL_TRUE, // enable pcie port RAM parity + * AL_TRUE, // enable pcie port AXI parity + * NULL, // use default latency/replay timers + * NULL, // use default gen2 pipe params + * NULL, // gen3_params not needed when max speed set to Gen2 + * NULL, // don't change TL credits + * NULL, // end point params not needed + * AL_FALSE, //no fast link + * AL_FALSE}; //return 0xFFFFFFFF for read transactions with + * //pci target error + * @endcode + * - now call al_pcie_port_config() with pcie_port and port_config_params + * @subsection link-init Link Initialization + * - once the port configured, we can start PCIe link: + * - call al_pcie_link_start() + * - call al_pcie_link_up_wait() + * - allocate al_pcie_link_status struct and call al_pcie_link_status() and + * check the link is established. + * + * @subsection cap Configuration Access Preparation + * - Once the link is established, we can prepare the port for pci + * configuration access, this stage requires system knowledge about the PCI + * buses enumeration. For example, if 5 buses were discovered on previously + * scanned root complex port, then we should start enumeration from bus 5 (PCI + * secondary bus), the sub-ordinary bus will be temporarily set to maximum + * value (255) until the scan process under this bus is finished, then it will + * updated to the maximum bus value found. So we use the following sequence: + * - call al_pcie_secondary_bus_set() with sec-bus = 5 + * - call al_pcie_subordinary_bus_set() with sub-bus = 255 + * + * @subsection cfg Configuration (Cfg) Access Generation + * - we assume using ECAM method, in this method, the software issues pcie Cfg + * access by accessing the ECAM memory space of the pcie port. For example, to + * issue 4 byte Cfg Read from bus B, Device D, Function F and register R, the + * software issues 4 byte read access to the following physical address + * ECAM base address of the port + (B << 20) + (D << 15) + (F << 12) + R. + * But, as the default size of the ECAM address space is less than + * needed full range (256MB), we modify the target_bus value prior to Cfg + * access in order make the port generate Cfg access with bus value set to the + * value of the target_bus rather than bits 27:20 of the physical address. + * - call al_pcie_target_bus_set() with target_bus set to the required bus of + * the next Cfg access to be issued, mask_target_bus will be set to 0xff. + * no need to call that function if the next Cfg access bus equals to the last + * value set to target_bus. + * + * @file al_hal_pcie.h + * @brief HAL Driver Header for the Annapurna Labs PCI Express port. + */ + +#ifndef _AL_HAL_PCIE_H_ +#define _AL_HAL_PCIE_H_ + +#include "al_hal_common.h" +#include "al_hal_pcie_regs.h" + +/******************************************************************************/ +/********************************* Constants **********************************/ +/******************************************************************************/ + +/** Inbound header credits sum - rev 0/1/2 */ +#define AL_PCIE_REV_1_2_IB_HCRD_SUM 97 +/** Inbound header credits sum - rev 3 */ +#define AL_PCIE_REV3_IB_HCRD_SUM 259 + +/** Number of extended registers */ +#define AL_PCIE_EX_REGS_NUM 40 + +/******************************************************************************* + * PCIe AER uncorrectable error bits + * To be used with the following functions: + * - al_pcie_aer_config + * - al_pcie_aer_uncorr_get_and_clear + ******************************************************************************/ +/** Data Link Protocol Error */ +#define AL_PCIE_AER_UNCORR_DLP_ERR AL_BIT(4) +/** Poisoned TLP */ +#define AL_PCIE_AER_UNCORR_POISIONED_TLP AL_BIT(12) +/** Flow Control Protocol Error */ +#define AL_PCIE_AER_UNCORR_FLOW_CTRL_ERR AL_BIT(13) +/** Completion Timeout */ +#define AL_PCIE_AER_UNCORR_COMPL_TO AL_BIT(14) +/** Completer Abort */ +#define AL_PCIE_AER_UNCORR_COMPL_ABT AL_BIT(15) +/** Unexpected Completion */ +#define AL_PCIE_AER_UNCORR_UNEXPCTED_COMPL AL_BIT(16) +/** Receiver Overflow */ +#define AL_PCIE_AER_UNCORR_RCV_OVRFLW AL_BIT(17) +/** Malformed TLP */ +#define AL_PCIE_AER_UNCORR_MLFRM_TLP AL_BIT(18) +/** ECRC Error */ +#define AL_PCIE_AER_UNCORR_ECRC_ERR AL_BIT(19) +/** Unsupported Request Error */ +#define AL_PCIE_AER_UNCORR_UNSUPRT_REQ_ERR AL_BIT(20) +/** Uncorrectable Internal Error */ +#define AL_PCIE_AER_UNCORR_INT_ERR AL_BIT(22) +/** AtomicOp Egress Blocked */ +#define AL_PCIE_AER_UNCORR_ATOMIC_EGRESS_BLK AL_BIT(24) + +/******************************************************************************* + * PCIe AER correctable error bits + * To be used with the following functions: + * - al_pcie_aer_config + * - al_pcie_aer_corr_get_and_clear + ******************************************************************************/ +/** Receiver Error */ +#define AL_PCIE_AER_CORR_RCV_ERR AL_BIT(0) +/** Bad TLP */ +#define AL_PCIE_AER_CORR_BAD_TLP AL_BIT(6) +/** Bad DLLP */ +#define AL_PCIE_AER_CORR_BAD_DLLP AL_BIT(7) +/** REPLAY_NUM Rollover */ +#define AL_PCIE_AER_CORR_RPLY_NUM_ROLL_OVR AL_BIT(8) +/** Replay Timer Timeout */ +#define AL_PCIE_AER_CORR_RPLY_TMR_TO AL_BIT(12) +/** Advisory Non-Fatal Error */ +#define AL_PCIE_AER_CORR_ADVISORY_NON_FTL_ERR AL_BIT(13) +/** Corrected Internal Error */ +#define AL_PCIE_AER_CORR_INT_ERR AL_BIT(14) + +/** The AER erroneous TLP header length [num DWORDs] */ +#define AL_PCIE_AER_ERR_TLP_HDR_NUM_DWORDS 4 + +/******************************************************************************/ +/************************* Data Structures and Types **************************/ +/******************************************************************************/ + +/** + * al_pcie_ib_hcrd_config: data structure internally used in order to config + * inbound posted/non-posted parameters. + * Note: it's required to have this structure in pcie_port handle since it has + * a state (required/not-required) which is determined by outbound + * outstanding configuration + */ +struct al_pcie_ib_hcrd_config { + /* Internally used - see 'al_pcie_ib_hcrd_os_ob_reads_config' */ + unsigned int nof_np_hdr; + + /* Internally used - see 'al_pcie_ib_hcrd_os_ob_reads_config' */ + unsigned int nof_p_hdr; +}; + +/* The Max Payload Size. Measured in bytes. + * DEFAULT: do not change the current MPS + */ +enum al_pcie_max_payload_size { + AL_PCIE_MPS_DEFAULT, + AL_PCIE_MPS_128 = 0, + AL_PCIE_MPS_256 = 1, + AL_PCIE_MPS_512 = 2, + AL_PCIE_MPS_1024 = 3, + AL_PCIE_MPS_2048 = 4, + AL_PCIE_MPS_4096 = 5, +}; + +/** + * al_pcie_port: data structure used by the HAL to handle a specific pcie port. + * this structure is allocated and set to zeros by the upper layer, then it is + * initialized by the al_pcie_port_handle_init() that should be called before any + * other function of this API. later, this handle passed to the API functions. + */ +struct al_pcie_port { + void __iomem *pcie_reg_base; + struct al_pcie_regs regs_ptrs; + struct al_pcie_regs *regs; + uint32_t *ex_regs_ptrs[AL_PCIE_EX_REGS_NUM]; + void *ex_regs; + void __iomem *pbs_regs; + + /* Revision ID */ + uint8_t rev_id; + unsigned int port_id; + uint8_t max_lanes; + uint8_t max_num_of_pfs; + + /* Internally used */ + struct al_pcie_ib_hcrd_config ib_hcrd_config; +}; + +/** + * al_pcie_pf: the pf handle, a data structure used to handle PF specific + * functionality. Initialized using "al_pcie_pf_handle_init()" + */ +struct al_pcie_pf { + unsigned int pf_num; + struct al_pcie_port *pcie_port; +}; + +/** Operating mode (endpoint, root complex) */ +enum al_pcie_operating_mode { + AL_PCIE_OPERATING_MODE_EP, + AL_PCIE_OPERATING_MODE_RC, + AL_PCIE_OPERATING_MODE_UNKNOWN +}; + +/* The maximum link speed, measured GT/s (Giga transfer / second) + * DEFAULT: do not change the current speed + * GEN1: 2.5 GT/s + * GEN2: 5 GT/s + * GEN3: 8GT/s + * + * Note: The values of this enumerator are important for proper behavior + */ +enum al_pcie_link_speed { + AL_PCIE_LINK_SPEED_DEFAULT, + AL_PCIE_LINK_SPEED_GEN1 = 1, + AL_PCIE_LINK_SPEED_GEN2 = 2, + AL_PCIE_LINK_SPEED_GEN3 = 3 +}; + +/** PCIe capabilities that supported by a specific port */ +struct al_pcie_max_capability { + al_bool end_point_mode_supported; + al_bool root_complex_mode_supported; + enum al_pcie_link_speed max_speed; + uint8_t max_lanes; + al_bool reversal_supported; + uint8_t atu_regions_num; + uint32_t atu_min_size; +}; + +/** PCIe link related parameters */ +struct al_pcie_link_params { + enum al_pcie_link_speed max_speed; + al_bool enable_reversal; + enum al_pcie_max_payload_size max_payload_size; + +}; + +/** PCIe gen2 link parameters */ +struct al_pcie_gen2_params { + al_bool tx_swing_low; /* set tx swing low when true, and tx swing full when false */ + al_bool tx_compliance_receive_enable; + al_bool set_deemphasis; +}; + +/** PCIe gen 3 standard per lane equalization parameters */ +struct al_pcie_gen3_lane_eq_params { + uint8_t downstream_port_transmitter_preset; + uint8_t downstream_port_receiver_preset_hint; + uint8_t upstream_port_transmitter_preset; + uint8_t upstream_port_receiver_preset_hint; +}; + +/** PCIe gen 3 equalization parameters */ +struct al_pcie_gen3_params { + al_bool perform_eq; + al_bool interrupt_enable_on_link_eq_request; + struct al_pcie_gen3_lane_eq_params *eq_params; /* array of lanes params */ + int eq_params_elements; /* number of elements in the eq_params array */ + + al_bool eq_disable; /* disables the equalization feature */ + al_bool eq_phase2_3_disable; /* Equalization Phase 2 and Phase 3 */ + /* Disable (RC mode only) */ + uint8_t local_lf; /* Full Swing (FS) Value for Gen3 Transmit Equalization */ + /* Value Range: 12 through 63 (decimal).*/ + + uint8_t local_fs; /* Low Frequency (LF) Value for Gen3 Transmit Equalization */ +}; + +/** Transport Layer credits parameters */ +struct al_pcie_tl_credits_params { +}; + +/** Various configuration features */ +struct al_pcie_features { + /** + * Enable MSI fix from the SATA to the PCIe EP + * Only valid for port 0, when enabled as EP + */ + al_bool sata_ep_msi_fix; +}; + +/** + * Inbound posted/non-posted header credits and outstanding outbound reads + * completion header configuration + * + * Constraints: + * - nof_cpl_hdr + nof_np_hdr + nof_p_hdr == + * AL_PCIE_REV_1_2_IB_HCRD_SUM/AL_PCIE_REV3_IB_HCRD_SUM + * - nof_cpl_hdr > 0 + * - nof_p_hdr > 0 + * - nof_np_hdr > 0 + */ +struct al_pcie_ib_hcrd_os_ob_reads_config { + /** Max number of outstanding outbound reads */ + uint8_t nof_outstanding_ob_reads; + + /** + * This value set the possible outstanding headers CMPLs , the core + * can get (the core always advertise infinite credits for CMPLs). + */ + unsigned int nof_cpl_hdr; + + /** + * This value set the possible outstanding headers reads (non-posted + * transactions), the core can get (it set the value in the init FC + * process). + */ + unsigned int nof_np_hdr; + + /** + * This value set the possible outstanding headers writes (posted + * transactions), the core can get (it set the value in the init FC + * process). + */ + unsigned int nof_p_hdr; +}; + +/** PCIe Ack/Nak Latency and Replay timers */ +struct al_pcie_latency_replay_timers { + uint16_t round_trip_lat_limit; + uint16_t replay_timer_limit; +}; + +/* SRIS KP counter values */ +struct al_pcie_sris_params { + /** set to AL_TRUE to use defaults and ignore the other parameters */ + al_bool use_defaults; + uint16_t kp_counter_gen3; /* only for Gen3 */ + uint16_t kp_counter_gen21; +}; + +/** Relaxed ordering params */ +struct al_pcie_relaxed_ordering_params { + al_bool enable_tx_relaxed_ordering; + al_bool enable_rx_relaxed_ordering; +}; + +/** PCIe port configuration parameters + * This structure includes the parameters that the HAL should apply to the port + * (by al_pcie_port_config()). + * The fields that are pointers (e.g. link_params) can be set to NULL, in that + * case, the al_pcie_port_config() will keep the current HW settings. + */ +struct al_pcie_port_config_params { + struct al_pcie_link_params *link_params; + al_bool enable_axi_snoop; + al_bool enable_ram_parity_int; + al_bool enable_axi_parity_int; + struct al_pcie_latency_replay_timers *lat_rply_timers; + struct al_pcie_gen2_params *gen2_params; + struct al_pcie_gen3_params *gen3_params; + struct al_pcie_tl_credits_params *tl_credits; + struct al_pcie_features *features; + /* Sets all internal timers to Fast Mode for speeding up simulation.*/ + al_bool fast_link_mode; + /* + * when true, the PCI unit will return Slave Error/Decoding Error to the master unit in case + * of error. when false, the value 0xFFFFFFFF will be returned without error indication. + */ + al_bool enable_axi_slave_err_resp; + struct al_pcie_sris_params *sris_params; + struct al_pcie_relaxed_ordering_params *relaxed_ordering_params; +}; + +/** BAR register configuration parameters (Endpoint Mode only) */ +struct al_pcie_ep_bar_params { + al_bool enable; + al_bool memory_space; /**< memory or io */ + al_bool memory_64_bit; /**< is memory space is 64 bit */ + al_bool memory_is_prefetchable; + uint64_t size; /* the bar size in bytes */ +}; + +/** PF config params (EP mode only) */ +struct al_pcie_pf_config_params { + al_bool cap_d1_d3hot_dis; + al_bool cap_flr_dis; + al_bool cap_aspm_dis; + al_bool bar_params_valid; + struct al_pcie_ep_bar_params bar_params[6]; + struct al_pcie_ep_bar_params exp_bar_params;/* expansion ROM BAR*/ +}; + +/** PCIe link status */ +struct al_pcie_link_status { + al_bool link_up; + enum al_pcie_link_speed speed; + uint8_t lanes; + uint8_t ltssm_state; +}; + +/** PCIe lane status */ +struct al_pcie_lane_status { + al_bool is_reset; + enum al_pcie_link_speed requested_speed; +}; + +/** PCIe MSIX capability configuration parameters */ +struct al_pcie_msix_params { + uint16_t table_size; + uint16_t table_offset; + uint8_t table_bar; + uint16_t pba_offset; + uint16_t pba_bar; +}; + +/** PCIE AER capability parameters */ +struct al_pcie_aer_params { + /** ECRC Generation Enable */ + al_bool ecrc_gen_en; + /** ECRC Check Enable */ + al_bool ecrc_chk_en; + + /** + * Enabled reporting of correctable errors (bit mask) + * See 'AL_PCIE_AER_CORR_*' for details + * 0 - no reporting at all + */ + unsigned int enabled_corr_err; + /** + * Enabled reporting of non-fatal uncorrectable errors (bit mask) + * See 'AL_PCIE_AER_UNCORR_*' for details + * 0 - no reporting at all + */ + unsigned int enabled_uncorr_non_fatal_err; + /** + * Enabled reporting of fatal uncorrectable errors (bit mask) + * See 'AL_PCIE_AER_UNCORR_*' for details + * 0 - no reporting at all + */ + unsigned int enabled_uncorr_fatal_err; +}; + +/******************************************************************************/ +/********************************** PCIe API **********************************/ +/******************************************************************************/ + +/*************************** PCIe Initialization API **************************/ + +/** + * Initializes a PCIe port handle structure. + * + * @param pcie_port an allocated, non-initialized instance. + * @param pcie_reg_base the virtual base address of the port internal + * registers + * @param pbs_reg_base the virtual base address of the pbs functional + * registers + * @param port_id the port id (used mainly for debug messages) + * + * @return 0 if no error found. + */ +int al_pcie_port_handle_init(struct al_pcie_port *pcie_port, + void __iomem *pcie_reg_base, + void __iomem *pbs_reg_base, + unsigned int port_id); + +/** + * Initializes a PCIe pf handle structure + * @param pcie_pf an allocated, non-initialized instance of pf handle + * @param pcie_port pcie port handle + * @param pf_num physical function number + * @return 0 if no error found + */ +int al_pcie_pf_handle_init( + struct al_pcie_pf *pcie_pf, + struct al_pcie_port *pcie_port, + unsigned int pf_num); + +/************************** Pre PCIe Port Enable API **************************/ + +/** + * @brief set current pcie operating mode (root complex or endpoint) + * This function can be called only before enabling the controller using + * al_pcie_port_enable(). + * + * @param pcie_port pcie port handle + * @param mode pcie operating mode + * + * @return 0 if no error found. + */ +int al_pcie_port_operating_mode_config(struct al_pcie_port *pcie_port, + enum al_pcie_operating_mode mode); + +/** + * Configure number of lanes connected to this port. + * This function can be called only before enabling the controller using al_pcie_port_enable(). + * + * @param pcie_port pcie port handle + * @param lanes number of lanes + * Note: this function must be called before any al_pcie_port_config() calls + * + * @return 0 if no error found. + */ +int al_pcie_port_max_lanes_set(struct al_pcie_port *pcie_port, uint8_t lanes); + +/** + * Set maximum physical function numbers + * @param pcie_port pcie port handle + * @param max_num_of_pfs number of physical functions + * Note: this function must be called before any al_pcie_pf_config() calls + */ +int al_pcie_port_max_num_of_pfs_set( + struct al_pcie_port *pcie_port, + uint8_t max_num_of_pfs); + +/** + * @brief Inbound posted/non-posted header credits and outstanding outbound + * reads completion header configuration + * + * @param pcie_port pcie port handle + * @param ib_hcrd_os_ob_reads_config + * Inbound header credits and outstanding outbound reads + * configuration + */ +int al_pcie_port_ib_hcrd_os_ob_reads_config( + struct al_pcie_port *pcie_port, + struct al_pcie_ib_hcrd_os_ob_reads_config *ib_hcrd_os_ob_reads_config); + +/** return PCIe operating mode + * @param pcie_port pcie port handle + * @return operating mode + */ +enum al_pcie_operating_mode al_pcie_operating_mode_get( + struct al_pcie_port *pcie_port); + +/**************************** PCIe Port Enable API ****************************/ + +/** Enable PCIe unit (deassert reset) + * + * @param pcie_port pcie port handle + * + * @return 0 if no error found. + */ +int al_pcie_port_enable(struct al_pcie_port *pcie_port); + +/** Disable PCIe unit (assert reset) + * + * @param pcie_port pcie port handle + */ +void al_pcie_port_disable(struct al_pcie_port *pcie_port); + +/** + * Port memory shutdown/up + * Caution: This function can be called only when the controller is disabled + * + * @param pcie_port pcie port handle + * @param enable memory shutdown enable or disable + * + */ +int al_pcie_port_memory_shutdown_set( + struct al_pcie_port *pcie_port, + al_bool enable); + +/** + * Check if port enabled or not + * @param pcie_port pcie port handle + * @return AL_TRUE of port enabled and AL_FALSE otherwise + */ +al_bool al_pcie_port_is_enabled(struct al_pcie_port *pcie_port); + +/*************************** PCIe Configuration API ***************************/ + +/** + * @brief configure pcie port (mode, link params, etc..) + * this function must be called before initializing the link + * + * @param pcie_port pcie port handle + * @param params configuration structure. + * + * @return 0 if no error found + */ +int al_pcie_port_config(struct al_pcie_port *pcie_port, + const struct al_pcie_port_config_params *params); + +/** + * @brief Configure a specific PF (EP params, sriov params, ...) + * this function must be called before any datapath transactions + * + * @param pcie_pf pcie pf handle + * @param params configuration structure. + * + * @return 0 if no error found + */ +int al_pcie_pf_config( + struct al_pcie_pf *pcie_pf, + const struct al_pcie_pf_config_params *params); + +/************************** PCIe Link Operations API **************************/ + +/** + * @brief start pcie link + * + * @param pcie_port pcie port handle + * + * @return 0 if no error found + */ +int al_pcie_link_start(struct al_pcie_port *pcie_port); + +/** + * @brief stop pcie link + * + * @param pcie_port pcie port handle + * + * @return 0 if no error found + */ +int al_pcie_link_stop(struct al_pcie_port *pcie_port); + +/** + * @brief trigger link-disable + * + * @param pcie_port pcie port handle + * @param disable AL_TRUE to disable the link and AL_FALSE to enable it + * + * Note: this functionality differs from "al_pcie_link_stop" as it's a spec + * functionality where both sides of the PCIe agrees to disable the link + * @return 0 if no error found + */ +int al_pcie_link_disable(struct al_pcie_port *pcie_port, al_bool disable); + +/** + * @brief wait for link up indication + * this function waits for link up indication, it polls LTSSM state until link is ready + * + * @param pcie_port pcie port handle + * @param timeout_ms maximum timeout in milli-seconds to wait for link up + * + * @return 0 if link up indication detected + * -ETIME if not. + */ +int al_pcie_link_up_wait(struct al_pcie_port *pcie_port, uint32_t timeout_ms); + +/** + * @brief get link status + * + * @param pcie_port pcie port handle + * @param status structure for link status + * + * @return 0 if no error found + */ +int al_pcie_link_status(struct al_pcie_port *pcie_port, struct al_pcie_link_status *status); + +/** + * @brief get lane status + * + * @param pcie_port + * pcie port handle + * @param lane + * PCIe lane + * @param status + * Pointer to returned structure for lane status + * + */ +void al_pcie_lane_status_get( + struct al_pcie_port *pcie_port, + unsigned int lane, + struct al_pcie_lane_status *status); + +/** + * @brief trigger hot reset + * + * @param pcie_port pcie port handle + * @param enable AL_TRUE to enable hot-reset and AL_FALSE to disable it + * + * @return 0 if no error found + */ +int al_pcie_link_hot_reset(struct al_pcie_port *pcie_port, al_bool enable); + +/** + * @brief trigger link-retain + * this function initiates Link retraining by directing the Physical Layer LTSSM + * to the Recovery state. If the LTSSM is already in Recovery or Configuration, + * re-entering Recovery is permitted but not required. + + * @param pcie_port pcie port handle + * + * Note: there's no need to disable initiating link-retrain + * @return 0 if no error found + */ +int al_pcie_link_retrain(struct al_pcie_port *pcie_port); + +/** + * @brief change port speed + * this function changes the port speed, it doesn't wait for link re-establishment + * + * @param pcie_port pcie port handle + * @param new_speed the new speed gen to set + * + * @return 0 if no error found + */ +int al_pcie_link_change_speed(struct al_pcie_port *pcie_port, enum al_pcie_link_speed new_speed); + +/* TODO: check if this function needed */ +int al_pcie_link_change_width(struct al_pcie_port *pcie_port, uint8_t width); + +/**************************** Post Link Start API *****************************/ + +/************************** Snoop Configuration API ***************************/ + +/** + * @brief configure pcie port axi snoop + * + * @param pcie_port pcie port handle + * @param enable_axi_snoop enable snoop. + * + * @return 0 if no error found + */ +/* TODO: Can this API be called after port enable? */ +int al_pcie_port_snoop_config(struct al_pcie_port *pcie_port, + al_bool enable_axi_snoop); + +/************************** Configuration Space API ***************************/ + +/** + * Configuration Space Access Through PCI-E_ECAM_Ext PASW (RC mode only) + */ + +/** + * @brief get base address of pci configuration space header + * @param pcie_pf pcie pf handle + * @param addr pointer for returned address; + * @return 0 if no error found + */ +int al_pcie_config_space_get( + struct al_pcie_pf *pcie_pf, + uint8_t __iomem **addr); + +/** + * Read data from the local configuration space + * + * @param pcie_pf pcie pf handle + * @param reg_offset Configuration space register offset + * @return Read data + */ +uint32_t al_pcie_local_cfg_space_read( + struct al_pcie_pf *pcie_pf, + unsigned int reg_offset); + +/** + * Write data to the local configuration space + * + * @param pcie_pf PCIe pf handle + * @param reg_offset Configuration space register offset + * @param data Data to write + * @param cs2 Should be AL_TRUE if dbi_cs2 must be asserted + * to enable writing to this register, according to + * the PCIe Core specifications + * @param allow_ro_wr AL_TRUE to allow writing into read-only regs + * + */ +void al_pcie_local_cfg_space_write( + struct al_pcie_pf *pcie_pf, + unsigned int reg_offset, + uint32_t data, + al_bool cs2, + al_bool allow_ro_wr); + +/** + * @brief set target_bus and mask_target_bus + * @param pcie_port pcie port handle + * @param target_bus + * @param mask_target_bus + * @return 0 if no error found + */ +int al_pcie_target_bus_set(struct al_pcie_port *pcie_port, + uint8_t target_bus, + uint8_t mask_target_bus); + +/** + * @brief get target_bus and mask_target_bus + * @param pcie_port pcie port handle + * @param target_bus + * @param mask_target_bus + * @return 0 if no error found + */ +int al_pcie_target_bus_get(struct al_pcie_port *pcie_port, + uint8_t *target_bus, + uint8_t *mask_target_bus); + +/** + * Set secondary bus number + * + * @param pcie_port pcie port handle + * @param secbus pci secondary bus number + * + * @return 0 if no error found. + */ +int al_pcie_secondary_bus_set(struct al_pcie_port *pcie_port, uint8_t secbus); + +/** + * Set subordinary bus number + * + * @param pcie_port pcie port handle + * @param subbus the highest bus number of all of the buses that can be reached + * downstream of the PCIE instance. + * + * @return 0 if no error found. + */ +int al_pcie_subordinary_bus_set(struct al_pcie_port *pcie_port,uint8_t subbus); + +/** + * @brief Enable/disable deferring incoming configuration requests until + * initialization is complete. When enabled, the core completes incoming + * configuration requests with a Configuration Request Retry Status. + * Other incoming Requests complete with Unsupported Request status. + * + * @param pcie_port pcie port handle + * @param en enable/disable + */ +void al_pcie_app_req_retry_set(struct al_pcie_port *pcie_port, al_bool en); + +/*************** Internal Address Translation Unit (ATU) API ******************/ + +enum al_pcie_atu_dir { + AL_PCIE_ATU_DIR_OUTBOUND = 0, + AL_PCIE_ATU_DIR_INBOUND = 1, +}; + +enum al_pcie_atu_tlp { + AL_PCIE_TLP_TYPE_MEM = 0, + AL_PCIE_TLP_TYPE_IO = 2, + AL_PCIE_TLP_TYPE_CFG0 = 4, + AL_PCIE_TLP_TYPE_CFG1 = 5, + AL_PCIE_TLP_TYPE_MSG = 0x10, + AL_PCIE_TLP_TYPE_RESERVED = 0x1f +}; + +enum al_pcie_atu_response { + AL_PCIE_RESPONSE_NORMAL = 0, + AL_PCIE_RESPONSE_UR = 1, + AL_PCIE_RESPONSE_CA = 2 +}; + +struct al_pcie_atu_region { + al_bool enable; + /* outbound or inbound */ + enum al_pcie_atu_dir direction; + /* region index */ + uint8_t index; + uint64_t base_addr; + /** limit marks the region's end address. only bits [39:0] are valid + * given the Alpine PoC maximum physical address space + */ + uint64_t limit; + /** the address that matches will be translated to this address + offset + */ + uint64_t target_addr; + al_bool invert_matching; + /* pcie tlp type*/ + enum al_pcie_atu_tlp tlp_type; + /* pcie frame header attr field*/ + uint8_t attr; + /** + * outbound specific params + */ + /* pcie message code */ + uint8_t msg_code; + al_bool cfg_shift_mode; + /** + * inbound specific params + */ + uint8_t bar_number; + /* BAR match mode, used in EP for MEM and IO tlps*/ + uint8_t match_mode; + /** + * For outbound: enables taking the function number of the translated + * TLP from the PCIe core. For inbound: enables ATU function match mode + * Note: this boolean is ignored in RC mode + */ + al_bool function_match_bypass_mode; + /** + * The function number to match/bypass (see previous parameter) + * Note: this parameter is ignored when previous param is FALSE + */ + uint8_t function_match_bypass_mode_number; + /* response code */ + enum al_pcie_atu_response response; + al_bool enable_attr_match_mode; + al_bool enable_msg_match_mode; + /** + * USE WITH CAUTION: setting this boolean to AL_TRUE allows setting the + * outbound ATU even after link is already started. DO NOT SET this + * boolean to AL_TRUE unless there have been NO traffic before calling + * al_pcie_atu_region_set function + */ + al_bool enforce_ob_atu_region_set; +}; + +/** + * @brief program internal ATU region entry + * @param pcie_port pcie port handle + * @param atu_region data structure that contains the region index and the + * translation parameters + * @return 0 if no error + */ +int al_pcie_atu_region_set( + struct al_pcie_port *pcie_port, + struct al_pcie_atu_region *atu_region); + +/** + * @brief get internal ATU is enabled and base/target addresses + * @param pcie_port pcie port handle + * @param direction input: iATU direction (IB/OB) + * @param index input: iATU index + * @param enable output: AL_TRUE if the iATU is enabled + * @param base_addr output: the iATU base address + * @param target_addr output: the iATU target address + */ +void al_pcie_atu_region_get_fields( + struct al_pcie_port *pcie_port, + enum al_pcie_atu_dir direction, uint8_t index, + al_bool *enable, uint64_t *base_addr, uint64_t *target_addr); + +/** + * @brief Configure axi io bar. + * every hit to this bar will override size to 4 bytes. + * @param pcie_port pcie port handle + * @param start the first address of the memory + * @param end the last address of the memory + * @return + */ +void al_pcie_axi_io_config( + struct al_pcie_port *pcie_port, + al_phys_addr_t start, + al_phys_addr_t end); + +/************** Interrupt generation (Endpoint mode Only) API *****************/ + +enum al_pcie_legacy_int_type{ + AL_PCIE_LEGACY_INTA = 0, + AL_PCIE_LEGACY_INTB, + AL_PCIE_LEGACY_INTC, + AL_PCIE_LEGACY_INTD +}; + +/** + * @brief generate INTx Assert/DeAssert Message + * @param pcie_pf pcie pf handle + * @param assert when true, Assert Message is sent + * @param type type of message (INTA, INTB, etc) + * @return 0 if no error found + */ +int al_pcie_legacy_int_gen( + struct al_pcie_pf *pcie_pf, + al_bool assert, + enum al_pcie_legacy_int_type type); + +/** + * @brief generate MSI interrupt + * @param pcie_pf pcie pf handle + * @param vector the vector index to send interrupt for. + * @return 0 if no error found + */ +int al_pcie_msi_int_gen(struct al_pcie_pf *pcie_pf, uint8_t vector); + +/** + * @brief configure MSIX capability + * @param pcie_pf pcie pf handle + * @param msix_params MSIX capability configuration parameters + * @return 0 if no error found + */ +int al_pcie_msix_config( + struct al_pcie_pf *pcie_pf, + struct al_pcie_msix_params *msix_params); + +/** + * @brief check whether MSIX capability is enabled + * @param pcie_pf pcie pf handle + * @return AL_TRUE if MSIX capability is enabled, AL_FALSE otherwise + */ +al_bool al_pcie_msix_enabled(struct al_pcie_pf *pcie_pf); + +/** + * @brief check whether MSIX capability is masked + * @param pcie_pf pcie pf handle + * @return AL_TRUE if MSIX capability is masked, AL_FALSE otherwise + */ +al_bool al_pcie_msix_masked(struct al_pcie_pf *pcie_pf); + +/******************** Advanced Error Reporting (AER) API **********************/ + +/** + * @brief configure AER capability + * @param pcie_pf pcie pf handle + * @param params AER capability configuration parameters + * @return 0 if no error found + */ +int al_pcie_aer_config( + struct al_pcie_pf *pcie_pf, + struct al_pcie_aer_params *params); + +/** + * @brief AER uncorretable errors get and clear + * @param pcie_pf pcie pf handle + * @return bit mask of uncorrectable errors - see 'AL_PCIE_AER_UNCORR_*' for + * details + */ +unsigned int al_pcie_aer_uncorr_get_and_clear(struct al_pcie_pf *pcie_pf); + +/** + * @brief AER corretable errors get and clear + * @param pcie_pf pcie pf handle + * @return bit mask of correctable errors - see 'AL_PCIE_AER_CORR_*' for + * details + */ +unsigned int al_pcie_aer_corr_get_and_clear(struct al_pcie_pf *pcie_pf); + +/** + * @brief AER get the header for the TLP corresponding to a detected error + * @param pcie_pf pcie pf handle + * @param hdr pointer to an array for getting the header + */ +void al_pcie_aer_err_tlp_hdr_get( + struct al_pcie_pf *pcie_pf, + uint32_t hdr[AL_PCIE_AER_ERR_TLP_HDR_NUM_DWORDS]); + +/******************** Loop-Back mode (RC and Endpoint modes) ******************/ + +/** + * @brief enter local pipe loop-back mode + * This mode will connect the pipe RX signals to TX. + * no need to start link when using this mode. + * Gen3 equalization must be disabled before enabling this mode + * The caller must make sure the port is ready to accept the TLPs it sends to + * itself. for example, BARs should be initialized before sending memory TLPs. + * + * @param pcie_port pcie port handle + * @return 0 if no error found + */ +int al_pcie_local_pipe_loopback_enter(struct al_pcie_port *pcie_port); + +/** + * @brief exit local pipe loopback mode + * + * @param pcie_port pcie port handle + * @return 0 if no error found + */ +int al_pcie_local_pipe_loopback_exit(struct al_pcie_port *pcie_port); + +/** + * @brief enter master remote loopback mode + * No need to configure the link partner to enter slave remote loopback mode + * as this should be done as response to special training sequence directives + * when master works in remote loopback mode. + * The caller must make sure the port is ready to accept the TLPs it sends to + * itself. for example, BARs should be initialized before sending memory TLPs. + * + * @param pcie_port pcie port handle + * @return 0 if no error found + */ +int al_pcie_remote_loopback_enter(struct al_pcie_port *pcie_port); + +/** + * @brief exit remote loopback mode + * + * @param pcie_port pcie port handle + * @return 0 if no error found + */ +int al_pcie_remote_loopback_exit(struct al_pcie_port *pcie_port); + +#endif +/** @} end of grouppcie group */ Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_axi_reg.h =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_axi_reg.h (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_axi_reg.h (revision 283031) @@ -0,0 +1,1501 @@ +/*- +******************************************************************************** +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __AL_PCIE_HAL_AXI_REG_H__ +#define __AL_PCIE_HAL_AXI_REG_H__ + +#include "al_hal_plat_types.h" + +#ifdef __cplusplus +extern "C" { +#endif +/* +* Unit Registers +*/ + + + +struct al_pcie_rev1_2_axi_ctrl { + /* [0x0] */ + uint32_t global; + uint32_t rsrvd_0; + /* [0x8] */ + uint32_t master_bctl; + /* [0xc] */ + uint32_t master_rctl; + /* [0x10] */ + uint32_t master_ctl; + /* [0x14] */ + uint32_t master_arctl; + /* [0x18] */ + uint32_t master_awctl; + /* [0x1c] */ + uint32_t slave_rctl; + /* [0x20] */ + uint32_t slv_wctl; + /* [0x24] */ + uint32_t slv_ctl; + /* [0x28] */ + uint32_t dbi_ctl; + /* [0x2c] */ + uint32_t vmid_mask; + uint32_t rsrvd[4]; +}; +struct al_pcie_rev3_axi_ctrl { + /* [0x0] */ + uint32_t global; + uint32_t rsrvd_0; + /* [0x8] */ + uint32_t master_bctl; + /* [0xc] */ + uint32_t master_rctl; + /* [0x10] */ + uint32_t master_ctl; + /* [0x14] */ + uint32_t master_arctl; + /* [0x18] */ + uint32_t master_awctl; + /* [0x1c] */ + uint32_t slave_rctl; + /* [0x20] */ + uint32_t slv_wctl; + /* [0x24] */ + uint32_t slv_ctl; + /* [0x28] */ + uint32_t dbi_ctl; + /* [0x2c] */ + uint32_t vmid_mask; +}; +struct al_pcie_rev1_axi_ob_ctrl { + /* [0x0] */ + uint32_t cfg_target_bus; + /* [0x4] */ + uint32_t cfg_control; + /* [0x8] */ + uint32_t io_start_l; + /* [0xc] */ + uint32_t io_start_h; + /* [0x10] */ + uint32_t io_limit_l; + /* [0x14] */ + uint32_t io_limit_h; + /* [0x18] */ + uint32_t msg_start_l; + /* [0x1c] */ + uint32_t msg_start_h; + /* [0x20] */ + uint32_t msg_limit_l; + /* [0x24] */ + uint32_t msg_limit_h; + uint32_t rsrvd[6]; +}; +struct al_pcie_rev2_axi_ob_ctrl { + /* [0x0] */ + uint32_t cfg_target_bus; + /* [0x4] */ + uint32_t cfg_control; + /* [0x8] */ + uint32_t io_start_l; + /* [0xc] */ + uint32_t io_start_h; + /* [0x10] */ + uint32_t io_limit_l; + /* [0x14] */ + uint32_t io_limit_h; + /* [0x18] */ + uint32_t msg_start_l; + /* [0x1c] */ + uint32_t msg_start_h; + /* [0x20] */ + uint32_t msg_limit_l; + /* [0x24] */ + uint32_t msg_limit_h; + /* + * [0x28] this register override the VMID field in the AXUSER [19:4], + * for the AXI master port. + */ + uint32_t vmid_reg_ovrd; + /* [0x2c] this register override the ADDR[63:32] AXI master port. */ + uint32_t addr_high_reg_ovrd_value; + /* [0x30] this register override the ADDR[63:32] AXI master port. */ + uint32_t addr_high_reg_ovrd_sel; + /* + * [0x34] Define the size to replace in the master axi address bits + * [63:32] + */ + uint32_t addr_size_replace; + uint32_t rsrvd[2]; +}; +struct al_pcie_rev3_axi_ob_ctrl { + /* [0x0] */ + uint32_t cfg_target_bus; + /* [0x4] */ + uint32_t cfg_control; + /* [0x8] */ + uint32_t io_start_l; + /* [0xc] */ + uint32_t io_start_h; + /* [0x10] */ + uint32_t io_limit_l; + /* [0x14] */ + uint32_t io_limit_h; + /* [0x18] */ + uint32_t aw_msg_start_l; + /* [0x1c] */ + uint32_t aw_msg_start_h; + /* [0x20] */ + uint32_t aw_msg_limit_l; + /* [0x24] */ + uint32_t aw_msg_limit_h; + /* [0x28] */ + uint32_t ar_msg_start_l; + /* [0x2c] */ + uint32_t ar_msg_start_h; + /* [0x30] */ + uint32_t ar_msg_limit_l; + /* [0x34] */ + uint32_t ar_msg_limit_h; + /* [0x38] */ + uint32_t io_addr_mask_h; + /* [0x3c] */ + uint32_t ar_msg_addr_mask_h; + /* [0x40] */ + uint32_t aw_msg_addr_mask_h; + /* + * [0x44] this register override the VMID field in the AXUSER [19:4], + * for the AXI master port. + */ + uint32_t vmid_reg_ovrd; + /* [0x48] this register override the ADDR[63:32] AXI master port. */ + uint32_t addr_high_reg_ovrd_value; + /* [0x4c] this register override the ADDR[63:32] AXI master port. */ + uint32_t addr_high_reg_ovrd_sel; + /* + * [0x50] Define the size to replace in the master axi address bits + * [63:32] + */ + uint32_t addr_size_replace; + uint32_t rsrvd[3]; +}; +struct al_pcie_revx_axi_msg { + /* [0x0] */ + uint32_t addr_high; + /* [0x4] */ + uint32_t addr_low; + /* [0x8] */ + uint32_t type; +}; +struct al_pcie_revx_axi_pcie_status { + /* [0x0] */ + uint32_t debug; +}; +struct al_pcie_revx_axi_rd_parity { + /* [0x0] */ + uint32_t log_high; + /* [0x4] */ + uint32_t log_low; +}; +struct al_pcie_revx_axi_rd_cmpl { + /* [0x0] */ + uint32_t cmpl_log_high; + /* [0x4] */ + uint32_t cmpl_log_low; +}; +struct al_pcie_revx_axi_rd_to { + /* [0x0] */ + uint32_t to_log_high; + /* [0x4] */ + uint32_t to_log_low; +}; +struct al_pcie_revx_axi_wr_cmpl { + /* [0x0] */ + uint32_t wr_cmpl_log_high; + /* [0x4] */ + uint32_t wr_cmpl_log_low; +}; +struct al_pcie_revx_axi_wr_to { + /* [0x0] */ + uint32_t wr_to_log_high; + /* [0x4] */ + uint32_t wr_to_log_low; +}; +struct al_pcie_revx_axi_pcie_global { + /* [0x0] */ + uint32_t conf; +}; +struct al_pcie_rev1_2_axi_status { + /* [0x0] */ + uint32_t lane0; + /* [0x4] */ + uint32_t lane1; + /* [0x8] */ + uint32_t lane2; + /* [0xc] */ + uint32_t lane3; +}; +struct al_pcie_rev3_axi_status { + /* [0x0] */ + uint32_t lane0; + /* [0x4] */ + uint32_t lane1; + /* [0x8] */ + uint32_t lane2; + /* [0xc] */ + uint32_t lane3; + /* [0x10] */ + uint32_t lane4; + /* [0x14] */ + uint32_t lane5; + /* [0x18] */ + uint32_t lane6; + /* [0x1c] */ + uint32_t lane7; + uint32_t rsrvd[8]; +}; +struct al_pcie_rev1_2_axi_conf { + /* [0x0] */ + uint32_t zero_lane0; + /* [0x4] */ + uint32_t zero_lane1; + /* [0x8] */ + uint32_t zero_lane2; + /* [0xc] */ + uint32_t zero_lane3; + /* [0x10] */ + uint32_t one_lane0; + /* [0x14] */ + uint32_t one_lane1; + /* [0x18] */ + uint32_t one_lane2; + /* [0x1c] */ + uint32_t one_lane3; +}; +struct al_pcie_rev3_axi_conf { + /* [0x0] */ + uint32_t zero_lane0; + /* [0x4] */ + uint32_t zero_lane1; + /* [0x8] */ + uint32_t zero_lane2; + /* [0xc] */ + uint32_t zero_lane3; + /* [0x10] */ + uint32_t zero_lane4; + /* [0x14] */ + uint32_t zero_lane5; + /* [0x18] */ + uint32_t zero_lane6; + /* [0x1c] */ + uint32_t zero_lane7; + /* [0x20] */ + uint32_t one_lane0; + /* [0x24] */ + uint32_t one_lane1; + /* [0x28] */ + uint32_t one_lane2; + /* [0x2c] */ + uint32_t one_lane3; + /* [0x30] */ + uint32_t one_lane4; + /* [0x34] */ + uint32_t one_lane5; + /* [0x38] */ + uint32_t one_lane6; + /* [0x3c] */ + uint32_t one_lane7; + uint32_t rsrvd[16]; +}; + +struct al_pcie_revx_axi_msg_attr_axuser_table { + /* [0x0] 4 option, the index comes from */ + uint32_t entry_vec; +}; + +struct al_pcie_revx_axi_parity { + /* [0x0] */ + uint32_t en_axi; + /* [0x4] */ + uint32_t status_axi; +}; +struct al_pcie_revx_axi_pos_logged { + /* [0x0] */ + uint32_t error_low; + /* [0x4] */ + uint32_t error_high; +}; +struct al_pcie_revx_axi_ordering { + /* [0x0] */ + uint32_t pos_cntl; +}; +struct al_pcie_revx_axi_link_down { + /* [0x0] */ + uint32_t reset_extend; +}; +struct al_pcie_revx_axi_pre_configuration { + /* [0x0] */ + uint32_t pcie_core_setup; +}; +struct al_pcie_revx_axi_init_fc { + /* + * Revision 1/2: + * [0x0] The sum of all the fields below must be 97 + * Revision 3: + * [0x0] The sum of all the fields below must be 259 + * */ + uint32_t cfg; +}; +struct al_pcie_revx_axi_int_grp_a_axi { + /* + * [0x0] Interrupt Cause Register + * Set by hardware. + * - If MSI-X is enabled, and auto_clear control bit =TRUE, + * automatically cleared after MSI-X message associated with this + * specific interrupt bit is sent (MSI-X acknowledge is received). + * - Software can set a bit in this register by writing 1 to the + * associated bit in the Interrupt Cause Set register. + * Write-0 clears a bit. Write-1 has no effect. + * - On CPU Read -- If clear_on_read control bit =TRUE, automatically + * cleared (all bits are cleared). + * When there is a conflict, and on the same clock cycle hardware tries + * to set a bit in the Interrupt Cause register, the specific bit is set + * to ensure the interrupt indication is not lost. + */ + uint32_t cause; + uint32_t rsrvd_0; + /* + * [0x8] Interrupt Cause Set Register + * Writing 1 to a bit in this register sets its corresponding cause bit, + * enabling software to generate a hardware interrupt. Write 0 has no + * effect. + */ + uint32_t cause_set; + uint32_t rsrvd_1; + /* + * [0x10] Interrupt Mask Register + * If Auto-mask control bit =TRUE, automatically set to 1 after MSI-X + * message associate to the associate interrupt bit is sent (AXI write + * acknowledge is received) + */ + uint32_t mask; + uint32_t rsrvd_2; + /* + * [0x18] Interrupt Mask Clear Register + * Used when auto-mask control bit=True. It enables the CPU to clear a + * specific bit, preventing a scenario in which the CPU overrides + * another bit with 1 (old value) that hardware has just cleared to 0. + * Writing 0 to this register clears its corresponding mask bit. Write 1 + * has no effect. + */ + uint32_t mask_clear; + uint32_t rsrvd_3; + /* + * [0x20] Interrupt Status Register + * This register latches the status of the interrupt source. + */ + uint32_t status; + uint32_t rsrvd_4; + /* [0x28] Interrupt Control Register */ + uint32_t control; + uint32_t rsrvd_5; + /* + * [0x30] Interrupt Mask Register + * Each bit in this register masks the corresponding cause bit for + * generating an Abort signal. Its default value is determined by unit + * instantiation. + * Abort = Wire-OR of Cause & !Interrupt_Abort_Mask). + * This register provides an error handling configuration for error + * interrupts. + */ + uint32_t abort_mask; + uint32_t rsrvd_6; + /* + * [0x38] Interrupt Log Register + * Each bit in this register masks the corresponding cause bit for + * capturing the log registers. Its default value is determined by unit + * instantiatio.n + * Log_capture = Wire-OR of Cause & !Interrupt_Log_Mask). + * This register provides an error handling configuration for error + * interrupts. + */ + uint32_t log_mask; + uint32_t rsrvd; +}; + +struct al_pcie_rev3_axi_eq_ovrd_tx_rx_values { + /* [0x0] */ + uint32_t cfg_0; + /* [0x4] */ + uint32_t cfg_1; + /* [0x8] */ + uint32_t cfg_2; + /* [0xc] */ + uint32_t cfg_3; + /* [0x10] */ + uint32_t cfg_4; + /* [0x14] */ + uint32_t cfg_5; + /* [0x18] */ + uint32_t cfg_6; + /* [0x1c] */ + uint32_t cfg_7; + /* [0x20] */ + uint32_t cfg_8; + /* [0x24] */ + uint32_t cfg_9; + /* [0x28] */ + uint32_t cfg_10; + /* [0x2c] */ + uint32_t cfg_11; + uint32_t rsrvd[12]; +}; +struct al_pcie_rev3_axi_dbg_outstading_trans_axi { + /* [0x0] */ + uint32_t read_master_counter; + /* [0x4] */ + uint32_t write_master_counter; + /* [0x8] */ + uint32_t read_slave_counter; +}; +struct al_pcie_revx_axi_device_id { + /* [0x0] */ + uint32_t device_rev_id; +}; +struct al_pcie_revx_axi_power_mang_ovrd_cntl { + /* [0x0] */ + uint32_t cfg_static_nof_elidle; + /* [0x4] */ + uint32_t cfg_l0s_wait_ovrd; + /* [0x8] */ + uint32_t cfg_l12_wait_ovrd; + /* [0xc] */ + uint32_t cfg_l0s_delay_in_p0s; + /* [0x10] */ + uint32_t cfg_l12_delay_in_p12; + /* [0x14] */ + uint32_t cfg_l12_delay_in_p12_clk_rst; + /* [0x18] */ + uint32_t cfg_delay_powerdown_bus; + uint32_t rsrvd; +}; +struct al_pcie_rev3_axi_dbg_outstading_trans_axi_write { + /* [0x0] */ + uint32_t slave_counter; +}; +struct al_pcie_rev3_axi_attr_ovrd { + /* + * [0x0] In case of hit on the io message bar and + * a*_cfg_outbound_msg_no_snoop_n, the message attributes come from this + * register + */ + uint32_t write_msg_ctrl_0; + /* [0x4] in case of message this register set the below attributes */ + uint32_t write_msg_ctrl_1; + /* + * [0x8] In case of hit on the io message bar and + * a*_cfg_outbound_msg_no_snoop_n, the message attributes come from this + * register + */ + uint32_t read_msg_ctrl_0; + /* [0xc] in case of message this register set the below attributes */ + uint32_t read_msg_ctrl_1; + /* [0x10] in case of message this register set the below attributes */ + uint32_t pf_sel; + uint32_t rsrvd[3]; +}; +struct al_pcie_rev3_axi_pf_axi_attr_ovrd { + /* + * [0x0] In case of hit on the io message bar and + * a*_cfg_outbound_msg_no_snoop_n, the message attributes come from this + * register + */ + uint32_t func_ctrl_0; + /* [0x4] in case of message this register set the below attributes */ + uint32_t func_ctrl_1; + /* + * [0x8] In case of hit on the io message bar and + * a*_cfg_outbound_msg_no_snoop_n, the message attributes come from this + * register + */ + uint32_t func_ctrl_2; + /* + * [0xc] In case of hit on the io message bar and + * a*_cfg_outbound_msg_no_snoop_n, the message attributes come from this + * register + */ + uint32_t func_ctrl_3; + /* + * [0x10] In case of hit on the io message bar and + * a*_cfg_outbound_msg_no_snoop_n, the message attributes come from this + * register + */ + uint32_t func_ctrl_4; + /* + * [0x14] In case of hit on the io message bar and + * a*_cfg_outbound_msg_no_snoop_n, the message attributes come from this + * register + */ + uint32_t func_ctrl_5; + /* + * [0x18] In case of hit on the io message bar and + * a*_cfg_outbound_msg_no_snoop_n, the message attributes come from this + * register + */ + uint32_t func_ctrl_6; + /* + * [0x1c] In case of hit on the io message bar and + * a*_cfg_outbound_msg_no_snoop_n, the message attributes come from this + * register + */ + uint32_t func_ctrl_7; + /* + * [0x20] In case of hit on the io message bar and + * a*_cfg_outbound_msg_no_snoop_n, the message attributes come from this + * register + */ + uint32_t func_ctrl_8; + /* + * [0x24] In case of hit on the io message bar and + * a*_cfg_outbound_msg_no_snoop_n, the message attributes come from this + * register + */ + uint32_t func_ctrl_9; + uint32_t rsrvd[6]; +}; + +struct al_pcie_revx_axi_regs { + uint32_t rsrvd_0[91]; + struct al_pcie_revx_axi_device_id device_id; /* [0x16c] */ +}; + +struct al_pcie_rev1_axi_regs { + struct al_pcie_rev1_2_axi_ctrl ctrl; /* [0x0] */ + struct al_pcie_rev1_axi_ob_ctrl ob_ctrl; /* [0x40] */ + uint32_t rsrvd_0[4]; + struct al_pcie_revx_axi_msg msg; /* [0x90] */ + struct al_pcie_revx_axi_pcie_status pcie_status; /* [0x9c] */ + struct al_pcie_revx_axi_rd_parity rd_parity; /* [0xa0] */ + struct al_pcie_revx_axi_rd_cmpl rd_cmpl; /* [0xa8] */ + struct al_pcie_revx_axi_rd_to rd_to; /* [0xb0] */ + struct al_pcie_revx_axi_wr_cmpl wr_cmpl; /* [0xb8] */ + struct al_pcie_revx_axi_wr_to wr_to; /* [0xc0] */ + struct al_pcie_revx_axi_pcie_global pcie_global; /* [0xc8] */ + struct al_pcie_rev1_2_axi_status status; /* [0xcc] */ + struct al_pcie_rev1_2_axi_conf conf; /* [0xdc] */ + struct al_pcie_revx_axi_parity parity; /* [0xfc] */ + struct al_pcie_revx_axi_pos_logged pos_logged; /* [0x104] */ + struct al_pcie_revx_axi_ordering ordering; /* [0x10c] */ + struct al_pcie_revx_axi_link_down link_down; /* [0x110] */ + struct al_pcie_revx_axi_pre_configuration pre_configuration; /* [0x114] */ + struct al_pcie_revx_axi_init_fc init_fc; /* [0x118] */ + uint32_t rsrvd_1[20]; + struct al_pcie_revx_axi_device_id device_id; /* [0x16c] */ + uint32_t rsrvd_2[36]; + struct al_pcie_revx_axi_int_grp_a_axi int_grp_a; /* [0x200] */ +}; + +struct al_pcie_rev2_axi_regs { + struct al_pcie_rev1_2_axi_ctrl ctrl; /* [0x0] */ + struct al_pcie_rev2_axi_ob_ctrl ob_ctrl; /* [0x40] */ + uint32_t rsrvd_0[4]; + struct al_pcie_revx_axi_msg msg; /* [0x90] */ + struct al_pcie_revx_axi_pcie_status pcie_status; /* [0x9c] */ + struct al_pcie_revx_axi_rd_parity rd_parity; /* [0xa0] */ + struct al_pcie_revx_axi_rd_cmpl rd_cmpl; /* [0xa8] */ + struct al_pcie_revx_axi_rd_to rd_to; /* [0xb0] */ + struct al_pcie_revx_axi_wr_cmpl wr_cmpl; /* [0xb8] */ + struct al_pcie_revx_axi_wr_to wr_to; /* [0xc0] */ + struct al_pcie_revx_axi_pcie_global pcie_global; /* [0xc8] */ + struct al_pcie_rev1_2_axi_status status; /* [0xcc] */ + struct al_pcie_rev1_2_axi_conf conf; /* [0xdc] */ + struct al_pcie_revx_axi_parity parity; /* [0xfc] */ + struct al_pcie_revx_axi_pos_logged pos_logged; /* [0x104] */ + struct al_pcie_revx_axi_ordering ordering; /* [0x10c] */ + struct al_pcie_revx_axi_link_down link_down; /* [0x110] */ + struct al_pcie_revx_axi_pre_configuration pre_configuration; /* [0x114] */ + struct al_pcie_revx_axi_init_fc init_fc; /* [0x118] */ + uint32_t rsrvd_1[20]; + struct al_pcie_revx_axi_device_id device_id; /* [0x16c] */ + uint32_t rsrvd_2[36]; + struct al_pcie_revx_axi_int_grp_a_axi int_grp_a; /* [0x200] */ +}; + +struct al_pcie_rev3_axi_regs { + struct al_pcie_rev3_axi_ctrl ctrl; /* [0x0] */ + struct al_pcie_rev3_axi_ob_ctrl ob_ctrl;/* [0x30] */ + struct al_pcie_revx_axi_msg msg; /* [0x90] */ + struct al_pcie_revx_axi_pcie_status pcie_status; /* [0x9c] */ + struct al_pcie_revx_axi_rd_parity rd_parity; /* [0xa0] */ + struct al_pcie_revx_axi_rd_cmpl rd_cmpl; /* [0xa8] */ + struct al_pcie_revx_axi_rd_to rd_to; /* [0xb0] */ + struct al_pcie_revx_axi_wr_cmpl wr_cmpl; /* [0xb8] */ + struct al_pcie_revx_axi_wr_to wr_to; /* [0xc0] */ + struct al_pcie_revx_axi_pcie_global pcie_global; /* [0xc8] */ + uint32_t rsrvd_0; + struct al_pcie_revx_axi_parity parity; /* [0xd0] */ + struct al_pcie_revx_axi_pos_logged pos_logged; /* [0xd8] */ + struct al_pcie_revx_axi_ordering ordering; /* [0xe0] */ + struct al_pcie_revx_axi_link_down link_down; /* [0xe4] */ + struct al_pcie_revx_axi_pre_configuration pre_configuration;/* [0xe8] */ + struct al_pcie_revx_axi_init_fc init_fc; /* [0xec] */ + uint32_t rsrvd_1[4]; + struct al_pcie_rev3_axi_eq_ovrd_tx_rx_values eq_ovrd_tx_rx_values;/* [0x100] */ + struct al_pcie_rev3_axi_dbg_outstading_trans_axi dbg_outstading_trans_axi;/* [0x160] */ + struct al_pcie_revx_axi_device_id device_id; /* [0x16c] */ + struct al_pcie_revx_axi_power_mang_ovrd_cntl power_mang_ovrd_cntl;/* [0x170] */ + struct al_pcie_rev3_axi_dbg_outstading_trans_axi_write dbg_outstading_trans_axi_write;/* [0x190] */ + uint32_t rsrvd_2[3]; + struct al_pcie_rev3_axi_attr_ovrd axi_attr_ovrd; /* [0x1a0] */ + struct al_pcie_rev3_axi_pf_axi_attr_ovrd pf_axi_attr_ovrd[REV3_MAX_NUM_OF_PFS];/* [0x1c0] */ + uint32_t rsrvd_3[64]; + struct al_pcie_rev3_axi_status status; /* [0x3c0] */ + struct al_pcie_rev3_axi_conf conf; /* [0x400] */ + uint32_t rsrvd_4[32]; + struct al_pcie_revx_axi_msg_attr_axuser_table msg_attr_axuser_table; /* [0x500] */ + uint32_t rsrvd_5[191]; + struct al_pcie_revx_axi_int_grp_a_axi int_grp_a; /* [0x800] */ +}; + +/* +* Registers Fields +*/ + +/**** Device ID register ****/ +#define PCIE_AXI_DEVICE_ID_REG_DEV_ID_MASK AL_FIELD_MASK(31, 16) +#define PCIE_AXI_DEVICE_ID_REG_DEV_ID_SHIFT 16 +#define PCIE_AXI_DEVICE_ID_REG_DEV_ID_X4 (0 << PCIE_AXI_DEVICE_ID_REG_DEV_ID_SHIFT) +#define PCIE_AXI_DEVICE_ID_REG_DEV_ID_X8 (2 << PCIE_AXI_DEVICE_ID_REG_DEV_ID_SHIFT) +#define PCIE_AXI_DEVICE_ID_REG_REV_ID_MASK AL_FIELD_MASK(15, 0) +#define PCIE_AXI_DEVICE_ID_REG_REV_ID_SHIFT 0 + +/**** Global register ****/ +/* + * Not in use. + * Disable completion after inbound posted ordering enforcement to AXI bridge. + */ +#define PCIE_AXI_CTRL_GLOBAL_CPL_AFTER_P_ORDER_DIS (1 << 0) +/* + * Not in use. + * Enforce completion after write ordering on AXI bridge. Only for CPU read + * requests. + */ +#define PCIE_AXI_CTRL_GLOBAL_CPU_CPL_ONLY_EN (1 << 1) +/* When linked down, map all transactions to PCIe to DEC ERR. */ +#define PCIE_AXI_CTRL_GLOBAL_BLOCK_PCIE_SLAVE_EN (1 << 2) +/* + * Wait for the NIC to flush before enabling reset to the PCIe core, on a link + * down event. + */ +#define PCIE_AXI_CTRL_GLOBAL_WAIT_SLV_FLUSH_EN (1 << 3) +/* + * When the BME is cleared and this bit is set, it causes all transactions that + * do not get to the PCIe to be returned with DECERR. + */ +#define PCIE_REV1_2_AXI_CTRL_GLOBAL_MEM_BAR_MAP_TO_ERR (1 << 4) +#define PCIE_REV3_AXI_CTRL_GLOBAL_MEM_BAR_MAP_TO_ERR_MASK 0x00000FF0 +#define PCIE_REV3_AXI_CTRL_GLOBAL_MEM_BAR_MAP_TO_ERR_SHIFT 4 +/* + * Wait for the DBI port (the port that enables access to the internal PCIe core + * registers) to flush before enabling reset to the PCIe core on link down + * event. + */ +#define PCIE_REV1_2_AXI_CTRL_GLOBAL_WAIT_DBI_FLUSH_EN (1 << 5) +#define PCIE_REV3_AXI_CTRL_GLOBAL_WAIT_DBI_FLUSH_EN (1 << 12) +/* Reserved. Read undefined; must read as zeros. */ +#define PCIE_REV3_AXI_CTRL_GLOBAL_CFG_FLUSH_DBI_AXI (1 << 13) +/* Reserved. Read undefined; must read as zeros. */ +#define PCIE_REV3_AXI_CTRL_GLOBAL_CFG_HOLD_LNKDWN_RESET_SW (1 << 14) +/* Reserved. Read undefined; must read as zeros. */ +#define PCIE_REV3_AXI_CTRL_GLOBAL_CFG_MASK_CORECLK_ACT_CLK_RST (1 << 15) +/* Reserved. Read undefined; must read as zeros. */ +#define PCIE_REV3_AXI_CTRL_GLOBAL_CFG_MASK_RXELECIDLE_CLK_RST (1 << 16) +/* Reserved. Read undefined; must read as zeros. */ +#define PCIE_REV3_AXI_CTRL_GLOBAL_CFG_ALLOW_NONSTICKY_RESET_WHEN_LNKDOWN_CLK_RST (1 << 17) + +/* + * When set, adds parity on the write and read address channels, and write data + * channel. + */ +#define PCIE_REV1_2_AXI_CTRL_GLOBAL_PARITY_CALC_EN_MSTR (1 << 16) +#define PCIE_REV3_AXI_CTRL_GLOBAL_PARITY_CALC_EN_MSTR (1 << 18) +/* When set, enables parity check on the read data. */ +#define PCIE_REV1_2_AXI_CTRL_GLOBAL_PARITY_ERR_EN_RD (1 << 17) +#define PCIE_REV3_AXI_CTRL_GLOBAL_PARITY_ERR_EN_RD (1 << 19) +/* + * When set, adds parity on the RD data channel. + */ +#define PCIE_REV1_2_AXI_CTRL_GLOBAL_PARITY_CALC_EN_SLV (1 << 18) +#define PCIE_REV3_AXI_CTRL_GLOBAL_PARITY_CALC_EN_SLV (1 << 20) +/* + * When set, enables parity check on the write data. + */ +#define PCIE_REV1_2_AXI_CTRL_GLOBAL_PARITY_ERR_EN_WR (1 << 19) +#define PCIE_REV3_AXI_CTRL_GLOBAL_PARITY_ERR_EN_WR (1 << 21) +/* + * When set, error track for timeout and parity is disabled, i.e., the logged + * address for parity/timeout/cmpl errors on the AXI master port is not valid, + * and timeout and completion errors check are disabled. + */ +#define PCIE_REV1_2_AXI_CTRL_GLOBAL_ERROR_TRACK_DIS (1 << 20) +#define PCIE_REV3_AXI_CTRL_GLOBAL_ERROR_TRACK_DIS (1 << 22) + +/**** Master_Arctl register ****/ +/* override arcache */ +#define PCIE_AXI_CTRL_MASTER_ARCTL_OVR_ARCACHE (1 << 0) +/* arache value */ +#define PCIE_AXI_CTRL_MASTER_ARCTL_ARACHE_VA_MASK 0x0000001E +#define PCIE_AXI_CTRL_MASTER_ARCTL_ARACHE_VA_SHIFT 1 +/* arprot override */ +#define PCIE_AXI_CTRL_MASTER_ARCTL_ARPROT_OVR (1 << 5) +/* arprot value */ +#define PCIE_AXI_CTRL_MASTER_ARCTL_ARPROT_VALUE_MASK 0x000001C0 +#define PCIE_AXI_CTRL_MASTER_ARCTL_ARPROT_VALUE_SHIFT 6 +/* vmid val */ +#define PCIE_AXI_CTRL_MASTER_ARCTL_VMID_VAL_MASK 0x01FFFE00 +#define PCIE_AXI_CTRL_MASTER_ARCTL_VMID_VAL_SHIFT 9 +/* IPA value */ +#define PCIE_AXI_CTRL_MASTER_ARCTL_IPA_VAL (1 << 25) +/* overide snoop inidcation, if not set take it from mstr_armisc ... */ +#define PCIE_AXI_CTRL_MASTER_ARCTL_OVR_SNOOP (1 << 26) +/* +snoop indication value when override */ +#define PCIE_AXI_CTRL_MASTER_ARCTL_SNOOP (1 << 27) +/* +arqos value */ +#define PCIE_AXI_CTRL_MASTER_ARCTL_ARQOS_MASK 0xF0000000 +#define PCIE_AXI_CTRL_MASTER_ARCTL_ARQOS_SHIFT 28 + +/**** Master_Awctl register ****/ +/* override arcache */ +#define PCIE_AXI_CTRL_MASTER_AWCTL_OVR_ARCACHE (1 << 0) +/* awache value */ +#define PCIE_AXI_CTRL_MASTER_AWCTL_AWACHE_VA_MASK 0x0000001E +#define PCIE_AXI_CTRL_MASTER_AWCTL_AWACHE_VA_SHIFT 1 +/* awprot override */ +#define PCIE_AXI_CTRL_MASTER_AWCTL_AWPROT_OVR (1 << 5) +/* awprot value */ +#define PCIE_AXI_CTRL_MASTER_AWCTL_AWPROT_VALUE_MASK 0x000001C0 +#define PCIE_AXI_CTRL_MASTER_AWCTL_AWPROT_VALUE_SHIFT 6 +/* vmid val */ +#define PCIE_AXI_CTRL_MASTER_AWCTL_VMID_VAL_MASK 0x01FFFE00 +#define PCIE_AXI_CTRL_MASTER_AWCTL_VMID_VAL_SHIFT 9 +/* IPA value */ +#define PCIE_AXI_CTRL_MASTER_AWCTL_IPA_VAL (1 << 25) +/* overide snoop inidcation, if not set take it from mstr_armisc ... */ +#define PCIE_AXI_CTRL_MASTER_AWCTL_OVR_SNOOP (1 << 26) +/* +snoop indication value when override */ +#define PCIE_AXI_CTRL_MASTER_AWCTL_SNOOP (1 << 27) +/* +awqos value */ +#define PCIE_AXI_CTRL_MASTER_AWCTL_AWQOS_MASK 0xF0000000 +#define PCIE_AXI_CTRL_MASTER_AWCTL_AWQOS_SHIFT 28 + +/**** slv_ctl register ****/ +#define PCIE_AXI_CTRL_SLV_CTRL_IO_BAR_EN (1 << 6) + +/**** Cfg_Target_Bus register ****/ +/* + * Defines which MSBs to complete the number of the bust that arrived from ECAM. + * If set to 0, take the bit from the ECAM bar, otherwise from the busnum of + * this register. + * The LSB for the bus number comes on the addr[*:20]. + */ +#define PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_MASK_MASK 0x000000FF +#define PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_MASK_SHIFT 0 +/* Target bus number for outbound configuration type0 and type1 access */ +#define PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_BUSNUM_MASK 0x0000FF00 +#define PCIE_AXI_MISC_OB_CTRL_CFG_TARGET_BUS_BUSNUM_SHIFT 8 + +/**** Cfg_Control register ****/ +/* Primary bus number */ +#define PCIE_AXI_MISC_OB_CTRL_CFG_CONTROL_PBUS_MASK 0x000000FF +#define PCIE_AXI_MISC_OB_CTRL_CFG_CONTROL_PBUS_SHIFT 0 +/* + * + * Subordinate bus number + */ +#define PCIE_AXI_MISC_OB_CTRL_CFG_CONTROL_SUBBUS_MASK 0x0000FF00 +#define PCIE_AXI_MISC_OB_CTRL_CFG_CONTROL_SUBBUS_SHIFT 8 +/* Secondary bus nnumber */ +#define PCIE_AXI_MISC_OB_CTRL_CFG_CONTROL_SEC_BUS_MASK 0x00FF0000 +#define PCIE_AXI_MISC_OB_CTRL_CFG_CONTROL_SEC_BUS_SHIFT 16 +/* Enable outbound configuration access through iATU. */ +#define PCIE_AXI_MISC_OB_CTRL_CFG_CONTROL_IATU_EN (1 << 31) + +/**** IO_Start_H register ****/ +/* + * + * Outbound ATIU I/O start address high + */ +#define PCIE_AXI_MISC_OB_CTRL_IO_START_H_ADDR_MASK 0x000003FF +#define PCIE_AXI_MISC_OB_CTRL_IO_START_H_ADDR_SHIFT 0 + +/**** IO_Limit_H register ****/ +/* + * + * Outbound ATIU I/O limit address high + */ +#define PCIE_AXI_MISC_OB_CTRL_IO_LIMIT_H_ADDR_MASK 0x000003FF +#define PCIE_AXI_MISC_OB_CTRL_IO_LIMIT_H_ADDR_SHIFT 0 + +/**** Msg_Start_H register ****/ +/* + * + * Outbound ATIU msg-no-data start address high + */ +#define PCIE_AXI_MISC_OB_CTRL_MSG_START_H_ADDR_MASK 0x000003FF +#define PCIE_AXI_MISC_OB_CTRL_MSG_START_H_ADDR_SHIFT 0 + +/**** Msg_Limit_H register ****/ +/* + * + * Outbound ATIU msg-no-data limit address high + */ +#define PCIE_AXI_MISC_OB_CTRL_MSG_LIMIT_H_ADDR_MASK 0x000003FF +#define PCIE_AXI_MISC_OB_CTRL_MSG_LIMIT_H_ADDR_SHIFT 0 + +/**** vmid_reg_ovrd register ****/ +/* + * select if to take the value from register or from address[63:48]: + * 1'b1: register value. + * 1'b0: from address[63:48] + */ +#define PCIE_AXI_MISC_OB_CTRL_VMID_REG_OVRD_SEL_MASK 0x0000FFFF +#define PCIE_AXI_MISC_OB_CTRL_VMID_REG_OVRD_SEL_SHIFT 0 +/* vmid override value. */ +#define PCIE_AXI_MISC_OB_CTRL_VMID_REG_OVRD_VALUE_MASK 0xFFFF0000 +#define PCIE_AXI_MISC_OB_CTRL_VMID_REG_OVRD_VALUE_SHIFT 16 + +/**** addr_size_replace register ****/ +/* + * Size in bits to replace from bit [63:64-N], when equal zero no replace is + * done. + */ +#define PCIE_AXI_MISC_OB_CTRL_ADDR_SIZE_REPLACE_VALUE_MASK 0x0000FFFF +#define PCIE_AXI_MISC_OB_CTRL_ADDR_SIZE_REPLACE_VALUE_SHIFT 0 +/* Reserved. */ +#define PCIE_AXI_MISC_OB_CTRL_ADDR_SIZE_REPLACE_RSRVD_MASK 0xFFFF0000 +#define PCIE_AXI_MISC_OB_CTRL_ADDR_SIZE_REPLACE_RSRVD_SHIFT 16 + +/**** type register ****/ +/* Type of message */ +#define PCIE_AXI_MISC_MSG_TYPE_TYPE_MASK 0x00FFFFFF +#define PCIE_AXI_MISC_MSG_TYPE_TYPE_SHIFT 0 +/* Reserved */ +#define PCIE_AXI_MISC_MSG_TYPE_RSRVD_MASK 0xFF000000 +#define PCIE_AXI_MISC_MSG_TYPE_RSRVD_SHIFT 24 + +/**** debug register ****/ +/* Causes ACI PCIe reset, including ,master/slave/DBI (registers). */ +#define PCIE_AXI_MISC_PCIE_STATUS_DEBUG_AXI_BRIDGE_RESET (1 << 0) +/* + * Causes reset of the entire PCIe core (including the AXI bridge). + * When set, the software must not address the PCI core (through the MEM space + * and REG space). + */ +#define PCIE_AXI_MISC_PCIE_STATUS_DEBUG_CORE_RESET (1 << 1) +/* + * Indicates that the SB is empty from the request to the PCIe (not including + * registers). + */ +#define PCIE_AXI_MISC_PCIE_STATUS_DEBUG_SB_FLUSH_OB_STATUS (1 << 2) +/* MAP and transaction to the PCIe core to ERROR. */ +#define PCIE_AXI_MISC_PCIE_STATUS_DEBUG_SB_MAP_TO_ERR (1 << 3) +/* Indicates that the pcie_core clock is gated off */ +#define PCIE_AXI_MISC_PCIE_STATUS_DEBUG_CORE_CLK_GATE_OFF (1 << 4) +/* Reserved */ +#define PCIE_AXI_MISC_PCIE_STATUS_DEBUG_RSRVD_MASK 0xFFFFFFE0 +#define PCIE_AXI_MISC_PCIE_STATUS_DEBUG_RSRVD_SHIFT 5 + +/**** conf register ****/ +/* + * Device Type + * Indicates the specific type of this PCI Express Function. It is also used to + * set the + * Device/Port Type field. + * + * 4'b0000: PCI Express Endpoint + * 4'b0001: Legacy PCI Express Endpoint + * 4'b0100: Root Port of PCI Express Root Complex + * + * Must be programmed before link training sequence, according to the reset + * strap. + * Change this register should be when the pci_exist (in the PBS regfile) is + * zero. + */ +#define PCIE_AXI_MISC_PCIE_GLOBAL_CONF_DEV_TYPE_MASK 0x0000000F +#define PCIE_AXI_MISC_PCIE_GLOBAL_CONF_DEV_TYPE_SHIFT 0 +/* + * [i] - Lane i active + * Change this register should be when the pci_exist (in the PBS regfile) is + * zero. + */ +#define PCIE_REV1_2_AXI_MISC_PCIE_GLOBAL_CONF_NOF_ACT_LANES_MASK 0x000000F0 +#define PCIE_REV1_2_AXI_MISC_PCIE_GLOBAL_CONF_RESERVED_MASK 0xFFFFFF00 +#define PCIE_REV1_2_AXI_MISC_PCIE_GLOBAL_CONF_RESERVED_SHIFT 8 +#define PCIE_REVX_AXI_MISC_PCIE_GLOBAL_CONF_NOF_ACT_LANES_SHIFT 4 +#define PCIE_REV3_AXI_MISC_PCIE_GLOBAL_CONF_NOF_ACT_LANES_MASK 0x000FFFF0 +#define PCIE_REV3_AXI_MISC_PCIE_GLOBAL_CONF_RESERVED_MASK 0xFFF00000 +#define PCIE_REV3_AXI_MISC_PCIE_GLOBAL_CONF_RESERVED_SHIFT 20 + +#define PCIE_REV1_2_AXI_MISC_PCIE_GLOBAL_CONF_MEM_SHUTDOWN 0x100 +#define PCIE_REV3_AXI_MISC_PCIE_GLOBAL_CONF_MEM_SHUTDOWN 0x100000 + +/**** laneX register ****/ +#define PCIE_AXI_STATUS_LANE_IS_RESET AL_BIT(13) +#define PCIE_AXI_STATUS_LANE_REQUESTED_SPEED_MASK AL_FIELD_MASK(2, 0) +#define PCIE_AXI_STATUS_LANE_REQUESTED_SPEED_SHIFT 0 + +/**** zero_laneX register ****/ +/* phy_mac_local_fs */ +#define PCIE_AXI_MISC_ZERO_LANEX_PHY_MAC_LOCAL_FS_MASK 0x0000003f +#define PCIE_AXI_MISC_ZERO_LANEX_PHY_MAC_LOCAL_FS_SHIFT 0 +/* phy_mac_local_lf */ +#define PCIE_AXI_MISC_ZERO_LANEX_PHY_MAC_LOCAL_LF_MASK 0x00000fc0 +#define PCIE_AXI_MISC_ZERO_LANEX_PHY_MAC_LOCAL_LF_SHIFT 6 + +/**** en_axi register ****/ +/* u4_ram2p */ +#define PCIE_AXI_PARITY_EN_AXI_U4_RAM2P AL_BIT(1) + +/**** pos_cntl register ****/ +/* Disables POS. */ +#define PCIE_AXI_POS_ORDER_AXI_POS_BYPASS (1 << 0) +/* Clear the POS data structure. */ +#define PCIE_AXI_POS_ORDER_AXI_POS_CLEAR (1 << 1) +/* Read push all write. */ +#define PCIE_AXI_POS_ORDER_AXI_POS_RSO_ENABLE (1 << 2) +/* + * Causes the PCIe core to wait for all the BRESPs before issuing a read + * request. + */ +#define PCIE_AXI_POS_ORDER_AXI_DW_RD_FLUSH_WR (1 << 3) +/* + * When set, to 1'b1 supports interleaving data return from the PCIe core. Valid + * only when cfg_bypass_cmpl_after_write_fix is set. + */ +#define PCIE_AXI_POS_ORDER_RD_CMPL_AFTER_WR_SUPPORT_RD_INTERLV (1 << 4) +/* When set, to 1'b1 disables read completion after write ordering. */ +#define PCIE_AXI_POS_ORDER_BYPASS_CMPL_AFTER_WR_FIX (1 << 5) +/* + * When set, disables EP mode read cmpl on the master port push slave writes, + * when each read response from the master is not interleaved. + */ +#define PCIE_AXI_POS_ORDER_EP_CMPL_AFTER_WR_DIS (1 << 6) +/* When set, disables EP mode read cmpl on the master port push slave writes. */ +#define PCIE_AXI_POS_ORDER_EP_CMPL_AFTER_WR_SUPPORT_INTERLV_DIS (1 << 7) +/* should be zero */ +#define PCIE_AXI_POS_ORDER_9_8 AL_FIELD_MASK(9, 8) +/* Give the segmentation buffer not to wait for P writes to end in the AXI + * bridge before releasing the CMPL. + */ +#define PCIE_AXI_POS_ORDER_SEGMENT_BUFFER_DONT_WAIT_FOR_P_WRITES AL_BIT(10) +/* should be zero */ +#define PCIE_AXI_POS_ORDER_11 AL_BIT(11) +/** + * When set cause pcie core to send ready in the middle of the read data + * burst returning from the DRAM to the PCIe core + */ +#define PCIE_AXI_POS_ORDER_SEND_READY_ON_READ_DATA_BURST AL_BIT(12) +/* When set disable the ATS CAP. */ +#define PCIE_AXI_CORE_SETUP_ATS_CAP_DIS AL_BIT(13) +/* When set disable D3/D2/D1 PME support */ +#define PCIE_AXI_POS_ORDER_DISABLE_DX_PME AL_BIT(14) +/* When set enable nonsticky reset when linkdown hot reset */ +#define PCIE_AXI_POS_ORDER_ENABLE_NONSTICKY_RESET_ON_HOT_RESET AL_BIT(15) +/* When set, terminate message with data as UR request */ +#define PCIE_AXI_TERMINATE_DATA_MSG_AS_UR_REQ AL_BIT(16) + +/**** pcie_core_setup register ****/ +/* + * This Value delay the rate change to the serdes, until the EIOS is sent by the + * serdes. Should be program before the pcie_exist, is asserted. + */ +#define PCIE_AXI_CORE_SETUP_DELAY_MAC_PHY_RATE_MASK 0x000000FF +#define PCIE_AXI_CORE_SETUP_DELAY_MAC_PHY_RATE_SHIFT 0 +/* + * Limit the number of outstanding AXI reads that the PCIe core can get. Should + * be program before the pcie_exist, is asserted. + */ +#define PCIE_AXI_CORE_SETUP_NOF_READS_ONSLAVE_INTRF_PCIE_CORE_MASK 0x0000FF00 +#define PCIE_AXI_CORE_SETUP_NOF_READS_ONSLAVE_INTRF_PCIE_CORE_SHIFT 8 +/* Enable the sriov feature. */ +#define PCIE_AXI_REV1_2_CORE_SETUP_SRIOV_ENABLE AL_BIT(16) +/* not in use */ +#define PCIE_AXI_REV3_CORE_SETUP_NOT_IN_USE (1 << 16) +/* Reserved. Read undefined; must read as zeros. */ +#define PCIE_AXI_REV3_CORE_SETUP_CFG_DELAY_AFTER_PCIE_EXIST_MASK 0x0FFE0000 +#define PCIE_AXI_REV3_CORE_SETUP_CFG_DELAY_AFTER_PCIE_EXIST_SHIFT 17 + +/**** cfg register ****/ +/* This value set the possible out standing headers writes (post ... */ +#define PCIE_AXI_REV1_2_INIT_FC_CFG_NOF_P_HDR_MASK 0x0000007F +#define PCIE_AXI_REV1_2_INIT_FC_CFG_NOF_P_HDR_SHIFT 0 +/* This value set the possible out standing headers reads (non-p ... */ +#define PCIE_AXI_REV1_2_INIT_FC_CFG_NOF_NP_HDR_MASK 0x00003F80 +#define PCIE_AXI_REV1_2_INIT_FC_CFG_NOF_NP_HDR_SHIFT 7 +/* This value set the possible out standing headers CMPLs , the ... */ +#define PCIE_AXI_REV1_2_INIT_FC_CFG_NOF_CPL_HDR_MASK 0x001FC000 +#define PCIE_AXI_REV1_2_INIT_FC_CFG_NOF_CPL_HDR_SHIFT 14 + +#define PCIE_AXI_REV1_2_INIT_FC_CFG_RSRVD_MASK 0xFFE00000 +#define PCIE_AXI_REV1_2_INIT_FC_CFG_RSRVD_SHIFT 21 + +/* This value set the possible out standing headers writes (post ... */ +#define PCIE_AXI_REV3_INIT_FC_CFG_NOF_P_HDR_MASK 0x000001FF +#define PCIE_AXI_REV3_INIT_FC_CFG_NOF_P_HDR_SHIFT 0 +/* This value set the possible out standing headers reads (non-p ... */ +#define PCIE_AXI_REV3_INIT_FC_CFG_NOF_NP_HDR_MASK 0x0003FE00 +#define PCIE_AXI_REV3_INIT_FC_CFG_NOF_NP_HDR_SHIFT 9 +/* This value set the possible out standing headers CMPLs , the ... */ +#define PCIE_AXI_REV3_INIT_FC_CFG_NOF_CPL_HDR_MASK 0x07FC0000 +#define PCIE_AXI_REV3_INIT_FC_CFG_NOF_CPL_HDR_SHIFT 18 + /* + * [27] cfg_cpl_p_rr: do round robin on the SB output btw Posted and CPL. + * [28] cfg_np_pass_p_rr, in case RR between CPL AND P, allow to pass NP in case + * p is empty. + * [29] cfg_np_part_of_rr_arb: NP also is a part of the round robin arbiter. + */ +#define PCIE_AXI_REV3_INIT_FC_CFG_RSRVD_MASK 0xF8000000 +#define PCIE_AXI_REV3_INIT_FC_CFG_RSRVD_SHIFT 27 + +/**** write_msg_ctrl_0 register ****/ +/* + * choose if 17 in the AXUSER indicate message hint (1'b1) or no snoop + * indication (1'b0) + */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_0_AW_CFG_OUTBOUND_MSG_NO_SNOOP_N (1 << 0) +/* this bit define if the message is with data or without */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_0_AW_CFG_MSG_WITH_DATA (1 << 1) +/* message code for message with data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_0_AW_CFG_MSG_CODE_DATA_MASK 0x000003FC +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_0_AW_CFG_MSG_CODE_DATA_SHIFT 2 +/* message code for message without data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_0_AW_CFG_MSG_CODE_MASK 0x0003FC00 +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_0_AW_CFG_MSG_CODE_SHIFT 10 +/* message ST value */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_0_AW_CFG_MSG_ST_MASK 0x03FC0000 +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_0_AW_CFG_MSG_ST_SHIFT 18 +/* message NO-SNOOP */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_0_AW_CFG_MSG_NO_SNOOP (1 << 26) +/* message TH bit */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_0_AW_CFG_MSG_TH (1 << 27) +/* message PH bits */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_0_AW_CFG_MSG_PH_MASK 0x30000000 +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_0_AW_CFG_MSG_PH_SHIFT 28 +/* Rsrvd */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_0_RSRVD_MASK 0xC0000000 +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_0_RSRVD_SHIFT 30 + +/**** write_msg_ctrl_1 register ****/ +/* message type */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_1_AW_CFG_MISC_MSG_TYPE_VALUE_MASK 0x0000001F +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_1_AW_CFG_MISC_MSG_TYPE_VALUE_SHIFT 0 +/* this bit define if the message is with data or without */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_1_AW_CFG_MSG_DATA_TYPE_VALUE_MASK 0x000003E0 +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_1_AW_CFG_MSG_DATA_TYPE_VALUE_SHIFT 5 +/* override axi size for message with no data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_1_AW_CFG_MSG_NO_DATA_AXI_SIZE_OVRD (1 << 10) +/* override the AXI size to the pcie core for message with no data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_1_AW_CFG_MSG_NO_DATA_AXI_SIZE_MSG_MASK 0x00003800 +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_1_AW_CFG_MSG_NO_DATA_AXI_SIZE_MSG_SHIFT 11 +/* override axi size for message with data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_1_AW_CFG_MSG_DATA_AXI_SIZE_OVRD (1 << 14) +/* override the AXI size to the pcie core for message with data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_1_AW_CFG_MSG_DATA_AXI_SIZE_MSG_MASK 0x00038000 +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_1_AW_CFG_MSG_DATA_AXI_SIZE_MSG_SHIFT 15 +/* Rsrvd */ +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_1_RSRVD_MASK 0xFFFC0000 +#define PCIE_AXI_AXI_ATTR_OVRD_WR_MSG_CTRL_1_RSRVD_SHIFT 18 + +/**** read_msg_ctrl_0 register ****/ +/* + * choose if 17 in the AXUSER indicate message hint (1'b1) or no snoop + * indication (1'b0) + */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_0_AR_CFG_OUTBOUND_MSG_NO_SNOOP_N (1 << 0) +/* this bit define if the message is with data or without */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_0_AR_CFG_MSG_WITH_DATA (1 << 1) +/* message code for message with data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_0_AR_CFG_MSG_CODE_DATA_MASK 0x000003FC +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_0_AR_CFG_MSG_CODE_DATA_SHIFT 2 +/* message code for message without data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_0_AR_CFG_MSG_CODE_MASK 0x0003FC00 +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_0_AR_CFG_MSG_CODE_SHIFT 10 +/* message ST value */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_0_AR_CFG_MSG_ST_MASK 0x03FC0000 +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_0_AR_CFG_MSG_ST_SHIFT 18 +/* message NO-SNOOP */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_0_AR_CFG_MSG_NO_SNOOP (1 << 26) +/* message TH bit */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_0_AR_CFG_MSG_TH (1 << 27) +/* message PH bits */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_0_AR_CFG_MSG_PH_MASK 0x30000000 +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_0_AR_CFG_MSG_PH_SHIFT 28 +/* Rsrvd */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_0_RSRVD_MASK 0xC0000000 +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_0_RSRVD_SHIFT 30 + +/**** read_msg_ctrl_1 register ****/ +/* message type */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_1_AR_CFG_MISC_MSG_TYPE_VALUE_MASK 0x0000001F +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_1_AR_CFG_MISC_MSG_TYPE_VALUE_SHIFT 0 +/* this bit define if the message is with data or without */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_1_AR_CFG_MSG_DATA_TYPE_VALUE_MASK 0x000003E0 +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_1_AR_CFG_MSG_DATA_TYPE_VALUE_SHIFT 5 +/* override axi size for message with no data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_1_AR_CFG_MSG_NO_DATA_AXI_SIZE_OVRD (1 << 10) +/* override the AXI size to the pcie core for message with no data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_1_AR_CFG_MSG_NO_DATA_AXI_SIZE_MSG_MASK 0x00003800 +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_1_AR_CFG_MSG_NO_DATA_AXI_SIZE_MSG_SHIFT 11 +/* override axi size for message with data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_1_AR_CFG_MSG_DATA_AXI_SIZE_OVRD (1 << 14) +/* override the AXI size to the pcie core for message with data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_1_AR_CFG_MSG_DATA_AXI_SIZE_MSG_MASK 0x00038000 +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_1_AR_CFG_MSG_DATA_AXI_SIZE_MSG_SHIFT 15 +/* Rsrvd */ +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_1_RSRVD_MASK 0xFFFC0000 +#define PCIE_AXI_AXI_ATTR_OVRD_READ_MSG_CTRL_1_RSRVD_SHIFT 18 + +/**** pf_sel register ****/ +/* message type */ +#define PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT0_OVRD_FROM_AXUSER (1 << 0) +/* this bit define if the message is with data or without */ +#define PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT0_OVRD_FROM_REG (1 << 1) +/* override axi size for message with no data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT0_ADDR_OFFSET_MASK 0x0000003C +#define PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT0_ADDR_OFFSET_SHIFT 2 +/* override the AXI size to the pcie core for message with no data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_CFG_PF_BIT0_OVRD (1 << 6) +/* Rsrvd */ +#define PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_RSRVD_7 (1 << 7) +/* message type */ +#define PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT1_OVRD_FROM_AXUSER (1 << 8) +/* this bit define if the message is with data or without */ +#define PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT1_OVRD_FROM_REG (1 << 9) +/* override axi size for message with no data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT1_ADDR_OFFSET_MASK 0x00003C00 +#define PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_PF_BIT1_ADDR_OFFSET_SHIFT 10 +/* override the AXI size to the pcie core for message with no data. */ +#define PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_CFG_PF_BIT1_OVRD (1 << 14) +/* Rsrvd */ +#define PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_RSRVD_MASK 0xFFFF8000 +#define PCIE_AXI_AXI_ATTR_OVRD_PF_SEL_RSRVD_SHIFT 15 + + /**** func_ctrl_0 register ****/ +/* choose the field from the axuser */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_0_PF_VEC_TH_OVRD_FROM_AXUSER (1 << 0) +/* choose the field from register */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_0_PF_VEC_TH_OVRD_FROM_REG (1 << 1) +/* field offset from the address portions according to the spec */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_0_PF_VEC_TH_ADDR_OFFSET_MASK 0x0000003C +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_0_PF_VEC_TH_ADDR_OFFSET_SHIFT 2 +/* register value override */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_0_CFG_TH_OVRD (1 << 6) +/* choose the field from the axuser */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_0_PF_VEC_ST_VEC_OVRD_FROM_AXUSER_MASK 0x00007F80 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_0_PF_VEC_ST_VEC_OVRD_FROM_AXUSER_SHIFT 7 +/* choose the field from register */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_0_PF_VEC_ST_VEC_OVRD_FROM_REG_MASK 0x007F8000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_0_PF_VEC_ST_VEC_OVRD_FROM_REG_SHIFT 15 +/* register value override */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_0_CFG_ST_VEC_OVRD_MASK 0x7F800000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_0_CFG_ST_VEC_OVRD_SHIFT 23 +/* Rsrvd */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_0_RSRVD (1 << 31) + +/**** func_ctrl_2 register ****/ +/* choose the field from the axuser */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_PF_VEC_PH_VEC_OVRD_FROM_AXUSER_MASK 0x00000003 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_PF_VEC_PH_VEC_OVRD_FROM_AXUSER_SHIFT 0 +/* choose the field from register */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_PF_VEC_PH_VEC_OVRD_FROM_REG_MASK 0x0000000C +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_PF_VEC_PH_VEC_OVRD_FROM_REG_SHIFT 2 +/* in case the field take from the address, offset field for each bit. */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_PF_VEC_PH_VEC_ADDR_OFFSET_MASK 0x00000FF0 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_PF_VEC_PH_VEC_ADDR_OFFSET_SHIFT 4 +/* register value override */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_CFG_PH_VEC_OVRD_MASK 0x00003000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_CFG_PH_VEC_OVRD_SHIFT 12 +/* Rsrvd */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_RSRVD_14_15_MASK 0x0000C000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_RSRVD_14_15_SHIFT 14 +/* choose the field from the axuser */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_PF_VEC_VMID89_VEC_OVRD_FROM_AXUSER_MASK 0x00030000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_PF_VEC_VMID89_VEC_OVRD_FROM_AXUSER_SHIFT 16 +/* choose the field from register */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_PF_VEC_VMID89_VEC_OVRD_FROM_REG_MASK 0x000C0000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_PF_VEC_VMID89_VEC_OVRD_FROM_REG_SHIFT 18 +/* in case the field take from the address, offset field for each bit. */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_PF_VEC_VMID89_VEC_ADDR_OFFSET_MASK 0x0FF00000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_PF_VEC_VMID89_VEC_ADDR_OFFSET_SHIFT 20 +/* register value override */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_CFG_VMID89_VEC_OVRD_MASK 0x30000000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_CFG_VMID89_VEC_OVRD_SHIFT 28 +/* Rsrvd */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_RSRVD_MASK 0xC0000000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_2_RSRVD_SHIFT 30 + +/**** func_ctrl_3 register ****/ +/* + * When set take the corresponding bit address from register + * pf_vec_mem_addr44_53_ovrd + */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_3_PF_VEC_MEM_ADDR44_53_SEL_MASK 0x000003FF +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_3_PF_VEC_MEM_ADDR44_53_SEL_SHIFT 0 +/* override value. */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_3_PF_VEC_MEM_ADDR44_53_OVRD_MASK 0x000FFC00 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_3_PF_VEC_MEM_ADDR44_53_OVRD_SHIFT 10 +/* + * When set take the corresponding bit address from register + * pf_vec_mem_addr54_63_ovrd + */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_3_PF_VEC_MEM_ADDR54_63_SEL_MASK 0x3FF00000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_3_PF_VEC_MEM_ADDR54_63_SEL_SHIFT 20 +/* Rsrvd */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_3_RSRVD_MASK 0xC0000000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_3_RSRVD_SHIFT 30 + +/**** func_ctrl_4 register ****/ +/* When set take the corresponding bit address from vmid value. */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_4_PF_VEC_MEM_ADDR54_63_SEL_VMID_MASK 0x000003FF +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_4_PF_VEC_MEM_ADDR54_63_SEL_VMID_SHIFT 0 +/* override value. */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_4_PF_VEC_MEM_ADDR54_63_OVRD_MASK 0x000FFC00 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_4_PF_VEC_MEM_ADDR54_63_OVRD_SHIFT 10 +/* Rsrvd */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_4_RSRVD_MASK 0xFFF00000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_4_RSRVD_SHIFT 20 + +/**** func_ctrl_5 register ****/ +/* + * When set take the corresponding bit address [63:44] from + * aw_pf_vec_msg_addr_ovrd + */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_5_AW_PF_VEC_MSG_ADDR_SEL_MASK 0x000FFFFF +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_5_AW_PF_VEC_MSG_ADDR_SEL_SHIFT 0 +/* Rsrvd */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_5_RSRVD_MASK 0xFFF00000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_5_RSRVD_SHIFT 20 + +/**** func_ctrl_6 register ****/ +/* override value. */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_6_AW_PF_VEC_MSG_ADDR_OVRD_MASK 0x000FFFFF +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_6_AW_PF_VEC_MSG_ADDR_OVRD_SHIFT 0 +/* Rsrvd */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_6_RSRVD_MASK 0xFFF00000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_6_RSRVD_SHIFT 20 + +/**** func_ctrl_7 register ****/ +/* + * When set take the corresponding bit address [63:44] from + * ar_pf_vec_msg_addr_ovrd + */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_7_AR_PF_VEC_MSG_ADDR_SEL_MASK 0x000FFFFF +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_7_AR_PF_VEC_MSG_ADDR_SEL_SHIFT 0 +/* Rsrvd */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_7_RSRVD_MASK 0xFFF00000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_7_RSRVD_SHIFT 20 + +/**** func_ctrl_8 register ****/ +/* override value. */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_8_AR_PF_VEC_MSG_ADDR_OVRD_MASK 0x000FFFFF +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_8_AR_PF_VEC_MSG_ADDR_OVRD_SHIFT 0 +/* Rsrvd */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_8_RSRVD_MASK 0xFFF00000 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_8_RSRVD_SHIFT 20 + +/**** func_ctrl_9 register ****/ +/* no snoop override */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_9_PF_VEC_NO_SNOOP_OVRD (1 << 0) +/* no snoop override value */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_9_PF_VEC_NO_SNOOP_OVRD_VALUE (1 << 1) +/* atu bypass override */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_9_PF_VEC_ATU_BYPASS_OVRD (1 << 2) +/* atu bypass override value */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_9_PF_VEC_ATU_BYPASS_OVRD_VALUE (1 << 3) +/* Rsrvd */ +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_9_RSRVD_MASK 0xFFFFFFF0 +#define PCIE_AXI_PF_AXI_ATTR_OVRD_FUNC_CTRL_9_RSRVD_SHIFT 4 + +/**** entry_vec register ****/ +/* entry0 */ +#define PCIE_AXI_MSG_ATTR_AXUSER_TABLE_ENTRY_VEC_ENTRY_0_MASK 0x0000001F +#define PCIE_AXI_MSG_ATTR_AXUSER_TABLE_ENTRY_VEC_ENTRY_0_SHIFT 0 +/* entry1 */ +#define PCIE_AXI_MSG_ATTR_AXUSER_TABLE_ENTRY_VEC_ENTRY_1_MASK 0x000003E0 +#define PCIE_AXI_MSG_ATTR_AXUSER_TABLE_ENTRY_VEC_ENTRY_1_SHIFT 5 +/* entry2 */ +#define PCIE_AXI_MSG_ATTR_AXUSER_TABLE_ENTRY_VEC_ENTRY_2_MASK 0x00007C00 +#define PCIE_AXI_MSG_ATTR_AXUSER_TABLE_ENTRY_VEC_ENTRY_2_SHIFT 10 +/* entry3 */ +#define PCIE_AXI_MSG_ATTR_AXUSER_TABLE_ENTRY_VEC_ENTRY_3_MASK 0x000F8000 +#define PCIE_AXI_MSG_ATTR_AXUSER_TABLE_ENTRY_VEC_ENTRY_3_SHIFT 15 +/* atu bypass for message "write" */ +#define PCIE_AXI_MSG_ATTR_AXUSER_TABLE_ENTRY_VEC_AW_MSG_ATU_BYPASS (1 << 20) +/* atu bypass for message "read" */ +#define PCIE_AXI_MSG_ATTR_AXUSER_TABLE_ENTRY_VEC_AR_MSG_ATU_BYPASS (1 << 21) +/* Rsrvd */ +#define PCIE_AXI_MSG_ATTR_AXUSER_TABLE_ENTRY_VEC_RSRVD_MASK 0xFFC00000 +#define PCIE_AXI_MSG_ATTR_AXUSER_TABLE_ENTRY_VEC_RSRVD_SHIFT 22 + +/**** int_cause_grp_A_axi register ****/ +/* + * Master Response Composer Lookup Error + * Overflow that occurred in a lookup table of the Outbound responses. This + * indicates that there was a violation for the number of outstanding NP + * requests issued for the Inbound direction. + * Write zero to clear. + */ +#define PCIE_AXI_INT_GRP_A_CAUSE_GM_COMPOSER_LOOKUP_ERR (1 << 0) +/* + * Indicates a PARITY ERROR on the master data read channel. + * Write zero to clear. + */ +#define PCIE_AXI_INT_GRP_A_CAUSE_PARITY_ERR_DATA_PATH_RD (1 << 2) +/* + * Indicates a PARITY ERROR on the slave addr read channel. + * Write zero to clear. + */ +#define PCIE_AXI_INT_GRP_A_CAUSE_PARITY_ERR_OUT_ADDR_RD (1 << 3) +/* + * Indicates a PARITY ERROR on the slave addr write channel. + * Write zero to clear. + */ +#define PCIE_AXI_INT_GRP_A_CAUSE_PARITY_ERR_OUT_ADDR_WR (1 << 4) +/* + * Indicates a PARITY ERROR on the slave data write channel. + * Write zero to clear. + */ +#define PCIE_AXI_INT_GRP_A_CAUSE_PARITY_ERR_OUT_DATA_WR (1 << 5) +/* Reserved */ +#define PCIE_AXI_INT_GRP_A_CAUSE_RESERVED_6 (1 << 6) +/* + * Software error: ECAM write request with invalid bus number. + * Write Zero to clear + */ +#define PCIE_AXI_INT_GRP_A_CAUSE_SW_ECAM_ERR_RD (1 << 7) +/* + * Software error: ECAM read request with invalid bus number. + * Write Zero to clear. + */ +#define PCIE_AXI_INT_GRP_A_CAUSE_SW_ECAM_ERR_WR (1 << 8) +/* Indicates an ERROR in the PCIe application cause register. */ +#define PCIE_AXI_INT_GRP_A_CAUSE_PCIE_CORE_INT (1 << 9) +/* + * Whenever the Master AXI finishes writing a message, it sets this bit. + * Whenever the int is cleared, the message information MSG_* regs are no longer + * valid. + */ +#define PCIE_AXI_INT_GRP_A_CAUSE_MSTR_AXI_GETOUT_MSG (1 << 10) +/* Read AXI compilation has ERROR. */ +#define PCIE_AXI_INT_GRP_A_CAUSE_RD_CMPL_ERR (1 << 11) +/* Write AXI compilation has ERROR. */ +#define PCIE_AXI_INT_GRP_A_CAUSE_WR_CMPL_ERR (1 << 12) +/* Read AXI compilation has timed out. */ +#define PCIE_AXI_INT_GRP_A_CAUSE_RD_CMPL_TO (1 << 13) +/* Write AXI compilation has timed out. */ +#define PCIE_AXI_INT_GRP_A_CAUSE_WR_CMPL_TO (1 << 14) +/* Parity error AXI domain */ +#define PCIE_AXI_INT_GRP_A_CAUSE_PARITY_ERROR_AXI (1 << 15) +/* POS error interrupt */ +#define PCIE_AXI_INT_GRP_A_CAUSE_POS_AXI_BRESP (1 << 16) +/* The outstanding write counter become full should never happen */ +#define PCIE_AXI_INT_GRP_A_CAUSE_WRITE_CNT_FULL_ERR (1 << 17) +/* BRESP received before the write counter increment. */ +#define PCIE_AXI_INT_GRP_A_CAUSE_BRESP_BEFORE_WR_CNT_INC_ERR (1 << 18) + +/**** int_control_grp_A_axi register ****/ +/* When Clear_on_Read =1, all bits of the Cause register are cleared on read. */ +#define PCIE_AXI_INT_GRP_A_CTRL_CLEAR_ON_READ (1 << 0) +/* + * (Must be set only when MSIX is enabled.) + * When Auto-Mask =1 and an MSI-X ACK for this bit is received, its + * corresponding bit in the mask register is set, masking future interrupts. + */ +#define PCIE_AXI_INT_GRP_A_CTRL_AUTO_MASK (1 << 1) +/* + * Auto_Clear (RW) + * When Auto-Clear =1, the bits in the Interrupt Cause register are auto-cleared + * after MSI-X is acknowledged. Must be used only if MSI-X is enabled. + */ +#define PCIE_AXI_INT_GRP_A_CTRL_AUTO_CLEAR (1 << 2) +/* + * When set,_on_Posedge =1, the bits in the Interrupt Cause register are set on + * the posedge of the interrupt source, i.e., when interrupt source =1 and + * Interrupt Status = 0. + * When set,_on_Posedge =0, the bits in the Interrupt Cause register are set + * when interrupt source =1. + */ +#define PCIE_AXI_INT_GRP_A_CTRL_SET_ON_POS (1 << 3) +/* + * When Moderation_Reset =1, all Moderation timers associated with the interrupt + * cause bits are cleared to 0, enabling immediate interrupt assertion if any + * unmasked cause bit is set to 1. This bit is self-negated. + */ +#define PCIE_AXI_INT_GRP_A_CTRL_MOD_RST (1 << 4) +/* + * When mask_msi_x =1, no MSI-X from this group is sent. This bit is set to 1 + * when the associate summary bit in this group is used to generate a single + * MSI-X for this group. + */ +#define PCIE_AXI_INT_GRP_A_CTRL_MASK_MSI_X (1 << 5) +/* MSI-X AWID value. Same ID for all cause bits. */ +#define PCIE_AXI_INT_GRP_A_CTRL_AWID_MASK 0x00000F00 +#define PCIE_AXI_INT_GRP_A_CTRL_AWID_SHIFT 8 +/* + * This value determines the interval between interrupts. Writing ZERO disables + * Moderation. + */ +#define PCIE_AXI_INT_GRP_A_CTRL_MOD_INTV_MASK 0x00FF0000 +#define PCIE_AXI_INT_GRP_A_CTRL_MOD_INTV_SHIFT 16 +/* + * This value determines the Moderation_Timer_Clock speed. + * 0- Moderation-timer is decremented every 1x256 SB clock cycles ~1uS. + * 1- Moderation-timer is decremented every 2x256 SB clock cycles ~2uS. + * N- Moderation-timer is decremented every Nx256 SB clock cycles ~(N+1) uS. + */ +#define PCIE_AXI_INT_GRP_A_CTRL_MOD_RES_MASK 0x0F000000 +#define PCIE_AXI_INT_GRP_A_CTRL_MOD_RES_SHIFT 24 + +#ifdef __cplusplus +} +#endif + +#endif /* __AL_HAL_pcie_axi_REG_H */ + +/** @} end of ... group */ Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_axi_reg.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_interrupts.h =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_interrupts.h (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_interrupts.h (revision 283031) @@ -0,0 +1,271 @@ +/*- +******************************************************************************** +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef _AL_HAL_PCIE_INTERRUPTS_H_ +#define _AL_HAL_PCIE_INTERRUPTS_H_ + +#include "al_hal_common.h" +#include "al_hal_pcie.h" +#include "al_hal_iofic.h" + +/** + * @defgroup group_pcie_interrupts PCIe interrupts + * @ingroup grouppcie + * @{ + * The PCIe interrupts HAL can be used to control PCIe unit interrupts. + * There are 5 groups of interrupts: app group A, B, C, D and AXI. + * Only 2 interrupts go from the pcie unit to the GIC: + * 1. Summary for all the int groups (AXI+APP CORE). + * 2. INTA assert/deassert (RC only). + * For the specific GIC interrupt line, please check the architecture reference + * manual. + * The reset mask state of all interrupts is: Masked + * + * @file al_hal_pcie_interrupts.h + * + */ + +/** + * PCIe interrupt groups + */ +enum al_pcie_int_group { + AL_PCIE_INT_GRP_A, + AL_PCIE_INT_GRP_B, + AL_PCIE_INT_GRP_C, /* Rev3 only */ + AL_PCIE_INT_GRP_D, /* Rev3 only */ + AL_PCIE_INT_GRP_AXI_A, +}; + +/** + * App group A interrupts mask - don't change + * All interrupts not listed below should be masked + */ +enum al_pcie_app_int_grp_a { + /** [RC only] Deassert_INTD received */ + AL_PCIE_APP_INT_DEASSERT_INTD = AL_BIT(0), + /** [RC only] Deassert_INTC received */ + AL_PCIE_APP_INT_DEASSERT_INTC = AL_BIT(1), + /** [RC only] Deassert_INTB received */ + AL_PCIE_APP_INT_DEASSERT_INTB = AL_BIT(2), + /** + * [RC only] Deassert_INTA received - there's a didcated GIC interrupt + * line that reflects the status of ASSERT/DEASSERT of INTA + */ + AL_PCIE_APP_INT_DEASSERT_INTA = AL_BIT(3), + /** [RC only] Assert_INTD received */ + AL_PCIE_APP_INT_ASSERT_INTD = AL_BIT(4), + /** [RC only] Assert_INTC received */ + AL_PCIE_APP_INT_ASSERT_INTC = AL_BIT(5), + /** [RC only] Assert_INTB received */ + AL_PCIE_APP_INT_ASSERT_INTB = AL_BIT(6), + /** + * [RC only] Assert_INTA received - there's a didcated GIC interrupt + * line that reflects the status of ASSERT/DEASSERT of INTA + */ + AL_PCIE_APP_INT_ASSERT_INTA = AL_BIT(7), + /** [RC only] MSI Controller Interrupt */ + AL_PCIE_APP_INT_MSI_CNTR_RCV_INT = AL_BIT(8), + /** [EP only] MSI sent grant */ + AL_PCIE_APP_INT_MSI_TRNS_GNT = AL_BIT(9), + /** [RC only] System error detected (ERR_COR, ERR_FATAL, ERR_NONFATAL) */ + AL_PCIE_APP_INT_SYS_ERR_RC = AL_BIT(10), + /** [EP only] Software initiates FLR on a Physical Function */ + AL_PCIE_APP_INT_FLR_PF_ACTIVE = AL_BIT(11), + /** [RC only] Root Error Command register assertion notification */ + AL_PCIE_APP_INT_AER_RC_ERR = AL_BIT(12), + /** [RC only] Root Error Command register assertion notification With MSI or MSIX enabled */ + AL_PCIE_APP_INT_AER_RC_ERR_MSI = AL_BIT(13), + /** [RC only] PME Status bit assertion in the Root Status register With INTA */ + AL_PCIE_APP_INT_PME_INT = AL_BIT(15), + /** [RC only] PME Status bit assertion in the Root Status register With MSI or MSIX enabled */ + AL_PCIE_APP_INT_PME_MSI = AL_BIT(16), + /** [RC/EP] The core assert link down event, whenever the link is going down */ + AL_PCIE_APP_INT_LINK_DOWN = AL_BIT(21), + /** [EP only] When the EP gets a command to shut down, signal the software to block any new TLP. */ + AL_PCIE_APP_INT_PM_XTLH_BLOCK_TLP = AL_BIT(22), + /** [RC/EP] PHY/MAC link up */ + AL_PCIE_APP_INT_XMLH_LINK_UP = AL_BIT(23), + /** [RC/EP] Data link up */ + AL_PCIE_APP_INT_RDLH_LINK_UP = AL_BIT(24), + /** [RC/EP] The LTSSM is in RCVRY_LOCK state. */ + AL_PCIE_APP_INT_LTSSM_RCVRY_STATE = AL_BIT(25), + /** + * [RC/EP] CFG write transaction to the configuration space by the RC peer + * For RC the int/ will be set from DBI write (internal SoC write)] + */ + AL_PCIE_APP_INT_CFG_WR = AL_BIT(26), + /** [EP only] CFG access in EP mode */ + AL_PCIE_APP_INT_CFG_ACCESS = AL_BIT(31), +}; + +/** + * App group B interrupts mask - don't change + * All interrupts not listed below should be masked + */ +enum al_pcie_app_int_grp_b { + /** [RC only] PM_PME Message received */ + AL_PCIE_APP_INT_GRP_B_PM_PME_MSG_RCVD = AL_BIT(0), + /** [RC only] PME_TO_Ack Message received */ + AL_PCIE_APP_INT_GRP_B_PME_TO_ACK_MSG_RCVD = AL_BIT(1), + /** [EP only] PME_Turn_Off Message received */ + AL_PCIE_APP_INT_GRP_B_PME_TURN_OFF_MSG_RCVD = AL_BIT(2), + /** [RC only] ERR_CORR Message received */ + AL_PCIE_APP_INT_GRP_B_CORR_ERR_MSG_RCVD = AL_BIT(3), + /** [RC only] ERR_NONFATAL Message received */ + AL_PCIE_APP_INT_GRP_B_NON_FTL_ERR_MSG_RCVD = AL_BIT(4), + /** [RC only] ERR_FATAL Message received */ + AL_PCIE_APP_INT_GRP_B_FTL_ERR_MSG_RCVD = AL_BIT(5), + /** + * [RC/EP] Vendor Defined Message received + * Asserted when a vevdor message is received (with no data), buffers 2 + * messages only, and latch the headers in registers + */ + AL_PCIE_APP_INT_GRP_B_VNDR_MSG_A_RCVD = AL_BIT(6), + /** + * [RC/EP] Vendor Defined Message received + * Asserted when a vevdor message is received (with no data), buffers 2 + * messages only, and latch the headers in registers + */ + AL_PCIE_APP_INT_GRP_B_VNDR_MSG_B_RCVD = AL_BIT(7), + /** [EP only] Link Autonomous Bandwidth Status is updated */ + AL_PCIE_APP_INT_GRP_B_LNK_BW_UPD = AL_BIT(12), + /** [EP only] Link Equalization Request bit in the Link Status 2 Register has been set */ + AL_PCIE_APP_INT_GRP_B_LNK_EQ_REQ = AL_BIT(13), + /** [RC/EP] OB Vendor message request is granted by the PCIe core */ + AL_PCIE_APP_INT_GRP_B_OB_VNDR_MSG_REQ_GRNT = AL_BIT(14), + /** [RC only] CPL timeout from the PCIe core indiication */ + AL_PCIE_APP_INT_GRP_B_CPL_TO = AL_BIT(15), + /** [RC/EP] Slave Response Composer Lookup Error */ + AL_PCIE_APP_INT_GRP_B_SLV_RESP_COMP_LKUP_ERR = AL_BIT(16), + /** [RC/EP] Parity Error */ + AL_PCIE_APP_INT_GRP_B_PARITY_ERR = AL_BIT(17), + /** [EP only] Speed change request */ + AL_PCIE_APP_INT_GRP_B_SPEED_CHANGE = AL_BIT(31), +}; + +/** + * AXI interrupts mask - don't change + * These are internal errors that can happen on the internal chip interface + * between the PCIe port and the I/O Fabric over the AXI bus. The notion of + * master and slave refer to the PCIe port master interface towards the I/O + * Fabric (i.e. for inbound PCIe writes/reads toward the I/O Fabric), while the + * slave interface refer to the I/O Fabric to PCIe port interface where the + * internal chip DMAs and CPU cluster is initiating transactions. + * All interrupts not listed below should be masked. + */ +enum al_pcie_axi_int { + /** [RC/EP] Master Response Composer Lookup Error */ + AL_PCIE_AXI_INT_MSTR_RESP_COMP_LKUP_ERR = AL_BIT(0), + /** [RC/EP] PARITY ERROR on the master data read channel */ + AL_PCIE_AXI_INT_PARITY_ERR_MSTR_DATA_RD_CHNL = AL_BIT(2), + /** [RC/EP] PARITY ERROR on the slave addr read channel */ + AL_PCIE_AXI_INT_PARITY_ERR_SLV_ADDR_RD_CHNL = AL_BIT(3), + /** [RC/EP] PARITY ERROR on the slave addr write channel */ + AL_PCIE_AXI_INT_PARITY_ERR_SLV_ADDR_WR_CHNL = AL_BIT(4), + /** [RC/EP] PARITY ERROR on the slave data write channel */ + AL_PCIE_AXI_INT_PARITY_ERR_SLV_DATA_WR_CHNL = AL_BIT(5), + /** [RC only] Software error: ECAM write request with invalid bus number */ + AL_PCIE_AXI_INT_ECAM_WR_REQ_INVLD_BUS_NUM = AL_BIT(7), + /** [RC only] Software error: ECAM read request with invalid bus number */ + AL_PCIE_AXI_INT_ECAM_RD_REQ_INVLD_BUS_NUM = AL_BIT(8), + /** [RC/EP] Read AXI completion has ERROR */ + AL_PCIE_AXI_INT_RD_AXI_COMPL_ERR = AL_BIT(11), + /** [RC/EP] Write AXI completion has ERROR */ + AL_PCIE_AXI_INT_WR_AXI_COMPL_ERR = AL_BIT(12), + /** [RC/EP] Read AXI completion has timed out */ + AL_PCIE_AXI_INT_RD_AXI_COMPL_TO = AL_BIT(13), + /** [RC/EP] Write AXI completion has timed out */ + AL_PCIE_AXI_INT_WR_AXI_COMPL_TO = AL_BIT(14), + /** [RC/EP] Parity error AXI domain */ + AL_PCIE_AXI_INT_AXI_DOM_PARITY_ERR = AL_BIT(15), + /** [RC/EP] POS error interrupt */ + AL_PCIE_AXI_INT_POS_ERR = AL_BIT(16), +}; + +/** + * @brief Initialize and configure PCIe controller interrupts + * Doesn't change the mask state of the interrupts + * The reset mask state of all interrupts is: Masked + * + * @param pcie_port pcie port handle + */ +void al_pcie_ints_config(struct al_pcie_port *pcie_port); + +/** + * Unmask PCIe app group interrupts + * @param pcie_port pcie_port pcie port handle + * @param int_group interrupt group + * @param int_mask int_mask interrupts to unmask ('1' to unmask) + */ +void al_pcie_app_int_grp_unmask( + struct al_pcie_port *pcie_port, + enum al_pcie_int_group int_group, + uint32_t int_mask); + +/** + * Mask PCIe app group interrupts + * @param pcie_port pcie_port pcie port handle + * @param int_group interrupt group + * @param int_mask int_mask interrupts to unmask ('1' to mask) + */ +void al_pcie_app_int_grp_mask( + struct al_pcie_port *pcie_port, + enum al_pcie_int_group int_group, + uint32_t int_mask); + +/** + * Clear the PCIe app group interrupt cause + * @param pcie_port pcie port handle + * @param int_group interrupt group + * @param int_cause interrupt cause + */ +void al_pcie_app_int_grp_cause_clear( + struct al_pcie_port *pcie_port, + enum al_pcie_int_group int_group, + uint32_t int_cause); + +/** + * Read PCIe app group interrupt cause + * @param pcie_port pcie port handle + * @param int_group interrupt group + * @return interrupt cause or 0 in case the group is not supported + */ +uint32_t al_pcie_app_int_grp_cause_read( + struct al_pcie_port *pcie_port, + enum al_pcie_int_group int_group); + +#endif +/** @} end of group_pcie_interrupts group */ Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_interrupts.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_regs.h =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_regs.h (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_regs.h (revision 283031) @@ -0,0 +1,594 @@ +/*- +******************************************************************************** +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __AL_HAL_PCIE_REGS_H__ +#define __AL_HAL_PCIE_REGS_H__ + +/* Note: Definitions before the includes so axi/wrapper regs sees them */ + +/** Maximum physical functions supported */ +#define REV1_2_MAX_NUM_OF_PFS 1 +#define REV3_MAX_NUM_OF_PFS 4 +#define AL_MAX_NUM_OF_PFS 4 /* the maximum between all Revisions */ + +#include "al_hal_pcie_axi_reg.h" +#ifndef AL_PCIE_EX +#include "al_hal_pcie_w_reg.h" +#else +#include "al_hal_pcie_w_reg_ex.h" +#endif + +/** + * Revision IDs: + * ID_0: SlickRock M0 + * ID_1: SlickRock A0 + * ID_2: PeakRock x4 + * ID_3: PeakRock x8 + */ +#define AL_PCIE_REV_ID_0 0 +#define AL_PCIE_REV_ID_1 1 +#define AL_PCIE_REV_ID_2 2 +#define AL_PCIE_REV_ID_3 3 + +#define AL_PCIE_AXI_REGS_OFFSET 0x0 +#define AL_PCIE_REV_1_2_APP_REGS_OFFSET 0x1000 +#define AL_PCIE_REV_3_APP_REGS_OFFSET 0x2000 +#define AL_PCIE_REV_1_2_CORE_CONF_BASE_OFFSET 0x2000 +#define AL_PCIE_REV_3_CORE_CONF_BASE_OFFSET 0x10000 + +/** Maximum number of lanes supported */ +#define REV1_2_MAX_NUM_LANES 4 +#define REV3_MAX_NUM_LANES 8 +#define AL_MAX_NUM_OF_LANES 8 /* the maximum between all Revisions */ + +struct al_pcie_core_iatu_regs { + uint32_t index; + uint32_t cr1; + uint32_t cr2; + uint32_t lower_base_addr; + uint32_t upper_base_addr; + uint32_t limit_addr; + uint32_t lower_target_addr; + uint32_t upper_target_addr; + uint32_t cr3; + uint32_t rsrvd[(0x270 - 0x224) >> 2]; +}; + +struct al_pcie_core_port_regs { + uint32_t ack_lat_rply_timer; + uint32_t reserved1[(0x10 - 0x4) >> 2]; + uint32_t port_link_ctrl; + uint32_t reserved2[(0x18 - 0x14) >> 2]; + uint32_t timer_ctrl_max_func_num; + uint32_t filter_mask_reg_1; + uint32_t reserved3[(0x48 - 0x20) >> 2]; + uint32_t vc0_posted_rcv_q_ctrl; + uint32_t vc0_non_posted_rcv_q_ctrl; + uint32_t vc0_comp_rcv_q_ctrl; + uint32_t reserved4[(0x10C - 0x54) >> 2]; + uint32_t gen2_ctrl; + uint32_t reserved5[(0x190 - 0x110) >> 2]; + uint32_t gen3_ctrl; + uint32_t gen3_eq_fs_lf; + uint32_t gen3_eq_preset_to_coef_map; + uint32_t gen3_eq_preset_idx; + uint32_t reserved6; + uint32_t gen3_eq_status; + uint32_t gen3_eq_ctrl; + uint32_t reserved7[(0x1B8 - 0x1AC) >> 2]; + uint32_t pipe_loopback_ctrl; + uint32_t rd_only_wr_en; + uint32_t reserved8[(0x1D0 - 0x1C0) >> 2]; + uint32_t axi_slave_err_resp; + uint32_t reserved9[(0x200 - 0x1D4) >> 2]; + struct al_pcie_core_iatu_regs iatu; + uint32_t reserved10[(0x448 - 0x270) >> 2]; +}; + +struct al_pcie_core_aer_regs { + /* 0x0 - PCI Express Extended Capability Header */ + uint32_t header; + /* 0x4 - Uncorrectable Error Status Register */ + uint32_t uncorr_err_stat; + /* 0x8 - Uncorrectable Error Mask Register */ + uint32_t uncorr_err_mask; + /* 0xc - Uncorrectable Error Severity Register */ + uint32_t uncorr_err_severity; + /* 0x10 - Correctable Error Status Register */ + uint32_t corr_err_stat; + /* 0x14 - Correctable Error Mask Register */ + uint32_t corr_err_mask; + /* 0x18 - Advanced Error Capabilities and Control Register */ + uint32_t cap_and_ctrl; + /* 0x1c - Header Log Registers */ + uint32_t header_log[4]; + /* 0x2c - Root Error Command Register */ + uint32_t root_err_cmd; + /* 0x30 - Root Error Status Register */ + uint32_t root_err_stat; + /* 0x34 - Error Source Identification Register */ + uint32_t err_src_id; +}; + +struct al_pcie_core_reg_space_rev_1_2 { + uint32_t config_header[0x40 >> 2]; + uint32_t pcie_pm_cap_base; + uint32_t reserved1[(0x70 - 0x44) >> 2]; + uint32_t pcie_cap_base; + uint32_t pcie_dev_cap_base; + uint32_t pcie_dev_ctrl_status; + uint32_t pcie_link_cap_base; + uint32_t reserved2[(0xB0 - 0x80) >> 2]; + uint32_t msix_cap_base; + uint32_t reserved3[(0x100 - 0xB4) >> 2]; + struct al_pcie_core_aer_regs aer; + uint32_t reserved4[(0x150 - + (0x100 + + sizeof(struct al_pcie_core_aer_regs))) >> 2]; + uint32_t pcie_sec_ext_cap_base; + uint32_t reserved5[(0x700 - 0x154) >> 2]; + struct al_pcie_core_port_regs port_regs; + uint32_t reserved6[(0x1000 - + (0x700 + + sizeof(struct al_pcie_core_port_regs))) >> 2]; +}; + +struct al_pcie_core_reg_space_rev_3 { + uint32_t config_header[0x40 >> 2]; + uint32_t pcie_pm_cap_base; + uint32_t reserved1[(0x70 - 0x44) >> 2]; + uint32_t pcie_cap_base; + uint32_t pcie_dev_cap_base; + uint32_t pcie_dev_ctrl_status; + uint32_t pcie_link_cap_base; + uint32_t reserved2[(0xB0 - 0x80) >> 2]; + uint32_t msix_cap_base; + uint32_t reserved3[(0x100 - 0xB4) >> 2]; + struct al_pcie_core_aer_regs aer; + uint32_t reserved4[(0x158 - + (0x100 + + sizeof(struct al_pcie_core_aer_regs))) >> 2]; + /* pcie_sec_cap is only applicable for function 0 */ + uint32_t pcie_sec_ext_cap_base; + uint32_t reserved5[(0x178 - 0x15C) >> 2]; + /* tph capability is only applicable for rev3 */ + uint32_t tph_cap_base; + uint32_t reserved6[(0x700 - 0x17C) >> 2]; + /* port_regs is only applicable for function 0 */ + struct al_pcie_core_port_regs port_regs; + uint32_t reserved7[(0x1000 - + (0x700 + + sizeof(struct al_pcie_core_port_regs))) >> 2]; +}; + +struct al_pcie_rev3_core_reg_space { + struct al_pcie_core_reg_space_rev_3 func[REV3_MAX_NUM_OF_PFS]; +}; + +struct al_pcie_core_reg_space { + uint32_t *config_header; + uint32_t *pcie_pm_cap_base; + uint32_t *pcie_cap_base; + uint32_t *pcie_dev_cap_base; + uint32_t *pcie_dev_ctrl_status; + uint32_t *pcie_link_cap_base; + uint32_t *msix_cap_base; + struct al_pcie_core_aer_regs *aer; + uint32_t *pcie_sec_ext_cap_base; + uint32_t *tph_cap_base; +}; + +struct al_pcie_revx_regs { + struct al_pcie_revx_axi_regs __iomem axi; +}; + +struct al_pcie_rev1_regs { + struct al_pcie_rev1_axi_regs __iomem axi; + uint32_t reserved1[(AL_PCIE_REV_1_2_APP_REGS_OFFSET - + (AL_PCIE_AXI_REGS_OFFSET + + sizeof(struct al_pcie_rev1_axi_regs))) >> 2]; + struct al_pcie_rev1_w_regs __iomem app; + uint32_t reserved2[(AL_PCIE_REV_1_2_CORE_CONF_BASE_OFFSET - + (AL_PCIE_REV_1_2_APP_REGS_OFFSET + + sizeof(struct al_pcie_rev1_w_regs))) >> 2]; + struct al_pcie_core_reg_space_rev_1_2 core_space; +}; + +struct al_pcie_rev2_regs { + struct al_pcie_rev2_axi_regs __iomem axi; + uint32_t reserved1[(AL_PCIE_REV_1_2_APP_REGS_OFFSET - + (AL_PCIE_AXI_REGS_OFFSET + + sizeof(struct al_pcie_rev2_axi_regs))) >> 2]; + struct al_pcie_rev2_w_regs __iomem app; + uint32_t reserved2[(AL_PCIE_REV_1_2_CORE_CONF_BASE_OFFSET - + (AL_PCIE_REV_1_2_APP_REGS_OFFSET + + sizeof(struct al_pcie_rev2_w_regs))) >> 2]; + struct al_pcie_core_reg_space_rev_1_2 core_space; +}; + +struct al_pcie_rev3_regs { + struct al_pcie_rev3_axi_regs __iomem axi; + uint32_t reserved1[(AL_PCIE_REV_3_APP_REGS_OFFSET - + (AL_PCIE_AXI_REGS_OFFSET + + sizeof(struct al_pcie_rev3_axi_regs))) >> 2]; + struct al_pcie_rev3_w_regs __iomem app; + uint32_t reserved2[(AL_PCIE_REV_3_CORE_CONF_BASE_OFFSET - + (AL_PCIE_REV_3_APP_REGS_OFFSET + + sizeof(struct al_pcie_rev3_w_regs))) >> 2]; + struct al_pcie_rev3_core_reg_space core_space; +}; + +struct al_pcie_axi_ctrl { + uint32_t *global; + uint32_t *master_arctl; + uint32_t *master_awctl; + uint32_t *slv_ctl; +}; + +struct al_pcie_axi_ob_ctrl { + uint32_t *cfg_target_bus; + uint32_t *cfg_control; + uint32_t *io_start_l; + uint32_t *io_start_h; + uint32_t *io_limit_l; + uint32_t *io_limit_h; +}; + +struct al_pcie_axi_pcie_global { + uint32_t *conf; +}; + +struct al_pcie_axi_conf { + uint32_t *zero_lane0; + uint32_t *zero_lane1; + uint32_t *zero_lane2; + uint32_t *zero_lane3; + uint32_t *zero_lane4; + uint32_t *zero_lane5; + uint32_t *zero_lane6; + uint32_t *zero_lane7; +}; + +struct al_pcie_axi_status { + uint32_t *lane[AL_MAX_NUM_OF_LANES]; +}; + +struct al_pcie_axi_parity { + uint32_t *en_axi; +}; + +struct al_pcie_axi_ordering { + uint32_t *pos_cntl; +}; + +struct al_pcie_axi_pre_configuration { + uint32_t *pcie_core_setup; +}; + +struct al_pcie_axi_init_fc { + uint32_t *cfg; +}; + +struct al_pcie_axi_attr_ovrd { + uint32_t *write_msg_ctrl_0; + uint32_t *write_msg_ctrl_1; + uint32_t *pf_sel; +}; + +struct al_pcie_axi_pf_axi_attr_ovrd { + uint32_t *func_ctrl_0; + uint32_t *func_ctrl_1; + uint32_t *func_ctrl_2; + uint32_t *func_ctrl_3; + uint32_t *func_ctrl_4; + uint32_t *func_ctrl_5; + uint32_t *func_ctrl_6; + uint32_t *func_ctrl_7; + uint32_t *func_ctrl_8; + uint32_t *func_ctrl_9; +}; + +struct al_pcie_axi_msg_attr_axuser_table { + uint32_t *entry_vec; +}; + +struct al_pcie_axi_regs { + struct al_pcie_axi_ctrl ctrl; + struct al_pcie_axi_ob_ctrl ob_ctrl; + struct al_pcie_axi_pcie_global pcie_global; + struct al_pcie_axi_conf conf; + struct al_pcie_axi_status status; + struct al_pcie_axi_parity parity; + struct al_pcie_axi_ordering ordering; + struct al_pcie_axi_pre_configuration pre_configuration; + struct al_pcie_axi_init_fc init_fc; + struct al_pcie_revx_axi_int_grp_a_axi *int_grp_a; + /* Rev3 only */ + struct al_pcie_axi_attr_ovrd axi_attr_ovrd; + struct al_pcie_axi_pf_axi_attr_ovrd pf_axi_attr_ovrd[REV3_MAX_NUM_OF_PFS]; + struct al_pcie_axi_msg_attr_axuser_table msg_attr_axuser_table; +}; + +struct al_pcie_w_global_ctrl { + uint32_t *port_init; + uint32_t *pm_control; + uint32_t *events_gen[REV3_MAX_NUM_OF_PFS]; + uint32_t *corr_err_sts_int; + uint32_t *uncorr_err_sts_int; + uint32_t *sris_kp_counter; +}; + +struct al_pcie_w_soc_int { + uint32_t *mask_inta_leg_0; + uint32_t *mask_inta_leg_3; /* Rev 2/3 only */ + uint32_t *mask_msi_leg_0; + uint32_t *mask_msi_leg_3; /* Rev 2/3 only */ +}; +struct al_pcie_w_atu { + uint32_t *in_mask_pair; + uint32_t *out_mask_pair; +}; + +struct al_pcie_w_regs { + struct al_pcie_w_global_ctrl global_ctrl; + struct al_pcie_revx_w_debug *debug; + struct al_pcie_revx_w_ap_user_send_msg *ap_user_send_msg; + struct al_pcie_w_soc_int soc_int[REV3_MAX_NUM_OF_PFS]; + struct al_pcie_revx_w_cntl_gen *ctrl_gen; + struct al_pcie_revx_w_parity *parity; + struct al_pcie_w_atu atu; + struct al_pcie_revx_w_status_per_func *status_per_func[REV3_MAX_NUM_OF_PFS]; + struct al_pcie_revx_w_int_grp *int_grp_a; + struct al_pcie_revx_w_int_grp *int_grp_b; + struct al_pcie_revx_w_int_grp *int_grp_c; + struct al_pcie_revx_w_int_grp *int_grp_d; +}; + +struct al_pcie_regs { + struct al_pcie_axi_regs axi; + struct al_pcie_w_regs app; + struct al_pcie_core_port_regs *port_regs; + struct al_pcie_core_reg_space core_space[REV3_MAX_NUM_OF_PFS]; +}; + +#define PCIE_AXI_MISC_PCIE_GLOBAL_CONF_DEV_TYPE_EP 0 +#define PCIE_AXI_MISC_PCIE_GLOBAL_CONF_DEV_TYPE_RC 4 + +#define PCIE_PORT_GEN2_CTRL_DIRECT_SPEED_CHANGE AL_BIT(17) +#define PCIE_PORT_GEN2_CTRL_TX_SWING_LOW_SHIFT 18 +#define PCIE_PORT_GEN2_CTRL_TX_COMPLIANCE_RCV_SHIFT 19 +#define PCIE_PORT_GEN2_CTRL_DEEMPHASIS_SET_SHIFT 20 +#define PCIE_PORT_GEN2_CTRL_NUM_OF_LANES_MASK AL_FIELD_MASK(12, 8) +#define PCIE_PORT_GEN2_CTRL_NUM_OF_LANES_SHIFT 8 + +#define PCIE_PORT_GEN3_CTRL_EQ_PHASE_2_3_DISABLE_SHIFT 9 +#define PCIE_PORT_GEN3_CTRL_EQ_DISABLE_SHIFT 16 + +#define PCIE_PORT_GEN3_EQ_LF_SHIFT 0 +#define PCIE_PORT_GEN3_EQ_LF_MASK 0x3f +#define PCIE_PORT_GEN3_EQ_FS_SHIFT 6 +#define PCIE_PORT_GEN3_EQ_FS_MASK (0x3f << PCIE_PORT_GEN3_EQ_FS_SHIFT) + +#define PCIE_PORT_LINK_CTRL_LB_EN_SHIFT 2 +#define PCIE_PORT_LINK_CTRL_FAST_LINK_EN_SHIFT 7 +#define PCIE_PORT_LINK_CTRL_LINK_CAPABLE_MASK AL_FIELD_MASK(21, 16) +#define PCIE_PORT_LINK_CTRL_LINK_CAPABLE_SHIFT 16 + +#define PCIE_PORT_PIPE_LOOPBACK_CTRL_PIPE_LB_EN_SHIFT 31 + +#define PCIE_PORT_AXI_SLAVE_ERR_RESP_ALL_MAPPING_SHIFT 0 + +/** timer_ctrl_max_func_num register + * Max physical function number (for example: 0 for 1PF, 3 for 4PFs) + */ +#define PCIE_PORT_GEN3_MAX_FUNC_NUM AL_FIELD_MASK(7, 0) + +/* filter_mask_reg_1 register */ +/** + * SKP Interval Value. + * The number of symbol times to wait between transmitting SKP ordered sets + */ +#define PCIE_FLT_MASK_SKP_INT_VAL_MASK AL_FIELD_MASK(10, 0) + +/* + * 0: Treat Function MisMatched TLPs as UR + * 1: Treat Function MisMatched TLPs as Supported + */ +#define CX_FLT_MASK_UR_FUNC_MISMATCH AL_BIT(16) + +/* + * 0: Treat CFG type1 TLPs as UR for EP; Supported for RC + * 1: Treat CFG type1 TLPs as Supported for EP; UR for RC + */ +#define CX_FLT_MASK_CFG_TYPE1_RE_AS_UR AL_BIT(19) + +/* + * 0: Enforce requester id match for received CPL TLPs. + * A violation results in cpl_abort, and possibly AER of unexp_cpl_err, + * cpl_rcvd_ur, cpl_rcvd_ca + * 1: Mask requester id match for received CPL TLPs + */ +#define CX_FLT_MASK_CPL_REQID_MATCH AL_BIT(22) + +/* + * 0: Enforce function match for received CPL TLPs. + * A violation results in cpl_abort, and possibly AER of unexp_cpl_err, + * cpl_rcvd_ur, cpl_rcvd_ca + * 1: Mask function match for received CPL TLPs + */ +#define CX_FLT_MASK_CPL_FUNC_MATCH AL_BIT(23) + +/* vc0_posted_rcv_q_ctrl register */ +#define RADM_PQ_HCRD_VC0_MASK AL_FIELD_MASK(19, 12) +#define RADM_PQ_HCRD_VC0_SHIFT 12 + +/* vc0_non_posted_rcv_q_ctrl register */ +#define RADM_NPQ_HCRD_VC0_MASK AL_FIELD_MASK(19, 12) +#define RADM_NPQ_HCRD_VC0_SHIFT 12 + +/* vc0_comp_rcv_q_ctrl register */ +#define RADM_CPLQ_HCRD_VC0_MASK AL_FIELD_MASK(19, 12) +#define RADM_CPLQ_HCRD_VC0_SHIFT 12 + +/**** iATU, Control Register 1 ****/ + +/** + * When the Address and BAR matching logic in the core indicate that a MEM-I/O + * transaction matches a BAR in the function corresponding to this value, then + * address translation proceeds. This check is only performed if the "Function + * Number Match Enable" bit of the "iATU Control 2 Register" is set + */ +#define PCIE_IATU_CR1_FUNC_NUM_MASK AL_FIELD_MASK(24, 20) +#define PCIE_IATU_CR1_FUNC_NUM_SHIFT 20 + +/**** iATU, Control Register 2 ****/ +/** For outbound regions, the Function Number Translation Bypass mode enables + * taking the function number of the translated TLP from the PCIe core + * interface and not from the "Function Number" field of CR1. + * For inbound regions, this bit should be asserted when physical function + * match mode needs to be enabled + */ +#define PCIE_IATU_CR2_FUNC_NUM_TRANS_BYPASS_FUNC_MATCH_ENABLE_MASK AL_BIT(19) +#define PCIE_IATU_CR2_FUNC_NUM_TRANS_BYPASS_FUNC_MATCH_ENABLE_SHIFT 19 + +/* pcie_dev_ctrl_status register */ +#define PCIE_PORT_DEV_CTRL_STATUS_CORR_ERR_REPORT_EN AL_BIT(0) +#define PCIE_PORT_DEV_CTRL_STATUS_NON_FTL_ERR_REPORT_EN AL_BIT(1) +#define PCIE_PORT_DEV_CTRL_STATUS_FTL_ERR_REPORT_EN AL_BIT(2) +#define PCIE_PORT_DEV_CTRL_STATUS_UNSUP_REQ_REPORT_EN AL_BIT(3) + +#define PCIE_PORT_DEV_CTRL_STATUS_MPS_MASK AL_FIELD_MASK(7, 5) +#define PCIE_PORT_DEV_CTRL_STATUS_MPS_SHIFT 5 +#define PCIE_PORT_DEV_CTRL_STATUS_MPS_VAL_256 (1 << PCIE_PORT_DEV_CTRL_STATUS_MPS_SHIFT) + +#define PCIE_PORT_DEV_CTRL_STATUS_MRRS_MASK AL_FIELD_MASK(14, 12) +#define PCIE_PORT_DEV_CTRL_STATUS_MRRS_SHIFT 12 +#define PCIE_PORT_DEV_CTRL_STATUS_MRRS_VAL_256 (1 << PCIE_PORT_DEV_CTRL_STATUS_MRRS_SHIFT) + +/****************************************************************************** + * AER registers + ******************************************************************************/ +/* PCI Express Extended Capability ID */ +#define PCIE_AER_CAP_ID_MASK AL_FIELD_MASK(15, 0) +#define PCIE_AER_CAP_ID_SHIFT 0 +#define PCIE_AER_CAP_ID_VAL 1 +/* Capability Version */ +#define PCIE_AER_CAP_VER_MASK AL_FIELD_MASK(19, 16) +#define PCIE_AER_CAP_VER_SHIFT 16 +#define PCIE_AER_CAP_VER_VAL 2 + +/* First Error Pointer */ +#define PCIE_AER_CTRL_STAT_FIRST_ERR_PTR_MASK AL_FIELD_MASK(4, 0) +#define PCIE_AER_CTRL_STAT_FIRST_ERR_PTR_SHIFT 0 +/* ECRC Generation Capability */ +#define PCIE_AER_CTRL_STAT_ECRC_GEN_SUPPORTED AL_BIT(5) +/* ECRC Generation Enable */ +#define PCIE_AER_CTRL_STAT_ECRC_GEN_EN AL_BIT(6) +/* ECRC Check Capable */ +#define PCIE_AER_CTRL_STAT_ECRC_CHK_SUPPORTED AL_BIT(7) +/* ECRC Check Enable */ +#define PCIE_AER_CTRL_STAT_ECRC_CHK_EN AL_BIT(8) + +/* Correctable Error Reporting Enable */ +#define PCIE_AER_ROOT_ERR_CMD_CORR_ERR_RPRT_EN AL_BIT(0) +/* Non-Fatal Error Reporting Enable */ +#define PCIE_AER_ROOT_ERR_CMD_NON_FTL_ERR_RPRT_EN AL_BIT(1) +/* Fatal Error Reporting Enable */ +#define PCIE_AER_ROOT_ERR_CMD_FTL_ERR_RPRT_EN AL_BIT(2) + +/* ERR_COR Received */ +#define PCIE_AER_ROOT_ERR_STAT_CORR_ERR AL_BIT(0) +/* Multiple ERR_COR Received */ +#define PCIE_AER_ROOT_ERR_STAT_CORR_ERR_MULTI AL_BIT(1) +/* ERR_FATAL/NONFATAL Received */ +#define PCIE_AER_ROOT_ERR_STAT_FTL_NON_FTL_ERR AL_BIT(2) +/* Multiple ERR_FATAL/NONFATAL Received */ +#define PCIE_AER_ROOT_ERR_STAT_FTL_NON_FTL_ERR_MULTI AL_BIT(3) +/* First Uncorrectable Fatal */ +#define PCIE_AER_ROOT_ERR_STAT_FIRST_UNCORR_FTL AL_BIT(4) +/* Non-Fatal Error Messages Received */ +#define PCIE_AER_ROOT_ERR_STAT_NON_FTL_RCVD AL_BIT(5) +/* Fatal Error Messages Received */ +#define PCIE_AER_ROOT_ERR_STAT_FTL_RCVD AL_BIT(6) +/* Advanced Error Interrupt Message Number */ +#define PCIE_AER_ROOT_ERR_STAT_ERR_INT_MSG_NUM_MASK AL_FIELD_MASK(31, 27) +#define PCIE_AER_ROOT_ERR_STAT_ERR_INT_MSG_NUM_SHIFT 27 + +/* ERR_COR Source Identification */ +#define PCIE_AER_SRC_ID_CORR_ERR_MASK AL_FIELD_MASK(15, 0) +#define PCIE_AER_SRC_ID_CORR_ERR_SHIFT 0 +/* ERR_FATAL/NONFATAL Source Identification */ +#define PCIE_AER_SRC_ID_CORR_ERR_FTL_NON_FTL_MASK AL_FIELD_MASK(31, 16) +#define PCIE_AER_SRC_ID_CORR_ERR_FTL_NON_FTL_SHIFT 16 + +/* AER message */ +#define PCIE_AER_MSG_REQID_MASK AL_FIELD_MASK(31, 16) +#define PCIE_AER_MSG_REQID_SHIFT 16 +#define PCIE_AER_MSG_TYPE_MASK AL_FIELD_MASK(15, 8) +#define PCIE_AER_MSG_TYPE_SHIFT 8 +#define PCIE_AER_MSG_RESERVED AL_FIELD_MASK(7, 1) +#define PCIE_AER_MSG_VALID AL_BIT(0) +/* AER message ack */ +#define PCIE_AER_MSG_ACK AL_BIT(0) +/* AER errors definitions */ +#define AL_PCIE_AER_TYPE_CORR (0x30) +#define AL_PCIE_AER_TYPE_NON_FATAL (0x31) +#define AL_PCIE_AER_TYPE_FATAL (0x33) +/* Requester ID Bus */ +#define AL_PCIE_REQID_BUS_NUM_SHIFT (8) + +/****************************************************************************** + * TPH registers + ******************************************************************************/ +#define PCIE_TPH_NEXT_POINTER AL_FIELD_MASK(31, 20) + +/****************************************************************************** + * Config Header registers + ******************************************************************************/ +/** + * see BIST_HEADER_TYPE_LATENCY_CACHE_LINE_SIZE_REG in core spec + * Note: valid only for EP mode + */ +#define PCIE_BIST_HEADER_TYPE_BASE 0xc +#define PCIE_BIST_HEADER_TYPE_MULTI_FUNC_MASK AL_BIT(23) + +/****************************************************************************** + * SRIS KP counters default values + ******************************************************************************/ +#define PCIE_SRIS_KP_COUNTER_GEN3_DEFAULT_VAL (0x24) +#define PCIE_SRIS_KP_COUNTER_GEN21_DEFAULT_VAL (0x4B) + +#endif Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_regs.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_w_reg.h =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_w_reg.h (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_w_reg.h (revision 283031) @@ -0,0 +1,1505 @@ +/*- +******************************************************************************** +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + + +#ifndef __AL_HAL_PCIE_W_REG_H__ +#define __AL_HAL_PCIE_W_REG_H__ + +#ifdef __cplusplus +extern "C" { +#endif +/* +* Unit Registers +*/ + + + +struct al_pcie_rev1_w_global_ctrl { + /* [0x0] */ + uint32_t port_init; + /* [0x4] */ + uint32_t port_status; + /* [0x8] */ + uint32_t pm_control; + uint32_t rsrvd_0; + /* [0x10] */ + uint32_t events_gen; + uint32_t rsrvd[3]; +}; +struct al_pcie_rev2_w_global_ctrl { + /* [0x0] */ + uint32_t port_init; + /* [0x4] */ + uint32_t port_status; + /* [0x8] */ + uint32_t pm_control; + uint32_t rsrvd_0; + /* [0x10] */ + uint32_t events_gen; + /* [0x14] */ + uint32_t pended_corr_err_sts_int; + /* [0x18] */ + uint32_t pended_uncorr_err_sts_int; + /* [0x1c] */ + uint32_t sris_kp_counter_value; +}; +struct al_pcie_rev3_w_global_ctrl { + /* [0x0] */ + uint32_t port_init; + /* [0x4] */ + uint32_t port_status; + /* [0x8] */ + uint32_t pm_control; + /* [0xc] */ + uint32_t pended_corr_err_sts_int; + /* [0x10] */ + uint32_t pended_uncorr_err_sts_int; + /* [0x14] */ + uint32_t sris_kp_counter_value; + uint32_t rsrvd[2]; +}; + +struct al_pcie_rev3_w_events_gen_per_func { + /* [0x0] */ + uint32_t events_gen; +}; +struct al_pcie_rev3_w_pm_state_per_func { + /* [0x0] */ + uint32_t pm_state_per_func; +}; +struct al_pcie_rev3_w_cfg_bars_ovrd { + /* [0x0] */ + uint32_t bar0_mask_lsb; + /* [0x4] */ + uint32_t bar0_mask_msb; + /* [0x8] */ + uint32_t bar0_limit_lsb; + /* [0xc] */ + uint32_t bar0_limit_msb; + /* [0x10] */ + uint32_t bar0_start_lsb; + /* [0x14] */ + uint32_t bar0_start_msb; + /* [0x18] */ + uint32_t bar0_ctrl; + /* [0x1c] */ + uint32_t bar1_mask_lsb; + /* [0x20] */ + uint32_t bar1_mask_msb; + /* [0x24] */ + uint32_t bar1_limit_lsb; + /* [0x28] */ + uint32_t bar1_limit_msb; + /* [0x2c] */ + uint32_t bar1_start_lsb; + /* [0x30] */ + uint32_t bar1_start_msb; + /* [0x34] */ + uint32_t bar1_ctrl; + /* [0x38] */ + uint32_t bar2_mask_lsb; + /* [0x3c] */ + uint32_t bar2_mask_msb; + /* [0x40] */ + uint32_t bar2_limit_lsb; + /* [0x44] */ + uint32_t bar2_limit_msb; + /* [0x48] */ + uint32_t bar2_start_lsb; + /* [0x4c] */ + uint32_t bar2_start_msb; + /* [0x50] */ + uint32_t bar2_ctrl; + /* [0x54] */ + uint32_t bar3_mask_lsb; + /* [0x58] */ + uint32_t bar3_mask_msb; + /* [0x5c] */ + uint32_t bar3_limit_lsb; + /* [0x60] */ + uint32_t bar3_limit_msb; + /* [0x64] */ + uint32_t bar3_start_lsb; + /* [0x68] */ + uint32_t bar3_start_msb; + /* [0x6c] */ + uint32_t bar3_ctrl; + /* [0x70] */ + uint32_t bar4_mask_lsb; + /* [0x74] */ + uint32_t bar4_mask_msb; + /* [0x78] */ + uint32_t bar4_limit_lsb; + /* [0x7c] */ + uint32_t bar4_limit_msb; + /* [0x80] */ + uint32_t bar4_start_lsb; + /* [0x84] */ + uint32_t bar4_start_msb; + /* [0x88] */ + uint32_t bar4_ctrl; + /* [0x8c] */ + uint32_t bar5_mask_lsb; + /* [0x90] */ + uint32_t bar5_mask_msb; + /* [0x94] */ + uint32_t bar5_limit_lsb; + /* [0x98] */ + uint32_t bar5_limit_msb; + /* [0x9c] */ + uint32_t bar5_start_lsb; + /* [0xa0] */ + uint32_t bar5_start_msb; + /* [0xa4] */ + uint32_t bar5_ctrl; + uint32_t rsrvd[2]; +}; + +struct al_pcie_revx_w_debug { + /* [0x0] */ + uint32_t info_0; + /* [0x4] */ + uint32_t info_1; + /* [0x8] */ + uint32_t info_2; + /* [0xc] */ + uint32_t info_3; +}; +struct al_pcie_revx_w_ob_ven_msg { + /* [0x0] */ + uint32_t control; + /* [0x4] */ + uint32_t param_1; + /* [0x8] */ + uint32_t param_2; + /* [0xc] */ + uint32_t data_high; + uint32_t rsrvd_0; + /* [0x14] */ + uint32_t data_low; +}; +struct al_pcie_revx_w_ap_user_send_msg { + /* [0x0] */ + uint32_t req_info; + /* [0x4] */ + uint32_t ack_info; +}; +struct al_pcie_revx_w_link_down { + /* [0x0] */ + uint32_t reset_delay; + /* [0x4] */ + uint32_t reset_extend_rsrvd; +}; +struct al_pcie_revx_w_cntl_gen { + /* [0x0] */ + uint32_t features; +}; +struct al_pcie_revx_w_parity { + /* [0x0] */ + uint32_t en_core; + /* [0x4] */ + uint32_t status_core; +}; +struct al_pcie_revx_w_last_wr { + /* [0x0] */ + uint32_t cfg_addr; +}; +struct al_pcie_rev1_2_w_atu { + /* [0x0] */ + uint32_t in_mask_pair[6]; + /* [0x18] */ + uint32_t out_mask_pair[6]; +}; +struct al_pcie_rev3_w_atu { + /* [0x0] */ + uint32_t in_mask_pair[12]; + /* [0x30] */ + uint32_t out_mask_pair[8]; + /* [0x50] */ + uint32_t reg_out_mask; + uint32_t rsrvd[11]; +}; +struct al_pcie_rev3_w_cfg_func_ext { + /* [0x0] */ + uint32_t cfg; +}; +struct al_pcie_rev3_w_app_hdr_interface_send { + /* [0x0] */ + uint32_t app_hdr_31_0; + /* [0x4] */ + uint32_t app_hdr_63_32; + /* [0x8] */ + uint32_t app_hdr_95_64; + /* [0xc] */ + uint32_t app_hdr_127_96; + /* [0x10] */ + uint32_t app_err_bus; + /* [0x14] */ + uint32_t app_func_num_advisory; + /* [0x18] */ + uint32_t app_hdr_cmd; +}; +struct al_pcie_rev3_w_diag_command { + /* [0x0] */ + uint32_t diag_ctrl; +}; +struct al_pcie_rev1_w_soc_int { + /* [0x0] */ + uint32_t status_0; + /* [0x4] */ + uint32_t status_1; + /* [0x8] */ + uint32_t status_2; + /* [0xc] */ + uint32_t mask_inta_leg_0; + /* [0x10] */ + uint32_t mask_inta_leg_1; + /* [0x14] */ + uint32_t mask_inta_leg_2; + /* [0x18] */ + uint32_t mask_msi_leg_0; + /* [0x1c] */ + uint32_t mask_msi_leg_1; + /* [0x20] */ + uint32_t mask_msi_leg_2; + /* [0x24] */ + uint32_t msi_leg_cntl; +}; +struct al_pcie_rev2_w_soc_int { + /* [0x0] */ + uint32_t status_0; + /* [0x4] */ + uint32_t status_1; + /* [0x8] */ + uint32_t status_2; + /* [0xc] */ + uint32_t status_3; + /* [0x10] */ + uint32_t mask_inta_leg_0; + /* [0x14] */ + uint32_t mask_inta_leg_1; + /* [0x18] */ + uint32_t mask_inta_leg_2; + /* [0x1c] */ + uint32_t mask_inta_leg_3; + /* [0x20] */ + uint32_t mask_msi_leg_0; + /* [0x24] */ + uint32_t mask_msi_leg_1; + /* [0x28] */ + uint32_t mask_msi_leg_2; + /* [0x2c] */ + uint32_t mask_msi_leg_3; + /* [0x30] */ + uint32_t msi_leg_cntl; +}; +struct al_pcie_rev3_w_soc_int_per_func { + /* [0x0] */ + uint32_t status_0; + /* [0x4] */ + uint32_t status_1; + /* [0x8] */ + uint32_t status_2; + /* [0xc] */ + uint32_t status_3; + /* [0x10] */ + uint32_t mask_inta_leg_0; + /* [0x14] */ + uint32_t mask_inta_leg_1; + /* [0x18] */ + uint32_t mask_inta_leg_2; + /* [0x1c] */ + uint32_t mask_inta_leg_3; + /* [0x20] */ + uint32_t mask_msi_leg_0; + /* [0x24] */ + uint32_t mask_msi_leg_1; + /* [0x28] */ + uint32_t mask_msi_leg_2; + /* [0x2c] */ + uint32_t mask_msi_leg_3; + /* [0x30] */ + uint32_t msi_leg_cntl; +}; + +struct al_pcie_revx_w_ap_err { + /* + * [0x0] latch the header in case of any error occur in the core, read + * on clear of the last register in the bind. + */ + uint32_t hdr_log; +}; +struct al_pcie_revx_w_status_per_func { + /* + * [0x0] latch the header in case of any error occure in the core, read + * on clear of the last register in the bind. + */ + uint32_t status_per_func; +}; +struct al_pcie_revx_w_int_grp { + /* + * [0x0] Interrupt Cause Register + * Set by hardware + * - If MSI-X is enabled and auto_clear control bit =TRUE, automatically + * cleared after MSI-X message associated with this specific interrupt + * bit is sent (MSI-X acknowledge is received). + * - Software can set a bit in this register by writing 1 to the + * associated bit in the Interrupt Cause Set register + * Write-0 clears a bit. Write-1 has no effect. + * - On CPU Read - If clear_on_read control bit =TRUE, automatically + * cleared (all bits are cleared). + * When there is a conflict and on the same clock cycle, hardware tries + * to set a bit in the Interrupt Cause register, the specific bit is set + * to ensure the interrupt indication is not lost. + */ + uint32_t cause; + uint32_t rsrvd_0; + /* + * [0x8] Interrupt Cause Set Register + * Writing 1 to a bit in this register sets its corresponding cause bit, + * enabling software to generate a hardware interrupt. Write 0 has no + * effect. + */ + uint32_t cause_set; + uint32_t rsrvd_1; + /* + * [0x10] Interrupt Mask Register + * If Auto-mask control bit =TRUE, automatically set to 1 after MSI-X + * message associatd with the associated interrupt bit is sent (AXI + * write acknowledge is received). + */ + uint32_t mask; + uint32_t rsrvd_2; + /* + * [0x18] Interrupt Mask Clear Register + * Used when auto-mask control bit=True. Enables CPU to clear a specific + * bit. It prevents a scenario in which the CPU overrides another bit + * with 1 (old value) that hardware has just cleared to 0. + * Write 0 to this register clears its corresponding mask bit. Write 1 + * has no effect. + */ + uint32_t mask_clear; + uint32_t rsrvd_3; + /* + * [0x20] Interrupt Status Register + * This register latches the status of the interrupt source. + */ + uint32_t status; + uint32_t rsrvd_4; + /* [0x28] Interrupt Control Register */ + uint32_t control; + uint32_t rsrvd_5; + /* + * [0x30] Interrupt Mask Register + * Each bit in this register masks the corresponding cause bit for + * generating an Abort signal. Its default value is determined by unit + * instantiation. + * (Abort = Wire-OR of Cause & !Interrupt_Abort_Mask) + * This register provides error handling configuration for error + * interrupts + */ + uint32_t abort_mask; + uint32_t rsrvd_6; + /* + * [0x38] Interrupt Log Register + * Each bit in this register masks the corresponding cause bit for + * capturing the log registers. Its default value is determined by unit + * instantiation. + * (Log_capture = Wire-OR of Cause & !Interrupt_Log_Mask) + * This register provides error handling configuration for error + * interrupts. + */ + uint32_t log_mask; + uint32_t rsrvd; +}; + +struct al_pcie_rev1_w_regs { + struct al_pcie_rev1_w_global_ctrl global_ctrl; /* [0x0] */ + uint32_t rsrvd_0[24]; + struct al_pcie_revx_w_debug debug; /* [0x80] */ + struct al_pcie_revx_w_ob_ven_msg ob_ven_msg; /* [0x90] */ + uint32_t rsrvd_1[86]; + struct al_pcie_rev1_w_soc_int soc_int; /* [0x200] */ + struct al_pcie_revx_w_link_down link_down; /* [0x228] */ + struct al_pcie_revx_w_cntl_gen ctrl_gen; /* [0x230] */ + struct al_pcie_revx_w_parity parity; /* [0x234] */ + struct al_pcie_revx_w_last_wr last_wr; /* [0x23c] */ + struct al_pcie_rev1_2_w_atu atu; /* [0x240] */ + uint32_t rsrvd_2[36]; + struct al_pcie_revx_w_int_grp int_grp_a_m0; /* [0x300] */ + struct al_pcie_revx_w_int_grp int_grp_b_m0; /* [0x340] */ + uint32_t rsrvd_3[32]; + struct al_pcie_revx_w_int_grp int_grp_a; /* [0x400] */ + struct al_pcie_revx_w_int_grp int_grp_b; /* [0x440] */ +}; + +struct al_pcie_rev2_w_regs { + struct al_pcie_rev2_w_global_ctrl global_ctrl; /* [0x0] */ + uint32_t rsrvd_0[24]; + struct al_pcie_revx_w_debug debug; /* [0x80] */ + struct al_pcie_revx_w_ob_ven_msg ob_ven_msg; /* [0x90] */ + struct al_pcie_revx_w_ap_user_send_msg ap_user_send_msg; /* [0xa8] */ + uint32_t rsrvd_1[20]; + struct al_pcie_rev2_w_soc_int soc_int; /* [0x100] */ + uint32_t rsrvd_2[61]; + struct al_pcie_revx_w_link_down link_down; /* [0x228] */ + struct al_pcie_revx_w_cntl_gen ctrl_gen; /* [0x230] */ + struct al_pcie_revx_w_parity parity; /* [0x234] */ + struct al_pcie_revx_w_last_wr last_wr; /* [0x23c] */ + struct al_pcie_rev1_2_w_atu atu; /* [0x240] */ + uint32_t rsrvd_3[6]; + struct al_pcie_revx_w_ap_err ap_err[4]; /* [0x288] */ + uint32_t rsrvd_4[26]; + struct al_pcie_revx_w_status_per_func status_per_func; /* [0x300] */ + uint32_t rsrvd_5[63]; + struct al_pcie_revx_w_int_grp int_grp_a; /* [0x400] */ + struct al_pcie_revx_w_int_grp int_grp_b; /* [0x440] */ +}; + +struct al_pcie_rev3_w_regs { + struct al_pcie_rev3_w_global_ctrl global_ctrl; /* [0x0] */ + uint32_t rsrvd_0[24]; + struct al_pcie_revx_w_debug debug; /* [0x80] */ + struct al_pcie_revx_w_ob_ven_msg ob_ven_msg; /* [0x90] */ + struct al_pcie_revx_w_ap_user_send_msg ap_user_send_msg; /* [0xa8] */ + uint32_t rsrvd_1[94]; + struct al_pcie_revx_w_link_down link_down; /* [0x228] */ + struct al_pcie_revx_w_cntl_gen ctrl_gen; /* [0x230] */ + struct al_pcie_revx_w_parity parity; /* [0x234] */ + struct al_pcie_revx_w_last_wr last_wr; /* [0x23c] */ + struct al_pcie_rev3_w_atu atu; /* [0x240] */ + uint32_t rsrvd_2[8]; + struct al_pcie_rev3_w_cfg_func_ext cfg_func_ext; /* [0x2e0] */ + struct al_pcie_rev3_w_app_hdr_interface_send app_hdr_interface_send;/* [0x2e4] */ + struct al_pcie_rev3_w_diag_command diag_command; /* [0x300] */ + uint32_t rsrvd_3[3]; + struct al_pcie_rev3_w_soc_int_per_func soc_int_per_func[REV3_MAX_NUM_OF_PFS]; /* [0x310] */ + uint32_t rsrvd_4[44]; + struct al_pcie_rev3_w_events_gen_per_func events_gen_per_func[REV3_MAX_NUM_OF_PFS]; /* [0x490] */ + uint32_t rsrvd_5[4]; + struct al_pcie_rev3_w_pm_state_per_func pm_state_per_func[REV3_MAX_NUM_OF_PFS];/* [0x4b0] */ + uint32_t rsrvd_6[16]; + struct al_pcie_rev3_w_cfg_bars_ovrd cfg_bars_ovrd[REV3_MAX_NUM_OF_PFS]; /* [0x500] */ + uint32_t rsrvd_7[176]; + uint32_t rsrvd_8[16]; + struct al_pcie_revx_w_ap_err ap_err[5]; /* [0xac0] */ + uint32_t rsrvd_9[11]; + struct al_pcie_revx_w_status_per_func status_per_func[4]; /* [0xb00] */ + uint32_t rsrvd_10[316]; + struct al_pcie_revx_w_int_grp int_grp_a; /* [0x1000] */ + struct al_pcie_revx_w_int_grp int_grp_b; /* [0x1040] */ + struct al_pcie_revx_w_int_grp int_grp_c; /* [0x1080] */ + struct al_pcie_revx_w_int_grp int_grp_d; /* [0x10c0] */ +}; + +/* +* Registers Fields +*/ + + +/**** Port_Init register ****/ +/* Enable port to start LTSSM Link Training */ +#define PCIE_W_GLOBAL_CTRL_PORT_INIT_APP_LTSSM_EN_MASK (1 << 0) +#define PCIE_W_GLOBAL_CTRL_PORT_INIT_APP_LTSSM_EN_SHIFT (0) +/* + * Device Type + * Indicates the specific type of this PCIe Function. It is also used to set the + * Device/Port Type field. + * 4'b0000: PCIe Endpoint + * 4'b0001: Legacy PCIe Endpoint + * 4'b0100: Root Port of PCIe Root Complex + * Must be programmed before link training sequence. According to the reset + * strap + */ +#define PCIE_W_GLOBAL_CTRL_PORT_INIT_DEVICE_TYPE_MASK 0x000000F0 +#define PCIE_W_GLOBAL_CTRL_PORT_INIT_DEVICE_TYPE_SHIFT 4 +/* + * Performs Manual Lane reversal for transmit Lanes. + * Must be programmed before link training sequence. + */ +#define PCIE_W_GLOBAL_CTRL_PORT_INIT_TX_LANE_FLIP_EN (1 << 8) +/* + * Performs Manual Lane reversal for receive Lanes. + * Must be programmed before link training sequence. + */ +#define PCIE_W_GLOBAL_CTRL_PORT_INIT_RX_LANE_FLIP_EN (1 << 9) +/* + * Auxiliary Power Detected + * Indicates that auxiliary power (Vaux) is present. This one move to reset + * strap from + */ +#define PCIE_W_GLOBAL_CTRL_PORT_INIT_SYS_AUX_PWR_DET_NOT_USE (1 << 10) + +/**** Port_Status register ****/ +/* PHY Link up/down indicator */ +#define PCIE_W_GLOBAL_CTRL_PORT_STS_PHY_LINK_UP (1 << 0) +/* + * Data Link Layer up/down indicator + * This status from the Flow Control Initialization State Machine indicates that + * Flow Control has been initiated and the Data Link Layer is ready to transmit + * and receive packets. + */ +#define PCIE_W_GLOBAL_CTRL_PORT_STS_DL_LINK_UP (1 << 1) +/* Reset request due to link down status. */ +#define PCIE_W_GLOBAL_CTRL_PORT_STS_LINK_REQ_RST (1 << 2) +/* Power management is in L0s state.. */ +#define PCIE_W_GLOBAL_CTRL_PORT_STS_PM_LINKST_IN_L0S (1 << 3) +/* Power management is in L1 state. */ +#define PCIE_W_GLOBAL_CTRL_PORT_STS_PM_LINKST_IN_L1 (1 << 4) +/* Power management is in L2 state. */ +#define PCIE_W_GLOBAL_CTRL_PORT_STS_PM_LINKST_IN_L2 (1 << 5) +/* Power management is exiting L2 state. */ +#define PCIE_W_GLOBAL_CTRL_PORT_STS_PM_LINKST_L2_EXIT (1 << 6) +/* Power state of the device. */ +#define PCIE_W_GLOBAL_CTRL_PORT_STS_PM_DSTATE_MASK 0x00000380 +#define PCIE_W_GLOBAL_CTRL_PORT_STS_PM_DSTATE_SHIFT 7 +/* tie to zero. */ +#define PCIE_W_GLOBAL_CTRL_PORT_STS_XMLH_IN_RL0S (1 << 10) +/* Timeout count before flush */ +#define PCIE_W_GLOBAL_CTRL_PORT_STS_LINK_TOUT_FLUSH_NOT (1 << 11) +/* Segmentation buffer not empty */ +#define PCIE_W_GLOBAL_CTRL_PORT_STS_RADM_Q_NOT_EMPTY (1 << 12) +/* + * Clock Turnoff Request + * Allows clock generation module to turn off core_clk based on the current + * power management state: + * 0: core_clk is required to be active for the current power state. + * 1: The current power state allows core_clk to be shut down. + * This does not indicate the clock requirement for the PHY. + */ +#define PCIE_W_GLOBAL_CTRL_PORT_STS_CORE_CLK_REQ_N (1 << 31) + +/**** PM_Control register ****/ +/* + * Wake Up. Used by application logic to wake up the PMC state machine from a + * D1, D2, or D3 power state. EP mode only. Change the value from 0 to 1 to send + * the message. Per function the upper bits are not use for ocie core less than + * 8 functions + */ +#define PCIE_W_REV1_2_GLOBAL_CTRL_PM_CONTROL_PM_XMT_PME (1 << 0) +#define PCIE_W_REV3_GLOBAL_CTRL_PM_CONTROL_PM_XMT_PME_FUNC_MASK 0x000000FF +#define PCIE_W_REV3_GLOBAL_CTRL_PM_CONTROL_PM_XMT_PME_FUNC_SHIFT 0 +/* + * Request to Enter ASPM L1. + * The core ignores the L1 entry request on app_req_entr_l1 when it is busy + * processing a transaction. + */ +#define PCIE_W_REV1_2_GLOBAL_CTRL_PM_CONTROL_REQ_ENTR_L1 (1 << 3) +#define PCIE_W_REV3_GLOBAL_CTRL_PM_CONTROL_REQ_ENTR_L1 (1 << 8) +/* + * Request to exit ASPM L1. + * Only effective if L1 is enabled. + */ +#define PCIE_W_REV1_2_GLOBAL_CTRL_PM_CONTROL_REQ_EXIT_L1 (1 << 4) +#define PCIE_W_REV3_GLOBAL_CTRL_PM_CONTROL_REQ_EXIT_L1 (1 << 9) +/* + * Indication that component is ready to enter the L23 state. The core delays + * sending PM_Enter_L23 (in response to PM_Turn_Off) until this signal becomes + * active. + * EP mode + */ +#define PCIE_W_REV1_2_GLOBAL_CTRL_PM_CONTROL_READY_ENTR_L23 (1 << 5) +#define PCIE_W_REV3_GLOBAL_CTRL_PM_CONTROL_READY_ENTR_L23 (1 << 10) +/* + * Request to generate a PM_Turn_Off Message to communicate transition to L2/L3 + * Ready state to downstream components. Host must wait PM_Turn_Off_Ack messages + * acceptance RC mode. + */ +#define PCIE_W_REV1_2_GLOBAL_CTRL_PM_CONTROL_PM_XMT_TURNOFF (1 << 6) +#define PCIE_W_REV3_GLOBAL_CTRL_PM_CONTROL_PM_XMT_TURNOFF (1 << 11) +/* + * Provides a capability to defer incoming Configuration Requests until + * initialization is complete. When app_req_retry_en is asserted, the core + * completes incoming Configuration Requests with a Configuration Request Retry + * Status. Other incoming Requests complete with Unsupported Request status. + */ +#define PCIE_W_REV1_2_GLOBAL_CTRL_PM_CONTROL_APP_REQ_RETRY_EN (1 << 7) +#define PCIE_W_REV3_GLOBAL_CTRL_PM_CONTROL_APP_REQ_RETRY_EN (1 << 12) +/* + * Core core gate enable + * If set, core_clk is gated off whenever a clock turnoff request allows the + * clock generation module to turn off core_clk (Port_Status.core_clk_req_n + * field), and the PHY supports a request to disable clock gating. If not, the + * core clock turns off in P2 mode in any case (PIPE). + */ +#define PCIE_W_GLOBAL_CTRL_PM_CONTROL_CORE_CLK_GATE (1 << 31) + +/**** sris_kp_counter_value register ****/ +/* skp counter when SRIS disable */ +#define PCIE_W_GLOBAL_CTRL_SRIS_KP_COUNTER_VALUE_GEN3_NO_SRIS_MASK 0x000001FF +#define PCIE_W_GLOBAL_CTRL_SRIS_KP_COUNTER_VALUE_GEN3_NO_SRIS_SHIFT 0 +/* skp counter when SRIS enable */ +#define PCIE_W_GLOBAL_CTRL_SRIS_KP_COUNTER_VALUE_GEN3_SRIS_MASK 0x0003FE00 +#define PCIE_W_GLOBAL_CTRL_SRIS_KP_COUNTER_VALUE_GEN3_SRIS_SHIFT 9 +/* skp counter when SRIS enable for gen3 */ +#define PCIE_W_GLOBAL_CTRL_SRIS_KP_COUNTER_VALUE_GEN21_SRIS_MASK 0x1FFC0000 +#define PCIE_W_GLOBAL_CTRL_SRIS_KP_COUNTER_VALUE_GEN21_SRIS_SHIFT 18 +/* mask the interrupt to the soc in case correctable error occur in the ARI. */ +#define PCIE_W_GLOBAL_CTRL_SRIS_KP_COUNTER_VALUE_RSRVD_MASK 0x60000000 +#define PCIE_W_GLOBAL_CTRL_SRIS_KP_COUNTER_VALUE_RSRVD_SHIFT 29 +/* not in use in the pcie_x8 core. */ +#define PCIE_W_GLOBAL_CTRL_SRIS_KP_COUNTER_VALUE_PCIE_X4_SRIS_EN (1 << 31) + +/**** Events_Gen register ****/ +/* INT_D. Not supported */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_ASSERT_INTD (1 << 0) +/* INT_C. Not supported */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_ASSERT_INTC (1 << 1) +/* INT_B. Not supported */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_ASSERT_INTB (1 << 2) +/* Transmit INT_A Interrupt ControlEvery transition from 0 to 1 ... */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_ASSERT_INTA (1 << 3) +/* A request to generate an outbound MSI interrupt when MSI is e ... */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_MSI_TRNS_REQ (1 << 4) +/* Set the MSI vector before issuing msi_trans_req. */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_MSI_VECTOR_MASK 0x000003E0 +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_MSI_VECTOR_SHIFT 5 +/* The application requests hot reset to a downstream device */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_APP_RST_INIT (1 << 10) +/* The application request unlock message to be sent */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_UNLOCK_GEN (1 << 30) +/* Indicates that FLR on a Physical Function has been completed */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_FLR_PF_DONE (1 << 31) + +/**** Cpl_TO_Info register ****/ +/* The Traffic Class of the timed out CPL */ +#define PCIE_W_LCL_LOG_CPL_TO_INFO_TC_MASK 0x00000003 +#define PCIE_W_LCL_LOG_CPL_TO_INFO_TC_SHIFT 0 +/* Indicates which Virtual Function (VF) had a CPL timeout */ +#define PCIE_W_LCL_LOG_CPL_TO_INFO_FUN_NUM_MASK 0x000000FC +#define PCIE_W_LCL_LOG_CPL_TO_INFO_FUN_NUM_SHIFT 2 +/* The Tag field of the timed out CPL */ +#define PCIE_W_LCL_LOG_CPL_TO_INFO_TAG_MASK 0x0000FF00 +#define PCIE_W_LCL_LOG_CPL_TO_INFO_TAG_SHIFT 8 +/* The Attributes field of the timed out CPL */ +#define PCIE_W_LCL_LOG_CPL_TO_INFO_ATTR_MASK 0x00030000 +#define PCIE_W_LCL_LOG_CPL_TO_INFO_ATTR_SHIFT 16 +/* The Len field of the timed out CPL */ +#define PCIE_W_LCL_LOG_CPL_TO_INFO_LEN_MASK 0x3FFC0000 +#define PCIE_W_LCL_LOG_CPL_TO_INFO_LEN_SHIFT 18 +/* + * Write 1 to this field to clear the information logged in the register. New + * logged information will only be valid when the interrupt is cleared . + */ +#define PCIE_W_LCL_LOG_CPL_TO_INFO_VALID (1 << 31) +#define PCIE_W_LCL_LOG_CPL_TO_INFO_VALID_SHIFT (31) + +/**** Rcv_Msg0_0 register ****/ +/* The Requester ID of the received message */ +#define PCIE_W_LCL_LOG_RCV_MSG0_0_REQ_ID_MASK 0x0000FFFF +#define PCIE_W_LCL_LOG_RCV_MSG0_0_REQ_ID_SHIFT 0 +/* + * Valid logged message + * Writing 1 to this bit enables new message capturing. Write one to clear + */ +#define PCIE_W_LCL_LOG_RCV_MSG0_0_VALID (1 << 31) + +/**** Rcv_Msg1_0 register ****/ +/* The Requester ID of the received message */ +#define PCIE_W_LCL_LOG_RCV_MSG1_0_REQ_ID_MASK 0x0000FFFF +#define PCIE_W_LCL_LOG_RCV_MSG1_0_REQ_ID_SHIFT 0 +/* + * Valid logged message + * Writing 1 to this bit enables new message capturing. Write one to clear + */ +#define PCIE_W_LCL_LOG_RCV_MSG1_0_VALID (1 << 31) + +/**** Core_Queues_Status register ****/ +/* + * Indicates which entries in the CPL lookup table + * have valid entries stored. NOT supported. + */ +#define PCIE_W_LCL_LOG_CORE_Q_STATUS_CPL_LUT_VALID_MASK 0x0000FFFF +#define PCIE_W_LCL_LOG_CORE_Q_STATUS_CPL_LUT_VALID_SHIFT 0 + +/**** Cpl_to register ****/ +#define PCIE_W_LCL_LOG_CPL_TO_REQID_MASK 0x0000FFFF +#define PCIE_W_LCL_LOG_CPL_TO_REQID_SHIFT 0 + +/**** Debug_Info_0 register ****/ +/* Indicates the current power state */ +#define PCIE_W_DEBUG_INFO_0_PM_CURRENT_STATE_MASK 0x00000007 +#define PCIE_W_DEBUG_INFO_0_PM_CURRENT_STATE_SHIFT 0 +/* Current state of the LTSSM */ +#define PCIE_W_DEBUG_INFO_0_LTSSM_STATE_MASK 0x000001F8 +#define PCIE_W_DEBUG_INFO_0_LTSSM_STATE_SHIFT 3 +/* Decode of the Recovery. Equalization LTSSM state */ +#define PCIE_W_DEBUG_INFO_0_LTSSM_STATE_RCVRY_EQ (1 << 9) +/* State of selected internal signals, for debug purposes only */ +#define PCIE_W_DEBUG_INFO_0_CXPL_DEBUG_INFO_EI_MASK 0x03FFFC00 +#define PCIE_W_DEBUG_INFO_0_CXPL_DEBUG_INFO_EI_SHIFT 10 + +/**** control register ****/ +/* Indication to send vendor message; when clear the message was sent. */ +#define PCIE_W_OB_VEN_MSG_CONTROL_REQ (1 << 0) + +/**** param_1 register ****/ +/* Vendor message parameters */ +#define PCIE_W_OB_VEN_MSG_PARAM_1_FMT_MASK 0x00000003 +#define PCIE_W_OB_VEN_MSG_PARAM_1_FMT_SHIFT 0 +/* Vendor message parameters */ +#define PCIE_W_OB_VEN_MSG_PARAM_1_TYPE_MASK 0x0000007C +#define PCIE_W_OB_VEN_MSG_PARAM_1_TYPE_SHIFT 2 +/* Vendor message parameters */ +#define PCIE_W_OB_VEN_MSG_PARAM_1_TC_MASK 0x00000380 +#define PCIE_W_OB_VEN_MSG_PARAM_1_TC_SHIFT 7 +/* Vendor message parameters */ +#define PCIE_W_OB_VEN_MSG_PARAM_1_TD (1 << 10) +/* Vendor message parameters */ +#define PCIE_W_OB_VEN_MSG_PARAM_1_EP (1 << 11) +/* Vendor message parameters */ +#define PCIE_W_OB_VEN_MSG_PARAM_1_ATTR_MASK 0x00003000 +#define PCIE_W_OB_VEN_MSG_PARAM_1_ATTR_SHIFT 12 +/* Vendor message parameters */ +#define PCIE_W_OB_VEN_MSG_PARAM_1_LEN_MASK 0x00FFC000 +#define PCIE_W_OB_VEN_MSG_PARAM_1_LEN_SHIFT 14 +/* Vendor message parameters */ +#define PCIE_W_OB_VEN_MSG_PARAM_1_TAG_MASK 0xFF000000 +#define PCIE_W_OB_VEN_MSG_PARAM_1_TAG_SHIFT 24 + +/**** param_2 register ****/ +/* Vendor message parameters */ +#define PCIE_W_OB_VEN_MSG_PARAM_2_REQ_ID_MASK 0x0000FFFF +#define PCIE_W_OB_VEN_MSG_PARAM_2_REQ_ID_SHIFT 0 +/* Vendor message parameters */ +#define PCIE_W_OB_VEN_MSG_PARAM_2_CODE_MASK 0x00FF0000 +#define PCIE_W_OB_VEN_MSG_PARAM_2_CODE_SHIFT 16 +/* Vendor message parameters */ +#define PCIE_W_OB_VEN_MSG_PARAM_2_RSVD_31_24_MASK 0xFF000000 +#define PCIE_W_OB_VEN_MSG_PARAM_2_RSVD_31_24_SHIFT 24 + +/**** ack_info register ****/ +/* Vendor message parameters */ +#define PCIE_W_AP_USER_SEND_MSG_ACK_INFO_ACK (1 << 0) + +/**** features register ****/ +/* Enable MSI fix from the SATA to the PCIe EP - Only valid for port zero */ +#define PCIE_W_CTRL_GEN_FEATURES_SATA_EP_MSI_FIX AL_BIT(16) + +/**** in/out_mask_x_y register ****/ +/* When bit [i] set to 1 it maks the compare in the atu_in/out wind ... */ +#define PCIE_W_ATU_MASK_EVEN_ODD_ATU_MASK_40_32_EVEN_MASK 0x0000FFFF +#define PCIE_W_ATU_MASK_EVEN_ODD_ATU_MASK_40_32_EVEN_SHIFT 0 +/* When bit [i] set to 1 it maks the compare in the atu_in/out wind ... */ +#define PCIE_W_ATU_MASK_EVEN_ODD_ATU_MASK_40_32_ODD_MASK 0xFFFF0000 +#define PCIE_W_ATU_MASK_EVEN_ODD_ATU_MASK_40_32_ODD_SHIFT 16 + +/**** cfg register ****/ +/* + * The 2-bit TPH Requester Enabled field of each TPH + * Requester Control register. + */ +#define PCIE_W_CFG_FUNC_EXT_CFG_CFG_TPH_REQ_EN_MASK 0x000000FF +#define PCIE_W_CFG_FUNC_EXT_CFG_CFG_TPH_REQ_EN_SHIFT 0 +/* SRIS mode enable. */ +#define PCIE_W_CFG_FUNC_EXT_CFG_APP_SRIS_MODE (1 << 8) +/* + * + */ +#define PCIE_W_CFG_FUNC_EXT_CFG_RSRVD_MASK 0xFFFFFE00 +#define PCIE_W_CFG_FUNC_EXT_CFG_RSRVD_SHIFT 9 + +/**** app_func_num_advisory register ****/ +/* + * The number of the function that is reporting the error + * indicated app_err_bus, valid when app_hdr_valid is asserted. + * Correctable and Uncorrected Internal errors (app_err_bus[10:9]) are + * not function specific, and are recorded for all physical functions, + * regardless of the value this bus. Function numbering starts at '0'. + */ +#define PCIE_W_APP_HDR_INTERFACE_SEND_APP_FUNC_NUM_ADVISORY_APP_ERR_FUNC_NUM_MASK 0x0000FFFF +#define PCIE_W_APP_HDR_INTERFACE_SEND_APP_FUNC_NUM_ADVISORY_APP_ERR_FUNC_NUM_SHIFT 0 +/* + * Description: Indicates that your application error is an advisory + * error. Your application should assert app_err_advisory under either + * of the following conditions: + * - The core is configured to mask completion timeout errors, your + * application is reporting a completion timeout error app_err_bus, + * and your application intends to resend the request. In such cases + * the error is an advisory error, as described in PCI Express 3.0 + * Specification. When your application does not intend to resend + * the request, then your application must keep app_err_advisory + * de-asserted when reporting a completion timeout error. + * - The core is configured to forward poisoned TLPs to your + * application and your application is going to treat the poisoned + * TLP as a normal TLP, as described in PCI Express 3.0 + * Specification. Upon receipt of a poisoned TLP, your application + * must report the error app_err_bus, and either assert + * app_err_advisory (to indicate an advisory error) or de-assert + * app_err_advisory (to indicate that your application is dropping the + * TLP). + * For more details, see the PCI Express 3.0 Specification to determine + * when an application error is an advisory error. + */ +#define PCIE_W_APP_HDR_INTERFACE_SEND_APP_FUNC_NUM_ADVISORY_APP_ERR_ADVISORY (1 << 16) +/* + * Rsrvd. + */ +#define PCIE_W_APP_HDR_INTERFACE_SEND_APP_FUNC_NUM_ADVISORY_RSRVD_MASK 0xFFFE0000 +#define PCIE_W_APP_HDR_INTERFACE_SEND_APP_FUNC_NUM_ADVISORY_RSRVD_SHIFT 17 + +/**** app_hdr_cmd register ****/ +/* + * When set the header is send (need to clear before sending the next message). + */ +#define PCIE_W_APP_HDR_INTERFACE_SEND_APP_HDR_CMD_APP_HDR_VALID (1 << 0) +/* + * Rsrvd. + */ +#define PCIE_W_APP_HDR_INTERFACE_SEND_APP_HDR_CMD_RSRVD_MASK 0xFFFFFFFE +#define PCIE_W_APP_HDR_INTERFACE_SEND_APP_HDR_CMD_RSRVD_SHIFT 1 + +/**** diag_ctrl register ****/ +/* + * The 2-bit TPH Requester Enabled field of each TPH + * Requester Control register. + */ +#define PCIE_W_DIAG_COMMAND_DIAG_CTRL_DIAG_CTRL_BUS_MASK 0x00000007 +#define PCIE_W_DIAG_COMMAND_DIAG_CTRL_DIAG_CTRL_BUS_SHIFT 0 +/* + * + */ +#define PCIE_W_DIAG_COMMAND_DIAG_CTRL_RSRVD_MASK 0xFFFFFFF8 +#define PCIE_W_DIAG_COMMAND_DIAG_CTRL_RSRVD_SHIFT 3 + + +/**** Events_Gen register ****/ +/* INT_D. Not supported */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_ASSERT_INTD (1 << 0) +/* INT_C. Not supported */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_ASSERT_INTC (1 << 1) +/* INT_B. Not supported */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_ASSERT_INTB (1 << 2) +/* + * Transmit INT_A Interrupt Control + * Every transition from 0 to 1 schedules an Assert_ INT interrupt message for + * transmit. + * Every transition from 1 to 0, schedules a Deassert_INT interrupt message for + * transmit. Which interrupt, the PCIe only use INTA message. + */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_ASSERT_INTA (1 << 3) +/* + * A request to generate an outbound MSI interrupt when MSI is enabled. Change + * from 1'b0 to 1'b1 to create an MSI write to be sent. + */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_MSI_TRNS_REQ (1 << 4) +/* Set the MSI vector before issuing msi_trans_req. */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_MSI_VECTOR_MASK 0x000003E0 +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_MSI_VECTOR_SHIFT 5 +/* + * The application requests hot reset to a downstream device. Change the value + * from 0 to 1 to send hot reset. Only func 0 is supported. + */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_APP_RST_INIT (1 << 10) +/* + * The application request unlock message to be sent. Change the value from 0 to + * 1 to send the message. Only func 0 is supported. + */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_UNLOCK_GEN (1 << 30) +/* Indicates that FLR on a Physical Function has been completed. */ +#define PCIE_W_GLOBAL_CTRL_EVENTS_GEN_FLR_PF_DONE (1 << 31) + +/**** pm_state_per_func register ****/ +/* + * Description: The current power management D-state of the + * function: + * \u25a0 000b: D0 + * \u25a0 001b: D1 + * \u25a0 010b: D2 + * \u25a0 011b: D3 + * \u25a0 100b: Uninitialized + * \u25a0 Other values: Not applicable + * There are 3 bits of pm_dstate for each configured function. + */ +#define PCIE_W_PM_STATE_PER_FUNC_PM_STATE_PER_FUNC_PM_DSTATE_MASK 0x0000000F +#define PCIE_W_PM_STATE_PER_FUNC_PM_STATE_PER_FUNC_PM_DSTATE_SHIFT 0 +/* + * PME Status bit from the PMCSR. There is 1 bit of + * pm_status for each configured function + */ +#define PCIE_W_PM_STATE_PER_FUNC_PM_STATE_PER_FUNC_PM_STATUS (1 << 4) +/* + * PME Enable bit in the PMCSR. There is 1 bit of + * pm_pme_en for each configured function. + */ +#define PCIE_W_PM_STATE_PER_FUNC_PM_STATE_PER_FUNC_PM_PME_EN (1 << 5) +/* + * Auxiliary Power Enable bit in the Device Control + * register. There is 1 bit of aux_pm_en for each configured function. + */ +#define PCIE_W_PM_STATE_PER_FUNC_PM_STATE_PER_FUNC_AUX_PME_EN (1 << 6) +/* + * This field should be set according to the MAX_FUNC_NUM set in the PCIe core, + * it uses as mask (bit per function) to the dsate when set to zero. + */ +#define PCIE_W_PM_STATE_PER_FUNC_PM_STATE_PER_FUNC_ASPM_PF_ENABLE_MAX_FUNC_NUMBER (1 << 7) +/* + * This field should be set according to the MAX_FUNC_NUM set in the PCIe core, + * it uses as mask (bit per function) to the ASPM contrl bit, when set to zero. + */ +#define PCIE_W_PM_STATE_PER_FUNC_PM_STATE_PER_FUNC_DSATE_PF_ENABLE_MAX_FUNC_NUMBER (1 << 8) + +/**** bar0_ctrl register ****/ +/* bar is en and override the internal PF bar. */ +#define PCIE_W_CFG_BARS_OVRD_BAR0_CTRL_BAR_EN_MASK 0x00000003 +#define PCIE_W_CFG_BARS_OVRD_BAR0_CTRL_BAR_EN_SHIFT 0 +/* bar is io */ +#define PCIE_W_CFG_BARS_OVRD_BAR0_CTRL_BAR_IO_MASK 0x0000000C +#define PCIE_W_CFG_BARS_OVRD_BAR0_CTRL_BAR_IO_SHIFT 2 +/* Reserved. */ +#define PCIE_W_CFG_BARS_OVRD_BAR0_CTRL_RSRVS_MASK 0xFFFFFFF0 +#define PCIE_W_CFG_BARS_OVRD_BAR0_CTRL_RSRVS_SHIFT 4 + +/**** bar1_ctrl register ****/ +/* bar is en and override the internal PF bar. */ +#define PCIE_W_CFG_BARS_OVRD_BAR1_CTRL_BAR_EN_MASK 0x00000003 +#define PCIE_W_CFG_BARS_OVRD_BAR1_CTRL_BAR_EN_SHIFT 0 +/* bar is io */ +#define PCIE_W_CFG_BARS_OVRD_BAR1_CTRL_BAR_IO_MASK 0x0000000C +#define PCIE_W_CFG_BARS_OVRD_BAR1_CTRL_BAR_IO_SHIFT 2 +/* Reserved. */ +#define PCIE_W_CFG_BARS_OVRD_BAR1_CTRL_RSRVS_MASK 0xFFFFFFF0 +#define PCIE_W_CFG_BARS_OVRD_BAR1_CTRL_RSRVS_SHIFT 4 + +/**** bar2_ctrl register ****/ +/* bar is en and override the internal PF bar. */ +#define PCIE_W_CFG_BARS_OVRD_BAR2_CTRL_BAR_EN_MASK 0x00000003 +#define PCIE_W_CFG_BARS_OVRD_BAR2_CTRL_BAR_EN_SHIFT 0 +/* bar is io */ +#define PCIE_W_CFG_BARS_OVRD_BAR2_CTRL_BAR_IO_MASK 0x0000000C +#define PCIE_W_CFG_BARS_OVRD_BAR2_CTRL_BAR_IO_SHIFT 2 +/* Reserved. */ +#define PCIE_W_CFG_BARS_OVRD_BAR2_CTRL_RSRVS_MASK 0xFFFFFFF0 +#define PCIE_W_CFG_BARS_OVRD_BAR2_CTRL_RSRVS_SHIFT 4 + +/**** bar3_ctrl register ****/ +/* bar is en and override the internal PF bar. */ +#define PCIE_W_CFG_BARS_OVRD_BAR3_CTRL_BAR_EN_MASK 0x00000003 +#define PCIE_W_CFG_BARS_OVRD_BAR3_CTRL_BAR_EN_SHIFT 0 +/* bar is io */ +#define PCIE_W_CFG_BARS_OVRD_BAR3_CTRL_BAR_IO_MASK 0x0000000C +#define PCIE_W_CFG_BARS_OVRD_BAR3_CTRL_BAR_IO_SHIFT 2 +/* Reserved. */ +#define PCIE_W_CFG_BARS_OVRD_BAR3_CTRL_RSRVS_MASK 0xFFFFFFF0 +#define PCIE_W_CFG_BARS_OVRD_BAR3_CTRL_RSRVS_SHIFT 4 + +/**** bar4_ctrl register ****/ +/* bar is en and override the internal PF bar. */ +#define PCIE_W_CFG_BARS_OVRD_BAR4_CTRL_BAR_EN_MASK 0x00000003 +#define PCIE_W_CFG_BARS_OVRD_BAR4_CTRL_BAR_EN_SHIFT 0 +/* bar is io */ +#define PCIE_W_CFG_BARS_OVRD_BAR4_CTRL_BAR_IO_MASK 0x0000000C +#define PCIE_W_CFG_BARS_OVRD_BAR4_CTRL_BAR_IO_SHIFT 2 +/* Reserved. */ +#define PCIE_W_CFG_BARS_OVRD_BAR4_CTRL_RSRVS_MASK 0xFFFFFFF0 +#define PCIE_W_CFG_BARS_OVRD_BAR4_CTRL_RSRVS_SHIFT 4 + +/**** bar5_ctrl register ****/ +/* bar is en and override the internal PF bar. */ +#define PCIE_W_CFG_BARS_OVRD_BAR5_CTRL_BAR_EN_MASK 0x00000003 +#define PCIE_W_CFG_BARS_OVRD_BAR5_CTRL_BAR_EN_SHIFT 0 +/* bar is io */ +#define PCIE_W_CFG_BARS_OVRD_BAR5_CTRL_BAR_IO_MASK 0x0000000C +#define PCIE_W_CFG_BARS_OVRD_BAR5_CTRL_BAR_IO_SHIFT 2 +/* Reserved. */ +#define PCIE_W_CFG_BARS_OVRD_BAR5_CTRL_RSRVS_MASK 0xFFFFFFF0 +#define PCIE_W_CFG_BARS_OVRD_BAR5_CTRL_RSRVS_SHIFT 4 + +/**** cause_A register ****/ +/* Deassert_INTD received. Write zero to clear this bit. */ +#define PCIE_W_INT_GRP_A_CAUSE_A_DEASSERT_INTD (1 << 0) +/* Deassert_INTC received. Write zero to clear this bit. */ +#define PCIE_W_INT_GRP_A_CAUSE_A_DEASSERT_INTC (1 << 1) +/* Deassert_INTB received. Write zero to clear this bit. */ +#define PCIE_W_INT_GRP_A_CAUSE_A_DEASSERT_INTB (1 << 2) +/* Deassert_INTA received. Write zero to clear this bit. */ +#define PCIE_W_INT_GRP_A_CAUSE_A_DEASSERT_INTA (1 << 3) +/* Assert_INTD received. Write zero to clear this bit. */ +#define PCIE_W_INT_GRP_A_CAUSE_A_ASSERT_INTD (1 << 4) +/* Assert_INTC received. Write zero to clear this bit. */ +#define PCIE_W_INT_GRP_A_CAUSE_A_ASSERT_INTC (1 << 5) +/* Assert_INTC received. Write zero to clear this bit. */ +#define PCIE_W_INT_GRP_A_CAUSE_A_ASSERT_INTB (1 << 6) +/* Assert_INTA received. Write zero to clear this bit. */ +#define PCIE_W_INT_GRP_A_CAUSE_A_ASSERT_INTA (1 << 7) +/* + * MSI Controller Interrupt + * MSI interrupt is being received. Write zero to clear this bit + */ +#define PCIE_W_INT_GRP_A_CAUSE_A_MSI_CNTR_RCV_INT (1 << 8) +/* + * MSI sent grant. Write zero to clear this bit. + */ +#define PCIE_W_INT_GRP_A_CAUSE_A_MSI_TRNS_GNT (1 << 9) +/* + * System error detected + * Indicates if any device in the hierarchy reports any of the following errors + * and the associated enable bit is set in the Root Control register: + * ERR_COR + * ERR_FATAL + * ERR_NONFATAL + * Also asserted when an internal error is detected. Write zero to clear this + * bit. + */ +#define PCIE_W_INT_GRP_A_CAUSE_A_SYS_ERR_RC (1 << 10) +/* + * Set when software initiates FLR on a Physical Function by writing to the + * Initiate FLR register bit of that function Write zero to clear this bit. + */ +#define PCIE_W_REV1_2_INT_GRP_A_CAUSE_A_FLR_PF_ACTIVE (1 << 11) +#define PCIE_W_REV3_INT_GRP_A_CAUSE_A_RSRVD_11 (1 << 11) +/* + * Reported error condition causes a bit to be set in the Root Error Status + * register and the associated error message reporting enable bit is set in the + * Root Error Command Register. Write zero to clear this bit. + */ +#define PCIE_W_REV1_2_INT_GRP_A_CAUSE_A_AER_RC_ERR (1 << 12) +#define PCIE_W_REV3_INT_GRP_A_CAUSE_A_RSRVD_12 (1 << 12) +/* + * The core asserts aer_rc_err_msi when all of the following conditions are + * true: + * - MSI or MSI-X is enabled. + * - A reported error condition causes a bit to be set in the Root Error Status + * register. + * - The associated error message reporting enable bit is set in the Root Error + * Command register Write zero to clear this bit + */ +#define PCIE_W_REV1_2_INT_GRP_A_CAUSE_A_AER_RC_ERR_MSI (1 << 13) +#define PCIE_W_REV3_INT_GRP_A_CAUSE_A_RSRVD_13 (1 << 13) +/* + * Wake Up. Wake up from power management unit. + * The core generates wake to request the system to restore power and clock when + * a beacon has been detected. wake is an active high signal and its rising edge + * should be detected to drive the WAKE# on the connector Write zero to clear + * this bit + */ +#define PCIE_W_INT_GRP_A_CAUSE_A_WAKE (1 << 14) +/* + * The core asserts cfg_pme_int when all of the following conditions are true: + * - INTx Assertion Disable bit in the Command register is 0. + * - PME Interrupt Enable bit in the Root Control register is set to 1. + * - PME Status bit in the Root Status register is set to 1. Write zero to clear + * this bit + */ +#define PCIE_W_REV1_2_INT_GRP_A_CAUSE_A_PME_INT (1 << 15) +#define PCIE_W_REV3_INT_GRP_A_CAUSE_A_RSRVD_15 (1 << 15) +/* + * The core asserts cfg_pme_msi when all of the following conditions are true: + * - MSI or MSI-X is enabled. + * - PME Interrupt Enable bit in the Root Control register is set to 1. + * - PME Status bit in the Root Status register is set to 1. Write zero to clear + * this bit + */ +#define PCIE_W_REV1_2_INT_GRP_A_CAUSE_A_PME_MSI (1 << 16) +#define PCIE_W_REV3_INT_GRP_A_CAUSE_A_RSRVD_16 (1 << 16) +/* + * The core asserts hp_pme when all of the following conditions are true: + * - The PME Enable bit in the Power Management Control and Status register is + * set to 1. + * - Any bit in the Slot Status register transitions from 0 to 1 and the + * associated event notification is enabled in the Slot Control register. Write + * zero to clear this bit + */ +#define PCIE_W_INT_GRP_A_CAUSE_A_HP_PME (1 << 17) +/* + * The core asserts hp_int when all of the following conditions are true: + * - INTx Assertion Disable bit in the Command register is 0. + * - Hot-Plug interrupts are enabled in the Slot Control register. + * - Any bit in the Slot Status register is equal to 1, and the associated event + * notification is enabled in the Slot Control register. Write zero to clear + * this bit + */ +#define PCIE_W_REV1_2_INT_GRP_A_CAUSE_A_HP_INT (1 << 18) +/* The outstanding write counter become full should never happen */ +#define PCIE_W_REV3_INT_GRP_A_CAUSE_A_WRITE_COUNTER_FULL_ERR (1 << 18) + + +/* + * The core asserts hp_msi when the logical AND of the following conditions + * transitions from false to true: + * - MSI or MSI-X is enabled. + * - Hot-Plug interrupts are enabled in the Slot Control register. + * - Any bit in the Slot Status register transitions from 0 to 1 and the + * associated event notification is enabled in the Slot Control register. + */ +#define PCIE_W_INT_GRP_A_CAUSE_A_HP_MSI (1 << 19) +/* Read VPD registers notification */ +#define PCIE_W_REV1_2_INT_GRP_A_CAUSE_A_VPD_INT (1 << 20) +/* not use */ +#define PCIE_W_REV3_INT_GRP_A_CAUSE_A_NOT_USE (1 << 20) + +/* + * The core assert link down event, whenever the link is going down. Write zero + * to clear this bit, pulse signal + */ +#define PCIE_W_INT_GRP_A_CAUSE_A_LINK_DOWN_EVENT (1 << 21) +/* + * When the EP gets a command to shut down, signal the software to block any new + * TLP. + */ +#define PCIE_W_INT_GRP_A_CAUSE_A_PM_XTLH_BLOCK_TLP (1 << 22) +/* PHY/MAC link up */ +#define PCIE_W_INT_GRP_A_CAUSE_A_XMLH_LINK_UP (1 << 23) +/* Data link up */ +#define PCIE_W_INT_GRP_A_CAUSE_A_RDLH_LINK_UP (1 << 24) +/* The ltssm is in RCVRY_LOCK state. */ +#define PCIE_W_INT_GRP_A_CAUSE_A_LTSSM_RCVRY_STATE (1 << 25) +/* + * Config write transaction to the config space by the RC peer, enable this + * interrupt only for EP mode. + */ +#define PCIE_W_INT_GRP_A_CAUSE_A_CFG_WR_EVENT (1 << 26) +/* AER error */ +#define PCIE_W_INT_GRP_A_CAUSE_A_AP_PENDED_CORR_ERR_STS_INT (1 << 28) +/* AER error */ +#define PCIE_W_INT_GRP_A_CAUSE_A_AP_PENDED_UNCORR_ERR_STS_INT (1 << 29) + +/**** control_A register ****/ +/* When Clear_on_Read =1, all bits of Cause register are cleared on read. */ +#define PCIE_W_INT_GRP_A_CONTROL_A_CLEAR_ON_READ (1 << 0) +/* + * (Must be set only when MSIX is enabled.) + * When Auto-Mask =1 and an MSI-X ACK for this bit is received, its + * corresponding bit in the Mask register is set, masking future interrupts. + */ +#define PCIE_W_INT_GRP_A_CONTROL_A_AUTO_MASK (1 << 1) +/* + * Auto_Clear (RW) + * When Auto-Clear =1, the bits in the Interrupt Cause register are auto-cleared + * after MSI-X is acknowledged. Must be used only if MSI-X is enabled. + */ +#define PCIE_W_INT_GRP_A_CONTROL_A_AUTO_CLEAR (1 << 2) +/* + * When Set_on_Posedge =1, the bits in the Interrupt Cause register are set on + * the posedge of the interrupt source, i.e., when interrupt source =1 and + * Interrupt Status = 0. + * When Set_on_Posedge =0, the bits in the Interrupt Cause register are set when + * interrupt source =1. + */ +#define PCIE_W_INT_GRP_A_CONTROL_A_SET_ON_POSEDGE (1 << 3) +/* + * When Moderation_Reset =1, all Moderation timers associated with the interrupt + * cause bits are cleared to 0, enabling immediate interrupt assertion if any + * unmasked cause bit is set to 1. This bit is self-negated. + */ +#define PCIE_W_INT_GRP_A_CONTROL_A_MOD_RST (1 << 4) +/* + * When mask_msi_x =1, no MSI-X from this group is sent. This bit must be set to + * 1 when the associated summary bit in this group is used to generate a single + * MSI-X for this group. + */ +#define PCIE_W_INT_GRP_A_CONTROL_A_MASK_MSI_X (1 << 5) +/* MSI-X AWID value. Same ID for all cause bits. */ +#define PCIE_W_INT_GRP_A_CONTROL_A_AWID_MASK 0x00000F00 +#define PCIE_W_INT_GRP_A_CONTROL_A_AWID_SHIFT 8 +/* + * This value determines the interval between interrupts; writing ZERO disables + * Moderation. + */ +#define PCIE_W_INT_GRP_A_CONTROL_A_MOD_INTV_MASK 0x00FF0000 +#define PCIE_W_INT_GRP_A_CONTROL_A_MOD_INTV_SHIFT 16 +/* + * This value determines the Moderation_Timer_Clock speed. + * 0- Moderation-timer is decremented every 1x256 SB clock cycles ~1uS. + * 1- Moderation-timer is decremented every 2x256 SB clock cycles ~2uS. + * N- Moderation-timer is decremented every Nx256 SB clock cycles ~(N+1) uS. + */ +#define PCIE_W_INT_GRP_A_CONTROL_A_MOD_RES_MASK 0x0F000000 +#define PCIE_W_INT_GRP_A_CONTROL_A_MOD_RES_SHIFT 24 + +/**** cause_B register ****/ +/* Indicates that the core received a PM_PME Message. Write Zero to clear. */ +#define PCIE_W_INT_GRP_B_CAUSE_B_MSG_PM_PME (1 << 0) +/* + * Indicates that the core received a PME_TO_Ack Message. Write Zero to clear. + */ +#define PCIE_W_INT_GRP_B_CAUSE_B_MSG_PM_TO_ACK (1 << 1) +/* + * Indicates that the core received an PME_Turn_Off Message. Write Zero to + * clear. + * EP mode only + */ +#define PCIE_W_INT_GRP_B_CAUSE_B_MSG_PM_TURNOFF (1 << 2) +/* Indicates that the core received an ERR_CORR Message. Write Zero to clear. */ +#define PCIE_W_INT_GRP_B_CAUSE_B_MSG_CORRECTABLE_ERR (1 << 3) +/* + * Indicates that the core received an ERR_NONFATAL Message. Write Zero to + * clear. + */ +#define PCIE_W_INT_GRP_B_CAUSE_B_MSG_NONFATAL_ERR (1 << 4) +/* + * Indicates that the core received an ERR_FATAL Message. Write Zero to clear. + */ +#define PCIE_W_INT_GRP_B_CAUSE_B_MSG_FATAL_ERR (1 << 5) +/* + * Indicates that the core received a Vendor Defined Message. Write Zero to + * clear. + */ +#define PCIE_W_INT_GRP_B_CAUSE_B_MSG_VENDOR_0 (1 << 6) +/* + * Indicates that the core received a Vendor Defined Message. Write Zero to + * clear. + */ +#define PCIE_W_INT_GRP_B_CAUSE_B_MSG_VENDOR_1 (1 << 7) +/* Indicates that the core received an Unlock Message. Write Zero to clear. */ +#define PCIE_W_INT_GRP_B_CAUSE_B_MSG_UNLOCK (1 << 8) +/* + * Notification when the Link Autonomous Bandwidth Status register (Link Status + * register bit 15) is updated and the Link Autonomous Bandwidth Interrupt + * Enable (Link Control register bit 11) is set. This bit is not applicable to, + * and is reserved, for Endpoint device. Write Zero to clear + */ +#define PCIE_W_INT_GRP_B_CAUSE_B_LINK_AUTO_BW_INT (1 << 12) +/* + * Notification that the Link Equalization Request bit in the Link Status 2 + * Register has been set. Write Zero to clear. + */ +#define PCIE_W_INT_GRP_B_CAUSE_B_LINK_EQ_REQ_INT (1 << 13) +/* + * OB Vendor message request is granted by the PCIe core Write Zero to clear. + */ +#define PCIE_W_INT_GRP_B_CAUSE_B_VENDOR_MSG_GRANT (1 << 14) +/* CPL timeout from the PCIe core inidication. Write Zero to clear */ +#define PCIE_W_INT_GRP_B_CAUSE_B_CMP_TIME_OUT (1 << 15) +/* + * Slave Response Composer Lookup Error + * Indicates that an overflow occurred in a lookup table of the Inbound + * responses. This indicates that there was a violation of the number of + * outstanding NP requests issued for the Outbound direction. Write zero to + * clear + */ +#define PCIE_W_INT_GRP_B_CAUSE_B_RADMX_CMPOSER_LOOKUP_ERR (1 << 16) +/* Parity Error */ +#define PCIE_W_INT_GRP_B_CAUSE_B_PARITY_ERROR_CORE (1 << 17) + +/**** control_B register ****/ +/* When Clear_on_Read =1, all bits of the Cause register are cleared on read. */ +#define PCIE_W_INT_GRP_B_CONTROL_B_CLEAR_ON_READ (1 << 0) +/* + * (Must be set only when MSIX is enabled.) + * When Auto-Mask =1 and an MSI-X ACK for this bit is received, its + * corresponding bit in the Mask register is set, masking future interrupts. + */ +#define PCIE_W_INT_GRP_B_CONTROL_B_AUTO_MASK (1 << 1) +/* + * Auto_Clear (RW) + * When Auto-Clear =1, the bits in the Interrupt Cause register are auto-cleared + * after MSI-X is acknowledged. Must be used only if MSI-X is enabled. + */ +#define PCIE_W_INT_GRP_B_CONTROL_B_AUTO_CLEAR (1 << 2) +/* + * When Set_on_Posedge =1, the bits in the interrupt Cause register are set on + * the posedge of the interrupt source, i.e., when Interrupt Source =1 and + * Interrupt Status = 0. + * When Set_on_Posedge =0, the bits in the Interrupt Cause register are set when + * Interrupt Source =1. + */ +#define PCIE_W_INT_GRP_B_CONTROL_B_SET_ON_POSEDGE (1 << 3) +/* + * When Moderation_Reset =1, all Moderation timers associated with the interrupt + * cause bits are cleared to 0, enabling an immediate interrupt assertion if any + * unmasked cause bit is set to 1. This bit is self-negated. + */ +#define PCIE_W_INT_GRP_B_CONTROL_B_MOD_RST (1 << 4) +/* + * When mask_msi_x =1, no MSI-X from this group is sent. This bit must be set to + * 1 when the associated summary bit in this group is used to generate a single + * MSI-X for this group. + */ +#define PCIE_W_INT_GRP_B_CONTROL_B_MASK_MSI_X (1 << 5) +/* MSI-X AWID value. Same ID for all cause bits. */ +#define PCIE_W_INT_GRP_B_CONTROL_B_AWID_MASK 0x00000F00 +#define PCIE_W_INT_GRP_B_CONTROL_B_AWID_SHIFT 8 +/* + * This value determines the interval between interrupts. Writing ZERO disables + * Moderation. + */ +#define PCIE_W_INT_GRP_B_CONTROL_B_MOD_INTV_MASK 0x00FF0000 +#define PCIE_W_INT_GRP_B_CONTROL_B_MOD_INTV_SHIFT 16 +/* + * This value determines the Moderation_Timer_Clock speed. + * 0- Moderation-timer is decremented every 1x256 SB clock cycles ~1uS. + * 1- Moderation-timer is decremented every 2x256 SB clock cycles ~2uS. + * N- Moderation-timer is decremented every Nx256 SB clock cycles ~(N+1) uS. + */ +#define PCIE_W_INT_GRP_B_CONTROL_B_MOD_RES_MASK 0x0F000000 +#define PCIE_W_INT_GRP_B_CONTROL_B_MOD_RES_SHIFT 24 + +/**** cause_C register ****/ +/* VPD interrupt, ot read/write frpm EEPROM */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_VPD_INT_FUNC_MASK 0x0000000F +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_VPD_INT_FUNC_SHIFT 0 +/* flr PF active */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_CFG_FLR_PF_ACTIVE_MASK 0x000000F0 +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_CFG_FLR_PF_ACTIVE_SHIFT 4 +/* System ERR RC. */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_CFG_SYS_ERR_RC_MASK 0x00000F00 +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_CFG_SYS_ERR_RC_SHIFT 8 +/* AER RC INT */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_CFG_AER_RC_ERR_INT_MASK 0x0000F000 +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_CFG_AER_RC_ERR_INT_SHIFT 12 +/* AER RC MSI */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_CFG_AER_RC_ERR_MSI_MASK 0x000F0000 +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_CFG_AER_RC_ERR_MSI_SHIFT 16 +/* PME MSI */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_CFG_PME_MSI_MASK 0x00F00000 +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_CFG_PME_MSI_SHIFT 20 +/* PME int */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_CFG_PME_INT_MASK 0x0F000000 +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_CFG_PME_INT_SHIFT 24 +/* SB overflow */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_RADM_QOVERFLOW (1 << 28) +/* ecrc was injected through the diag_ctrl bus */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_ECRC_INJECTED (1 << 29) +/* lcrc was injected through the diag_ctrl bus */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_LCRC_INJECTED (1 << 30) +/* lcrc was injected through the diag_ctrl bus */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CAUSE_GRP_C_RSRVD (1 << 31) + +/**** control_C register ****/ +/* When Clear_on_Read =1, all bits of Cause register are cleared on read. */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CONTROL_GRP_C_CLEAR_ON_READ (1 << 0) +/* + * (Must be set only when MSIX is enabled.) + * When Auto-Mask =1 and an MSI-X ACK for this bit is received, its + * corresponding bit in the Mask register is set, masking future interrupts. + */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CONTROL_GRP_C_AUTO_MASK (1 << 1) +/* + * Auto_Clear (RW) + * When Auto-Clear =1, the bits in the Interrupt Cause register are auto-cleared + * after MSI-X is acknowledged. Must be used only if MSI-X is enabled. + */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CONTROL_GRP_C_AUTO_CLEAR (1 << 2) +/* + * When Set_on_Posedge =1, the bits in the Interrupt Cause register are set on + * the posedge of the interrupt source, i.e., when interrupt source =1 and + * Interrupt Status = 0. + * When Set_on_Posedge =0, the bits in the Interrupt Cause register are set when + * interrupt source =1. + */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CONTROL_GRP_C_SET_ON_POSEDGE (1 << 3) +/* + * When Moderation_Reset =1, all Moderation timers associated with the interrupt + * cause bits are cleared to 0, enabling immediate interrupt assertion if any + * unmasked cause bit is set to 1. This bit is self-negated. + */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CONTROL_GRP_C_MOD_RST (1 << 4) +/* + * When mask_msi_x =1, no MSI-X from this group is sent. This bit must be set to + * 1 when the associated summary bit in this group is used to generate a single + * MSI-X for this group. + */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CONTROL_GRP_C_MASK_MSI_X (1 << 5) +/* MSI-X AWID value. Same ID for all cause bits. */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CONTROL_GRP_C_AWID_MASK 0x00000F00 +#define PCIE_W_INTERRUPT_GRP_C_INT_CONTROL_GRP_C_AWID_SHIFT 8 +/* + * This value determines the interval between interrupts; writing ZERO disables + * Moderation. + */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CONTROL_GRP_C_MOD_INTV_MASK 0x00FF0000 +#define PCIE_W_INTERRUPT_GRP_C_INT_CONTROL_GRP_C_MOD_INTV_SHIFT 16 +/* + * This value determines the Moderation_Timer_Clock speed. + * 0- Moderation-timer is decremented every 1x256 SB clock cycles ~1uS. + * 1- Moderation-timer is decremented every 2x256 SB clock cycles ~2uS. + * N- Moderation-timer is decremented every Nx256 SB clock cycles ~(N+1) uS. + */ +#define PCIE_W_INTERRUPT_GRP_C_INT_CONTROL_GRP_C_MOD_RES_MASK 0x0F000000 +#define PCIE_W_INTERRUPT_GRP_C_INT_CONTROL_GRP_C_MOD_RES_SHIFT 24 + +/**** control_D register ****/ +/* When Clear_on_Read =1, all bits of Cause register are cleared on read. */ +#define PCIE_W_INTERRUPT_GRP_D_INT_CONTROL_GRP_D_CLEAR_ON_READ (1 << 0) +/* + * (Must be set only when MSIX is enabled.) + * When Auto-Mask =1 and an MSI-X ACK for this bit is received, its + * corresponding bit in the Mask register is set, masking future interrupts. + */ +#define PCIE_W_INTERRUPT_GRP_D_INT_CONTROL_GRP_D_AUTO_MASK (1 << 1) +/* + * Auto_Clear (RW) + * When Auto-Clear =1, the bits in the Interrupt Cause register are auto-cleared + * after MSI-X is acknowledged. Must be used only if MSI-X is enabled. + */ +#define PCIE_W_INTERRUPT_GRP_D_INT_CONTROL_GRP_D_AUTO_CLEAR (1 << 2) +/* + * When Set_on_Posedge =1, the bits in the Interrupt Cause register are set on + * the posedge of the interrupt source, i.e., when interrupt source =1 and + * Interrupt Status = 0. + * When Set_on_Posedge =0, the bits in the Interrupt Cause register are set when + * interrupt source =1. + */ +#define PCIE_W_INTERRUPT_GRP_D_INT_CONTROL_GRP_D_SET_ON_POSEDGE (1 << 3) +/* + * When Moderation_Reset =1, all Moderation timers associated with the interrupt + * cause bits are cleared to 0, enabling immediate interrupt assertion if any + * unmasked cause bit is set to 1. This bit is self-negated. + */ +#define PCIE_W_INTERRUPT_GRP_D_INT_CONTROL_GRP_D_MOD_RST (1 << 4) +/* + * When mask_msi_x =1, no MSI-X from this group is sent. This bit must be set to + * 1 when the associated summary bit in this group is used to generate a single + * MSI-X for this group. + */ +#define PCIE_W_INTERRUPT_GRP_D_INT_CONTROL_GRP_D_MASK_MSI_X (1 << 5) +/* MSI-X AWID value. Same ID for all cause bits. */ +#define PCIE_W_INTERRUPT_GRP_D_INT_CONTROL_GRP_D_AWID_MASK 0x00000F00 +#define PCIE_W_INTERRUPT_GRP_D_INT_CONTROL_GRP_D_AWID_SHIFT 8 +/* + * This value determines the interval between interrupts; writing ZERO disables + * Moderation. + */ +#define PCIE_W_INTERRUPT_GRP_D_INT_CONTROL_GRP_D_MOD_INTV_MASK 0x00FF0000 +#define PCIE_W_INTERRUPT_GRP_D_INT_CONTROL_GRP_D_MOD_INTV_SHIFT 16 +/* + * This value determines the Moderation_Timer_Clock speed. + * 0- Moderation-timer is decremented every 1x256 SB clock cycles ~1uS. + * 1- Moderation-timer is decremented every 2x256 SB clock cycles ~2uS. + * N- Moderation-timer is decremented every Nx256 SB clock cycles ~(N+1) uS. + */ +#define PCIE_W_INTERRUPT_GRP_D_INT_CONTROL_GRP_D_MOD_RES_MASK 0x0F000000 +#define PCIE_W_INTERRUPT_GRP_D_INT_CONTROL_GRP_D_MOD_RES_SHIFT 24 +#ifdef __cplusplus +} +#endif + +#endif /* __AL_HAL_PCIE_W_REG_H */ + +/** @} end of ... group */ + + Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_pcie_w_reg.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_plat_services.h =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_plat_services.h (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_plat_services.h (revision 283031) @@ -0,0 +1,419 @@ +/*- +******************************************************************************* +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/** + * @defgroup group_services Platform Services API + * @{ + * The Platform Services API provides miscellaneous system services to HAL + * drivers, such as: + * - Registers read/write + * - Assertions + * - Memory barriers + * - Endianness conversions + * + * And more. + * @file plat_api/sample/al_hal_plat_services.h + * + * @brief API for Platform services provided for to HAL drivers + * + * + */ + +#ifndef __PLAT_SERVICES_H__ +#define __PLAT_SERVICES_H__ + +#include +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +/* Prototypes for all the bus_space structure functions */ +bs_protos(generic); +bs_protos(generic_armv4); + +#define __UNUSED __attribute__((unused)) + +/* *INDENT-OFF* */ +#ifdef __cplusplus +extern "C" { +#endif +/* *INDENT-ON* */ + +/* + * WMA: This is a hack which allows not modifying the __iomem accessing HAL code. + * On ARMv7, bus_handle holds the information about VA of accessed memory. It + * is possible to use direct load/store instruction instead of bus_dma machinery. + * WARNING: This is not guaranteed to stay that way forever, nor that + * on other architectures these variables behave similarly. Keep that + * in mind during porting to other systems. + */ +/** + * Read MMIO 8 bits register + * @param offset register offset + * + * @return register value + */ +static uint8_t al_reg_read8(uint8_t * offset); + +/** + * Read MMIO 16 bits register + * @param offset register offset + * + * @return register value + */ +static uint16_t al_reg_read16(uint16_t * offset); + +/** + * Read MMIO 32 bits register + * @param offset register offset + * + * @return register value + */ +static uint32_t al_reg_read32(uint32_t * offset); + +/** + * Read MMIO 64 bits register + * @param offset register offset + * + * @return register value + */ +uint64_t al_reg_read64(uint64_t * offset); + +/** + * Relaxed read MMIO 32 bits register + * + * Relaxed register read/write functions don't involve cpu instructions that + * force syncronization, nor ordering between the register access and memory + * data access. + * These instructions are used in performance critical code to avoid the + * overhead of the synchronization instructions. + * + * @param offset register offset + * + * @return register value + */ +#define al_bus_dma_to_va(bus_tag, bus_handle) ((void*)bus_handle) + +/** + * Relaxed read MMIO 32 bits register + * + * Relaxed register read/write functions don't involve cpu instructions that + * force syncronization, nor ordering between the register access and memory + * data access. + * These instructions are used in performance critical code to avoid the + * overhead of the synchronization instructions. + * + * @param offset register offset + * + * @return register value + */ +#define al_reg_read32_relaxed(l) generic_bs_r_4(NULL, (bus_space_handle_t)l, 0) + +/** + * Relaxed write to MMIO 32 bits register + * + * Relaxed register read/write functions don't involve cpu instructions that + * force syncronization, nor ordering between the register access and memory + * data access. + * These instructions are used in performance critical code to avoid the + * overhead of the synchronization instructions. + * + * @param offset register offset + * @param val value to write to the register + */ +#define al_reg_write32_relaxed(l,v) generic_bs_w_4(NULL, (bus_space_handle_t)l, 0, v) + +/** + * Write to MMIO 8 bits register + * @param offset register offset + * @param val value to write to the register + */ +#define al_reg_write8(l,v) do { dsb(); generic_bs_w_1(NULL, (bus_space_handle_t)l, 0, v); dmb(); } while (0) + +/** + * Write to MMIO 16 bits register + * @param offset register offset + * @param val value to write to the register + */ +#define al_reg_write16(l,v) do { dsb(); generic_bs_w_2(NULL, (bus_space_handle_t)l, 0, v); dmb(); } while (0) + +/** + * Write to MMIO 32 bits register + * @param offset register offset + * @param val value to write to the register + */ +#define al_reg_write32(l,v) do { dsb(); generic_bs_w_4(NULL, (bus_space_handle_t)l, 0, v); dmb(); } while (0) + +/** + * Write to MMIO 64 bits register + * @param offset register offset + * @param val value to write to the register + */ +#define al_reg_write64(l,v) do { dsb(); generic_bs_w_8(NULL, (bus_space_handle_t)l, 0, v); dmb(); } while (0) + +static inline uint8_t +al_reg_read8(uint8_t *l) +{ + dsb(); + + return (generic_bs_r_1(NULL, (bus_space_handle_t)l, 0)); +} + +static inline uint16_t +al_reg_read16(uint16_t *l) +{ + dsb(); + + return (generic_bs_r_2(NULL, (bus_space_handle_t)l, 0)); +} + +static inline uint32_t +al_reg_read32(uint32_t *l) +{ + dsb(); + + return (generic_bs_r_4(NULL, (bus_space_handle_t)l, 0)); +} + +#define AL_DBG_LEVEL_NONE 0 +#define AL_DBG_LEVEL_ERR 1 +#define AL_DBG_LEVEL_WARN 2 +#define AL_DBG_LEVEL_INFO 3 +#define AL_DBG_LEVEL_DBG 4 + +#define AL_DBG_LEVEL AL_DBG_LEVEL_ERR + +extern struct mtx al_dbg_lock; + +#define AL_DBG_LOCK() mtx_lock_spin(&al_dbg_lock) +#define AL_DBG_UNLOCK() mtx_unlock_spin(&al_dbg_lock) + +/** + * print message + * + * @param format The format string + * @param ... Additional arguments + */ +#define al_print(type, fmt, ...) do { if (AL_DBG_LEVEL >= AL_DBG_LEVEL_NONE) { AL_DBG_LOCK(); printf(fmt, ##__VA_ARGS__); AL_DBG_UNLOCK(); } } while(0) + +/** + * print error message + * + * @param format + */ +#define al_err(...) do { if (AL_DBG_LEVEL >= AL_DBG_LEVEL_ERR) { AL_DBG_LOCK(); printf(__VA_ARGS__); AL_DBG_UNLOCK(); } } while(0) + +/** + * print warning message + * + * @param format + */ +#define al_warn(...) do { if (AL_DBG_LEVEL >= AL_DBG_LEVEL_WARN) { AL_DBG_LOCK(); printf(__VA_ARGS__); AL_DBG_UNLOCK(); } } while(0) + +/** + * print info message + * + * @param format + */ +#define al_info(...) do { if (AL_DBG_LEVEL >= AL_DBG_LEVEL_INFO) { AL_DBG_LOCK(); printf(__VA_ARGS__); AL_DBG_UNLOCK(); } } while(0) + +/** + * print debug message + * + * @param format + */ +#define al_dbg(...) do { if (AL_DBG_LEVEL >= AL_DBG_LEVEL_DBG) { AL_DBG_LOCK(); printf(__VA_ARGS__); AL_DBG_UNLOCK(); } } while(0) + +/** + * Assertion + * + * @param condition + */ +#define al_assert(COND) \ + do { \ + if (!(COND)) \ + al_err( \ + "%s:%d:%s: Assertion failed! (%s)\n", \ + __FILE__, __LINE__, __func__, #COND); \ + } while(AL_FALSE) + +/** + * Make sure data will be visible by other masters (other CPUS and DMA). + * usually this is achieved by the ARM DMB instruction. + */ +static void al_data_memory_barrier(void); + +/** + * Make sure data will be visible by DMA masters, no restriction for other cpus + */ +static inline void +al_data_memory_barrier(void) +{ + dsb(); +} + +/** + * Make sure data will be visible in order by other cpus masters. + */ +static inline void +al_smp_data_memory_barrier(void) +{ + dsb(); +} + +/** + * Make sure write data will be visible in order by other cpus masters. + */ +static inline void +al_local_data_memory_barrier(void) +{ + dsb(); +} + +/** + * al_udelay - micro sec delay + */ +#define al_udelay(u) DELAY(u) + +/** + * al_msleep - mili sec delay + */ +#define al_msleep(m) DELAY((m) * 1000) + +/** + * swap half word to little endian + * + * @param x 16 bit value + * + * @return the value in little endian + */ +#define swap16_to_le(x) htole16(x) +/** + * swap word to little endian + * + * @param x 32 bit value + * + * @return the value in little endian + */ +#define swap32_to_le(x) htole32(x) + +/** + * swap 8 bytes to little endian + * + * @param x 64 bit value + * + * @return the value in little endian + */ +#define swap64_to_le(x) htole64(x) + +/** + * swap half word from little endian + * + * @param x 16 bit value + * + * @return the value in the cpu endianess + */ +#define swap16_from_le(x) le16toh(x) + +/** + * swap word from little endian + * + * @param x 32 bit value + * + * @return the value in the cpu endianess + */ +#define swap32_from_le(x) le32toh(x) + +/** + * swap 8 bytes from little endian + * + * @param x 64 bit value + * + * @return the value in the cpu endianess + */ +#define swap64_from_le(x) le64toh(x) + +/** + * Memory set + * + * @param p memory pointer + * @param val value for setting + * @param cnt number of bytes to set + */ +#define al_memset(p, val, cnt) memset(p, val, cnt) + +/** + * Memory copy + * + * @param p1 memory pointer + * @param p2 memory pointer + * @param cnt number of bytes to copy + */ +#define al_memcpy(p1, p2, cnt) memcpy(p1, p2, cnt) + +/** + * Memory compare + * + * @param p1 memory pointer + * @param p2 memory pointer + * @param cnt number of bytes to compare + */ +#define al_memcmp(p1, p2, cnt) memcmp(p1, p2, cnt) + +/** + * String compare + * + * @param s1 string pointer + * @param s2 string pointer + */ +#define al_strcmp(s1, s2) strcmp(s1, s2) + +#define al_get_cpu_id() 0 + +/* *INDENT-OFF* */ +#ifdef __cplusplus +} +#endif +/* *INDENT-ON* */ +/** @} end of Platform Services API group */ +#endif /* __PLAT_SERVICES_H__ */ Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_plat_services.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_plat_types.h =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_plat_types.h (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_plat_types.h (revision 283031) @@ -0,0 +1,94 @@ +/*- +******************************************************************************** +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/** + * @defgroup group_services Platform Services API + * @{ + * @file plat_api/sample/al_hal_plat_types.h + * + */ + +#ifndef __PLAT_TYPES_H__ +#define __PLAT_TYPES_H__ + +#include +#include +#include +#include + +/* *INDENT-OFF* */ +#ifdef __cplusplus +extern "C" { +#endif +/* *INDENT-ON* */ + +/* Basic data types */ +typedef int al_bool; /** boolean */ +#define AL_TRUE 1 +#define AL_FALSE 0 + + +/* define types */ +#ifndef AL_HAVE_TYPES +typedef unsigned char uint8_t; /** unsigned 8 bits */ +typedef unsigned short uint16_t; /** unsigned 16 bits */ +typedef unsigned int uint32_t; /** unsigned 32 bits */ +typedef unsigned long long uint64_t; /** unsigned 64 bits */ + +typedef signed char int8_t; /** signed 8 bits */ +typedef short int int16_t; /** signed 16 bits */ +typedef signed int int32_t; /** signed 32 bits */ + +/** An unsigned int that is guaranteed to be the same size as a pointer */ +/** C99 standard */ +typedef unsigned long uintptr_t; +#endif + + +/** in LPAE mode, the address address is 40 bit, we extend it to 64 bit */ +typedef uint64_t al_phys_addr_t; + +/** this defines the cpu endiancess. */ +#define PLAT_ARCH_IS_LITTLE() AL_TRUE + +/* *INDENT-OFF* */ +#ifdef __cplusplus +} +#endif +/* *INDENT-ON* */ +/** @} end of Platform Services API group */ + +#endif /* __PLAT_TYPES_H__ */ Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_plat_types.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_reg_utils.h =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_reg_utils.h (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_reg_utils.h (revision 283031) @@ -0,0 +1,188 @@ +/*- +******************************************************************************** +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/** + * @defgroup group_common HAL Common Layer + * @{ + * @file al_hal_reg_utils.h + * + * @brief Register utilities used by HALs and platform layer + * + * + */ + +#ifndef __AL_HAL_REG_UTILS_H__ +#define __AL_HAL_REG_UTILS_H__ + +#include "al_hal_plat_types.h" +#include "al_hal_plat_services.h" + +/* *INDENT-OFF* */ +#ifdef __cplusplus +extern "C" { +#endif +/* *INDENT-ON* */ + +#define AL_BIT(b) (1UL << (b)) + +#define AL_ADDR_LOW(x) ((uint32_t)((al_phys_addr_t)(x))) +#define AL_ADDR_HIGH(x) ((uint32_t)((((al_phys_addr_t)(x)) >> 16) >> 16)) + +/** get field out of 32 bit register */ +#define AL_REG_FIELD_GET(reg, mask, shift) (((reg) & (mask)) >> (shift)) + +/** set field of 32 bit register */ +#define AL_REG_FIELD_SET(reg, mask, shift, val) \ + (reg) = \ + (((reg) & (~(mask))) | \ + ((((unsigned)(val)) << (shift)) & (mask))) + +/** set field of 64 bit register */ +#define AL_REG_FIELD_SET_64(reg, mask, shift, val) \ + ((reg) = \ + (((reg) & (~(mask))) | \ + ((((uint64_t)(val)) << (shift)) & (mask)))) + +/** get single bit out of 32 bit register */ +#define AL_REG_BIT_GET(reg, shift) \ + AL_REG_FIELD_GET(reg, AL_BIT(shift), shift) + +#define AL_REG_BITS_FIELD(shift, val) \ + (((unsigned)(val)) << (shift)) + +/** set single bit field of 32 bit register to a given value */ +#define AL_REG_BIT_VAL_SET(reg, shift, val) \ + AL_REG_FIELD_SET(reg, AL_BIT(shift), shift, val) + +/** set single bit of 32 bit register to 1 */ +#define AL_REG_BIT_SET(reg, shift) \ + AL_REG_BIT_VAL_SET(reg, shift, 1) + +/** clear single bit of 32 bit register */ +#define AL_REG_BIT_CLEAR(reg, shift) \ + AL_REG_BIT_VAL_SET(reg, shift, 0) + + +#define AL_BIT_MASK(n) \ + (AL_BIT(n) - 1) + +#define AL_FIELD_MASK(msb, lsb) \ + (AL_BIT(msb) + AL_BIT_MASK(msb) - AL_BIT_MASK(lsb)) + +/** clear bits specified by clear_mask */ +#define AL_REG_MASK_CLEAR(reg, clear_mask) \ + ((reg) = (((reg) & (~(clear_mask))))) + +/** set bits specified by clear_mask */ +#define AL_REG_MASK_SET(reg, clear_mask) \ + ((reg) = (((reg) | (clear_mask)))) + + +/** clear bits specified by clear_mask, and set bits specified by set_mask */ +#define AL_REG_CLEAR_AND_SET(reg, clear_mask, set_mask) \ + (reg) = (((reg) & (~(clear_mask))) | (set_mask)) + +#define AL_ALIGN_UP(val, size) \ + ((size) * (((val) + (size) - 1) / (size))) + +/** take bits selected by mask from one data, the rest from background */ +#define AL_MASK_VAL(mask, data, background) \ + (((mask) & (data)) | ((~mask) & (background))) + +/** + * 8 bits register masked write + * + * @param reg + * register address + * @param mask + * bits not selected (1) by mask will be left unchanged + * @param data + * data to write. bits not selected by mask ignored. + */ +static inline void +al_reg_write8_masked(uint8_t __iomem *reg, uint8_t mask, uint8_t data) +{ + uint8_t temp; + temp = al_reg_read8(reg); + al_reg_write8(reg, AL_MASK_VAL(mask, data, temp)); +} + + +/** + * 16 bits register masked write + * + * @param reg + * register address + * @param mask + * bits not selected (1) by mask will be left unchanged + * @param data + * data to write. bits not selected by mask ignored. + */ +static inline void +al_reg_write16_masked(uint16_t __iomem *reg, uint16_t mask, uint16_t data) +{ + uint16_t temp; + temp = al_reg_read16(reg); + al_reg_write16(reg, AL_MASK_VAL(mask, data, temp)); +} + + +/** + * 32 bits register masked write + * + * @param reg + * register address + * @param mask + * bits not selected (1) by mask will be left unchanged + * @param data + * data to write. bits not selected by mask ignored. + */ +static inline void +al_reg_write32_masked(uint32_t __iomem *reg, uint32_t mask, uint32_t data) +{ + uint32_t temp; + temp = al_reg_read32(reg); + al_reg_write32(reg, AL_MASK_VAL(mask, data, temp)); +} + +/* *INDENT-OFF* */ +#ifdef __cplusplus +} +#endif +/* *INDENT-ON* */ +/** @} end of Common group */ +#endif + Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_reg_utils.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_types.h =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_types.h (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_types.h (revision 283031) @@ -0,0 +1,117 @@ +/*- +******************************************************************************** +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +/** + * @defgroup group_common HAL Common Layer + * @{ + * @file al_hal_types.h + * + * @brief macros used by HALs and platform layer + * + */ + +#ifndef __AL_HAL_TYPES_H__ +#define __AL_HAL_TYPES_H__ + +#include "al_hal_plat_types.h" +#include "al_hal_plat_services.h" + +/* *INDENT-OFF* */ +#ifdef __cplusplus +extern "C" { +#endif +/* *INDENT-ON* */ + +/* Common defines */ + +#if (!AL_TRUE) || (AL_FALSE) +#error "AL_TRUE must be non zero and AL_FALSE must be zero" +#endif + +typedef int AL_RETURN; + +#if !defined(NULL) +#define NULL (void *)0 +#endif + +#if !defined(likely) +#define likely(x) (__builtin_expect(!!(x), 1)) +#define unlikely(x) (__builtin_expect(!!(x), 0)) +#endif + + +#ifdef __GNUC__ +#if !defined(__packed) +#define __packed __attribute__ ((packed)) +#endif + /* packed and alinged types */ +#define __packed_a4 __attribute__ ((packed, aligned(4))) +#define __packed_a8 __attribute__ ((packed, aligned(8))) +#define __packed_a16 __attribute__ ((packed, aligned(16))) + +#else +#if !defined(__packed) +#error "__packed is not defined!!" +#endif +#endif + +#if !defined(__iomem) +#define __iomem +#endif + +#if !defined(__cache_aligned) +#ifdef __GNUC__ +#define __cache_aligned __attribute__ ((__aligned__(64))) +#else +#define __cache_aligned +#endif +#endif + +#if !defined(INLINE) +#ifdef __GNUC__ +#define INLINE inline +#else +#define INLINE +#endif +#endif + +/* *INDENT-OFF* */ +#ifdef __cplusplus +} +#endif +/* *INDENT-ON* */ +/** @} end of Common group */ +#endif /* __TYPES_H__ */ Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_types.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_unit_adapter_regs.h =================================================================== --- projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_unit_adapter_regs.h (nonexistent) +++ projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_unit_adapter_regs.h (revision 283031) @@ -0,0 +1,314 @@ +/*- +******************************************************************************** +Copyright (C) 2015 Annapurna Labs Ltd. + +This file may be licensed under the terms of the Annapurna Labs Commercial +License Agreement. + +Alternatively, this file can be distributed under the terms of the GNU General +Public License V2 as published by the Free Software Foundation and can be +found at http://www.gnu.org/licenses/gpl-2.0.html + +Alternatively, redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*******************************************************************************/ + +#ifndef __AL_HAL_UNIT_ADAPTER_REGS_H__ +#define __AL_HAL_UNIT_ADAPTER_REGS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define AL_PCI_COMMAND 0x04 /* 16 bits */ +#define AL_PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ +#define AL_PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ +#define AL_PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ + +#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */ + +#define AL_PCI_BASE_ADDRESS_SPACE_IO 0x01 +#define AL_PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ +#define AL_PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ +#define AL_PCI_BASE_ADDRESS_DEVICE_ID 0x0c + +#define AL_PCI_BASE_ADDRESS_0 0x10 +#define AL_PCI_BASE_ADDRESS_0_HI 0x14 +#define AL_PCI_BASE_ADDRESS_2 0x18 +#define AL_PCI_BASE_ADDRESS_2_HI 0x1c +#define AL_PCI_BASE_ADDRESS_4 0x20 +#define AL_PCI_BASE_ADDRESS_4_HI 0x24 + +#define AL_PCI_EXP_ROM_BASE_ADDRESS 0x30 + +#define AL_PCI_AXI_CFG_AND_CTR_0 0x110 +#define AL_PCI_AXI_CFG_AND_CTR_1 0x130 +#define AL_PCI_AXI_CFG_AND_CTR_2 0x150 +#define AL_PCI_AXI_CFG_AND_CTR_3 0x170 + +#define AL_PCI_APP_CONTROL 0x220 + +#define AL_PCI_SRIOV_TOTAL_AND_INITIAL_VFS 0x30c + +#define AL_PCI_VF_BASE_ADDRESS_0 0x324 + + +#define AL_PCI_EXP_CAP_BASE 0x40 +#define AL_PCI_EXP_DEVCAP 4 /* Device capabilities */ +#define AL_PCI_EXP_DEVCAP_PAYLOAD 0x07 /* Max_Payload_Size */ +#define AL_PCI_EXP_DEVCAP_PHANTOM 0x18 /* Phantom functions */ +#define AL_PCI_EXP_DEVCAP_EXT_TAG 0x20 /* Extended tags */ +#define AL_PCI_EXP_DEVCAP_L0S 0x1c0 /* L0s Acceptable Latency */ +#define AL_PCI_EXP_DEVCAP_L1 0xe00 /* L1 Acceptable Latency */ +#define AL_PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */ +#define AL_PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */ +#define AL_PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */ +#define AL_PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */ +#define AL_PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ +#define AL_PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ +#define AL_PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ +#define AL_PCI_EXP_DEVCTL 8 /* Device Control */ +#define AL_PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ +#define AL_PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ +#define AL_PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */ +#define AL_PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */ +#define AL_PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */ +#define AL_PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ +#define AL_PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */ +#define AL_PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */ +#define AL_PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ +#define AL_PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ +#define AL_PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ +#define AL_PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ +#define AL_PCI_EXP_DEVSTA 0xA /* Device Status */ +#define AL_PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */ +#define AL_PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */ +#define AL_PCI_EXP_DEVSTA_FED 0x04 /* Fatal Error Detected */ +#define AL_PCI_EXP_DEVSTA_URD 0x08 /* Unsupported Request Detected */ +#define AL_PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */ +#define AL_PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */ +#define AL_PCI_EXP_LNKCAP 0xC /* Link Capabilities */ +#define AL_PCI_EXP_LNKCAP_SLS 0xf /* Supported Link Speeds */ +#define AL_PCI_EXP_LNKCAP_SLS_2_5GB 0x1 /* LNKCAP2 SLS Vector bit 0 (2.5GT/s) */ +#define AL_PCI_EXP_LNKCAP_SLS_5_0GB 0x2 /* LNKCAP2 SLS Vector bit 1 (5.0GT/s) */ +#define AL_PCI_EXP_LNKCAP_MLW 0x3f0 /* Maximum Link Width */ +#define AL_PCI_EXP_LNKCAP_ASPMS 0xc00 /* ASPM Support */ +#define AL_PCI_EXP_LNKCAP_L0SEL 0x7000 /* L0s Exit Latency */ +#define AL_PCI_EXP_LNKCAP_L1EL 0x38000 /* L1 Exit Latency */ +#define AL_PCI_EXP_LNKCAP_CLKPM 0x40000 /* L1 Clock Power Management */ +#define AL_PCI_EXP_LNKCAP_SDERC 0x80000 /* Surprise Down Error Reporting Capable */ +#define AL_PCI_EXP_LNKCAP_DLLLARC 0x100000 /* Data Link Layer Link Active Reporting Capable */ +#define AL_PCI_EXP_LNKCAP_LBNC 0x200000 /* Link Bandwidth Notification Capability */ +#define AL_PCI_EXP_LNKCAP_PN 0xff000000 /* Port Number */ + +#define AL_PCI_EXP_LNKCTL 0x10 /* Link Control */ +#define AL_PCI_EXP_LNKCTL_LNK_DIS 0x4 /* Link Disable Status */ +#define AL_PCI_EXP_LNKCTL_LNK_RTRN 0x5 /* Link Retrain Status */ + +#define AL_PCI_EXP_LNKSTA 0x12 /* Link Status */ +#define AL_PCI_EXP_LNKSTA_CLS 0x000f /* Current Link Speed */ +#define AL_PCI_EXP_LNKSTA_CLS_2_5GB 0x01 /* Current Link Speed 2.5GT/s */ +#define AL_PCI_EXP_LNKSTA_CLS_5_0GB 0x02 /* Current Link Speed 5.0GT/s */ +#define AL_PCI_EXP_LNKSTA_CLS_8_0GB 0x03 /* Current Link Speed 8.0GT/s */ +#define AL_PCI_EXP_LNKSTA_NLW 0x03f0 /* Nogotiated Link Width */ +#define AL_PCI_EXP_LNKSTA_NLW_SHIFT 4 /* start of NLW mask in link status */ +#define AL_PCI_EXP_LNKSTA_LT 0x0800 /* Link Training */ +#define AL_PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */ +#define AL_PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */ +#define AL_PCI_EXP_LNKSTA_LBMS 0x4000 /* Link Bandwidth Management Status */ +#define AL_PCI_EXP_LNKSTA_LABS 0x8000 /* Link Autonomous Bandwidth Status */ + +#define AL_PCI_EXP_LNKCTL2 0x30 /* Link Control 2 */ + +#define AL_PCI_MSIX_MSGCTRL 0 /* MSIX message control reg */ +#define AL_PCI_MSIX_MSGCTRL_TBL_SIZE 0x7ff /* MSIX table size */ +#define AL_PCI_MSIX_MSGCTRL_TBL_SIZE_SHIFT 16 /* MSIX table size shift */ +#define AL_PCI_MSIX_MSGCTRL_EN 0x80000000 /* MSIX enable */ +#define AL_PCI_MSIX_MSGCTRL_MASK 0x40000000 /* MSIX mask */ + +#define AL_PCI_MSIX_TABLE 0x4 /* MSIX table offset and bar reg */ +#define AL_PCI_MSIX_TABLE_OFFSET 0xfffffff8 /* MSIX table offset */ +#define AL_PCI_MSIX_TABLE_BAR 0x7 /* MSIX table BAR */ + +#define AL_PCI_MSIX_PBA 0x8 /* MSIX pba offset and bar reg */ +#define AL_PCI_MSIX_PBA_OFFSET 0xfffffff8 /* MSIX pba offset */ +#define AL_PCI_MSIX_PBA_BAR 0x7 /* MSIX pba BAR */ + + +/* Adapter power management register 0 */ +#define AL_ADAPTER_PM_0 0x80 +#define AL_ADAPTER_PM_0_PM_NEXT_CAP_MASK 0xff00 +#define AL_ADAPTER_PM_0_PM_NEXT_CAP_SHIFT 8 +#define AL_ADAPTER_PM_0_PM_NEXT_CAP_VAL_MSIX 0x90 + +/* Adapter power management register 1 */ +#define AL_ADAPTER_PM_1 0x84 +#define AL_ADAPTER_PM_1_PME_EN 0x100 /* PM enable */ +#define AL_ADAPTER_PM_1_PWR_STATE_MASK 0x3 /* PM state mask */ +#define AL_ADAPTER_PM_1_PWR_STATE_D3 0x3 /* PM D3 state */ + +/* Sub Master Configuration & Control */ +#define AL_ADAPTER_SMCC 0x110 +#define AL_ADAPTER_SMCC_CONF_2 0x114 + +/* Interrupt_Cause register */ +#define AL_ADAPTER_INT_CAUSE 0x1B0 +#define AL_ADAPTER_INT_CAUSE_WR_ERR AL_BIT(1) +#define AL_ADAPTER_INT_CAUSE_RD_ERR AL_BIT(0) + +/* AXI_Master_Write_Error_Attribute_Latch register */ +/* AXI_Master_Read_Error_Attribute_Latch register */ +#define AL_ADAPTER_AXI_MSTR_WR_ERR_ATTR 0x1B4 +#define AL_ADAPTER_AXI_MSTR_RD_ERR_ATTR 0x1B8 + +#define AL_ADAPTER_AXI_MSTR_RD_WR_ERR_ATTR_COMP_STAT_MASK AL_FIELD_MASK(1, 0) +#define AL_ADAPTER_AXI_MSTR_RD_WR_ERR_ATTR_COMP_STAT_SHIFT 0 +#define AL_ADAPTER_AXI_MSTR_RD_WR_ERR_ATTR_MSTR_ID_MASK AL_FIELD_MASK(4, 2) +#define AL_ADAPTER_AXI_MSTR_RD_WR_ERR_ATTR_MSTR_ID_SHIFT 2 +#define AL_ADAPTER_AXI_MSTR_RD_WR_ERR_ATTR_ADDR_TO AL_BIT(8) +#define AL_ADAPTER_AXI_MSTR_RD_WR_ERR_ATTR_COMP_ERR AL_BIT(9) +#define AL_ADAPTER_AXI_MSTR_RD_WR_ERR_ATTR_COMP_TO AL_BIT(10) +#define AL_ADAPTER_AXI_MSTR_RD_WR_ERR_ATTR_ERR_BLK AL_BIT(11) +#define AL_ADAPTER_AXI_MSTR_RD_ERR_ATTR_RD_PARITY_ERR AL_BIT(12) + +/* Interrupt_Cause_mask register */ +#define AL_ADAPTER_INT_CAUSE_MASK 0x1BC +#define AL_ADAPTER_INT_CAUSE_MASK_WR_ERR AL_BIT(1) +#define AL_ADAPTER_INT_CAUSE_MASK_RD_ERR AL_BIT(0) + +/* AXI_Master_write_error_address_Latch register */ +#define AL_ADAPTER_AXI_MSTR_WR_ERR_LO_LATCH 0x1C0 + +/* AXI_Master_write_error_address_high_Latch register */ +#define AL_ADAPTER_AXI_MSTR_WR_ERR_HI_LATCH 0x1C4 + +/* AXI_Master_read_error_address_Latch register */ +#define AL_ADAPTER_AXI_MSTR_RD_ERR_LO_LATCH 0x1C8 + +/* AXI_Master_read_error_address_high_Latch register */ +#define AL_ADAPTER_AXI_MSTR_RD_ERR_HI_LATCH 0x1CC + +/* AXI_Master_Timeout register */ +#define AL_ADAPTER_AXI_MSTR_TO 0x1D0 +#define AL_ADAPTER_AXI_MSTR_TO_WR_MASK AL_FIELD_MASK(31, 16) +#define AL_ADAPTER_AXI_MSTR_TO_WR_SHIFT 16 +#define AL_ADAPTER_AXI_MSTR_TO_RD_MASK AL_FIELD_MASK(15, 0) +#define AL_ADAPTER_AXI_MSTR_TO_RD_SHIFT 0 + +/* + * Generic control registers + */ + +/* Control 0 */ +#define AL_ADAPTER_GENERIC_CONTROL_0 0x1E0 +/* Control 2 */ +#define AL_ADAPTER_GENERIC_CONTROL_2 0x1E8 +/* Control 3 */ +#define AL_ADAPTER_GENERIC_CONTROL_3 0x1EC +/* Control 9 */ +#define AL_ADAPTER_GENERIC_CONTROL_9 0x218 +/* Control 10 */ +#define AL_ADAPTER_GENERIC_CONTROL_10 0x21C +/* Control 11 */ +#define AL_ADAPTER_GENERIC_CONTROL_11 0x220 +/* Control 12 */ +#define AL_ADAPTER_GENERIC_CONTROL_12 0x224 +/* Control 13 */ +#define AL_ADAPTER_GENERIC_CONTROL_13 0x228 +/* Control 14 */ +#define AL_ADAPTER_GENERIC_CONTROL_14 0x22C +/* Control 15 */ +#define AL_ADAPTER_GENERIC_CONTROL_15 0x230 +/* Control 16 */ +#define AL_ADAPTER_GENERIC_CONTROL_16 0x234 +/* Control 17 */ +#define AL_ADAPTER_GENERIC_CONTROL_17 0x238 +/* Control 18 */ +#define AL_ADAPTER_GENERIC_CONTROL_18 0x23C +/* Control 19 */ +#define AL_ADAPTER_GENERIC_CONTROL_19 0x240 + +/* Enable clock gating */ +#define AL_ADAPTER_GENERIC_CONTROL_0_CLK_GATE_EN 0x01 +/* When set, all transactions through the PCI conf & mem BARs get timeout */ +#define AL_ADAPTER_GENERIC_CONTROL_0_ADAPTER_DIS 0x40 +#define AL_ADAPTER_GENERIC_CONTROL_0_ETH_RESET_1GMAC AL_BIT(18) +#define AL_ADAPTER_GENERIC_CONTROL_0_ETH_RESET_1GMAC_ON_FLR AL_BIT(26) + +/* + * SATA registers only + */ +/* Select 125MHz free running clock from IOFAB main PLL as SATA OOB clock + * instead of using power management ref clock + */ +#define AL_ADAPTER_GENERIC_CONTROL_10_SATA_OOB_CLK_SEL AL_BIT(26) +/* AXUSER selection and value per bit (1 = address, 0 = register) */ +/* Rx */ +#define AL_ADPTR_GEN_CTL_12_SATA_AWUSER_VAL_MASK AL_FIELD_MASK(15, 0) +#define AL_ADPTR_GEN_CTL_12_SATA_AWUSER_VAL_SHIFT 0 +#define AL_ADPTR_GEN_CTL_12_SATA_AWUSER_SEL_MASK AL_FIELD_MASK(31, 16) +#define AL_ADPTR_GEN_CTL_12_SATA_AWUSER_SEL_SHIFT 16 +/* Tx */ +#define AL_ADPTR_GEN_CTL_13_SATA_ARUSER_VAL_MASK AL_FIELD_MASK(15, 0) +#define AL_ADPTR_GEN_CTL_13_SATA_ARUSER_VAL_SHIFT 0 +#define AL_ADPTR_GEN_CTL_13_SATA_ARUSER_SEL_MASK AL_FIELD_MASK(31, 16) +#define AL_ADPTR_GEN_CTL_13_SATA_ARUSER_SEL_SHIFT 16 +/* Central VMID enabler. If set, then each entry will be used as programmed */ +#define AL_ADPTR_GEN_CTL_14_SATA_MSIX_VMID_SEL AL_BIT(0) +/* Allow access to store VMID values per entry */ +#define AL_ADPTR_GEN_CTL_14_SATA_MSIX_VMID_ACCESS_EN AL_BIT(1) +/* VMID Address select */ +/* Tx */ +#define AL_ADPTR_GEN_CTL_14_SATA_VM_ARADDR_SEL_MASK AL_FIELD_MASK(13, 8) +#define AL_ADPTR_GEN_CTL_14_SATA_VM_ARADDR_SEL_SHIFT 8 +/* Rx */ +#define AL_ADPTR_GEN_CTL_14_SATA_VM_AWADDR_SEL_MASK AL_FIELD_MASK(21, 16) +#define AL_ADPTR_GEN_CTL_14_SATA_VM_AWADDR_SEL_SHIFT 16 +/* Address Value */ +/* Rx */ +#define AL_ADPTR_GEN_CTL_15_SATA_VM_AWDDR_HI AL_FIELD_MASK(31, 0) +/* Tx */ +#define AL_ADPTR_GEN_CTL_16_SATA_VM_ARDDR_HI AL_FIELD_MASK(31, 0) + +/* + * ROB registers + */ +/* Read ROB_Enable, when disabled the read ROB is bypassed */ +#define AL_ADPTR_GEN_CTL_19_READ_ROB_EN AL_BIT(0) +/* Read force in-order of every read transaction */ +#define AL_ADPTR_GEN_CTL_19_READ_ROB_FORCE_INORDER AL_BIT(1) +/* Read software reset */ +#define AL_ADPTR_GEN_CTL_19_READ_ROB_SW_RESET AL_BIT(15) +/* Write ROB_Enable, when disabled_the_Write ROB is bypassed */ +#define AL_ADPTR_GEN_CTL_19_WRITE_ROB_EN AL_BIT(16) +/* Write force in-order of every write transaction */ +#define AL_ADPTR_GEN_CTL_19_WRITE_ROB_FORCE_INORDER AL_BIT(17) +/* Write software reset */ +#define AL_ADPTR_GEN_CTL_19_WRITE_ROB_SW_RESET AL_BIT(31) + +#ifdef __cplusplus +} +#endif + +#endif Property changes on: projects/ci20_mips/sys/arm/annapurna/alpine/hal/al_hal_unit_adapter_regs.h ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/arm/arm/cpufunc.c =================================================================== --- projects/ci20_mips/sys/arm/arm/cpufunc.c (revision 283030) +++ projects/ci20_mips/sys/arm/arm/cpufunc.c (revision 283031) @@ -1,1431 +1,1431 @@ /* $NetBSD: cpufunc.c,v 1.65 2003/11/05 12:53:15 scw Exp $ */ /*- * arm9 support code Copyright (C) 2001 ARM Ltd * Copyright (c) 1997 Mark Brinicombe. * Copyright (c) 1997 Causality Limited * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Causality Limited. * 4. The name of Causality Limited may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * RiscBSD kernel project * * cpufuncs.c * * C functions for supporting CPU / MMU / TLB specific operations. * * Created : 30/01/97 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(CPU_XSCALE_80321) || defined(CPU_XSCALE_80219) #include #include #endif /* * Some definitions in i81342reg.h clash with i80321reg.h. * This only happens for the LINT kernel. As it happens, * we don't need anything from i81342reg.h that we already * got from somewhere else during a LINT compile. */ #if defined(CPU_XSCALE_81342) && !defined(COMPILING_LINT) #include #endif #ifdef CPU_XSCALE_IXP425 #include #include #endif /* PRIMARY CACHE VARIABLES */ int arm_picache_size; int arm_picache_line_size; int arm_picache_ways; int arm_pdcache_size; /* and unified */ int arm_pdcache_line_size; int arm_pdcache_ways; int arm_pcache_type; int arm_pcache_unified; int arm_dcache_align; int arm_dcache_align_mask; u_int arm_cache_level; u_int arm_cache_type[14]; u_int arm_cache_loc; int ctrl; #ifdef CPU_ARM9 struct cpu_functions arm9_cpufuncs = { /* CPU functions */ cpufunc_id, /* id */ cpufunc_nullop, /* cpwait */ /* MMU functions */ cpufunc_control, /* control */ cpufunc_domains, /* Domain */ arm9_setttb, /* Setttb */ cpufunc_faultstatus, /* Faultstatus */ cpufunc_faultaddress, /* Faultaddress */ /* TLB functions */ armv4_tlb_flushID, /* tlb_flushID */ arm9_tlb_flushID_SE, /* tlb_flushID_SE */ armv4_tlb_flushI, /* tlb_flushI */ (void *)armv4_tlb_flushI, /* tlb_flushI_SE */ armv4_tlb_flushD, /* tlb_flushD */ armv4_tlb_flushD_SE, /* tlb_flushD_SE */ /* Cache operations */ arm9_icache_sync_all, /* icache_sync_all */ arm9_icache_sync_range, /* icache_sync_range */ arm9_dcache_wbinv_all, /* dcache_wbinv_all */ arm9_dcache_wbinv_range, /* dcache_wbinv_range */ arm9_dcache_inv_range, /* dcache_inv_range */ arm9_dcache_wb_range, /* dcache_wb_range */ armv4_idcache_inv_all, /* idcache_inv_all */ arm9_idcache_wbinv_all, /* idcache_wbinv_all */ arm9_idcache_wbinv_range, /* idcache_wbinv_range */ cpufunc_nullop, /* l2cache_wbinv_all */ (void *)cpufunc_nullop, /* l2cache_wbinv_range */ (void *)cpufunc_nullop, /* l2cache_inv_range */ (void *)cpufunc_nullop, /* l2cache_wb_range */ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */ /* Other functions */ cpufunc_nullop, /* flush_prefetchbuf */ armv4_drain_writebuf, /* drain_writebuf */ cpufunc_nullop, /* flush_brnchtgt_C */ (void *)cpufunc_nullop, /* flush_brnchtgt_E */ (void *)cpufunc_nullop, /* sleep */ /* Soft functions */ cpufunc_null_fixup, /* dataabt_fixup */ cpufunc_null_fixup, /* prefetchabt_fixup */ arm9_context_switch, /* context_switch */ arm9_setup /* cpu setup */ }; #endif /* CPU_ARM9 */ #if defined(CPU_ARM9E) struct cpu_functions armv5_ec_cpufuncs = { /* CPU functions */ cpufunc_id, /* id */ cpufunc_nullop, /* cpwait */ /* MMU functions */ cpufunc_control, /* control */ cpufunc_domains, /* Domain */ armv5_ec_setttb, /* Setttb */ cpufunc_faultstatus, /* Faultstatus */ cpufunc_faultaddress, /* Faultaddress */ /* TLB functions */ armv4_tlb_flushID, /* tlb_flushID */ arm10_tlb_flushID_SE, /* tlb_flushID_SE */ armv4_tlb_flushI, /* tlb_flushI */ arm10_tlb_flushI_SE, /* tlb_flushI_SE */ armv4_tlb_flushD, /* tlb_flushD */ armv4_tlb_flushD_SE, /* tlb_flushD_SE */ /* Cache operations */ armv5_ec_icache_sync_all, /* icache_sync_all */ armv5_ec_icache_sync_range, /* icache_sync_range */ armv5_ec_dcache_wbinv_all, /* dcache_wbinv_all */ armv5_ec_dcache_wbinv_range, /* dcache_wbinv_range */ armv5_ec_dcache_inv_range, /* dcache_inv_range */ armv5_ec_dcache_wb_range, /* dcache_wb_range */ armv4_idcache_inv_all, /* idcache_inv_all */ armv5_ec_idcache_wbinv_all, /* idcache_wbinv_all */ armv5_ec_idcache_wbinv_range, /* idcache_wbinv_range */ cpufunc_nullop, /* l2cache_wbinv_all */ (void *)cpufunc_nullop, /* l2cache_wbinv_range */ (void *)cpufunc_nullop, /* l2cache_inv_range */ (void *)cpufunc_nullop, /* l2cache_wb_range */ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */ /* Other functions */ cpufunc_nullop, /* flush_prefetchbuf */ armv4_drain_writebuf, /* drain_writebuf */ cpufunc_nullop, /* flush_brnchtgt_C */ (void *)cpufunc_nullop, /* flush_brnchtgt_E */ (void *)cpufunc_nullop, /* sleep */ /* Soft functions */ cpufunc_null_fixup, /* dataabt_fixup */ cpufunc_null_fixup, /* prefetchabt_fixup */ arm10_context_switch, /* context_switch */ arm10_setup /* cpu setup */ }; struct cpu_functions sheeva_cpufuncs = { /* CPU functions */ cpufunc_id, /* id */ cpufunc_nullop, /* cpwait */ /* MMU functions */ cpufunc_control, /* control */ cpufunc_domains, /* Domain */ sheeva_setttb, /* Setttb */ cpufunc_faultstatus, /* Faultstatus */ cpufunc_faultaddress, /* Faultaddress */ /* TLB functions */ armv4_tlb_flushID, /* tlb_flushID */ arm10_tlb_flushID_SE, /* tlb_flushID_SE */ armv4_tlb_flushI, /* tlb_flushI */ arm10_tlb_flushI_SE, /* tlb_flushI_SE */ armv4_tlb_flushD, /* tlb_flushD */ armv4_tlb_flushD_SE, /* tlb_flushD_SE */ /* Cache operations */ armv5_ec_icache_sync_all, /* icache_sync_all */ armv5_ec_icache_sync_range, /* icache_sync_range */ armv5_ec_dcache_wbinv_all, /* dcache_wbinv_all */ sheeva_dcache_wbinv_range, /* dcache_wbinv_range */ sheeva_dcache_inv_range, /* dcache_inv_range */ sheeva_dcache_wb_range, /* dcache_wb_range */ armv4_idcache_inv_all, /* idcache_inv_all */ armv5_ec_idcache_wbinv_all, /* idcache_wbinv_all */ sheeva_idcache_wbinv_range, /* idcache_wbinv_all */ sheeva_l2cache_wbinv_all, /* l2cache_wbinv_all */ sheeva_l2cache_wbinv_range, /* l2cache_wbinv_range */ sheeva_l2cache_inv_range, /* l2cache_inv_range */ sheeva_l2cache_wb_range, /* l2cache_wb_range */ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */ /* Other functions */ cpufunc_nullop, /* flush_prefetchbuf */ armv4_drain_writebuf, /* drain_writebuf */ cpufunc_nullop, /* flush_brnchtgt_C */ (void *)cpufunc_nullop, /* flush_brnchtgt_E */ sheeva_cpu_sleep, /* sleep */ /* Soft functions */ cpufunc_null_fixup, /* dataabt_fixup */ cpufunc_null_fixup, /* prefetchabt_fixup */ arm10_context_switch, /* context_switch */ arm10_setup /* cpu setup */ }; #endif /* CPU_ARM9E */ #ifdef CPU_MV_PJ4B struct cpu_functions pj4bv7_cpufuncs = { /* CPU functions */ cpufunc_id, /* id */ armv7_drain_writebuf, /* cpwait */ /* MMU functions */ cpufunc_control, /* control */ cpufunc_domains, /* Domain */ armv7_setttb, /* Setttb */ cpufunc_faultstatus, /* Faultstatus */ cpufunc_faultaddress, /* Faultaddress */ /* TLB functions */ armv7_tlb_flushID, /* tlb_flushID */ armv7_tlb_flushID_SE, /* tlb_flushID_SE */ armv7_tlb_flushID, /* tlb_flushI */ armv7_tlb_flushID_SE, /* tlb_flushI_SE */ armv7_tlb_flushID, /* tlb_flushD */ armv7_tlb_flushID_SE, /* tlb_flushD_SE */ /* Cache operations */ armv7_idcache_wbinv_all, /* icache_sync_all */ armv7_icache_sync_range, /* icache_sync_range */ armv7_dcache_wbinv_all, /* dcache_wbinv_all */ armv7_dcache_wbinv_range, /* dcache_wbinv_range */ armv7_dcache_inv_range, /* dcache_inv_range */ armv7_dcache_wb_range, /* dcache_wb_range */ armv7_idcache_inv_all, /* idcache_inv_all */ armv7_idcache_wbinv_all, /* idcache_wbinv_all */ armv7_idcache_wbinv_range, /* idcache_wbinv_all */ (void *)cpufunc_nullop, /* l2cache_wbinv_all */ (void *)cpufunc_nullop, /* l2cache_wbinv_range */ (void *)cpufunc_nullop, /* l2cache_inv_range */ (void *)cpufunc_nullop, /* l2cache_wb_range */ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */ /* Other functions */ cpufunc_nullop, /* flush_prefetchbuf */ armv7_drain_writebuf, /* drain_writebuf */ cpufunc_nullop, /* flush_brnchtgt_C */ (void *)cpufunc_nullop, /* flush_brnchtgt_E */ (void *)cpufunc_nullop, /* sleep */ /* Soft functions */ cpufunc_null_fixup, /* dataabt_fixup */ cpufunc_null_fixup, /* prefetchabt_fixup */ armv7_context_switch, /* context_switch */ pj4bv7_setup /* cpu setup */ }; #endif /* CPU_MV_PJ4B */ #if defined(CPU_XSCALE_80321) || \ defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425) || \ defined(CPU_XSCALE_80219) struct cpu_functions xscale_cpufuncs = { /* CPU functions */ cpufunc_id, /* id */ xscale_cpwait, /* cpwait */ /* MMU functions */ xscale_control, /* control */ cpufunc_domains, /* domain */ xscale_setttb, /* setttb */ cpufunc_faultstatus, /* faultstatus */ cpufunc_faultaddress, /* faultaddress */ /* TLB functions */ armv4_tlb_flushID, /* tlb_flushID */ xscale_tlb_flushID_SE, /* tlb_flushID_SE */ armv4_tlb_flushI, /* tlb_flushI */ (void *)armv4_tlb_flushI, /* tlb_flushI_SE */ armv4_tlb_flushD, /* tlb_flushD */ armv4_tlb_flushD_SE, /* tlb_flushD_SE */ /* Cache operations */ xscale_cache_syncI, /* icache_sync_all */ xscale_cache_syncI_rng, /* icache_sync_range */ xscale_cache_purgeD, /* dcache_wbinv_all */ xscale_cache_purgeD_rng, /* dcache_wbinv_range */ xscale_cache_flushD_rng, /* dcache_inv_range */ xscale_cache_cleanD_rng, /* dcache_wb_range */ xscale_cache_flushID, /* idcache_inv_all */ xscale_cache_purgeID, /* idcache_wbinv_all */ xscale_cache_purgeID_rng, /* idcache_wbinv_range */ cpufunc_nullop, /* l2cache_wbinv_all */ (void *)cpufunc_nullop, /* l2cache_wbinv_range */ (void *)cpufunc_nullop, /* l2cache_inv_range */ (void *)cpufunc_nullop, /* l2cache_wb_range */ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */ /* Other functions */ cpufunc_nullop, /* flush_prefetchbuf */ armv4_drain_writebuf, /* drain_writebuf */ cpufunc_nullop, /* flush_brnchtgt_C */ (void *)cpufunc_nullop, /* flush_brnchtgt_E */ xscale_cpu_sleep, /* sleep */ /* Soft functions */ cpufunc_null_fixup, /* dataabt_fixup */ cpufunc_null_fixup, /* prefetchabt_fixup */ xscale_context_switch, /* context_switch */ xscale_setup /* cpu setup */ }; #endif /* CPU_XSCALE_80321 || CPU_XSCALE_PXA2X0 || CPU_XSCALE_IXP425 CPU_XSCALE_80219 */ #ifdef CPU_XSCALE_81342 struct cpu_functions xscalec3_cpufuncs = { /* CPU functions */ cpufunc_id, /* id */ xscale_cpwait, /* cpwait */ /* MMU functions */ xscale_control, /* control */ cpufunc_domains, /* domain */ xscalec3_setttb, /* setttb */ cpufunc_faultstatus, /* faultstatus */ cpufunc_faultaddress, /* faultaddress */ /* TLB functions */ armv4_tlb_flushID, /* tlb_flushID */ xscale_tlb_flushID_SE, /* tlb_flushID_SE */ armv4_tlb_flushI, /* tlb_flushI */ (void *)armv4_tlb_flushI, /* tlb_flushI_SE */ armv4_tlb_flushD, /* tlb_flushD */ armv4_tlb_flushD_SE, /* tlb_flushD_SE */ /* Cache operations */ xscalec3_cache_syncI, /* icache_sync_all */ xscalec3_cache_syncI_rng, /* icache_sync_range */ xscalec3_cache_purgeD, /* dcache_wbinv_all */ xscalec3_cache_purgeD_rng, /* dcache_wbinv_range */ xscale_cache_flushD_rng, /* dcache_inv_range */ xscalec3_cache_cleanD_rng, /* dcache_wb_range */ xscale_cache_flushID, /* idcache_inv_all */ xscalec3_cache_purgeID, /* idcache_wbinv_all */ xscalec3_cache_purgeID_rng, /* idcache_wbinv_range */ xscalec3_l2cache_purge, /* l2cache_wbinv_all */ xscalec3_l2cache_purge_rng, /* l2cache_wbinv_range */ xscalec3_l2cache_flush_rng, /* l2cache_inv_range */ xscalec3_l2cache_clean_rng, /* l2cache_wb_range */ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */ /* Other functions */ cpufunc_nullop, /* flush_prefetchbuf */ armv4_drain_writebuf, /* drain_writebuf */ cpufunc_nullop, /* flush_brnchtgt_C */ (void *)cpufunc_nullop, /* flush_brnchtgt_E */ xscale_cpu_sleep, /* sleep */ /* Soft functions */ cpufunc_null_fixup, /* dataabt_fixup */ cpufunc_null_fixup, /* prefetchabt_fixup */ xscalec3_context_switch, /* context_switch */ xscale_setup /* cpu setup */ }; #endif /* CPU_XSCALE_81342 */ #if defined(CPU_FA526) struct cpu_functions fa526_cpufuncs = { /* CPU functions */ cpufunc_id, /* id */ cpufunc_nullop, /* cpwait */ /* MMU functions */ cpufunc_control, /* control */ cpufunc_domains, /* domain */ fa526_setttb, /* setttb */ cpufunc_faultstatus, /* faultstatus */ cpufunc_faultaddress, /* faultaddress */ /* TLB functions */ armv4_tlb_flushID, /* tlb_flushID */ fa526_tlb_flushID_SE, /* tlb_flushID_SE */ armv4_tlb_flushI, /* tlb_flushI */ fa526_tlb_flushI_SE, /* tlb_flushI_SE */ armv4_tlb_flushD, /* tlb_flushD */ armv4_tlb_flushD_SE, /* tlb_flushD_SE */ /* Cache operations */ fa526_icache_sync_all, /* icache_sync_all */ fa526_icache_sync_range, /* icache_sync_range */ fa526_dcache_wbinv_all, /* dcache_wbinv_all */ fa526_dcache_wbinv_range, /* dcache_wbinv_range */ fa526_dcache_inv_range, /* dcache_inv_range */ fa526_dcache_wb_range, /* dcache_wb_range */ armv4_idcache_inv_all, /* idcache_inv_all */ fa526_idcache_wbinv_all, /* idcache_wbinv_all */ fa526_idcache_wbinv_range, /* idcache_wbinv_range */ cpufunc_nullop, /* l2cache_wbinv_all */ (void *)cpufunc_nullop, /* l2cache_wbinv_range */ (void *)cpufunc_nullop, /* l2cache_inv_range */ (void *)cpufunc_nullop, /* l2cache_wb_range */ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */ /* Other functions */ fa526_flush_prefetchbuf, /* flush_prefetchbuf */ armv4_drain_writebuf, /* drain_writebuf */ cpufunc_nullop, /* flush_brnchtgt_C */ fa526_flush_brnchtgt_E, /* flush_brnchtgt_E */ fa526_cpu_sleep, /* sleep */ /* Soft functions */ cpufunc_null_fixup, /* dataabt_fixup */ cpufunc_null_fixup, /* prefetchabt_fixup */ fa526_context_switch, /* context_switch */ fa526_setup /* cpu setup */ }; #endif /* CPU_FA526 */ #if defined(CPU_ARM1176) struct cpu_functions arm1176_cpufuncs = { /* CPU functions */ cpufunc_id, /* id */ cpufunc_nullop, /* cpwait */ /* MMU functions */ cpufunc_control, /* control */ cpufunc_domains, /* Domain */ arm11x6_setttb, /* Setttb */ cpufunc_faultstatus, /* Faultstatus */ cpufunc_faultaddress, /* Faultaddress */ /* TLB functions */ arm11_tlb_flushID, /* tlb_flushID */ arm11_tlb_flushID_SE, /* tlb_flushID_SE */ arm11_tlb_flushI, /* tlb_flushI */ arm11_tlb_flushI_SE, /* tlb_flushI_SE */ arm11_tlb_flushD, /* tlb_flushD */ arm11_tlb_flushD_SE, /* tlb_flushD_SE */ /* Cache operations */ arm11x6_icache_sync_all, /* icache_sync_all */ arm11x6_icache_sync_range, /* icache_sync_range */ arm11x6_dcache_wbinv_all, /* dcache_wbinv_all */ armv6_dcache_wbinv_range, /* dcache_wbinv_range */ armv6_dcache_inv_range, /* dcache_inv_range */ armv6_dcache_wb_range, /* dcache_wb_range */ armv6_idcache_inv_all, /* idcache_inv_all */ arm11x6_idcache_wbinv_all, /* idcache_wbinv_all */ arm11x6_idcache_wbinv_range, /* idcache_wbinv_range */ (void *)cpufunc_nullop, /* l2cache_wbinv_all */ (void *)cpufunc_nullop, /* l2cache_wbinv_range */ (void *)cpufunc_nullop, /* l2cache_inv_range */ (void *)cpufunc_nullop, /* l2cache_wb_range */ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */ /* Other functions */ arm11x6_flush_prefetchbuf, /* flush_prefetchbuf */ arm11_drain_writebuf, /* drain_writebuf */ cpufunc_nullop, /* flush_brnchtgt_C */ (void *)cpufunc_nullop, /* flush_brnchtgt_E */ arm11x6_sleep, /* sleep */ /* Soft functions */ cpufunc_null_fixup, /* dataabt_fixup */ cpufunc_null_fixup, /* prefetchabt_fixup */ arm11_context_switch, /* context_switch */ arm11x6_setup /* cpu setup */ }; #endif /*CPU_ARM1176 */ #if defined(CPU_CORTEXA) || defined(CPU_KRAIT) struct cpu_functions cortexa_cpufuncs = { /* CPU functions */ cpufunc_id, /* id */ cpufunc_nullop, /* cpwait */ /* MMU functions */ cpufunc_control, /* control */ cpufunc_domains, /* Domain */ armv7_setttb, /* Setttb */ cpufunc_faultstatus, /* Faultstatus */ cpufunc_faultaddress, /* Faultaddress */ /* * TLB functions. ARMv7 does all TLB ops based on a unified TLB model * whether the hardware implements separate I+D or not, so we use the * same 'ID' functions for all 3 variations. */ armv7_tlb_flushID, /* tlb_flushID */ armv7_tlb_flushID_SE, /* tlb_flushID_SE */ armv7_tlb_flushID, /* tlb_flushI */ armv7_tlb_flushID_SE, /* tlb_flushI_SE */ armv7_tlb_flushID, /* tlb_flushD */ armv7_tlb_flushID_SE, /* tlb_flushD_SE */ /* Cache operations */ armv7_icache_sync_all, /* icache_sync_all */ armv7_icache_sync_range, /* icache_sync_range */ armv7_dcache_wbinv_all, /* dcache_wbinv_all */ armv7_dcache_wbinv_range, /* dcache_wbinv_range */ armv7_dcache_inv_range, /* dcache_inv_range */ armv7_dcache_wb_range, /* dcache_wb_range */ armv7_idcache_inv_all, /* idcache_inv_all */ armv7_idcache_wbinv_all, /* idcache_wbinv_all */ armv7_idcache_wbinv_range, /* idcache_wbinv_range */ /* * Note: For CPUs using the PL310 the L2 ops are filled in when the * L2 cache controller is actually enabled. */ cpufunc_nullop, /* l2cache_wbinv_all */ (void *)cpufunc_nullop, /* l2cache_wbinv_range */ (void *)cpufunc_nullop, /* l2cache_inv_range */ (void *)cpufunc_nullop, /* l2cache_wb_range */ (void *)cpufunc_nullop, /* l2cache_drain_writebuf */ /* Other functions */ cpufunc_nullop, /* flush_prefetchbuf */ armv7_drain_writebuf, /* drain_writebuf */ cpufunc_nullop, /* flush_brnchtgt_C */ (void *)cpufunc_nullop, /* flush_brnchtgt_E */ - armv7_sleep, /* sleep */ + armv7_cpu_sleep, /* sleep */ /* Soft functions */ cpufunc_null_fixup, /* dataabt_fixup */ cpufunc_null_fixup, /* prefetchabt_fixup */ armv7_context_switch, /* context_switch */ cortexa_setup /* cpu setup */ }; #endif /* CPU_CORTEXA */ /* * Global constants also used by locore.s */ struct cpu_functions cpufuncs; u_int cputype; u_int cpu_reset_needs_v4_MMU_disable; /* flag used in locore.s */ #if defined(CPU_ARM9) || \ defined (CPU_ARM9E) || \ defined(CPU_ARM1176) || defined(CPU_XSCALE_80321) || \ defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425) || \ defined(CPU_FA526) || defined(CPU_MV_PJ4B) || \ defined(CPU_XSCALE_80219) || defined(CPU_XSCALE_81342) || \ defined(CPU_CORTEXA) || defined(CPU_KRAIT) /* Global cache line sizes, use 32 as default */ int arm_dcache_min_line_size = 32; int arm_icache_min_line_size = 32; int arm_idcache_min_line_size = 32; static void get_cachetype_cp15(void); /* Additional cache information local to this file. Log2 of some of the above numbers. */ static int arm_dcache_l2_nsets; static int arm_dcache_l2_assoc; static int arm_dcache_l2_linesize; static void get_cachetype_cp15() { u_int ctype, isize, dsize, cpuid; u_int clevel, csize, i, sel; u_int multiplier; u_char type; __asm __volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctype)); cpuid = cpufunc_id(); /* * ...and thus spake the ARM ARM: * * If an value corresponding to an unimplemented or * reserved ID register is encountered, the System Control * processor returns the value of the main ID register. */ if (ctype == cpuid) goto out; if (CPU_CT_FORMAT(ctype) == CPU_CT_ARMV7) { /* Resolve minimal cache line sizes */ arm_dcache_min_line_size = 1 << (CPU_CT_DMINLINE(ctype) + 2); arm_icache_min_line_size = 1 << (CPU_CT_IMINLINE(ctype) + 2); arm_idcache_min_line_size = min(arm_icache_min_line_size, arm_dcache_min_line_size); __asm __volatile("mrc p15, 1, %0, c0, c0, 1" : "=r" (clevel)); arm_cache_level = clevel; arm_cache_loc = CPU_CLIDR_LOC(arm_cache_level); i = 0; while ((type = (clevel & 0x7)) && i < 7) { if (type == CACHE_DCACHE || type == CACHE_UNI_CACHE || type == CACHE_SEP_CACHE) { sel = i << 1; __asm __volatile("mcr p15, 2, %0, c0, c0, 0" : : "r" (sel)); __asm __volatile("mrc p15, 1, %0, c0, c0, 0" : "=r" (csize)); arm_cache_type[sel] = csize; arm_dcache_align = 1 << (CPUV7_CT_xSIZE_LEN(csize) + 4); arm_dcache_align_mask = arm_dcache_align - 1; } if (type == CACHE_ICACHE || type == CACHE_SEP_CACHE) { sel = (i << 1) | 1; __asm __volatile("mcr p15, 2, %0, c0, c0, 0" : : "r" (sel)); __asm __volatile("mrc p15, 1, %0, c0, c0, 0" : "=r" (csize)); arm_cache_type[sel] = csize; } i++; clevel >>= 3; } } else { if ((ctype & CPU_CT_S) == 0) arm_pcache_unified = 1; /* * If you want to know how this code works, go read the ARM ARM. */ arm_pcache_type = CPU_CT_CTYPE(ctype); if (arm_pcache_unified == 0) { isize = CPU_CT_ISIZE(ctype); multiplier = (isize & CPU_CT_xSIZE_M) ? 3 : 2; arm_picache_line_size = 1U << (CPU_CT_xSIZE_LEN(isize) + 3); if (CPU_CT_xSIZE_ASSOC(isize) == 0) { if (isize & CPU_CT_xSIZE_M) arm_picache_line_size = 0; /* not present */ else arm_picache_ways = 1; } else { arm_picache_ways = multiplier << (CPU_CT_xSIZE_ASSOC(isize) - 1); } arm_picache_size = multiplier << (CPU_CT_xSIZE_SIZE(isize) + 8); } dsize = CPU_CT_DSIZE(ctype); multiplier = (dsize & CPU_CT_xSIZE_M) ? 3 : 2; arm_pdcache_line_size = 1U << (CPU_CT_xSIZE_LEN(dsize) + 3); if (CPU_CT_xSIZE_ASSOC(dsize) == 0) { if (dsize & CPU_CT_xSIZE_M) arm_pdcache_line_size = 0; /* not present */ else arm_pdcache_ways = 1; } else { arm_pdcache_ways = multiplier << (CPU_CT_xSIZE_ASSOC(dsize) - 1); } arm_pdcache_size = multiplier << (CPU_CT_xSIZE_SIZE(dsize) + 8); arm_dcache_align = arm_pdcache_line_size; arm_dcache_l2_assoc = CPU_CT_xSIZE_ASSOC(dsize) + multiplier - 2; arm_dcache_l2_linesize = CPU_CT_xSIZE_LEN(dsize) + 3; arm_dcache_l2_nsets = 6 + CPU_CT_xSIZE_SIZE(dsize) - CPU_CT_xSIZE_ASSOC(dsize) - CPU_CT_xSIZE_LEN(dsize); out: arm_dcache_align_mask = arm_dcache_align - 1; } } #endif /* ARM9 || XSCALE */ /* * Cannot panic here as we may not have a console yet ... */ int set_cpufuncs() { cputype = cpufunc_id(); cputype &= CPU_ID_CPU_MASK; #ifdef CPU_ARM9 if (((cputype & CPU_ID_IMPLEMENTOR_MASK) == CPU_ID_ARM_LTD || (cputype & CPU_ID_IMPLEMENTOR_MASK) == CPU_ID_TI) && (cputype & 0x0000f000) == 0x00009000) { cpufuncs = arm9_cpufuncs; cpu_reset_needs_v4_MMU_disable = 1; /* V4 or higher */ get_cachetype_cp15(); arm9_dcache_sets_inc = 1U << arm_dcache_l2_linesize; arm9_dcache_sets_max = (1U << (arm_dcache_l2_linesize + arm_dcache_l2_nsets)) - arm9_dcache_sets_inc; arm9_dcache_index_inc = 1U << (32 - arm_dcache_l2_assoc); arm9_dcache_index_max = 0U - arm9_dcache_index_inc; pmap_pte_init_generic(); goto out; } #endif /* CPU_ARM9 */ #if defined(CPU_ARM9E) if (cputype == CPU_ID_MV88FR131 || cputype == CPU_ID_MV88FR571_VD || cputype == CPU_ID_MV88FR571_41) { uint32_t sheeva_ctrl; sheeva_ctrl = (MV_DC_STREAM_ENABLE | MV_BTB_DISABLE | MV_L2_ENABLE); /* * Workaround for Marvell MV78100 CPU: Cache prefetch * mechanism may affect the cache coherency validity, * so it needs to be disabled. * * Refer to errata document MV-S501058-00C.pdf (p. 3.1 * L2 Prefetching Mechanism) for details. */ if (cputype == CPU_ID_MV88FR571_VD || cputype == CPU_ID_MV88FR571_41) sheeva_ctrl |= MV_L2_PREFETCH_DISABLE; sheeva_control_ext(0xffffffff & ~MV_WA_ENABLE, sheeva_ctrl); cpufuncs = sheeva_cpufuncs; get_cachetype_cp15(); pmap_pte_init_generic(); goto out; } else if (cputype == CPU_ID_ARM926EJS) { cpufuncs = armv5_ec_cpufuncs; get_cachetype_cp15(); pmap_pte_init_generic(); goto out; } #endif /* CPU_ARM9E */ #if defined(CPU_ARM1176) if (cputype == CPU_ID_ARM1176JZS) { cpufuncs = arm1176_cpufuncs; cpu_reset_needs_v4_MMU_disable = 1; /* V4 or higher */ get_cachetype_cp15(); pmap_pte_init_mmu_v6(); goto out; } #endif /* CPU_ARM1176 */ #if defined(CPU_CORTEXA) || defined(CPU_KRAIT) if (cputype == CPU_ID_CORTEXA5 || cputype == CPU_ID_CORTEXA7 || cputype == CPU_ID_CORTEXA8R1 || cputype == CPU_ID_CORTEXA8R2 || cputype == CPU_ID_CORTEXA8R3 || cputype == CPU_ID_CORTEXA9R1 || cputype == CPU_ID_CORTEXA9R2 || cputype == CPU_ID_CORTEXA9R3 || cputype == CPU_ID_CORTEXA12R0 || cputype == CPU_ID_CORTEXA15R0 || cputype == CPU_ID_CORTEXA15R1 || cputype == CPU_ID_CORTEXA15R2 || cputype == CPU_ID_CORTEXA15R3 || cputype == CPU_ID_KRAIT ) { cpufuncs = cortexa_cpufuncs; cpu_reset_needs_v4_MMU_disable = 1; /* V4 or higher */ get_cachetype_cp15(); pmap_pte_init_mmu_v6(); goto out; } #endif /* CPU_CORTEXA */ #if defined(CPU_MV_PJ4B) if (cputype == CPU_ID_MV88SV581X_V7 || cputype == CPU_ID_MV88SV584X_V7 || cputype == CPU_ID_ARM_88SV581X_V7) { cpufuncs = pj4bv7_cpufuncs; get_cachetype_cp15(); pmap_pte_init_mmu_v6(); goto out; } #endif /* CPU_MV_PJ4B */ #if defined(CPU_FA526) if (cputype == CPU_ID_FA526 || cputype == CPU_ID_FA626TE) { cpufuncs = fa526_cpufuncs; cpu_reset_needs_v4_MMU_disable = 1; /* SA needs it */ get_cachetype_cp15(); pmap_pte_init_generic(); goto out; } #endif /* CPU_FA526 */ #if defined(CPU_XSCALE_80321) || defined(CPU_XSCALE_80219) if (cputype == CPU_ID_80321_400 || cputype == CPU_ID_80321_600 || cputype == CPU_ID_80321_400_B0 || cputype == CPU_ID_80321_600_B0 || cputype == CPU_ID_80219_400 || cputype == CPU_ID_80219_600) { cpufuncs = xscale_cpufuncs; cpu_reset_needs_v4_MMU_disable = 1; /* XScale needs it */ get_cachetype_cp15(); pmap_pte_init_xscale(); goto out; } #endif /* CPU_XSCALE_80321 */ #if defined(CPU_XSCALE_81342) if (cputype == CPU_ID_81342) { cpufuncs = xscalec3_cpufuncs; cpu_reset_needs_v4_MMU_disable = 1; /* XScale needs it */ get_cachetype_cp15(); pmap_pte_init_xscale(); goto out; } #endif /* CPU_XSCALE_81342 */ #ifdef CPU_XSCALE_PXA2X0 /* ignore core revision to test PXA2xx CPUs */ if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA250 || (cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA27X || (cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA210) { cpufuncs = xscale_cpufuncs; cpu_reset_needs_v4_MMU_disable = 1; /* XScale needs it */ get_cachetype_cp15(); pmap_pte_init_xscale(); goto out; } #endif /* CPU_XSCALE_PXA2X0 */ #ifdef CPU_XSCALE_IXP425 if (cputype == CPU_ID_IXP425_533 || cputype == CPU_ID_IXP425_400 || cputype == CPU_ID_IXP425_266 || cputype == CPU_ID_IXP435) { cpufuncs = xscale_cpufuncs; cpu_reset_needs_v4_MMU_disable = 1; /* XScale needs it */ get_cachetype_cp15(); pmap_pte_init_xscale(); goto out; } #endif /* CPU_XSCALE_IXP425 */ /* * Bzzzz. And the answer was ... */ panic("No support for this CPU type (%08x) in kernel", cputype); return(ARCHITECTURE_NOT_PRESENT); out: uma_set_align(arm_dcache_align_mask); return (0); } /* * Fixup routines for data and prefetch aborts. * * Several compile time symbols are used * * DEBUG_FAULT_CORRECTION - Print debugging information during the * correction of registers after a fault. */ /* * Null abort fixup routine. * For use when no fixup is required. */ int cpufunc_null_fixup(arg) void *arg; { return(ABORT_FIXUP_OK); } /* * CPU Setup code */ #ifdef CPU_ARM9 void arm9_setup(void) { int cpuctrl, cpuctrlmask; cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_ROUNDROBIN; cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_ROM_ENABLE | CPU_CONTROL_BEND_ENABLE | CPU_CONTROL_AFLT_ENABLE | CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_VECRELOC | CPU_CONTROL_ROUNDROBIN; #ifndef ARM32_DISABLE_ALIGNMENT_FAULTS cpuctrl |= CPU_CONTROL_AFLT_ENABLE; #endif #ifdef __ARMEB__ cpuctrl |= CPU_CONTROL_BEND_ENABLE; #endif if (vector_page == ARM_VECTORS_HIGH) cpuctrl |= CPU_CONTROL_VECRELOC; /* Clear out the cache */ cpu_idcache_wbinv_all(); /* Set the control register */ cpu_control(cpuctrlmask, cpuctrl); ctrl = cpuctrl; } #endif /* CPU_ARM9 */ #if defined(CPU_ARM9E) void arm10_setup(void) { int cpuctrl, cpuctrlmask; cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_SYST_ENABLE | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_BPRD_ENABLE; cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_SYST_ENABLE | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_ROM_ENABLE | CPU_CONTROL_BEND_ENABLE | CPU_CONTROL_AFLT_ENABLE | CPU_CONTROL_BPRD_ENABLE | CPU_CONTROL_ROUNDROBIN | CPU_CONTROL_CPCLK; #ifndef ARM32_DISABLE_ALIGNMENT_FAULTS cpuctrl |= CPU_CONTROL_AFLT_ENABLE; #endif #ifdef __ARMEB__ cpuctrl |= CPU_CONTROL_BEND_ENABLE; #endif /* Clear out the cache */ cpu_idcache_wbinv_all(); /* Now really make sure they are clean. */ __asm __volatile ("mcr\tp15, 0, r0, c7, c7, 0" : : ); if (vector_page == ARM_VECTORS_HIGH) cpuctrl |= CPU_CONTROL_VECRELOC; /* Set the control register */ ctrl = cpuctrl; cpu_control(0xffffffff, cpuctrl); /* And again. */ cpu_idcache_wbinv_all(); } #endif /* CPU_ARM9E || CPU_ARM10 */ #if defined(CPU_ARM1176) \ || defined(CPU_MV_PJ4B) \ || defined(CPU_CORTEXA) || defined(CPU_KRAIT) static __inline void cpu_scc_setup_ccnt(void) { /* This is how you give userland access to the CCNT and PMCn * registers. * BEWARE! This gives write access also, which may not be what * you want! */ #ifdef _PMC_USER_READ_WRITE_ #if defined(CPU_ARM1176) /* Use the Secure User and Non-secure Access Validation Control Register * to allow userland access */ __asm volatile ("mcr p15, 0, %0, c15, c9, 0\n\t" : : "r"(0x00000001)); #else /* Set PMUSERENR[0] to allow userland access */ __asm volatile ("mcr p15, 0, %0, c9, c14, 0\n\t" : : "r"(0x00000001)); #endif #endif #if defined(CPU_ARM1176) /* Set PMCR[2,0] to enable counters and reset CCNT */ __asm volatile ("mcr p15, 0, %0, c15, c12, 0\n\t" : : "r"(0x00000005)); #else /* Set up the PMCCNTR register as a cyclecounter: * Set PMINTENCLR to 0xFFFFFFFF to block interrupts * Set PMCR[2,0] to enable counters and reset CCNT * Set PMCNTENSET to 0x80000000 to enable CCNT */ __asm volatile ("mcr p15, 0, %0, c9, c14, 2\n\t" "mcr p15, 0, %1, c9, c12, 0\n\t" "mcr p15, 0, %2, c9, c12, 1\n\t" : : "r"(0xFFFFFFFF), "r"(0x00000005), "r"(0x80000000)); #endif } #endif #if defined(CPU_ARM1176) void arm11x6_setup(void) { int cpuctrl, cpuctrl_wax; uint32_t auxctrl, auxctrl_wax; uint32_t tmp, tmp2; uint32_t sbz=0; uint32_t cpuid; cpuid = cpufunc_id(); cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_SYST_ENABLE | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_UNAL_ENABLE; /* * "write as existing" bits * inverse of this is mask */ cpuctrl_wax = (3 << 30) | /* SBZ */ (1 << 29) | /* FA */ (1 << 28) | /* TR */ (3 << 26) | /* SBZ */ (3 << 19) | /* SBZ */ (1 << 17); /* SBZ */ cpuctrl |= CPU_CONTROL_BPRD_ENABLE; cpuctrl |= CPU_CONTROL_V6_EXTPAGE; #ifdef __ARMEB__ cpuctrl |= CPU_CONTROL_BEND_ENABLE; #endif if (vector_page == ARM_VECTORS_HIGH) cpuctrl |= CPU_CONTROL_VECRELOC; auxctrl = 0; auxctrl_wax = ~0; /* * Enable an errata workaround */ if ((cpuid & CPU_ID_CPU_MASK) == CPU_ID_ARM1176JZS) { /* ARM1176JZSr0 */ auxctrl = ARM1176_AUXCTL_PHD; auxctrl_wax = ~ARM1176_AUXCTL_PHD; } /* Clear out the cache */ cpu_idcache_wbinv_all(); /* Now really make sure they are clean. */ __asm volatile ("mcr\tp15, 0, %0, c7, c7, 0" : : "r"(sbz)); /* Allow detection code to find the VFP if it's fitted. */ __asm volatile ("mcr\tp15, 0, %0, c1, c0, 2" : : "r" (0x0fffffff)); /* Set the control register */ ctrl = cpuctrl; cpu_control(~cpuctrl_wax, cpuctrl); __asm volatile ("mrc p15, 0, %0, c1, c0, 1\n\t" "and %1, %0, %2\n\t" "orr %1, %1, %3\n\t" "teq %0, %1\n\t" "mcrne p15, 0, %1, c1, c0, 1\n\t" : "=r"(tmp), "=r"(tmp2) : "r"(auxctrl_wax), "r"(auxctrl)); /* And again. */ cpu_idcache_wbinv_all(); cpu_scc_setup_ccnt(); } #endif /* CPU_ARM1176 */ #ifdef CPU_MV_PJ4B void pj4bv7_setup(void) { int cpuctrl; pj4b_config(); cpuctrl = CPU_CONTROL_MMU_ENABLE; #ifndef ARM32_DISABLE_ALIGNMENT_FAULTS cpuctrl |= CPU_CONTROL_AFLT_ENABLE; #endif cpuctrl |= CPU_CONTROL_DC_ENABLE; cpuctrl |= (0xf << 3); cpuctrl |= CPU_CONTROL_BPRD_ENABLE; cpuctrl |= CPU_CONTROL_IC_ENABLE; if (vector_page == ARM_VECTORS_HIGH) cpuctrl |= CPU_CONTROL_VECRELOC; cpuctrl |= (0x5 << 16) | (1 < 22); cpuctrl |= CPU_CONTROL_V6_EXTPAGE; /* Clear out the cache */ cpu_idcache_wbinv_all(); /* Set the control register */ ctrl = cpuctrl; cpu_control(0xFFFFFFFF, cpuctrl); /* And again. */ cpu_idcache_wbinv_all(); cpu_scc_setup_ccnt(); } #endif /* CPU_MV_PJ4B */ #if defined(CPU_CORTEXA) || defined(CPU_KRAIT) void cortexa_setup(void) { int cpuctrl, cpuctrlmask; cpuctrlmask = CPU_CONTROL_MMU_ENABLE | /* MMU enable [0] */ CPU_CONTROL_AFLT_ENABLE | /* Alignment fault [1] */ CPU_CONTROL_DC_ENABLE | /* DCache enable [2] */ CPU_CONTROL_BPRD_ENABLE | /* Branch prediction [11] */ CPU_CONTROL_IC_ENABLE | /* ICache enable [12] */ CPU_CONTROL_VECRELOC; /* Vector relocation [13] */ cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE | CPU_CONTROL_BPRD_ENABLE; #ifndef ARM32_DISABLE_ALIGNMENT_FAULTS cpuctrl |= CPU_CONTROL_AFLT_ENABLE; #endif /* Switch to big endian */ #ifdef __ARMEB__ cpuctrl |= CPU_CONTROL_BEND_ENABLE; #endif /* Check if the vector page is at the high address (0xffff0000) */ if (vector_page == ARM_VECTORS_HIGH) cpuctrl |= CPU_CONTROL_VECRELOC; /* Clear out the cache */ cpu_idcache_wbinv_all(); /* Set the control register */ ctrl = cpuctrl; cpu_control(cpuctrlmask, cpuctrl); /* And again. */ cpu_idcache_wbinv_all(); #ifdef SMP armv7_auxctrl((1 << 6) | (1 << 0), (1 << 6) | (1 << 0)); /* Enable SMP + TLB broadcasting */ #endif cpu_scc_setup_ccnt(); } #endif /* CPU_CORTEXA */ #if defined(CPU_FA526) void fa526_setup(void) { int cpuctrl, cpuctrlmask; cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_BPRD_ENABLE; cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_ROM_ENABLE | CPU_CONTROL_BEND_ENABLE | CPU_CONTROL_AFLT_ENABLE | CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_BPRD_ENABLE | CPU_CONTROL_CPCLK | CPU_CONTROL_VECRELOC; #ifndef ARM32_DISABLE_ALIGNMENT_FAULTS cpuctrl |= CPU_CONTROL_AFLT_ENABLE; #endif #ifdef __ARMEB__ cpuctrl |= CPU_CONTROL_BEND_ENABLE; #endif if (vector_page == ARM_VECTORS_HIGH) cpuctrl |= CPU_CONTROL_VECRELOC; /* Clear out the cache */ cpu_idcache_wbinv_all(); /* Set the control register */ ctrl = cpuctrl; cpu_control(0xffffffff, cpuctrl); } #endif /* CPU_FA526 */ #if defined(CPU_XSCALE_80321) || \ defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425) || \ defined(CPU_XSCALE_80219) || defined(CPU_XSCALE_81342) void xscale_setup(void) { uint32_t auxctl; int cpuctrl, cpuctrlmask; /* * The XScale Write Buffer is always enabled. Our option * is to enable/disable coalescing. Note that bits 6:3 * must always be enabled. */ cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_BPRD_ENABLE; cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_ROM_ENABLE | CPU_CONTROL_BEND_ENABLE | CPU_CONTROL_AFLT_ENABLE | CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_BPRD_ENABLE | CPU_CONTROL_CPCLK | CPU_CONTROL_VECRELOC | \ CPU_CONTROL_L2_ENABLE; #ifndef ARM32_DISABLE_ALIGNMENT_FAULTS cpuctrl |= CPU_CONTROL_AFLT_ENABLE; #endif #ifdef __ARMEB__ cpuctrl |= CPU_CONTROL_BEND_ENABLE; #endif if (vector_page == ARM_VECTORS_HIGH) cpuctrl |= CPU_CONTROL_VECRELOC; #ifdef CPU_XSCALE_CORE3 cpuctrl |= CPU_CONTROL_L2_ENABLE; #endif /* Clear out the cache */ cpu_idcache_wbinv_all(); /* * Set the control register. Note that bits 6:3 must always * be set to 1. */ ctrl = cpuctrl; /* cpu_control(cpuctrlmask, cpuctrl);*/ cpu_control(0xffffffff, cpuctrl); /* Make sure write coalescing is turned on */ __asm __volatile("mrc p15, 0, %0, c1, c0, 1" : "=r" (auxctl)); #ifdef XSCALE_NO_COALESCE_WRITES auxctl |= XSCALE_AUXCTL_K; #else auxctl &= ~XSCALE_AUXCTL_K; #endif #ifdef CPU_XSCALE_CORE3 auxctl |= XSCALE_AUXCTL_LLR; auxctl |= XSCALE_AUXCTL_MD_MASK; #endif __asm __volatile("mcr p15, 0, %0, c1, c0, 1" : : "r" (auxctl)); } #endif /* CPU_XSCALE_80321 || CPU_XSCALE_PXA2X0 || CPU_XSCALE_IXP425 CPU_XSCALE_80219 */ Index: projects/ci20_mips/sys/arm/arm/cpufunc_asm_armv7.S =================================================================== --- projects/ci20_mips/sys/arm/arm/cpufunc_asm_armv7.S (revision 283030) +++ projects/ci20_mips/sys/arm/arm/cpufunc_asm_armv7.S (revision 283031) @@ -1,374 +1,368 @@ /*- * Copyright (c) 2010 Per Odlund * Copyright (C) 2011 MARVELL INTERNATIONAL LTD. * All rights reserved. * * Developed by Semihalf. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of MARVELL nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include .cpu cortex-a8 .Lcoherency_level: .word _C_LABEL(arm_cache_loc) .Lcache_type: .word _C_LABEL(arm_cache_type) .Larmv7_dcache_line_size: .word _C_LABEL(arm_dcache_min_line_size) .Larmv7_icache_line_size: .word _C_LABEL(arm_icache_min_line_size) .Larmv7_idcache_line_size: .word _C_LABEL(arm_idcache_min_line_size) .Lway_mask: .word 0x3ff .Lmax_index: .word 0x7fff .Lpage_mask: .word 0xfff #define PT_NOS (1 << 5) #define PT_S (1 << 1) #define PT_INNER_NC 0 #define PT_INNER_WT (1 << 0) #define PT_INNER_WB ((1 << 0) | (1 << 6)) #define PT_INNER_WBWA (1 << 6) #define PT_OUTER_NC 0 #define PT_OUTER_WT (2 << 3) #define PT_OUTER_WB (3 << 3) #define PT_OUTER_WBWA (1 << 3) #ifdef SMP #define PT_ATTR (PT_S|PT_INNER_WBWA|PT_OUTER_WBWA|PT_NOS) #else #define PT_ATTR (PT_INNER_WBWA|PT_OUTER_WBWA) #endif ENTRY(armv7_setttb) dsb orr r0, r0, #PT_ATTR mcr CP15_TTBR0(r0) isb #ifdef SMP mcr CP15_TLBIALLIS #else mcr CP15_TLBIALL #endif dsb isb RET END(armv7_setttb) ENTRY(armv7_tlb_flushID) dsb #ifdef SMP mcr CP15_TLBIALLIS mcr CP15_BPIALLIS #else mcr CP15_TLBIALL mcr CP15_BPIALL #endif dsb isb mov pc, lr END(armv7_tlb_flushID) ENTRY(armv7_tlb_flushID_SE) ldr r1, .Lpage_mask bic r0, r0, r1 #ifdef SMP mcr CP15_TLBIMVAAIS(r0) mcr CP15_BPIALLIS #else mcr CP15_TLBIMVA(r0) mcr CP15_BPIALL #endif dsb isb mov pc, lr END(armv7_tlb_flushID_SE) /* Based on algorithm from ARM Architecture Reference Manual */ ENTRY(armv7_dcache_wbinv_all) stmdb sp!, {r4, r5, r6, r7, r8, r9} /* Get cache level */ ldr r0, .Lcoherency_level ldr r3, [r0] cmp r3, #0 beq Finished /* For each cache level */ mov r8, #0 Loop1: /* Get cache type for given level */ mov r2, r8, lsl #2 add r2, r2, r2 ldr r0, .Lcache_type ldr r1, [r0, r2] /* Get line size */ and r2, r1, #7 add r2, r2, #4 /* Get number of ways */ ldr r4, .Lway_mask ands r4, r4, r1, lsr #3 clz r5, r4 /* Get max index */ ldr r7, .Lmax_index ands r7, r7, r1, lsr #13 Loop2: mov r9, r4 Loop3: mov r6, r8, lsl #1 orr r6, r6, r9, lsl r5 orr r6, r6, r7, lsl r2 /* Clean and invalidate data cache by way/index */ mcr CP15_DCCISW(r6) subs r9, r9, #1 bge Loop3 subs r7, r7, #1 bge Loop2 Skip: add r8, r8, #1 cmp r3, r8 bne Loop1 Finished: dsb ldmia sp!, {r4, r5, r6, r7, r8, r9} RET END(armv7_dcache_wbinv_all) ENTRY(armv7_idcache_wbinv_all) stmdb sp!, {lr} bl armv7_dcache_wbinv_all #ifdef SMP mcr CP15_ICIALLUIS #else mcr CP15_ICIALLU #endif dsb isb ldmia sp!, {lr} RET END(armv7_idcache_wbinv_all) ENTRY(armv7_dcache_wb_range) ldr ip, .Larmv7_dcache_line_size ldr ip, [ip] sub r3, ip, #1 and r2, r0, r3 add r1, r1, r2 bic r0, r0, r3 .Larmv7_wb_next: mcr CP15_DCCMVAC(r0) add r0, r0, ip subs r1, r1, ip bhi .Larmv7_wb_next dsb /* data synchronization barrier */ RET END(armv7_dcache_wb_range) ENTRY(armv7_dcache_wbinv_range) ldr ip, .Larmv7_dcache_line_size ldr ip, [ip] sub r3, ip, #1 and r2, r0, r3 add r1, r1, r2 bic r0, r0, r3 .Larmv7_wbinv_next: mcr CP15_DCCIMVAC(r0) add r0, r0, ip subs r1, r1, ip bhi .Larmv7_wbinv_next dsb /* data synchronization barrier */ RET END(armv7_dcache_wbinv_range) /* * Note, we must not invalidate everything. If the range is too big we * must use wb-inv of the entire cache. */ ENTRY(armv7_dcache_inv_range) ldr ip, .Larmv7_dcache_line_size ldr ip, [ip] sub r3, ip, #1 and r2, r0, r3 add r1, r1, r2 bic r0, r0, r3 .Larmv7_inv_next: mcr CP15_DCIMVAC(r0) add r0, r0, ip subs r1, r1, ip bhi .Larmv7_inv_next dsb /* data synchronization barrier */ RET END(armv7_dcache_inv_range) ENTRY(armv7_idcache_wbinv_range) ldr ip, .Larmv7_idcache_line_size ldr ip, [ip] sub r3, ip, #1 and r2, r0, r3 add r1, r1, r2 bic r0, r0, r3 .Larmv7_id_wbinv_next: mcr CP15_ICIMVAU(r0) mcr CP15_DCCIMVAC(r0) add r0, r0, ip subs r1, r1, ip bhi .Larmv7_id_wbinv_next dsb /* data synchronization barrier */ isb /* instruction synchronization barrier */ RET END(armv7_idcache_wbinv_range) ENTRY_NP(armv7_icache_sync_all) #ifdef SMP mcr CP15_ICIALLUIS #else mcr CP15_ICIALLU #endif dsb /* data synchronization barrier */ isb /* instruction synchronization barrier */ RET END(armv7_icache_sync_all) ENTRY_NP(armv7_icache_sync_range) ldr ip, .Larmv7_icache_line_size ldr ip, [ip] sub r3, ip, #1 /* Address need not be aligned, but */ and r2, r0, r3 /* round length up if op spans line */ add r1, r1, r2 /* boundary: len += addr & linemask; */ .Larmv7_sync_next: mcr CP15_DCCMVAC(r0) mcr CP15_ICIMVAU(r0) add r0, r0, ip subs r1, r1, ip bhi .Larmv7_sync_next dsb /* data synchronization barrier */ isb /* instruction synchronization barrier */ RET END(armv7_icache_sync_range) ENTRY(armv7_cpu_sleep) dsb /* data synchronization barrier */ wfi /* wait for interrupt */ RET END(armv7_cpu_sleep) ENTRY(armv7_context_switch) dsb orr r0, r0, #PT_ATTR mcr CP15_TTBR0(r0) isb #ifdef SMP mcr CP15_TLBIALLIS #else mcr CP15_TLBIALL #endif dsb isb RET END(armv7_context_switch) ENTRY(armv7_drain_writebuf) dsb RET END(armv7_drain_writebuf) ENTRY(armv7_sev) dsb sev nop RET END(armv7_sev) ENTRY(armv7_auxctrl) mrc CP15_ACTLR(r2) bic r3, r2, r0 /* Clear bits */ eor r3, r3, r1 /* XOR bits */ teq r2, r3 mcrne CP15_ACTLR(r3) mov r0, r2 RET END(armv7_auxctrl) /* * Invalidate all I+D+branch cache. Used by startup code, which counts * on the fact that only r0-r3,ip are modified and no stack space is used. */ ENTRY(armv7_idcache_inv_all) mov r0, #0 mcr CP15_CSSELR(r0) @ set cache level to L1 mrc CP15_CCSIDR(r0) ubfx r2, r0, #13, #15 @ get num sets - 1 from CCSIDR ubfx r3, r0, #3, #10 @ get numways - 1 from CCSIDR clz r1, r3 @ number of bits to MSB of way lsl r3, r3, r1 @ shift into position mov ip, #1 @ lsl ip, ip, r1 @ ip now contains the way decr ubfx r0, r0, #0, #3 @ get linesize from CCSIDR add r0, r0, #4 @ apply bias lsl r2, r2, r0 @ shift sets by log2(linesize) add r3, r3, r2 @ merge numsets - 1 with numways - 1 sub ip, ip, r2 @ subtract numsets - 1 from way decr mov r1, #1 lsl r1, r1, r0 @ r1 now contains the set decr mov r2, ip @ r2 now contains set way decr /* r3 = ways/sets, r2 = way decr, r1 = set decr, r0 and ip are free */ 1: mcr CP15_DCISW(r3) @ invalidate line movs r0, r3 @ get current way/set beq 2f @ at 0 means we are done. movs r0, r0, lsl #10 @ clear way bits leaving only set bits subne r3, r3, r1 @ non-zero?, decrement set # subeq r3, r3, r2 @ zero?, decrement way # and restore set count b 1b 2: dsb @ wait for stores to finish mov r0, #0 @ and ... mcr CP15_ICIALLU @ invalidate instruction+branch cache isb @ instruction sync barrier bx lr @ return END(armv7_idcache_inv_all) -ENTRY_NP(armv7_sleep) - dsb - wfi - bx lr -END(armv7_sleep) - Index: projects/ci20_mips/sys/arm/arm/cpuinfo.c =================================================================== --- projects/ci20_mips/sys/arm/arm/cpuinfo.c (revision 283030) +++ projects/ci20_mips/sys/arm/arm/cpuinfo.c (revision 283031) @@ -1,138 +1,147 @@ /*- * Copyright 2014 Svatopluk Kraus * Copyright 2014 Michal Meloun * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include struct cpuinfo cpuinfo = { /* Use safe defaults for start */ .dcache_line_size = 32, .dcache_line_mask = 31, .icache_line_size = 32, .icache_line_mask = 31, }; /* Read and parse CPU id scheme */ void cpuinfo_init(void) { cpuinfo.midr = cp15_midr_get(); /* Test old version id schemes first */ if ((cpuinfo.midr & CPU_ID_IMPLEMENTOR_MASK) == CPU_ID_ARM_LTD) { if (CPU_ID_ISOLD(cpuinfo.midr)) { /* obsolete ARMv2 or ARMv3 CPU */ cpuinfo.midr = 0; return; } if (CPU_ID_IS7(cpuinfo.midr)) { if ((cpuinfo.midr & (1 << 23)) == 0) { /* obsolete ARMv3 CPU */ cpuinfo.midr = 0; return; } /* ARMv4T CPU */ cpuinfo.architecture = 1; cpuinfo.revision = (cpuinfo.midr >> 16) & 0x7F; } else { /* ARM new id scheme */ cpuinfo.architecture = (cpuinfo.midr >> 16) & 0x0F; cpuinfo.revision = (cpuinfo.midr >> 20) & 0x0F; } } else { /* non ARM -> must be new id scheme */ cpuinfo.architecture = (cpuinfo.midr >> 16) & 0x0F; cpuinfo.revision = (cpuinfo.midr >> 20) & 0x0F; } /* Parse rest of MIDR */ cpuinfo.implementer = (cpuinfo.midr >> 24) & 0xFF; cpuinfo.part_number = (cpuinfo.midr >> 4) & 0xFFF; cpuinfo.patch = cpuinfo.midr & 0x0F; /* CP15 c0,c0 regs 0-7 exist on all CPUs (although aliased with MIDR) */ cpuinfo.ctr = cp15_ctr_get(); cpuinfo.tcmtr = cp15_tcmtr_get(); cpuinfo.tlbtr = cp15_tlbtr_get(); cpuinfo.mpidr = cp15_mpidr_get(); cpuinfo.revidr = cp15_revidr_get(); /* if CPU is not v7 cpu id scheme */ if (cpuinfo.architecture != 0xF) return; cpuinfo.id_pfr0 = cp15_id_pfr0_get(); cpuinfo.id_pfr1 = cp15_id_pfr1_get(); cpuinfo.id_dfr0 = cp15_id_dfr0_get(); cpuinfo.id_afr0 = cp15_id_afr0_get(); cpuinfo.id_mmfr0 = cp15_id_mmfr0_get(); cpuinfo.id_mmfr1 = cp15_id_mmfr1_get(); cpuinfo.id_mmfr2 = cp15_id_mmfr2_get(); cpuinfo.id_mmfr3 = cp15_id_mmfr3_get(); cpuinfo.id_isar0 = cp15_id_isar0_get(); cpuinfo.id_isar1 = cp15_id_isar1_get(); cpuinfo.id_isar2 = cp15_id_isar2_get(); cpuinfo.id_isar3 = cp15_id_isar3_get(); cpuinfo.id_isar4 = cp15_id_isar4_get(); cpuinfo.id_isar5 = cp15_id_isar5_get(); /* Not yet - CBAR only exist on ARM SMP Cortex A CPUs cpuinfo.cbar = cp15_cbar_get(); */ /* Test if revidr is implemented */ if (cpuinfo.revidr == cpuinfo.midr) cpuinfo.revidr = 0; /* parsed bits of above registers */ /* id_mmfr0 */ cpuinfo.outermost_shareability = (cpuinfo.id_mmfr0 >> 8) & 0xF; cpuinfo.shareability_levels = (cpuinfo.id_mmfr0 >> 12) & 0xF; cpuinfo.auxiliary_registers = (cpuinfo.id_mmfr0 >> 20) & 0xF; cpuinfo.innermost_shareability = (cpuinfo.id_mmfr0 >> 28) & 0xF; /* id_mmfr2 */ cpuinfo.mem_barrier = (cpuinfo.id_mmfr2 >> 20) & 0xF; /* id_mmfr3 */ cpuinfo.coherent_walk = (cpuinfo.id_mmfr3 >> 20) & 0xF; cpuinfo.maintenance_broadcast =(cpuinfo.id_mmfr3 >> 12) & 0xF; /* id_pfr1 */ cpuinfo.generic_timer_ext = (cpuinfo.id_pfr1 >> 16) & 0xF; cpuinfo.virtualization_ext = (cpuinfo.id_pfr1 >> 12) & 0xF; cpuinfo.security_ext = (cpuinfo.id_pfr1 >> 4) & 0xF; /* L1 Cache sizes */ - cpuinfo.dcache_line_size = 1 << (CPU_CT_DMINLINE(cpuinfo.ctr ) + 2); + if (CPU_CT_FORMAT(cpuinfo.ctr) == CPU_CT_ARMV7) { + cpuinfo.dcache_line_size = + 1 << (CPU_CT_DMINLINE(cpuinfo.ctr) + 2); + cpuinfo.icache_line_size = + 1 << (CPU_CT_IMINLINE(cpuinfo.ctr) + 2); + } else { + cpuinfo.dcache_line_size = + 1 << (CPU_CT_xSIZE_LEN(CPU_CT_DSIZE(cpuinfo.ctr)) + 3); + cpuinfo.icache_line_size = + 1 << (CPU_CT_xSIZE_LEN(CPU_CT_ISIZE(cpuinfo.ctr)) + 3); + } cpuinfo.dcache_line_mask = cpuinfo.dcache_line_size - 1; - cpuinfo.icache_line_size= 1 << (CPU_CT_IMINLINE(cpuinfo.ctr ) + 2); cpuinfo.icache_line_mask = cpuinfo.icache_line_size - 1; } Index: projects/ci20_mips/sys/arm/arm/pmap.c =================================================================== --- projects/ci20_mips/sys/arm/arm/pmap.c (revision 283030) +++ projects/ci20_mips/sys/arm/arm/pmap.c (revision 283031) @@ -1,4807 +1,4813 @@ /* From: $NetBSD: pmap.c,v 1.148 2004/04/03 04:35:48 bsh Exp $ */ /*- * Copyright 2004 Olivier Houchard. * Copyright 2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Steve C. Woodford for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2002-2003 Wasabi Systems, Inc. * Copyright (c) 2001 Richard Earnshaw * Copyright (c) 2001-2002 Christopher Gilbert * All rights reserved. * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*- * Copyright (c) 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Charles M. Hannum. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 1994-1998 Mark Brinicombe. * Copyright (c) 1994 Brini. * All rights reserved. * * This code is derived from software written for Brini by Mark Brinicombe * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Mark Brinicombe. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * * RiscBSD kernel project * * pmap.c * * Machine dependant vm stuff * * Created : 20/09/94 */ /* * Special compilation symbols * PMAP_DEBUG - Build in pmap_debug_level code * * Note that pmap_mapdev() and pmap_unmapdev() are implemented in arm/devmap.c */ /* Include header files */ #include "opt_vm.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef PMAP_DEBUG #define PDEBUG(_lev_,_stat_) \ if (pmap_debug_level >= (_lev_)) \ ((_stat_)) #define dprintf printf int pmap_debug_level = 0; #define PMAP_INLINE #else /* PMAP_DEBUG */ #define PDEBUG(_lev_,_stat_) /* Nothing */ #define dprintf(x, arg...) #define PMAP_INLINE __inline #endif /* PMAP_DEBUG */ extern struct pv_addr systempage; extern int last_fault_code; /* * Internal function prototypes */ static void pmap_free_pv_entry (pv_entry_t); static pv_entry_t pmap_get_pv_entry(void); static int pmap_enter_locked(pmap_t, vm_offset_t, vm_page_t, vm_prot_t, u_int); static vm_paddr_t pmap_extract_locked(pmap_t pmap, vm_offset_t va); static void pmap_fix_cache(struct vm_page *, pmap_t, vm_offset_t); static void pmap_alloc_l1(pmap_t); static void pmap_free_l1(pmap_t); static int pmap_clearbit(struct vm_page *, u_int); static struct l2_bucket *pmap_get_l2_bucket(pmap_t, vm_offset_t); static struct l2_bucket *pmap_alloc_l2_bucket(pmap_t, vm_offset_t); static void pmap_free_l2_bucket(pmap_t, struct l2_bucket *, u_int); static vm_offset_t kernel_pt_lookup(vm_paddr_t); static MALLOC_DEFINE(M_VMPMAP, "pmap", "PMAP L1"); vm_offset_t virtual_avail; /* VA of first avail page (after kernel bss) */ vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */ vm_offset_t pmap_curmaxkvaddr; vm_paddr_t kernel_l1pa; vm_offset_t kernel_vm_end = 0; vm_offset_t vm_max_kernel_address; struct pmap kernel_pmap_store; static pt_entry_t *csrc_pte, *cdst_pte; static vm_offset_t csrcp, cdstp; static struct mtx cmtx; static void pmap_init_l1(struct l1_ttable *, pd_entry_t *); /* * These routines are called when the CPU type is identified to set up * the PTE prototypes, cache modes, etc. * * The variables are always here, just in case LKMs need to reference * them (though, they shouldn't). */ pt_entry_t pte_l1_s_cache_mode; pt_entry_t pte_l1_s_cache_mode_pt; pt_entry_t pte_l1_s_cache_mask; pt_entry_t pte_l2_l_cache_mode; pt_entry_t pte_l2_l_cache_mode_pt; pt_entry_t pte_l2_l_cache_mask; pt_entry_t pte_l2_s_cache_mode; pt_entry_t pte_l2_s_cache_mode_pt; pt_entry_t pte_l2_s_cache_mask; pt_entry_t pte_l2_s_prot_u; pt_entry_t pte_l2_s_prot_w; pt_entry_t pte_l2_s_prot_mask; pt_entry_t pte_l1_s_proto; pt_entry_t pte_l1_c_proto; pt_entry_t pte_l2_s_proto; void (*pmap_copy_page_func)(vm_paddr_t, vm_paddr_t); void (*pmap_copy_page_offs_func)(vm_paddr_t a_phys, vm_offset_t a_offs, vm_paddr_t b_phys, vm_offset_t b_offs, int cnt); void (*pmap_zero_page_func)(vm_paddr_t, int, int); struct msgbuf *msgbufp = 0; /* * Crashdump maps. */ static caddr_t crashdumpmap; extern void bcopy_page(vm_offset_t, vm_offset_t); extern void bzero_page(vm_offset_t); extern vm_offset_t alloc_firstaddr; char *_tmppt; /* * Metadata for L1 translation tables. */ struct l1_ttable { /* Entry on the L1 Table list */ SLIST_ENTRY(l1_ttable) l1_link; /* Entry on the L1 Least Recently Used list */ TAILQ_ENTRY(l1_ttable) l1_lru; /* Track how many domains are allocated from this L1 */ volatile u_int l1_domain_use_count; /* * A free-list of domain numbers for this L1. * We avoid using ffs() and a bitmap to track domains since ffs() * is slow on ARM. */ u_int8_t l1_domain_first; u_int8_t l1_domain_free[PMAP_DOMAINS]; /* Physical address of this L1 page table */ vm_paddr_t l1_physaddr; /* KVA of this L1 page table */ pd_entry_t *l1_kva; }; /* * Convert a virtual address into its L1 table index. That is, the * index used to locate the L2 descriptor table pointer in an L1 table. * This is basically used to index l1->l1_kva[]. * * Each L2 descriptor table represents 1MB of VA space. */ #define L1_IDX(va) (((vm_offset_t)(va)) >> L1_S_SHIFT) /* * L1 Page Tables are tracked using a Least Recently Used list. * - New L1s are allocated from the HEAD. * - Freed L1s are added to the TAIl. * - Recently accessed L1s (where an 'access' is some change to one of * the userland pmaps which owns this L1) are moved to the TAIL. */ static TAILQ_HEAD(, l1_ttable) l1_lru_list; /* * A list of all L1 tables */ static SLIST_HEAD(, l1_ttable) l1_list; static struct mtx l1_lru_lock; /* * The l2_dtable tracks L2_BUCKET_SIZE worth of L1 slots. * * This is normally 16MB worth L2 page descriptors for any given pmap. * Reference counts are maintained for L2 descriptors so they can be * freed when empty. */ struct l2_dtable { /* The number of L2 page descriptors allocated to this l2_dtable */ u_int l2_occupancy; /* List of L2 page descriptors */ struct l2_bucket { pt_entry_t *l2b_kva; /* KVA of L2 Descriptor Table */ vm_paddr_t l2b_phys; /* Physical address of same */ u_short l2b_l1idx; /* This L2 table's L1 index */ u_short l2b_occupancy; /* How many active descriptors */ } l2_bucket[L2_BUCKET_SIZE]; }; /* pmap_kenter_internal flags */ #define KENTER_CACHE 0x1 #define KENTER_USER 0x2 /* * Given an L1 table index, calculate the corresponding l2_dtable index * and bucket index within the l2_dtable. */ #define L2_IDX(l1idx) (((l1idx) >> L2_BUCKET_LOG2) & \ (L2_SIZE - 1)) #define L2_BUCKET(l1idx) ((l1idx) & (L2_BUCKET_SIZE - 1)) /* * Given a virtual address, this macro returns the * virtual address required to drop into the next L2 bucket. */ #define L2_NEXT_BUCKET(va) (((va) & L1_S_FRAME) + L1_S_SIZE) /* * We try to map the page tables write-through, if possible. However, not * all CPUs have a write-through cache mode, so on those we have to sync * the cache when we frob page tables. * * We try to evaluate this at compile time, if possible. However, it's * not always possible to do that, hence this run-time var. */ int pmap_needs_pte_sync; /* * Macro to determine if a mapping might be resident in the * instruction cache and/or TLB */ #define PV_BEEN_EXECD(f) (((f) & (PVF_REF | PVF_EXEC)) == (PVF_REF | PVF_EXEC)) /* * Macro to determine if a mapping might be resident in the * data cache and/or TLB */ #define PV_BEEN_REFD(f) (((f) & PVF_REF) != 0) #ifndef PMAP_SHPGPERPROC #define PMAP_SHPGPERPROC 200 #endif #define pmap_is_current(pm) ((pm) == pmap_kernel() || \ curproc->p_vmspace->vm_map.pmap == (pm)) static uma_zone_t pvzone = NULL; uma_zone_t l2zone; static uma_zone_t l2table_zone; static vm_offset_t pmap_kernel_l2dtable_kva; static vm_offset_t pmap_kernel_l2ptp_kva; static vm_paddr_t pmap_kernel_l2ptp_phys; static int pv_entry_count=0, pv_entry_max=0, pv_entry_high_water=0; static struct rwlock pvh_global_lock; void pmap_copy_page_offs_generic(vm_paddr_t a_phys, vm_offset_t a_offs, vm_paddr_t b_phys, vm_offset_t b_offs, int cnt); #if ARM_MMU_XSCALE == 1 void pmap_copy_page_offs_xscale(vm_paddr_t a_phys, vm_offset_t a_offs, vm_paddr_t b_phys, vm_offset_t b_offs, int cnt); #endif /* * This list exists for the benefit of pmap_map_chunk(). It keeps track * of the kernel L2 tables during bootstrap, so that pmap_map_chunk() can * find them as necessary. * * Note that the data on this list MUST remain valid after initarm() returns, * as pmap_bootstrap() uses it to contruct L2 table metadata. */ SLIST_HEAD(, pv_addr) kernel_pt_list = SLIST_HEAD_INITIALIZER(kernel_pt_list); static void pmap_init_l1(struct l1_ttable *l1, pd_entry_t *l1pt) { int i; l1->l1_kva = l1pt; l1->l1_domain_use_count = 0; l1->l1_domain_first = 0; for (i = 0; i < PMAP_DOMAINS; i++) l1->l1_domain_free[i] = i + 1; /* * Copy the kernel's L1 entries to each new L1. */ if (l1pt != pmap_kernel()->pm_l1->l1_kva) memcpy(l1pt, pmap_kernel()->pm_l1->l1_kva, L1_TABLE_SIZE); if ((l1->l1_physaddr = pmap_extract(pmap_kernel(), (vm_offset_t)l1pt)) == 0) panic("pmap_init_l1: can't get PA of L1 at %p", l1pt); SLIST_INSERT_HEAD(&l1_list, l1, l1_link); TAILQ_INSERT_TAIL(&l1_lru_list, l1, l1_lru); } static vm_offset_t kernel_pt_lookup(vm_paddr_t pa) { struct pv_addr *pv; SLIST_FOREACH(pv, &kernel_pt_list, pv_list) { if (pv->pv_pa == pa) return (pv->pv_va); } return (0); } #if ARM_MMU_GENERIC != 0 void pmap_pte_init_generic(void) { pte_l1_s_cache_mode = L1_S_B|L1_S_C; pte_l1_s_cache_mask = L1_S_CACHE_MASK_generic; pte_l2_l_cache_mode = L2_B|L2_C; pte_l2_l_cache_mask = L2_L_CACHE_MASK_generic; pte_l2_s_cache_mode = L2_B|L2_C; pte_l2_s_cache_mask = L2_S_CACHE_MASK_generic; /* * If we have a write-through cache, set B and C. If * we have a write-back cache, then we assume setting * only C will make those pages write-through. */ if (cpufuncs.cf_dcache_wb_range == (void *) cpufunc_nullop) { pte_l1_s_cache_mode_pt = L1_S_B|L1_S_C; pte_l2_l_cache_mode_pt = L2_B|L2_C; pte_l2_s_cache_mode_pt = L2_B|L2_C; } else { pte_l1_s_cache_mode_pt = L1_S_C; pte_l2_l_cache_mode_pt = L2_C; pte_l2_s_cache_mode_pt = L2_C; } pte_l2_s_prot_u = L2_S_PROT_U_generic; pte_l2_s_prot_w = L2_S_PROT_W_generic; pte_l2_s_prot_mask = L2_S_PROT_MASK_generic; pte_l1_s_proto = L1_S_PROTO_generic; pte_l1_c_proto = L1_C_PROTO_generic; pte_l2_s_proto = L2_S_PROTO_generic; pmap_copy_page_func = pmap_copy_page_generic; pmap_copy_page_offs_func = pmap_copy_page_offs_generic; pmap_zero_page_func = pmap_zero_page_generic; } #endif /* ARM_MMU_GENERIC != 0 */ #if ARM_MMU_XSCALE == 1 #if (ARM_NMMUS > 1) || defined (CPU_XSCALE_CORE3) static u_int xscale_use_minidata; #endif void pmap_pte_init_xscale(void) { uint32_t auxctl; int write_through = 0; pte_l1_s_cache_mode = L1_S_B|L1_S_C|L1_S_XSCALE_P; pte_l1_s_cache_mask = L1_S_CACHE_MASK_xscale; pte_l2_l_cache_mode = L2_B|L2_C; pte_l2_l_cache_mask = L2_L_CACHE_MASK_xscale; pte_l2_s_cache_mode = L2_B|L2_C; pte_l2_s_cache_mask = L2_S_CACHE_MASK_xscale; pte_l1_s_cache_mode_pt = L1_S_C; pte_l2_l_cache_mode_pt = L2_C; pte_l2_s_cache_mode_pt = L2_C; #ifdef XSCALE_CACHE_READ_WRITE_ALLOCATE /* * The XScale core has an enhanced mode where writes that * miss the cache cause a cache line to be allocated. This * is significantly faster than the traditional, write-through * behavior of this case. */ pte_l1_s_cache_mode |= L1_S_XSCALE_TEX(TEX_XSCALE_X); pte_l2_l_cache_mode |= L2_XSCALE_L_TEX(TEX_XSCALE_X); pte_l2_s_cache_mode |= L2_XSCALE_T_TEX(TEX_XSCALE_X); #endif /* XSCALE_CACHE_READ_WRITE_ALLOCATE */ #ifdef XSCALE_CACHE_WRITE_THROUGH /* * Some versions of the XScale core have various bugs in * their cache units, the work-around for which is to run * the cache in write-through mode. Unfortunately, this * has a major (negative) impact on performance. So, we * go ahead and run fast-and-loose, in the hopes that we * don't line up the planets in a way that will trip the * bugs. * * However, we give you the option to be slow-but-correct. */ write_through = 1; #elif defined(XSCALE_CACHE_WRITE_BACK) /* force write back cache mode */ write_through = 0; #elif defined(CPU_XSCALE_PXA2X0) /* * Intel PXA2[15]0 processors are known to have a bug in * write-back cache on revision 4 and earlier (stepping * A[01] and B[012]). Fixed for C0 and later. */ { uint32_t id, type; id = cpufunc_id(); type = id & ~(CPU_ID_XSCALE_COREREV_MASK|CPU_ID_REVISION_MASK); if (type == CPU_ID_PXA250 || type == CPU_ID_PXA210) { if ((id & CPU_ID_REVISION_MASK) < 5) { /* write through for stepping A0-1 and B0-2 */ write_through = 1; } } } #endif /* XSCALE_CACHE_WRITE_THROUGH */ if (write_through) { pte_l1_s_cache_mode = L1_S_C; pte_l2_l_cache_mode = L2_C; pte_l2_s_cache_mode = L2_C; } #if (ARM_NMMUS > 1) xscale_use_minidata = 1; #endif pte_l2_s_prot_u = L2_S_PROT_U_xscale; pte_l2_s_prot_w = L2_S_PROT_W_xscale; pte_l2_s_prot_mask = L2_S_PROT_MASK_xscale; pte_l1_s_proto = L1_S_PROTO_xscale; pte_l1_c_proto = L1_C_PROTO_xscale; pte_l2_s_proto = L2_S_PROTO_xscale; #ifdef CPU_XSCALE_CORE3 pmap_copy_page_func = pmap_copy_page_generic; pmap_copy_page_offs_func = pmap_copy_page_offs_generic; pmap_zero_page_func = pmap_zero_page_generic; xscale_use_minidata = 0; /* Make sure it is L2-cachable */ pte_l1_s_cache_mode |= L1_S_XSCALE_TEX(TEX_XSCALE_T); pte_l1_s_cache_mode_pt = pte_l1_s_cache_mode &~ L1_S_XSCALE_P; pte_l2_l_cache_mode |= L2_XSCALE_L_TEX(TEX_XSCALE_T) ; pte_l2_l_cache_mode_pt = pte_l1_s_cache_mode; pte_l2_s_cache_mode |= L2_XSCALE_T_TEX(TEX_XSCALE_T); pte_l2_s_cache_mode_pt = pte_l2_s_cache_mode; #else pmap_copy_page_func = pmap_copy_page_xscale; pmap_copy_page_offs_func = pmap_copy_page_offs_xscale; pmap_zero_page_func = pmap_zero_page_xscale; #endif /* * Disable ECC protection of page table access, for now. */ __asm __volatile("mrc p15, 0, %0, c1, c0, 1" : "=r" (auxctl)); auxctl &= ~XSCALE_AUXCTL_P; __asm __volatile("mcr p15, 0, %0, c1, c0, 1" : : "r" (auxctl)); } /* * xscale_setup_minidata: * * Set up the mini-data cache clean area. We require the * caller to allocate the right amount of physically and * virtually contiguous space. */ extern vm_offset_t xscale_minidata_clean_addr; extern vm_size_t xscale_minidata_clean_size; /* already initialized */ void xscale_setup_minidata(vm_offset_t l1pt, vm_offset_t va, vm_paddr_t pa) { pd_entry_t *pde = (pd_entry_t *) l1pt; pt_entry_t *pte; vm_size_t size; uint32_t auxctl; xscale_minidata_clean_addr = va; /* Round it to page size. */ size = (xscale_minidata_clean_size + L2_S_OFFSET) & L2_S_FRAME; for (; size != 0; va += L2_S_SIZE, pa += L2_S_SIZE, size -= L2_S_SIZE) { pte = (pt_entry_t *) kernel_pt_lookup( pde[L1_IDX(va)] & L1_C_ADDR_MASK); if (pte == NULL) panic("xscale_setup_minidata: can't find L2 table for " "VA 0x%08x", (u_int32_t) va); pte[l2pte_index(va)] = L2_S_PROTO | pa | L2_S_PROT(PTE_KERNEL, VM_PROT_READ) | L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X); } /* * Configure the mini-data cache for write-back with * read/write-allocate. * * NOTE: In order to reconfigure the mini-data cache, we must * make sure it contains no valid data! In order to do that, * we must issue a global data cache invalidate command! * * WE ASSUME WE ARE RUNNING UN-CACHED WHEN THIS ROUTINE IS CALLED! * THIS IS VERY IMPORTANT! */ /* Invalidate data and mini-data. */ __asm __volatile("mcr p15, 0, %0, c7, c6, 0" : : "r" (0)); __asm __volatile("mrc p15, 0, %0, c1, c0, 1" : "=r" (auxctl)); auxctl = (auxctl & ~XSCALE_AUXCTL_MD_MASK) | XSCALE_AUXCTL_MD_WB_RWA; __asm __volatile("mcr p15, 0, %0, c1, c0, 1" : : "r" (auxctl)); } #endif /* * Allocate an L1 translation table for the specified pmap. * This is called at pmap creation time. */ static void pmap_alloc_l1(pmap_t pm) { struct l1_ttable *l1; u_int8_t domain; /* * Remove the L1 at the head of the LRU list */ mtx_lock(&l1_lru_lock); l1 = TAILQ_FIRST(&l1_lru_list); TAILQ_REMOVE(&l1_lru_list, l1, l1_lru); /* * Pick the first available domain number, and update * the link to the next number. */ domain = l1->l1_domain_first; l1->l1_domain_first = l1->l1_domain_free[domain]; /* * If there are still free domain numbers in this L1, * put it back on the TAIL of the LRU list. */ if (++l1->l1_domain_use_count < PMAP_DOMAINS) TAILQ_INSERT_TAIL(&l1_lru_list, l1, l1_lru); mtx_unlock(&l1_lru_lock); /* * Fix up the relevant bits in the pmap structure */ pm->pm_l1 = l1; pm->pm_domain = domain + 1; } /* * Free an L1 translation table. * This is called at pmap destruction time. */ static void pmap_free_l1(pmap_t pm) { struct l1_ttable *l1 = pm->pm_l1; mtx_lock(&l1_lru_lock); /* * If this L1 is currently on the LRU list, remove it. */ if (l1->l1_domain_use_count < PMAP_DOMAINS) TAILQ_REMOVE(&l1_lru_list, l1, l1_lru); /* * Free up the domain number which was allocated to the pmap */ l1->l1_domain_free[pm->pm_domain - 1] = l1->l1_domain_first; l1->l1_domain_first = pm->pm_domain - 1; l1->l1_domain_use_count--; /* * The L1 now must have at least 1 free domain, so add * it back to the LRU list. If the use count is zero, * put it at the head of the list, otherwise it goes * to the tail. */ if (l1->l1_domain_use_count == 0) { TAILQ_INSERT_HEAD(&l1_lru_list, l1, l1_lru); } else TAILQ_INSERT_TAIL(&l1_lru_list, l1, l1_lru); mtx_unlock(&l1_lru_lock); } /* * Returns a pointer to the L2 bucket associated with the specified pmap * and VA, or NULL if no L2 bucket exists for the address. */ static PMAP_INLINE struct l2_bucket * pmap_get_l2_bucket(pmap_t pm, vm_offset_t va) { struct l2_dtable *l2; struct l2_bucket *l2b; u_short l1idx; l1idx = L1_IDX(va); if ((l2 = pm->pm_l2[L2_IDX(l1idx)]) == NULL || (l2b = &l2->l2_bucket[L2_BUCKET(l1idx)])->l2b_kva == NULL) return (NULL); return (l2b); } /* * Returns a pointer to the L2 bucket associated with the specified pmap * and VA. * * If no L2 bucket exists, perform the necessary allocations to put an L2 * bucket/page table in place. * * Note that if a new L2 bucket/page was allocated, the caller *must* * increment the bucket occupancy counter appropriately *before* * releasing the pmap's lock to ensure no other thread or cpu deallocates * the bucket/page in the meantime. */ static struct l2_bucket * pmap_alloc_l2_bucket(pmap_t pm, vm_offset_t va) { struct l2_dtable *l2; struct l2_bucket *l2b; u_short l1idx; l1idx = L1_IDX(va); PMAP_ASSERT_LOCKED(pm); rw_assert(&pvh_global_lock, RA_WLOCKED); if ((l2 = pm->pm_l2[L2_IDX(l1idx)]) == NULL) { /* * No mapping at this address, as there is * no entry in the L1 table. * Need to allocate a new l2_dtable. */ PMAP_UNLOCK(pm); rw_wunlock(&pvh_global_lock); if ((l2 = uma_zalloc(l2table_zone, M_NOWAIT)) == NULL) { rw_wlock(&pvh_global_lock); PMAP_LOCK(pm); return (NULL); } rw_wlock(&pvh_global_lock); PMAP_LOCK(pm); if (pm->pm_l2[L2_IDX(l1idx)] != NULL) { /* * Someone already allocated the l2_dtable while * we were doing the same. */ uma_zfree(l2table_zone, l2); l2 = pm->pm_l2[L2_IDX(l1idx)]; } else { bzero(l2, sizeof(*l2)); /* * Link it into the parent pmap */ pm->pm_l2[L2_IDX(l1idx)] = l2; } } l2b = &l2->l2_bucket[L2_BUCKET(l1idx)]; /* * Fetch pointer to the L2 page table associated with the address. */ if (l2b->l2b_kva == NULL) { pt_entry_t *ptep; /* * No L2 page table has been allocated. Chances are, this * is because we just allocated the l2_dtable, above. */ l2->l2_occupancy++; PMAP_UNLOCK(pm); rw_wunlock(&pvh_global_lock); ptep = uma_zalloc(l2zone, M_NOWAIT); rw_wlock(&pvh_global_lock); PMAP_LOCK(pm); if (l2b->l2b_kva != 0) { /* We lost the race. */ l2->l2_occupancy--; uma_zfree(l2zone, ptep); return (l2b); } l2b->l2b_phys = vtophys(ptep); if (ptep == NULL) { /* * Oops, no more L2 page tables available at this * time. We may need to deallocate the l2_dtable * if we allocated a new one above. */ l2->l2_occupancy--; if (l2->l2_occupancy == 0) { pm->pm_l2[L2_IDX(l1idx)] = NULL; uma_zfree(l2table_zone, l2); } return (NULL); } l2b->l2b_kva = ptep; l2b->l2b_l1idx = l1idx; } return (l2b); } static PMAP_INLINE void #ifndef PMAP_INCLUDE_PTE_SYNC pmap_free_l2_ptp(pt_entry_t *l2) #else pmap_free_l2_ptp(boolean_t need_sync, pt_entry_t *l2) #endif { #ifdef PMAP_INCLUDE_PTE_SYNC /* * Note: With a write-back cache, we may need to sync this * L2 table before re-using it. * This is because it may have belonged to a non-current * pmap, in which case the cache syncs would have been * skipped when the pages were being unmapped. If the * L2 table were then to be immediately re-allocated to * the *current* pmap, it may well contain stale mappings * which have not yet been cleared by a cache write-back * and so would still be visible to the mmu. */ if (need_sync) PTE_SYNC_RANGE(l2, L2_TABLE_SIZE_REAL / sizeof(pt_entry_t)); #endif uma_zfree(l2zone, l2); } /* * One or more mappings in the specified L2 descriptor table have just been * invalidated. * * Garbage collect the metadata and descriptor table itself if necessary. * * The pmap lock must be acquired when this is called (not necessary * for the kernel pmap). */ static void pmap_free_l2_bucket(pmap_t pm, struct l2_bucket *l2b, u_int count) { struct l2_dtable *l2; pd_entry_t *pl1pd, l1pd; pt_entry_t *ptep; u_short l1idx; /* * Update the bucket's reference count according to how many * PTEs the caller has just invalidated. */ l2b->l2b_occupancy -= count; /* * Note: * * Level 2 page tables allocated to the kernel pmap are never freed * as that would require checking all Level 1 page tables and * removing any references to the Level 2 page table. See also the * comment elsewhere about never freeing bootstrap L2 descriptors. * * We make do with just invalidating the mapping in the L2 table. * * This isn't really a big deal in practice and, in fact, leads * to a performance win over time as we don't need to continually * alloc/free. */ if (l2b->l2b_occupancy > 0 || pm == pmap_kernel()) return; /* * There are no more valid mappings in this level 2 page table. * Go ahead and NULL-out the pointer in the bucket, then * free the page table. */ l1idx = l2b->l2b_l1idx; ptep = l2b->l2b_kva; l2b->l2b_kva = NULL; pl1pd = &pm->pm_l1->l1_kva[l1idx]; /* * If the L1 slot matches the pmap's domain * number, then invalidate it. */ l1pd = *pl1pd & (L1_TYPE_MASK | L1_C_DOM_MASK); if (l1pd == (L1_C_DOM(pm->pm_domain) | L1_TYPE_C)) { *pl1pd = 0; PTE_SYNC(pl1pd); } /* * Release the L2 descriptor table back to the pool cache. */ #ifndef PMAP_INCLUDE_PTE_SYNC pmap_free_l2_ptp(ptep); #else pmap_free_l2_ptp(!pmap_is_current(pm), ptep); #endif /* * Update the reference count in the associated l2_dtable */ l2 = pm->pm_l2[L2_IDX(l1idx)]; if (--l2->l2_occupancy > 0) return; /* * There are no more valid mappings in any of the Level 1 * slots managed by this l2_dtable. Go ahead and NULL-out * the pointer in the parent pmap and free the l2_dtable. */ pm->pm_l2[L2_IDX(l1idx)] = NULL; uma_zfree(l2table_zone, l2); } /* * Pool cache constructors for L2 descriptor tables, metadata and pmap * structures. */ static int pmap_l2ptp_ctor(void *mem, int size, void *arg, int flags) { #ifndef PMAP_INCLUDE_PTE_SYNC struct l2_bucket *l2b; pt_entry_t *ptep, pte; vm_offset_t va = (vm_offset_t)mem & ~PAGE_MASK; /* * The mappings for these page tables were initially made using * pmap_kenter() by the pool subsystem. Therefore, the cache- * mode will not be right for page table mappings. To avoid * polluting the pmap_kenter() code with a special case for * page tables, we simply fix up the cache-mode here if it's not * correct. */ l2b = pmap_get_l2_bucket(pmap_kernel(), va); ptep = &l2b->l2b_kva[l2pte_index(va)]; pte = *ptep; if ((pte & L2_S_CACHE_MASK) != pte_l2_s_cache_mode_pt) { /* * Page tables must have the cache-mode set to * Write-Thru. */ *ptep = (pte & ~L2_S_CACHE_MASK) | pte_l2_s_cache_mode_pt; PTE_SYNC(ptep); cpu_tlb_flushD_SE(va); cpu_cpwait(); } #endif memset(mem, 0, L2_TABLE_SIZE_REAL); PTE_SYNC_RANGE(mem, L2_TABLE_SIZE_REAL / sizeof(pt_entry_t)); return (0); } /* * A bunch of routines to conditionally flush the caches/TLB depending * on whether the specified pmap actually needs to be flushed at any * given time. */ static PMAP_INLINE void pmap_tlb_flushID_SE(pmap_t pm, vm_offset_t va) { if (pmap_is_current(pm)) cpu_tlb_flushID_SE(va); } static PMAP_INLINE void pmap_tlb_flushD_SE(pmap_t pm, vm_offset_t va) { if (pmap_is_current(pm)) cpu_tlb_flushD_SE(va); } static PMAP_INLINE void pmap_tlb_flushID(pmap_t pm) { if (pmap_is_current(pm)) cpu_tlb_flushID(); } static PMAP_INLINE void pmap_tlb_flushD(pmap_t pm) { if (pmap_is_current(pm)) cpu_tlb_flushD(); } static int pmap_has_valid_mapping(pmap_t pm, vm_offset_t va) { pd_entry_t *pde; pt_entry_t *ptep; if (pmap_get_pde_pte(pm, va, &pde, &ptep) && ptep && ((*ptep & L2_TYPE_MASK) != L2_TYPE_INV)) return (1); return (0); } static PMAP_INLINE void pmap_idcache_wbinv_range(pmap_t pm, vm_offset_t va, vm_size_t len) { vm_size_t rest; CTR4(KTR_PMAP, "pmap_dcache_wbinv_range: pmap %p is_kernel %d va 0x%08x" " len 0x%x ", pm, pm == pmap_kernel(), va, len); if (pmap_is_current(pm) || pm == pmap_kernel()) { rest = MIN(PAGE_SIZE - (va & PAGE_MASK), len); while (len > 0) { if (pmap_has_valid_mapping(pm, va)) { cpu_idcache_wbinv_range(va, rest); cpu_l2cache_wbinv_range(va, rest); } len -= rest; va += rest; rest = MIN(PAGE_SIZE, len); } } } static PMAP_INLINE void pmap_dcache_wb_range(pmap_t pm, vm_offset_t va, vm_size_t len, boolean_t do_inv, boolean_t rd_only) { vm_size_t rest; CTR4(KTR_PMAP, "pmap_dcache_wb_range: pmap %p is_kernel %d va 0x%08x " "len 0x%x ", pm, pm == pmap_kernel(), va, len); CTR2(KTR_PMAP, " do_inv %d rd_only %d", do_inv, rd_only); if (pmap_is_current(pm)) { rest = MIN(PAGE_SIZE - (va & PAGE_MASK), len); while (len > 0) { if (pmap_has_valid_mapping(pm, va)) { if (do_inv && rd_only) { cpu_dcache_inv_range(va, rest); cpu_l2cache_inv_range(va, rest); } else if (do_inv) { cpu_dcache_wbinv_range(va, rest); cpu_l2cache_wbinv_range(va, rest); } else if (!rd_only) { cpu_dcache_wb_range(va, rest); cpu_l2cache_wb_range(va, rest); } } len -= rest; va += rest; rest = MIN(PAGE_SIZE, len); } } } static PMAP_INLINE void pmap_idcache_wbinv_all(pmap_t pm) { if (pmap_is_current(pm)) { cpu_idcache_wbinv_all(); cpu_l2cache_wbinv_all(); } } #ifdef notyet static PMAP_INLINE void pmap_dcache_wbinv_all(pmap_t pm) { if (pmap_is_current(pm)) { cpu_dcache_wbinv_all(); cpu_l2cache_wbinv_all(); } } #endif /* * PTE_SYNC_CURRENT: * * Make sure the pte is written out to RAM. * We need to do this for one of two cases: * - We're dealing with the kernel pmap * - There is no pmap active in the cache/tlb. * - The specified pmap is 'active' in the cache/tlb. */ #ifdef PMAP_INCLUDE_PTE_SYNC #define PTE_SYNC_CURRENT(pm, ptep) \ do { \ if (PMAP_NEEDS_PTE_SYNC && \ pmap_is_current(pm)) \ PTE_SYNC(ptep); \ } while (/*CONSTCOND*/0) #else #define PTE_SYNC_CURRENT(pm, ptep) /* nothing */ #endif /* * cacheable == -1 means we must make the entry uncacheable, 1 means * cacheable; */ static __inline void pmap_set_cache_entry(pv_entry_t pv, pmap_t pm, vm_offset_t va, int cacheable) { struct l2_bucket *l2b; pt_entry_t *ptep, pte; l2b = pmap_get_l2_bucket(pv->pv_pmap, pv->pv_va); ptep = &l2b->l2b_kva[l2pte_index(pv->pv_va)]; if (cacheable == 1) { pte = (*ptep & ~L2_S_CACHE_MASK) | pte_l2_s_cache_mode; if (l2pte_valid(pte)) { if (PV_BEEN_EXECD(pv->pv_flags)) { pmap_tlb_flushID_SE(pv->pv_pmap, pv->pv_va); } else if (PV_BEEN_REFD(pv->pv_flags)) { pmap_tlb_flushD_SE(pv->pv_pmap, pv->pv_va); } } } else { pte = *ptep &~ L2_S_CACHE_MASK; if ((va != pv->pv_va || pm != pv->pv_pmap) && l2pte_valid(pte)) { if (PV_BEEN_EXECD(pv->pv_flags)) { pmap_idcache_wbinv_range(pv->pv_pmap, pv->pv_va, PAGE_SIZE); pmap_tlb_flushID_SE(pv->pv_pmap, pv->pv_va); } else if (PV_BEEN_REFD(pv->pv_flags)) { pmap_dcache_wb_range(pv->pv_pmap, pv->pv_va, PAGE_SIZE, TRUE, (pv->pv_flags & PVF_WRITE) == 0); pmap_tlb_flushD_SE(pv->pv_pmap, pv->pv_va); } } } *ptep = pte; PTE_SYNC_CURRENT(pv->pv_pmap, ptep); } static void pmap_fix_cache(struct vm_page *pg, pmap_t pm, vm_offset_t va) { int pmwc = 0; int writable = 0, kwritable = 0, uwritable = 0; int entries = 0, kentries = 0, uentries = 0; struct pv_entry *pv; rw_assert(&pvh_global_lock, RA_WLOCKED); /* the cache gets written back/invalidated on context switch. * therefore, if a user page shares an entry in the same page or * with the kernel map and at least one is writable, then the * cache entry must be set write-through. */ TAILQ_FOREACH(pv, &pg->md.pv_list, pv_list) { /* generate a count of the pv_entry uses */ if (pv->pv_flags & PVF_WRITE) { if (pv->pv_pmap == pmap_kernel()) kwritable++; else if (pv->pv_pmap == pm) uwritable++; writable++; } if (pv->pv_pmap == pmap_kernel()) kentries++; else { if (pv->pv_pmap == pm) uentries++; entries++; } } /* * check if the user duplicate mapping has * been removed. */ if ((pm != pmap_kernel()) && (((uentries > 1) && uwritable) || (uwritable > 1))) pmwc = 1; TAILQ_FOREACH(pv, &pg->md.pv_list, pv_list) { /* check for user uncachable conditions - order is important */ if (pm != pmap_kernel() && (pv->pv_pmap == pm || pv->pv_pmap == pmap_kernel())) { if ((uentries > 1 && uwritable) || uwritable > 1) { /* user duplicate mapping */ if (pv->pv_pmap != pmap_kernel()) pv->pv_flags |= PVF_MWC; if (!(pv->pv_flags & PVF_NC)) { pv->pv_flags |= PVF_NC; pmap_set_cache_entry(pv, pm, va, -1); } continue; } else /* no longer a duplicate user */ pv->pv_flags &= ~PVF_MWC; } /* * check for kernel uncachable conditions * kernel writable or kernel readable with writable user entry */ if ((kwritable && (entries || kentries > 1)) || (kwritable > 1) || ((kwritable != writable) && kentries && (pv->pv_pmap == pmap_kernel() || (pv->pv_flags & PVF_WRITE) || (pv->pv_flags & PVF_MWC)))) { if (!(pv->pv_flags & PVF_NC)) { pv->pv_flags |= PVF_NC; pmap_set_cache_entry(pv, pm, va, -1); } continue; } /* kernel and user are cachable */ if ((pm == pmap_kernel()) && !(pv->pv_flags & PVF_MWC) && (pv->pv_flags & PVF_NC)) { pv->pv_flags &= ~PVF_NC; if (pg->md.pv_memattr != VM_MEMATTR_UNCACHEABLE) pmap_set_cache_entry(pv, pm, va, 1); continue; } /* user is no longer sharable and writable */ if (pm != pmap_kernel() && (pv->pv_pmap == pm || pv->pv_pmap == pmap_kernel()) && !pmwc && (pv->pv_flags & PVF_NC)) { pv->pv_flags &= ~(PVF_NC | PVF_MWC); if (pg->md.pv_memattr != VM_MEMATTR_UNCACHEABLE) pmap_set_cache_entry(pv, pm, va, 1); } } if ((kwritable == 0) && (writable == 0)) { pg->md.pvh_attrs &= ~PVF_MOD; vm_page_aflag_clear(pg, PGA_WRITEABLE); return; } } /* * Modify pte bits for all ptes corresponding to the given physical address. * We use `maskbits' rather than `clearbits' because we're always passing * constants and the latter would require an extra inversion at run-time. */ static int pmap_clearbit(struct vm_page *pg, u_int maskbits) { struct l2_bucket *l2b; struct pv_entry *pv; pt_entry_t *ptep, npte, opte; pmap_t pm; vm_offset_t va; u_int oflags; int count = 0; rw_wlock(&pvh_global_lock); if (maskbits & PVF_WRITE) maskbits |= PVF_MOD; /* * Clear saved attributes (modify, reference) */ pg->md.pvh_attrs &= ~(maskbits & (PVF_MOD | PVF_REF)); if (TAILQ_EMPTY(&pg->md.pv_list)) { rw_wunlock(&pvh_global_lock); return (0); } /* * Loop over all current mappings setting/clearing as appropos */ TAILQ_FOREACH(pv, &pg->md.pv_list, pv_list) { va = pv->pv_va; pm = pv->pv_pmap; oflags = pv->pv_flags; if (!(oflags & maskbits)) { if ((maskbits & PVF_WRITE) && (pv->pv_flags & PVF_NC)) { if (pg->md.pv_memattr != VM_MEMATTR_UNCACHEABLE) { PMAP_LOCK(pm); l2b = pmap_get_l2_bucket(pm, va); ptep = &l2b->l2b_kva[l2pte_index(va)]; *ptep |= pte_l2_s_cache_mode; PTE_SYNC(ptep); PMAP_UNLOCK(pm); } pv->pv_flags &= ~(PVF_NC | PVF_MWC); } continue; } pv->pv_flags &= ~maskbits; PMAP_LOCK(pm); l2b = pmap_get_l2_bucket(pm, va); ptep = &l2b->l2b_kva[l2pte_index(va)]; npte = opte = *ptep; if (maskbits & (PVF_WRITE|PVF_MOD)) { if ((pv->pv_flags & PVF_NC)) { /* * Entry is not cacheable: * * Don't turn caching on again if this is a * modified emulation. This would be * inconsitent with the settings created by * pmap_fix_cache(). Otherwise, it's safe * to re-enable cacheing. * * There's no need to call pmap_fix_cache() * here: all pages are losing their write * permission. */ if (maskbits & PVF_WRITE) { if (pg->md.pv_memattr != VM_MEMATTR_UNCACHEABLE) npte |= pte_l2_s_cache_mode; pv->pv_flags &= ~(PVF_NC | PVF_MWC); } } else if (opte & L2_S_PROT_W) { vm_page_dirty(pg); /* * Entry is writable/cacheable: check if pmap * is current if it is flush it, otherwise it * won't be in the cache */ if (PV_BEEN_EXECD(oflags)) pmap_idcache_wbinv_range(pm, pv->pv_va, PAGE_SIZE); else if (PV_BEEN_REFD(oflags)) pmap_dcache_wb_range(pm, pv->pv_va, PAGE_SIZE, (maskbits & PVF_REF) ? TRUE : FALSE, FALSE); } /* make the pte read only */ npte &= ~L2_S_PROT_W; } if (maskbits & PVF_REF) { if ((pv->pv_flags & PVF_NC) == 0 && (maskbits & (PVF_WRITE|PVF_MOD)) == 0) { /* * Check npte here; we may have already * done the wbinv above, and the validity * of the PTE is the same for opte and * npte. */ if (npte & L2_S_PROT_W) { if (PV_BEEN_EXECD(oflags)) pmap_idcache_wbinv_range(pm, pv->pv_va, PAGE_SIZE); else if (PV_BEEN_REFD(oflags)) pmap_dcache_wb_range(pm, pv->pv_va, PAGE_SIZE, TRUE, FALSE); } else if ((npte & L2_TYPE_MASK) != L2_TYPE_INV) { /* XXXJRT need idcache_inv_range */ if (PV_BEEN_EXECD(oflags)) pmap_idcache_wbinv_range(pm, pv->pv_va, PAGE_SIZE); else if (PV_BEEN_REFD(oflags)) pmap_dcache_wb_range(pm, pv->pv_va, PAGE_SIZE, TRUE, TRUE); } } /* * Make the PTE invalid so that we will take a * page fault the next time the mapping is * referenced. */ npte &= ~L2_TYPE_MASK; npte |= L2_TYPE_INV; } if (npte != opte) { count++; *ptep = npte; PTE_SYNC(ptep); /* Flush the TLB entry if a current pmap. */ if (PV_BEEN_EXECD(oflags)) pmap_tlb_flushID_SE(pm, pv->pv_va); else if (PV_BEEN_REFD(oflags)) pmap_tlb_flushD_SE(pm, pv->pv_va); } PMAP_UNLOCK(pm); } if (maskbits & PVF_WRITE) vm_page_aflag_clear(pg, PGA_WRITEABLE); rw_wunlock(&pvh_global_lock); return (count); } /* * main pv_entry manipulation functions: * pmap_enter_pv: enter a mapping onto a vm_page list * pmap_remove_pv: remove a mappiing from a vm_page list * * NOTE: pmap_enter_pv expects to lock the pvh itself * pmap_remove_pv expects the caller to lock the pvh before calling */ /* * pmap_enter_pv: enter a mapping onto a vm_page's PV list * * => caller should hold the proper lock on pvh_global_lock * => caller should have pmap locked * => we will (someday) gain the lock on the vm_page's PV list * => caller should adjust ptp's wire_count before calling * => caller should not adjust pmap's wire_count */ static void pmap_enter_pv(struct vm_page *pg, struct pv_entry *pve, pmap_t pm, vm_offset_t va, u_int flags) { rw_assert(&pvh_global_lock, RA_WLOCKED); PMAP_ASSERT_LOCKED(pm); if (pg->md.pv_kva != 0) { pve->pv_pmap = kernel_pmap; pve->pv_va = pg->md.pv_kva; pve->pv_flags = PVF_WRITE | PVF_UNMAN; if (pm != kernel_pmap) PMAP_LOCK(kernel_pmap); TAILQ_INSERT_HEAD(&pg->md.pv_list, pve, pv_list); TAILQ_INSERT_HEAD(&kernel_pmap->pm_pvlist, pve, pv_plist); if (pm != kernel_pmap) PMAP_UNLOCK(kernel_pmap); pg->md.pv_kva = 0; if ((pve = pmap_get_pv_entry()) == NULL) panic("pmap_kenter_pv: no pv entries"); } pve->pv_pmap = pm; pve->pv_va = va; pve->pv_flags = flags; TAILQ_INSERT_HEAD(&pg->md.pv_list, pve, pv_list); TAILQ_INSERT_HEAD(&pm->pm_pvlist, pve, pv_plist); pg->md.pvh_attrs |= flags & (PVF_REF | PVF_MOD); if (pve->pv_flags & PVF_WIRED) ++pm->pm_stats.wired_count; vm_page_aflag_set(pg, PGA_REFERENCED); } /* * * pmap_find_pv: Find a pv entry * * => caller should hold lock on vm_page */ static PMAP_INLINE struct pv_entry * pmap_find_pv(struct vm_page *pg, pmap_t pm, vm_offset_t va) { struct pv_entry *pv; rw_assert(&pvh_global_lock, RA_WLOCKED); TAILQ_FOREACH(pv, &pg->md.pv_list, pv_list) if (pm == pv->pv_pmap && va == pv->pv_va) break; return (pv); } /* * vector_page_setprot: * * Manipulate the protection of the vector page. */ void vector_page_setprot(int prot) { struct l2_bucket *l2b; pt_entry_t *ptep; l2b = pmap_get_l2_bucket(pmap_kernel(), vector_page); ptep = &l2b->l2b_kva[l2pte_index(vector_page)]; *ptep = (*ptep & ~L1_S_PROT_MASK) | L2_S_PROT(PTE_KERNEL, prot); PTE_SYNC(ptep); cpu_tlb_flushD_SE(vector_page); cpu_cpwait(); } /* * pmap_remove_pv: try to remove a mapping from a pv_list * * => caller should hold proper lock on pmap_main_lock * => pmap should be locked * => caller should hold lock on vm_page [so that attrs can be adjusted] * => caller should adjust ptp's wire_count and free PTP if needed * => caller should NOT adjust pmap's wire_count * => we return the removed pve */ static void pmap_nuke_pv(struct vm_page *pg, pmap_t pm, struct pv_entry *pve) { struct pv_entry *pv; rw_assert(&pvh_global_lock, RA_WLOCKED); PMAP_ASSERT_LOCKED(pm); TAILQ_REMOVE(&pg->md.pv_list, pve, pv_list); TAILQ_REMOVE(&pm->pm_pvlist, pve, pv_plist); if (pve->pv_flags & PVF_WIRED) --pm->pm_stats.wired_count; if (pg->md.pvh_attrs & PVF_MOD) vm_page_dirty(pg); if (TAILQ_FIRST(&pg->md.pv_list) == NULL) pg->md.pvh_attrs &= ~PVF_REF; else vm_page_aflag_set(pg, PGA_REFERENCED); if ((pve->pv_flags & PVF_NC) && ((pm == pmap_kernel()) || (pve->pv_flags & PVF_WRITE) || !(pve->pv_flags & PVF_MWC))) pmap_fix_cache(pg, pm, 0); else if (pve->pv_flags & PVF_WRITE) { TAILQ_FOREACH(pve, &pg->md.pv_list, pv_list) if (pve->pv_flags & PVF_WRITE) break; if (!pve) { pg->md.pvh_attrs &= ~PVF_MOD; vm_page_aflag_clear(pg, PGA_WRITEABLE); } } pv = TAILQ_FIRST(&pg->md.pv_list); if (pv != NULL && (pv->pv_flags & PVF_UNMAN) && TAILQ_NEXT(pv, pv_list) == NULL) { pm = kernel_pmap; pg->md.pv_kva = pv->pv_va; /* a recursive pmap_nuke_pv */ TAILQ_REMOVE(&pg->md.pv_list, pv, pv_list); TAILQ_REMOVE(&pm->pm_pvlist, pv, pv_plist); if (pv->pv_flags & PVF_WIRED) --pm->pm_stats.wired_count; pg->md.pvh_attrs &= ~PVF_REF; pg->md.pvh_attrs &= ~PVF_MOD; vm_page_aflag_clear(pg, PGA_WRITEABLE); pmap_free_pv_entry(pv); } } static struct pv_entry * pmap_remove_pv(struct vm_page *pg, pmap_t pm, vm_offset_t va) { struct pv_entry *pve; rw_assert(&pvh_global_lock, RA_WLOCKED); pve = TAILQ_FIRST(&pg->md.pv_list); while (pve) { if (pve->pv_pmap == pm && pve->pv_va == va) { /* match? */ pmap_nuke_pv(pg, pm, pve); break; } pve = TAILQ_NEXT(pve, pv_list); } if (pve == NULL && pg->md.pv_kva == va) pg->md.pv_kva = 0; return(pve); /* return removed pve */ } /* * * pmap_modify_pv: Update pv flags * * => caller should hold lock on vm_page [so that attrs can be adjusted] * => caller should NOT adjust pmap's wire_count * => we return the old flags * * Modify a physical-virtual mapping in the pv table */ static u_int pmap_modify_pv(struct vm_page *pg, pmap_t pm, vm_offset_t va, u_int clr_mask, u_int set_mask) { struct pv_entry *npv; u_int flags, oflags; PMAP_ASSERT_LOCKED(pm); rw_assert(&pvh_global_lock, RA_WLOCKED); if ((npv = pmap_find_pv(pg, pm, va)) == NULL) return (0); /* * There is at least one VA mapping this page. */ if (clr_mask & (PVF_REF | PVF_MOD)) pg->md.pvh_attrs |= set_mask & (PVF_REF | PVF_MOD); oflags = npv->pv_flags; npv->pv_flags = flags = (oflags & ~clr_mask) | set_mask; if ((flags ^ oflags) & PVF_WIRED) { if (flags & PVF_WIRED) ++pm->pm_stats.wired_count; else --pm->pm_stats.wired_count; } if ((flags ^ oflags) & PVF_WRITE) pmap_fix_cache(pg, pm, 0); return (oflags); } /* Function to set the debug level of the pmap code */ #ifdef PMAP_DEBUG void pmap_debug(int level) { pmap_debug_level = level; dprintf("pmap_debug: level=%d\n", pmap_debug_level); } #endif /* PMAP_DEBUG */ void pmap_pinit0(struct pmap *pmap) { PDEBUG(1, printf("pmap_pinit0: pmap = %08x\n", (u_int32_t) pmap)); bcopy(kernel_pmap, pmap, sizeof(*pmap)); bzero(&pmap->pm_mtx, sizeof(pmap->pm_mtx)); PMAP_LOCK_INIT(pmap); } /* * Initialize a vm_page's machine-dependent fields. */ void pmap_page_init(vm_page_t m) { TAILQ_INIT(&m->md.pv_list); m->md.pv_memattr = VM_MEMATTR_DEFAULT; } /* * Initialize the pmap module. * Called by vm_init, to initialize any structures that the pmap * system needs to map virtual memory. */ void pmap_init(void) { int shpgperproc = PMAP_SHPGPERPROC; l2zone = uma_zcreate("L2 Table", L2_TABLE_SIZE_REAL, pmap_l2ptp_ctor, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM | UMA_ZONE_NOFREE); l2table_zone = uma_zcreate("L2 Table", sizeof(struct l2_dtable), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM | UMA_ZONE_NOFREE); /* * Initialize the PV entry allocator. */ pvzone = uma_zcreate("PV ENTRY", sizeof (struct pv_entry), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM | UMA_ZONE_NOFREE); TUNABLE_INT_FETCH("vm.pmap.shpgperproc", &shpgperproc); pv_entry_max = shpgperproc * maxproc + vm_cnt.v_page_count; uma_zone_reserve_kva(pvzone, pv_entry_max); pv_entry_high_water = 9 * (pv_entry_max / 10); /* * Now it is safe to enable pv_table recording. */ PDEBUG(1, printf("pmap_init: done!\n")); } int pmap_fault_fixup(pmap_t pm, vm_offset_t va, vm_prot_t ftype, int user) { struct l2_dtable *l2; struct l2_bucket *l2b; pd_entry_t *pl1pd, l1pd; pt_entry_t *ptep, pte; vm_paddr_t pa; u_int l1idx; int rv = 0; l1idx = L1_IDX(va); rw_wlock(&pvh_global_lock); PMAP_LOCK(pm); /* * If there is no l2_dtable for this address, then the process * has no business accessing it. * * Note: This will catch userland processes trying to access * kernel addresses. */ l2 = pm->pm_l2[L2_IDX(l1idx)]; if (l2 == NULL) goto out; /* * Likewise if there is no L2 descriptor table */ l2b = &l2->l2_bucket[L2_BUCKET(l1idx)]; if (l2b->l2b_kva == NULL) goto out; /* * Check the PTE itself. */ ptep = &l2b->l2b_kva[l2pte_index(va)]; pte = *ptep; if (pte == 0) goto out; /* * Catch a userland access to the vector page mapped at 0x0 */ if (user && (pte & L2_S_PROT_U) == 0) goto out; if (va == vector_page) goto out; pa = l2pte_pa(pte); if ((ftype & VM_PROT_WRITE) && (pte & L2_S_PROT_W) == 0) { /* * This looks like a good candidate for "page modified" * emulation... */ struct pv_entry *pv; struct vm_page *pg; /* Extract the physical address of the page */ if ((pg = PHYS_TO_VM_PAGE(pa)) == NULL) { goto out; } /* Get the current flags for this page. */ pv = pmap_find_pv(pg, pm, va); if (pv == NULL) { goto out; } /* * Do the flags say this page is writable? If not then it * is a genuine write fault. If yes then the write fault is * our fault as we did not reflect the write access in the * PTE. Now we know a write has occurred we can correct this * and also set the modified bit */ if ((pv->pv_flags & PVF_WRITE) == 0) { goto out; } pg->md.pvh_attrs |= PVF_REF | PVF_MOD; vm_page_dirty(pg); pv->pv_flags |= PVF_REF | PVF_MOD; /* * Re-enable write permissions for the page. No need to call * pmap_fix_cache(), since this is just a * modified-emulation fault, and the PVF_WRITE bit isn't * changing. We've already set the cacheable bits based on * the assumption that we can write to this page. */ *ptep = (pte & ~L2_TYPE_MASK) | L2_S_PROTO | L2_S_PROT_W; PTE_SYNC(ptep); rv = 1; } else if ((pte & L2_TYPE_MASK) == L2_TYPE_INV) { /* * This looks like a good candidate for "page referenced" * emulation. */ struct pv_entry *pv; struct vm_page *pg; /* Extract the physical address of the page */ if ((pg = PHYS_TO_VM_PAGE(pa)) == NULL) goto out; /* Get the current flags for this page. */ pv = pmap_find_pv(pg, pm, va); if (pv == NULL) goto out; pg->md.pvh_attrs |= PVF_REF; pv->pv_flags |= PVF_REF; *ptep = (pte & ~L2_TYPE_MASK) | L2_S_PROTO; PTE_SYNC(ptep); rv = 1; } /* * We know there is a valid mapping here, so simply * fix up the L1 if necessary. */ pl1pd = &pm->pm_l1->l1_kva[l1idx]; l1pd = l2b->l2b_phys | L1_C_DOM(pm->pm_domain) | L1_C_PROTO; if (*pl1pd != l1pd) { *pl1pd = l1pd; PTE_SYNC(pl1pd); rv = 1; } #ifdef DEBUG /* * If 'rv == 0' at this point, it generally indicates that there is a * stale TLB entry for the faulting address. This happens when two or * more processes are sharing an L1. Since we don't flush the TLB on * a context switch between such processes, we can take domain faults * for mappings which exist at the same VA in both processes. EVEN IF * WE'VE RECENTLY FIXED UP THE CORRESPONDING L1 in pmap_enter(), for * example. * * This is extremely likely to happen if pmap_enter() updated the L1 * entry for a recently entered mapping. In this case, the TLB is * flushed for the new mapping, but there may still be TLB entries for * other mappings belonging to other processes in the 1MB range * covered by the L1 entry. * * Since 'rv == 0', we know that the L1 already contains the correct * value, so the fault must be due to a stale TLB entry. * * Since we always need to flush the TLB anyway in the case where we * fixed up the L1, or frobbed the L2 PTE, we effectively deal with * stale TLB entries dynamically. * * However, the above condition can ONLY happen if the current L1 is * being shared. If it happens when the L1 is unshared, it indicates * that other parts of the pmap are not doing their job WRT managing * the TLB. */ if (rv == 0 && pm->pm_l1->l1_domain_use_count == 1) { printf("fixup: pm %p, va 0x%lx, ftype %d - nothing to do!\n", pm, (u_long)va, ftype); printf("fixup: l2 %p, l2b %p, ptep %p, pl1pd %p\n", l2, l2b, ptep, pl1pd); printf("fixup: pte 0x%x, l1pd 0x%x, last code 0x%x\n", pte, l1pd, last_fault_code); #ifdef DDB Debugger(); #endif } #endif cpu_tlb_flushID_SE(va); cpu_cpwait(); rv = 1; out: rw_wunlock(&pvh_global_lock); PMAP_UNLOCK(pm); return (rv); } void pmap_postinit(void) { struct l2_bucket *l2b; struct l1_ttable *l1; pd_entry_t *pl1pt; pt_entry_t *ptep, pte; vm_offset_t va, eva; u_int loop, needed; needed = (maxproc / PMAP_DOMAINS) + ((maxproc % PMAP_DOMAINS) ? 1 : 0); needed -= 1; l1 = malloc(sizeof(*l1) * needed, M_VMPMAP, M_WAITOK); for (loop = 0; loop < needed; loop++, l1++) { /* Allocate a L1 page table */ va = (vm_offset_t)contigmalloc(L1_TABLE_SIZE, M_VMPMAP, 0, 0x0, 0xffffffff, L1_TABLE_SIZE, 0); if (va == 0) panic("Cannot allocate L1 KVM"); eva = va + L1_TABLE_SIZE; pl1pt = (pd_entry_t *)va; while (va < eva) { l2b = pmap_get_l2_bucket(pmap_kernel(), va); ptep = &l2b->l2b_kva[l2pte_index(va)]; pte = *ptep; pte = (pte & ~L2_S_CACHE_MASK) | pte_l2_s_cache_mode_pt; *ptep = pte; PTE_SYNC(ptep); cpu_tlb_flushD_SE(va); va += PAGE_SIZE; } pmap_init_l1(l1, pl1pt); } #ifdef DEBUG printf("pmap_postinit: Allocated %d static L1 descriptor tables\n", needed); #endif } /* * This is used to stuff certain critical values into the PCB where they * can be accessed quickly from cpu_switch() et al. */ void pmap_set_pcb_pagedir(pmap_t pm, struct pcb *pcb) { struct l2_bucket *l2b; pcb->pcb_pagedir = pm->pm_l1->l1_physaddr; pcb->pcb_dacr = (DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2)) | (DOMAIN_CLIENT << (pm->pm_domain * 2)); if (vector_page < KERNBASE) { pcb->pcb_pl1vec = &pm->pm_l1->l1_kva[L1_IDX(vector_page)]; l2b = pmap_get_l2_bucket(pm, vector_page); pcb->pcb_l1vec = l2b->l2b_phys | L1_C_PROTO | L1_C_DOM(pm->pm_domain) | L1_C_DOM(PMAP_DOMAIN_KERNEL); } else pcb->pcb_pl1vec = NULL; } void pmap_activate(struct thread *td) { pmap_t pm; struct pcb *pcb; pm = vmspace_pmap(td->td_proc->p_vmspace); pcb = td->td_pcb; critical_enter(); pmap_set_pcb_pagedir(pm, pcb); if (td == curthread) { u_int cur_dacr, cur_ttb; __asm __volatile("mrc p15, 0, %0, c2, c0, 0" : "=r"(cur_ttb)); __asm __volatile("mrc p15, 0, %0, c3, c0, 0" : "=r"(cur_dacr)); cur_ttb &= ~(L1_TABLE_SIZE - 1); if (cur_ttb == (u_int)pcb->pcb_pagedir && cur_dacr == pcb->pcb_dacr) { /* * No need to switch address spaces. */ critical_exit(); return; } /* * We MUST, I repeat, MUST fix up the L1 entry corresponding * to 'vector_page' in the incoming L1 table before switching * to it otherwise subsequent interrupts/exceptions (including * domain faults!) will jump into hyperspace. */ if (pcb->pcb_pl1vec) { *pcb->pcb_pl1vec = pcb->pcb_l1vec; /* * Don't need to PTE_SYNC() at this point since * cpu_setttb() is about to flush both the cache * and the TLB. */ } cpu_domains(pcb->pcb_dacr); cpu_setttb(pcb->pcb_pagedir); } critical_exit(); } static int pmap_set_pt_cache_mode(pd_entry_t *kl1, vm_offset_t va) { pd_entry_t *pdep, pde; pt_entry_t *ptep, pte; vm_offset_t pa; int rv = 0; /* * Make sure the descriptor itself has the correct cache mode */ pdep = &kl1[L1_IDX(va)]; pde = *pdep; if (l1pte_section_p(pde)) { if ((pde & L1_S_CACHE_MASK) != pte_l1_s_cache_mode_pt) { *pdep = (pde & ~L1_S_CACHE_MASK) | pte_l1_s_cache_mode_pt; PTE_SYNC(pdep); cpu_dcache_wbinv_range((vm_offset_t)pdep, sizeof(*pdep)); cpu_l2cache_wbinv_range((vm_offset_t)pdep, sizeof(*pdep)); rv = 1; } } else { pa = (vm_paddr_t)(pde & L1_C_ADDR_MASK); ptep = (pt_entry_t *)kernel_pt_lookup(pa); if (ptep == NULL) panic("pmap_bootstrap: No L2 for L2 @ va %p\n", ptep); ptep = &ptep[l2pte_index(va)]; pte = *ptep; if ((pte & L2_S_CACHE_MASK) != pte_l2_s_cache_mode_pt) { *ptep = (pte & ~L2_S_CACHE_MASK) | pte_l2_s_cache_mode_pt; PTE_SYNC(ptep); cpu_dcache_wbinv_range((vm_offset_t)ptep, sizeof(*ptep)); cpu_l2cache_wbinv_range((vm_offset_t)ptep, sizeof(*ptep)); rv = 1; } } return (rv); } static void pmap_alloc_specials(vm_offset_t *availp, int pages, vm_offset_t *vap, pt_entry_t **ptep) { vm_offset_t va = *availp; struct l2_bucket *l2b; if (ptep) { l2b = pmap_get_l2_bucket(pmap_kernel(), va); if (l2b == NULL) panic("pmap_alloc_specials: no l2b for 0x%x", va); *ptep = &l2b->l2b_kva[l2pte_index(va)]; } *vap = va; *availp = va + (PAGE_SIZE * pages); } /* * Bootstrap the system enough to run with virtual memory. * * On the arm this is called after mapping has already been enabled * and just syncs the pmap module with what has already been done. * [We can't call it easily with mapping off since the kernel is not * mapped with PA == VA, hence we would have to relocate every address * from the linked base (virtual) address "KERNBASE" to the actual * (physical) address starting relative to 0] */ #define PMAP_STATIC_L2_SIZE 16 void pmap_bootstrap(vm_offset_t firstaddr, struct pv_addr *l1pt) { static struct l1_ttable static_l1; static struct l2_dtable static_l2[PMAP_STATIC_L2_SIZE]; struct l1_ttable *l1 = &static_l1; struct l2_dtable *l2; struct l2_bucket *l2b; pd_entry_t pde; pd_entry_t *kernel_l1pt = (pd_entry_t *)l1pt->pv_va; pt_entry_t *ptep; vm_paddr_t pa; vm_offset_t va; vm_size_t size; int l1idx, l2idx, l2next = 0; PDEBUG(1, printf("firstaddr = %08x, lastaddr = %08x\n", firstaddr, vm_max_kernel_address)); virtual_avail = firstaddr; kernel_pmap->pm_l1 = l1; kernel_l1pa = l1pt->pv_pa; /* * Scan the L1 translation table created by initarm() and create * the required metadata for all valid mappings found in it. */ for (l1idx = 0; l1idx < (L1_TABLE_SIZE / sizeof(pd_entry_t)); l1idx++) { pde = kernel_l1pt[l1idx]; /* * We're only interested in Coarse mappings. * pmap_extract() can deal with section mappings without * recourse to checking L2 metadata. */ if ((pde & L1_TYPE_MASK) != L1_TYPE_C) continue; /* * Lookup the KVA of this L2 descriptor table */ pa = (vm_paddr_t)(pde & L1_C_ADDR_MASK); ptep = (pt_entry_t *)kernel_pt_lookup(pa); if (ptep == NULL) { panic("pmap_bootstrap: No L2 for va 0x%x, pa 0x%lx", (u_int)l1idx << L1_S_SHIFT, (long unsigned int)pa); } /* * Fetch the associated L2 metadata structure. * Allocate a new one if necessary. */ if ((l2 = kernel_pmap->pm_l2[L2_IDX(l1idx)]) == NULL) { if (l2next == PMAP_STATIC_L2_SIZE) panic("pmap_bootstrap: out of static L2s"); kernel_pmap->pm_l2[L2_IDX(l1idx)] = l2 = &static_l2[l2next++]; } /* * One more L1 slot tracked... */ l2->l2_occupancy++; /* * Fill in the details of the L2 descriptor in the * appropriate bucket. */ l2b = &l2->l2_bucket[L2_BUCKET(l1idx)]; l2b->l2b_kva = ptep; l2b->l2b_phys = pa; l2b->l2b_l1idx = l1idx; /* * Establish an initial occupancy count for this descriptor */ for (l2idx = 0; l2idx < (L2_TABLE_SIZE_REAL / sizeof(pt_entry_t)); l2idx++) { if ((ptep[l2idx] & L2_TYPE_MASK) != L2_TYPE_INV) { l2b->l2b_occupancy++; } } /* * Make sure the descriptor itself has the correct cache mode. * If not, fix it, but whine about the problem. Port-meisters * should consider this a clue to fix up their initarm() * function. :) */ if (pmap_set_pt_cache_mode(kernel_l1pt, (vm_offset_t)ptep)) { printf("pmap_bootstrap: WARNING! wrong cache mode for " "L2 pte @ %p\n", ptep); } } /* * Ensure the primary (kernel) L1 has the correct cache mode for * a page table. Bitch if it is not correctly set. */ for (va = (vm_offset_t)kernel_l1pt; va < ((vm_offset_t)kernel_l1pt + L1_TABLE_SIZE); va += PAGE_SIZE) { if (pmap_set_pt_cache_mode(kernel_l1pt, va)) printf("pmap_bootstrap: WARNING! wrong cache mode for " "primary L1 @ 0x%x\n", va); } cpu_dcache_wbinv_all(); cpu_l2cache_wbinv_all(); cpu_tlb_flushID(); cpu_cpwait(); PMAP_LOCK_INIT(kernel_pmap); CPU_FILL(&kernel_pmap->pm_active); kernel_pmap->pm_domain = PMAP_DOMAIN_KERNEL; TAILQ_INIT(&kernel_pmap->pm_pvlist); /* * Initialize the global pv list lock. */ rw_init_flags(&pvh_global_lock, "pmap pv global", RW_RECURSE); /* * Reserve some special page table entries/VA space for temporary * mapping of pages. */ pmap_alloc_specials(&virtual_avail, 1, &csrcp, &csrc_pte); pmap_set_pt_cache_mode(kernel_l1pt, (vm_offset_t)csrc_pte); pmap_alloc_specials(&virtual_avail, 1, &cdstp, &cdst_pte); pmap_set_pt_cache_mode(kernel_l1pt, (vm_offset_t)cdst_pte); size = ((vm_max_kernel_address - pmap_curmaxkvaddr) + L1_S_OFFSET) / L1_S_SIZE; pmap_alloc_specials(&virtual_avail, round_page(size * L2_TABLE_SIZE_REAL) / PAGE_SIZE, &pmap_kernel_l2ptp_kva, NULL); size = (size + (L2_BUCKET_SIZE - 1)) / L2_BUCKET_SIZE; pmap_alloc_specials(&virtual_avail, round_page(size * sizeof(struct l2_dtable)) / PAGE_SIZE, &pmap_kernel_l2dtable_kva, NULL); pmap_alloc_specials(&virtual_avail, 1, (vm_offset_t*)&_tmppt, NULL); pmap_alloc_specials(&virtual_avail, MAXDUMPPGS, (vm_offset_t *)&crashdumpmap, NULL); SLIST_INIT(&l1_list); TAILQ_INIT(&l1_lru_list); mtx_init(&l1_lru_lock, "l1 list lock", NULL, MTX_DEF); pmap_init_l1(l1, kernel_l1pt); cpu_dcache_wbinv_all(); cpu_l2cache_wbinv_all(); virtual_avail = round_page(virtual_avail); virtual_end = vm_max_kernel_address; kernel_vm_end = pmap_curmaxkvaddr; mtx_init(&cmtx, "TMP mappings mtx", NULL, MTX_DEF); pmap_set_pcb_pagedir(kernel_pmap, thread0.td_pcb); } /*************************************************** * Pmap allocation/deallocation routines. ***************************************************/ /* * Release any resources held by the given physical map. * Called when a pmap initialized by pmap_pinit is being released. * Should only be called if the map contains no valid mappings. */ void pmap_release(pmap_t pmap) { struct pcb *pcb; pmap_idcache_wbinv_all(pmap); cpu_l2cache_wbinv_all(); pmap_tlb_flushID(pmap); cpu_cpwait(); if (vector_page < KERNBASE) { struct pcb *curpcb = PCPU_GET(curpcb); pcb = thread0.td_pcb; if (pmap_is_current(pmap)) { /* * Frob the L1 entry corresponding to the vector * page so that it contains the kernel pmap's domain * number. This will ensure pmap_remove() does not * pull the current vector page out from under us. */ critical_enter(); *pcb->pcb_pl1vec = pcb->pcb_l1vec; cpu_domains(pcb->pcb_dacr); cpu_setttb(pcb->pcb_pagedir); critical_exit(); } pmap_remove(pmap, vector_page, vector_page + PAGE_SIZE); /* * Make sure cpu_switch(), et al, DTRT. This is safe to do * since this process has no remaining mappings of its own. */ curpcb->pcb_pl1vec = pcb->pcb_pl1vec; curpcb->pcb_l1vec = pcb->pcb_l1vec; curpcb->pcb_dacr = pcb->pcb_dacr; curpcb->pcb_pagedir = pcb->pcb_pagedir; } pmap_free_l1(pmap); dprintf("pmap_release()\n"); } /* * Helper function for pmap_grow_l2_bucket() */ static __inline int pmap_grow_map(vm_offset_t va, pt_entry_t cache_mode, vm_paddr_t *pap) { struct l2_bucket *l2b; pt_entry_t *ptep; vm_paddr_t pa; struct vm_page *pg; pg = vm_page_alloc(NULL, 0, VM_ALLOC_NOOBJ | VM_ALLOC_WIRED); if (pg == NULL) return (1); pa = VM_PAGE_TO_PHYS(pg); if (pap) *pap = pa; l2b = pmap_get_l2_bucket(pmap_kernel(), va); ptep = &l2b->l2b_kva[l2pte_index(va)]; *ptep = L2_S_PROTO | pa | cache_mode | L2_S_PROT(PTE_KERNEL, VM_PROT_READ | VM_PROT_WRITE); PTE_SYNC(ptep); return (0); } /* * This is the same as pmap_alloc_l2_bucket(), except that it is only * used by pmap_growkernel(). */ static __inline struct l2_bucket * pmap_grow_l2_bucket(pmap_t pm, vm_offset_t va) { struct l2_dtable *l2; struct l2_bucket *l2b; struct l1_ttable *l1; pd_entry_t *pl1pd; u_short l1idx; vm_offset_t nva; l1idx = L1_IDX(va); if ((l2 = pm->pm_l2[L2_IDX(l1idx)]) == NULL) { /* * No mapping at this address, as there is * no entry in the L1 table. * Need to allocate a new l2_dtable. */ nva = pmap_kernel_l2dtable_kva; if ((nva & PAGE_MASK) == 0) { /* * Need to allocate a backing page */ if (pmap_grow_map(nva, pte_l2_s_cache_mode, NULL)) return (NULL); } l2 = (struct l2_dtable *)nva; nva += sizeof(struct l2_dtable); if ((nva & PAGE_MASK) < (pmap_kernel_l2dtable_kva & PAGE_MASK)) { /* * The new l2_dtable straddles a page boundary. * Map in another page to cover it. */ if (pmap_grow_map(nva, pte_l2_s_cache_mode, NULL)) return (NULL); } pmap_kernel_l2dtable_kva = nva; /* * Link it into the parent pmap */ pm->pm_l2[L2_IDX(l1idx)] = l2; memset(l2, 0, sizeof(*l2)); } l2b = &l2->l2_bucket[L2_BUCKET(l1idx)]; /* * Fetch pointer to the L2 page table associated with the address. */ if (l2b->l2b_kva == NULL) { pt_entry_t *ptep; /* * No L2 page table has been allocated. Chances are, this * is because we just allocated the l2_dtable, above. */ nva = pmap_kernel_l2ptp_kva; ptep = (pt_entry_t *)nva; if ((nva & PAGE_MASK) == 0) { /* * Need to allocate a backing page */ if (pmap_grow_map(nva, pte_l2_s_cache_mode_pt, &pmap_kernel_l2ptp_phys)) return (NULL); PTE_SYNC_RANGE(ptep, PAGE_SIZE / sizeof(pt_entry_t)); } memset(ptep, 0, L2_TABLE_SIZE_REAL); l2->l2_occupancy++; l2b->l2b_kva = ptep; l2b->l2b_l1idx = l1idx; l2b->l2b_phys = pmap_kernel_l2ptp_phys; pmap_kernel_l2ptp_kva += L2_TABLE_SIZE_REAL; pmap_kernel_l2ptp_phys += L2_TABLE_SIZE_REAL; } /* Distribute new L1 entry to all other L1s */ SLIST_FOREACH(l1, &l1_list, l1_link) { pl1pd = &l1->l1_kva[L1_IDX(va)]; *pl1pd = l2b->l2b_phys | L1_C_DOM(PMAP_DOMAIN_KERNEL) | L1_C_PROTO; PTE_SYNC(pl1pd); } return (l2b); } /* * grow the number of kernel page table entries, if needed */ void pmap_growkernel(vm_offset_t addr) { pmap_t kpm = pmap_kernel(); if (addr <= pmap_curmaxkvaddr) return; /* we are OK */ /* * whoops! we need to add kernel PTPs */ /* Map 1MB at a time */ for (; pmap_curmaxkvaddr < addr; pmap_curmaxkvaddr += L1_S_SIZE) pmap_grow_l2_bucket(kpm, pmap_curmaxkvaddr); /* * flush out the cache, expensive but growkernel will happen so * rarely */ cpu_dcache_wbinv_all(); cpu_l2cache_wbinv_all(); cpu_tlb_flushD(); cpu_cpwait(); kernel_vm_end = pmap_curmaxkvaddr; } /* * Remove all pages from specified address space * this aids process exit speeds. Also, this code * is special cased for current process only, but * can have the more generic (and slightly slower) * mode enabled. This is much faster than pmap_remove * in the case of running down an entire address space. */ void pmap_remove_pages(pmap_t pmap) { struct pv_entry *pv, *npv; struct l2_bucket *l2b = NULL; vm_page_t m; pt_entry_t *pt; rw_wlock(&pvh_global_lock); PMAP_LOCK(pmap); cpu_idcache_wbinv_all(); cpu_l2cache_wbinv_all(); for (pv = TAILQ_FIRST(&pmap->pm_pvlist); pv; pv = npv) { if (pv->pv_flags & PVF_WIRED || pv->pv_flags & PVF_UNMAN) { /* Cannot remove wired or unmanaged pages now. */ npv = TAILQ_NEXT(pv, pv_plist); continue; } pmap->pm_stats.resident_count--; l2b = pmap_get_l2_bucket(pmap, pv->pv_va); KASSERT(l2b != NULL, ("No L2 bucket in pmap_remove_pages")); pt = &l2b->l2b_kva[l2pte_index(pv->pv_va)]; m = PHYS_TO_VM_PAGE(*pt & L2_ADDR_MASK); KASSERT((vm_offset_t)m >= KERNBASE, ("Trying to access non-existent page va %x pte %x", pv->pv_va, *pt)); *pt = 0; PTE_SYNC(pt); npv = TAILQ_NEXT(pv, pv_plist); pmap_nuke_pv(m, pmap, pv); if (TAILQ_EMPTY(&m->md.pv_list)) vm_page_aflag_clear(m, PGA_WRITEABLE); pmap_free_pv_entry(pv); pmap_free_l2_bucket(pmap, l2b, 1); } rw_wunlock(&pvh_global_lock); cpu_tlb_flushID(); cpu_cpwait(); PMAP_UNLOCK(pmap); } /*************************************************** * Low level mapping routines..... ***************************************************/ #ifdef ARM_HAVE_SUPERSECTIONS /* Map a super section into the KVA. */ void pmap_kenter_supersection(vm_offset_t va, uint64_t pa, int flags) { pd_entry_t pd = L1_S_PROTO | L1_S_SUPERSEC | (pa & L1_SUP_FRAME) | (((pa >> 32) & 0xf) << 20) | L1_S_PROT(PTE_KERNEL, VM_PROT_READ|VM_PROT_WRITE) | L1_S_DOM(PMAP_DOMAIN_KERNEL); struct l1_ttable *l1; vm_offset_t va0, va_end; KASSERT(((va | pa) & L1_SUP_OFFSET) == 0, ("Not a valid super section mapping")); if (flags & SECTION_CACHE) pd |= pte_l1_s_cache_mode; else if (flags & SECTION_PT) pd |= pte_l1_s_cache_mode_pt; va0 = va & L1_SUP_FRAME; va_end = va + L1_SUP_SIZE; SLIST_FOREACH(l1, &l1_list, l1_link) { va = va0; for (; va < va_end; va += L1_S_SIZE) { l1->l1_kva[L1_IDX(va)] = pd; PTE_SYNC(&l1->l1_kva[L1_IDX(va)]); } } } #endif /* Map a section into the KVA. */ void pmap_kenter_section(vm_offset_t va, vm_offset_t pa, int flags) { pd_entry_t pd = L1_S_PROTO | pa | L1_S_PROT(PTE_KERNEL, VM_PROT_READ|VM_PROT_WRITE) | L1_S_DOM(PMAP_DOMAIN_KERNEL); struct l1_ttable *l1; KASSERT(((va | pa) & L1_S_OFFSET) == 0, ("Not a valid section mapping")); if (flags & SECTION_CACHE) pd |= pte_l1_s_cache_mode; else if (flags & SECTION_PT) pd |= pte_l1_s_cache_mode_pt; SLIST_FOREACH(l1, &l1_list, l1_link) { l1->l1_kva[L1_IDX(va)] = pd; PTE_SYNC(&l1->l1_kva[L1_IDX(va)]); } } /* * Make a temporary mapping for a physical address. This is only intended * to be used for panic dumps. */ void * pmap_kenter_temporary(vm_paddr_t pa, int i) { vm_offset_t va; va = (vm_offset_t)crashdumpmap + (i * PAGE_SIZE); pmap_kenter(va, pa); return ((void *)crashdumpmap); } /* * add a wired page to the kva * note that in order for the mapping to take effect -- you * should do a invltlb after doing the pmap_kenter... */ static PMAP_INLINE void pmap_kenter_internal(vm_offset_t va, vm_offset_t pa, int flags) { struct l2_bucket *l2b; pt_entry_t *pte; pt_entry_t opte; struct pv_entry *pve; vm_page_t m; PDEBUG(1, printf("pmap_kenter: va = %08x, pa = %08x\n", (uint32_t) va, (uint32_t) pa)); l2b = pmap_get_l2_bucket(pmap_kernel(), va); if (l2b == NULL) l2b = pmap_grow_l2_bucket(pmap_kernel(), va); KASSERT(l2b != NULL, ("No L2 Bucket")); pte = &l2b->l2b_kva[l2pte_index(va)]; opte = *pte; PDEBUG(1, printf("pmap_kenter: pte = %08x, opte = %08x, npte = %08x\n", (uint32_t) pte, opte, *pte)); if (l2pte_valid(opte)) { pmap_kremove(va); } else { if (opte == 0) l2b->l2b_occupancy++; } *pte = L2_S_PROTO | pa | L2_S_PROT(PTE_KERNEL, VM_PROT_READ | VM_PROT_WRITE); if (flags & KENTER_CACHE) *pte |= pte_l2_s_cache_mode; if (flags & KENTER_USER) *pte |= L2_S_PROT_U; PTE_SYNC(pte); /* * A kernel mapping may not be the page's only mapping, so create a PV * entry to ensure proper caching. * * The existence test for the pvzone is used to delay the recording of * kernel mappings until the VM system is fully initialized. * * This expects the physical memory to have a vm_page_array entry. */ if (pvzone != NULL && (m = vm_phys_paddr_to_vm_page(pa)) != NULL) { rw_wlock(&pvh_global_lock); if (!TAILQ_EMPTY(&m->md.pv_list) || m->md.pv_kva != 0) { if ((pve = pmap_get_pv_entry()) == NULL) panic("pmap_kenter_internal: no pv entries"); PMAP_LOCK(pmap_kernel()); pmap_enter_pv(m, pve, pmap_kernel(), va, PVF_WRITE | PVF_UNMAN); pmap_fix_cache(m, pmap_kernel(), va); PMAP_UNLOCK(pmap_kernel()); } else { m->md.pv_kva = va; } rw_wunlock(&pvh_global_lock); } } void pmap_kenter(vm_offset_t va, vm_paddr_t pa) { pmap_kenter_internal(va, pa, KENTER_CACHE); } void pmap_kenter_nocache(vm_offset_t va, vm_paddr_t pa) { pmap_kenter_internal(va, pa, 0); } void pmap_kenter_device(vm_offset_t va, vm_size_t size, vm_paddr_t pa) { vm_offset_t sva; KASSERT((size & PAGE_MASK) == 0, ("%s: device mapping not page-sized", __func__)); sva = va; while (size != 0) { pmap_kenter_internal(va, pa, 0); va += PAGE_SIZE; pa += PAGE_SIZE; size -= PAGE_SIZE; } } void pmap_kremove_device(vm_offset_t va, vm_size_t size) { vm_offset_t sva; KASSERT((size & PAGE_MASK) == 0, ("%s: device mapping not page-sized", __func__)); sva = va; while (size != 0) { pmap_kremove(va); va += PAGE_SIZE; size -= PAGE_SIZE; } } void pmap_kenter_user(vm_offset_t va, vm_paddr_t pa) { pmap_kenter_internal(va, pa, KENTER_CACHE|KENTER_USER); /* * Call pmap_fault_fixup now, to make sure we'll have no exception * at the first use of the new address, or bad things will happen, * as we use one of these addresses in the exception handlers. */ pmap_fault_fixup(pmap_kernel(), va, VM_PROT_READ|VM_PROT_WRITE, 1); } vm_paddr_t pmap_kextract(vm_offset_t va) { return (pmap_extract_locked(kernel_pmap, va)); } /* * remove a page from the kernel pagetables */ void pmap_kremove(vm_offset_t va) { struct l2_bucket *l2b; pt_entry_t *pte, opte; struct pv_entry *pve; vm_page_t m; vm_offset_t pa; l2b = pmap_get_l2_bucket(pmap_kernel(), va); if (!l2b) return; KASSERT(l2b != NULL, ("No L2 Bucket")); pte = &l2b->l2b_kva[l2pte_index(va)]; opte = *pte; if (l2pte_valid(opte)) { /* pa = vtophs(va) taken from pmap_extract() */ switch (opte & L2_TYPE_MASK) { case L2_TYPE_L: pa = (opte & L2_L_FRAME) | (va & L2_L_OFFSET); break; default: pa = (opte & L2_S_FRAME) | (va & L2_S_OFFSET); break; } /* note: should never have to remove an allocation * before the pvzone is initialized. */ rw_wlock(&pvh_global_lock); PMAP_LOCK(pmap_kernel()); if (pvzone != NULL && (m = vm_phys_paddr_to_vm_page(pa)) && (pve = pmap_remove_pv(m, pmap_kernel(), va))) pmap_free_pv_entry(pve); PMAP_UNLOCK(pmap_kernel()); rw_wunlock(&pvh_global_lock); va = va & ~PAGE_MASK; cpu_dcache_wbinv_range(va, PAGE_SIZE); cpu_l2cache_wbinv_range(va, PAGE_SIZE); cpu_tlb_flushD_SE(va); cpu_cpwait(); *pte = 0; } } /* * Used to map a range of physical addresses into kernel * virtual address space. * * The value passed in '*virt' is a suggested virtual address for * the mapping. Architectures which can support a direct-mapped * physical to virtual region can return the appropriate address * within that region, leaving '*virt' unchanged. Other * architectures should map the pages starting at '*virt' and * update '*virt' with the first usable address after the mapped * region. */ vm_offset_t pmap_map(vm_offset_t *virt, vm_offset_t start, vm_offset_t end, int prot) { vm_offset_t sva = *virt; vm_offset_t va = sva; PDEBUG(1, printf("pmap_map: virt = %08x, start = %08x, end = %08x, " "prot = %d\n", (uint32_t) *virt, (uint32_t) start, (uint32_t) end, prot)); while (start < end) { pmap_kenter(va, start); va += PAGE_SIZE; start += PAGE_SIZE; } *virt = va; return (sva); } static void pmap_wb_page(vm_page_t m) { struct pv_entry *pv; TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) pmap_dcache_wb_range(pv->pv_pmap, pv->pv_va, PAGE_SIZE, FALSE, (pv->pv_flags & PVF_WRITE) == 0); } static void pmap_inv_page(vm_page_t m) { struct pv_entry *pv; TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) pmap_dcache_wb_range(pv->pv_pmap, pv->pv_va, PAGE_SIZE, TRUE, TRUE); } /* * Add a list of wired pages to the kva * this routine is only used for temporary * kernel mappings that do not need to have * page modification or references recorded. * Note that old mappings are simply written * over. The page *must* be wired. */ void pmap_qenter(vm_offset_t va, vm_page_t *m, int count) { int i; for (i = 0; i < count; i++) { pmap_wb_page(m[i]); pmap_kenter_internal(va, VM_PAGE_TO_PHYS(m[i]), KENTER_CACHE); va += PAGE_SIZE; } } /* * this routine jerks page mappings from the * kernel -- it is meant only for temporary mappings. */ void pmap_qremove(vm_offset_t va, int count) { vm_paddr_t pa; int i; for (i = 0; i < count; i++) { pa = vtophys(va); if (pa) { pmap_inv_page(PHYS_TO_VM_PAGE(pa)); pmap_kremove(va); } va += PAGE_SIZE; } } /* * pmap_object_init_pt preloads the ptes for a given object * into the specified pmap. This eliminates the blast of soft * faults on process startup and immediately after an mmap. */ void pmap_object_init_pt(pmap_t pmap, vm_offset_t addr, vm_object_t object, vm_pindex_t pindex, vm_size_t size) { VM_OBJECT_ASSERT_WLOCKED(object); KASSERT(object->type == OBJT_DEVICE || object->type == OBJT_SG, ("pmap_object_init_pt: non-device object")); } /* * pmap_is_prefaultable: * * Return whether or not the specified virtual address is elgible * for prefault. */ boolean_t pmap_is_prefaultable(pmap_t pmap, vm_offset_t addr) { pd_entry_t *pde; pt_entry_t *pte; if (!pmap_get_pde_pte(pmap, addr, &pde, &pte)) return (FALSE); KASSERT(pte != NULL, ("Valid mapping but no pte ?")); if (*pte == 0) return (TRUE); return (FALSE); } /* * Fetch pointers to the PDE/PTE for the given pmap/VA pair. * Returns TRUE if the mapping exists, else FALSE. * * NOTE: This function is only used by a couple of arm-specific modules. * It is not safe to take any pmap locks here, since we could be right * in the middle of debugging the pmap anyway... * * It is possible for this routine to return FALSE even though a valid * mapping does exist. This is because we don't lock, so the metadata * state may be inconsistent. * * NOTE: We can return a NULL *ptp in the case where the L1 pde is * a "section" mapping. */ boolean_t pmap_get_pde_pte(pmap_t pm, vm_offset_t va, pd_entry_t **pdp, pt_entry_t **ptp) { struct l2_dtable *l2; pd_entry_t *pl1pd, l1pd; pt_entry_t *ptep; u_short l1idx; if (pm->pm_l1 == NULL) return (FALSE); l1idx = L1_IDX(va); *pdp = pl1pd = &pm->pm_l1->l1_kva[l1idx]; l1pd = *pl1pd; if (l1pte_section_p(l1pd)) { *ptp = NULL; return (TRUE); } if (pm->pm_l2 == NULL) return (FALSE); l2 = pm->pm_l2[L2_IDX(l1idx)]; if (l2 == NULL || (ptep = l2->l2_bucket[L2_BUCKET(l1idx)].l2b_kva) == NULL) { return (FALSE); } *ptp = &ptep[l2pte_index(va)]; return (TRUE); } /* * Routine: pmap_remove_all * Function: * Removes this physical page from * all physical maps in which it resides. * Reflects back modify bits to the pager. * * Notes: * Original versions of this routine were very * inefficient because they iteratively called * pmap_remove (slow...) */ void pmap_remove_all(vm_page_t m) { pv_entry_t pv; pt_entry_t *ptep; struct l2_bucket *l2b; boolean_t flush = FALSE; pmap_t curpm; int flags = 0; KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_all: page %p is not managed", m)); if (TAILQ_EMPTY(&m->md.pv_list)) return; rw_wlock(&pvh_global_lock); /* * XXX This call shouldn't exist. Iterating over the PV list twice, * once in pmap_clearbit() and again below, is both unnecessary and * inefficient. The below code should itself write back the cache * entry before it destroys the mapping. */ pmap_clearbit(m, PVF_WRITE); curpm = vmspace_pmap(curproc->p_vmspace); while ((pv = TAILQ_FIRST(&m->md.pv_list)) != NULL) { if (flush == FALSE && (pv->pv_pmap == curpm || pv->pv_pmap == pmap_kernel())) flush = TRUE; PMAP_LOCK(pv->pv_pmap); /* * Cached contents were written-back in pmap_clearbit(), * but we still have to invalidate the cache entry to make * sure stale data are not retrieved when another page will be * mapped under this virtual address. */ if (pmap_is_current(pv->pv_pmap)) { cpu_dcache_inv_range(pv->pv_va, PAGE_SIZE); if (pmap_has_valid_mapping(pv->pv_pmap, pv->pv_va)) cpu_l2cache_inv_range(pv->pv_va, PAGE_SIZE); } if (pv->pv_flags & PVF_UNMAN) { /* remove the pv entry, but do not remove the mapping * and remember this is a kernel mapped page */ m->md.pv_kva = pv->pv_va; } else { /* remove the mapping and pv entry */ l2b = pmap_get_l2_bucket(pv->pv_pmap, pv->pv_va); KASSERT(l2b != NULL, ("No l2 bucket")); ptep = &l2b->l2b_kva[l2pte_index(pv->pv_va)]; *ptep = 0; PTE_SYNC_CURRENT(pv->pv_pmap, ptep); pmap_free_l2_bucket(pv->pv_pmap, l2b, 1); pv->pv_pmap->pm_stats.resident_count--; flags |= pv->pv_flags; } pmap_nuke_pv(m, pv->pv_pmap, pv); PMAP_UNLOCK(pv->pv_pmap); pmap_free_pv_entry(pv); } if (flush) { if (PV_BEEN_EXECD(flags)) pmap_tlb_flushID(curpm); else pmap_tlb_flushD(curpm); } vm_page_aflag_clear(m, PGA_WRITEABLE); rw_wunlock(&pvh_global_lock); } /* * Set the physical protection on the * specified range of this map as requested. */ void pmap_protect(pmap_t pm, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot) { struct l2_bucket *l2b; pt_entry_t *ptep, pte; vm_offset_t next_bucket; u_int flags; int flush; CTR4(KTR_PMAP, "pmap_protect: pmap %p sva 0x%08x eva 0x%08x prot %x", pm, sva, eva, prot); if ((prot & VM_PROT_READ) == 0) { pmap_remove(pm, sva, eva); return; } if (prot & VM_PROT_WRITE) { /* * If this is a read->write transition, just ignore it and let * vm_fault() take care of it later. */ return; } rw_wlock(&pvh_global_lock); PMAP_LOCK(pm); /* * OK, at this point, we know we're doing write-protect operation. * If the pmap is active, write-back the range. */ pmap_dcache_wb_range(pm, sva, eva - sva, FALSE, FALSE); flush = ((eva - sva) >= (PAGE_SIZE * 4)) ? 0 : -1; flags = 0; while (sva < eva) { next_bucket = L2_NEXT_BUCKET(sva); if (next_bucket > eva) next_bucket = eva; l2b = pmap_get_l2_bucket(pm, sva); if (l2b == NULL) { sva = next_bucket; continue; } ptep = &l2b->l2b_kva[l2pte_index(sva)]; while (sva < next_bucket) { if ((pte = *ptep) != 0 && (pte & L2_S_PROT_W) != 0) { struct vm_page *pg; u_int f; pg = PHYS_TO_VM_PAGE(l2pte_pa(pte)); pte &= ~L2_S_PROT_W; *ptep = pte; PTE_SYNC(ptep); if (!(pg->oflags & VPO_UNMANAGED)) { f = pmap_modify_pv(pg, pm, sva, PVF_WRITE, 0); if (f & PVF_WRITE) vm_page_dirty(pg); } else f = 0; if (flush >= 0) { flush++; flags |= f; } else if (PV_BEEN_EXECD(f)) pmap_tlb_flushID_SE(pm, sva); else if (PV_BEEN_REFD(f)) pmap_tlb_flushD_SE(pm, sva); } sva += PAGE_SIZE; ptep++; } } if (flush) { if (PV_BEEN_EXECD(flags)) pmap_tlb_flushID(pm); else if (PV_BEEN_REFD(flags)) pmap_tlb_flushD(pm); } rw_wunlock(&pvh_global_lock); PMAP_UNLOCK(pm); } /* * Insert the given physical page (p) at * the specified virtual address (v) in the * target physical map with the protection requested. * * If specified, the page will be wired down, meaning * that the related pte can not be reclaimed. * * NB: This is the only routine which MAY NOT lazy-evaluate * or lose information. That is, this routine must actually * insert this page into the given map NOW. */ int pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, u_int flags, int8_t psind __unused) { int rv; rw_wlock(&pvh_global_lock); PMAP_LOCK(pmap); rv = pmap_enter_locked(pmap, va, m, prot, flags); rw_wunlock(&pvh_global_lock); PMAP_UNLOCK(pmap); return (rv); } /* * The pvh global and pmap locks must be held. */ static int pmap_enter_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, u_int flags) { struct l2_bucket *l2b = NULL; struct vm_page *opg; struct pv_entry *pve = NULL; pt_entry_t *ptep, npte, opte; u_int nflags; u_int oflags; vm_paddr_t pa; PMAP_ASSERT_LOCKED(pmap); rw_assert(&pvh_global_lock, RA_WLOCKED); if (va == vector_page) { pa = systempage.pv_pa; m = NULL; } else { if ((m->oflags & VPO_UNMANAGED) == 0 && !vm_page_xbusied(m)) VM_OBJECT_ASSERT_LOCKED(m->object); pa = VM_PAGE_TO_PHYS(m); } nflags = 0; if (prot & VM_PROT_WRITE) nflags |= PVF_WRITE; if (prot & VM_PROT_EXECUTE) nflags |= PVF_EXEC; if ((flags & PMAP_ENTER_WIRED) != 0) nflags |= PVF_WIRED; PDEBUG(1, printf("pmap_enter: pmap = %08x, va = %08x, m = %08x, prot = %x, " "flags = %x\n", (uint32_t) pmap, va, (uint32_t) m, prot, flags)); if (pmap == pmap_kernel()) { l2b = pmap_get_l2_bucket(pmap, va); if (l2b == NULL) l2b = pmap_grow_l2_bucket(pmap, va); } else { do_l2b_alloc: l2b = pmap_alloc_l2_bucket(pmap, va); if (l2b == NULL) { if ((flags & PMAP_ENTER_NOSLEEP) == 0) { PMAP_UNLOCK(pmap); rw_wunlock(&pvh_global_lock); VM_WAIT; rw_wlock(&pvh_global_lock); PMAP_LOCK(pmap); goto do_l2b_alloc; } return (KERN_RESOURCE_SHORTAGE); } } ptep = &l2b->l2b_kva[l2pte_index(va)]; opte = *ptep; npte = pa; oflags = 0; if (opte) { /* * There is already a mapping at this address. * If the physical address is different, lookup the * vm_page. */ if (l2pte_pa(opte) != pa) opg = PHYS_TO_VM_PAGE(l2pte_pa(opte)); else opg = m; } else opg = NULL; if ((prot & (VM_PROT_ALL)) || (!m || m->md.pvh_attrs & PVF_REF)) { /* * - The access type indicates that we don't need * to do referenced emulation. * OR * - The physical page has already been referenced * so no need to re-do referenced emulation here. */ npte |= L2_S_PROTO; nflags |= PVF_REF; if (m && ((prot & VM_PROT_WRITE) != 0 || (m->md.pvh_attrs & PVF_MOD))) { /* * This is a writable mapping, and the * page's mod state indicates it has * already been modified. Make it * writable from the outset. */ nflags |= PVF_MOD; if (!(m->md.pvh_attrs & PVF_MOD)) vm_page_dirty(m); } if (m && opte) vm_page_aflag_set(m, PGA_REFERENCED); } else { /* * Need to do page referenced emulation. */ npte |= L2_TYPE_INV; } if (prot & VM_PROT_WRITE) { npte |= L2_S_PROT_W; if (m != NULL && (m->oflags & VPO_UNMANAGED) == 0) vm_page_aflag_set(m, PGA_WRITEABLE); } if (m->md.pv_memattr != VM_MEMATTR_UNCACHEABLE) npte |= pte_l2_s_cache_mode; if (m && m == opg) { /* * We're changing the attrs of an existing mapping. */ oflags = pmap_modify_pv(m, pmap, va, PVF_WRITE | PVF_EXEC | PVF_WIRED | PVF_MOD | PVF_REF, nflags); /* * We may need to flush the cache if we're * doing rw-ro... */ if (pmap_is_current(pmap) && (oflags & PVF_NC) == 0 && (opte & L2_S_PROT_W) != 0 && (prot & VM_PROT_WRITE) == 0 && (opte & L2_TYPE_MASK) != L2_TYPE_INV) { cpu_dcache_wb_range(va, PAGE_SIZE); cpu_l2cache_wb_range(va, PAGE_SIZE); } } else { /* * New mapping, or changing the backing page * of an existing mapping. */ if (opg) { /* * Replacing an existing mapping with a new one. * It is part of our managed memory so we * must remove it from the PV list */ if ((pve = pmap_remove_pv(opg, pmap, va))) { /* note for patch: the oflags/invalidation was moved * because PG_FICTITIOUS pages could free the pve */ oflags = pve->pv_flags; /* * If the old mapping was valid (ref/mod * emulation creates 'invalid' mappings * initially) then make sure to frob * the cache. */ if ((oflags & PVF_NC) == 0 && l2pte_valid(opte)) { if (PV_BEEN_EXECD(oflags)) { pmap_idcache_wbinv_range(pmap, va, PAGE_SIZE); } else if (PV_BEEN_REFD(oflags)) { pmap_dcache_wb_range(pmap, va, PAGE_SIZE, TRUE, (oflags & PVF_WRITE) == 0); } } /* free/allocate a pv_entry for UNMANAGED pages if * this physical page is not/is already mapped. */ if (m && (m->oflags & VPO_UNMANAGED) && !m->md.pv_kva && TAILQ_EMPTY(&m->md.pv_list)) { pmap_free_pv_entry(pve); pve = NULL; } } else if (m && (!(m->oflags & VPO_UNMANAGED) || m->md.pv_kva || !TAILQ_EMPTY(&m->md.pv_list))) pve = pmap_get_pv_entry(); } else if (m && (!(m->oflags & VPO_UNMANAGED) || m->md.pv_kva || !TAILQ_EMPTY(&m->md.pv_list))) pve = pmap_get_pv_entry(); if (m) { if ((m->oflags & VPO_UNMANAGED)) { if (!TAILQ_EMPTY(&m->md.pv_list) || m->md.pv_kva) { KASSERT(pve != NULL, ("No pv")); nflags |= PVF_UNMAN; pmap_enter_pv(m, pve, pmap, va, nflags); } else m->md.pv_kva = va; } else { KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva, ("pmap_enter: managed mapping within the clean submap")); KASSERT(pve != NULL, ("No pv")); pmap_enter_pv(m, pve, pmap, va, nflags); } } } /* * Make sure userland mappings get the right permissions */ if (pmap != pmap_kernel() && va != vector_page) { npte |= L2_S_PROT_U; } /* * Keep the stats up to date */ if (opte == 0) { l2b->l2b_occupancy++; pmap->pm_stats.resident_count++; } /* * If this is just a wiring change, the two PTEs will be * identical, so there's no need to update the page table. */ if (npte != opte) { boolean_t is_cached = pmap_is_current(pmap); *ptep = npte; if (is_cached) { /* * We only need to frob the cache/tlb if this pmap * is current */ PTE_SYNC(ptep); if (L1_IDX(va) != L1_IDX(vector_page) && l2pte_valid(npte)) { /* * This mapping is likely to be accessed as * soon as we return to userland. Fix up the * L1 entry to avoid taking another * page/domain fault. */ pd_entry_t *pl1pd, l1pd; pl1pd = &pmap->pm_l1->l1_kva[L1_IDX(va)]; l1pd = l2b->l2b_phys | L1_C_DOM(pmap->pm_domain) | L1_C_PROTO; if (*pl1pd != l1pd) { *pl1pd = l1pd; PTE_SYNC(pl1pd); } } } if (PV_BEEN_EXECD(oflags)) pmap_tlb_flushID_SE(pmap, va); else if (PV_BEEN_REFD(oflags)) pmap_tlb_flushD_SE(pmap, va); if (m) pmap_fix_cache(m, pmap, va); } return (KERN_SUCCESS); } /* * Maps a sequence of resident pages belonging to the same object. * The sequence begins with the given page m_start. This page is * mapped at the given virtual address start. Each subsequent page is * mapped at a virtual address that is offset from start by the same * amount as the page is offset from m_start within the object. The * last page in the sequence is the page with the largest offset from * m_start that can be mapped at a virtual address less than the given * virtual address end. Not every virtual page between start and end * is mapped; only those for which a resident page exists with the * corresponding offset from m_start are mapped. */ void pmap_enter_object(pmap_t pmap, vm_offset_t start, vm_offset_t end, vm_page_t m_start, vm_prot_t prot) { vm_page_t m; vm_pindex_t diff, psize; VM_OBJECT_ASSERT_LOCKED(m_start->object); psize = atop(end - start); m = m_start; rw_wlock(&pvh_global_lock); PMAP_LOCK(pmap); while (m != NULL && (diff = m->pindex - m_start->pindex) < psize) { pmap_enter_locked(pmap, start + ptoa(diff), m, prot & (VM_PROT_READ | VM_PROT_EXECUTE), PMAP_ENTER_NOSLEEP); m = TAILQ_NEXT(m, listq); } rw_wunlock(&pvh_global_lock); PMAP_UNLOCK(pmap); } /* * this code makes some *MAJOR* assumptions: * 1. Current pmap & pmap exists. * 2. Not wired. * 3. Read access. * 4. No page table pages. * but is *MUCH* faster than pmap_enter... */ void pmap_enter_quick(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot) { rw_wlock(&pvh_global_lock); PMAP_LOCK(pmap); pmap_enter_locked(pmap, va, m, prot & (VM_PROT_READ | VM_PROT_EXECUTE), PMAP_ENTER_NOSLEEP); rw_wunlock(&pvh_global_lock); PMAP_UNLOCK(pmap); } /* * Clear the wired attribute from the mappings for the specified range of * addresses in the given pmap. Every valid mapping within that range * must have the wired attribute set. In contrast, invalid mappings * cannot have the wired attribute set, so they are ignored. * * XXX Wired mappings of unmanaged pages cannot be counted by this pmap * implementation. */ void pmap_unwire(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) { struct l2_bucket *l2b; pt_entry_t *ptep, pte; pv_entry_t pv; vm_offset_t next_bucket; vm_page_t m; rw_wlock(&pvh_global_lock); PMAP_LOCK(pmap); while (sva < eva) { next_bucket = L2_NEXT_BUCKET(sva); if (next_bucket > eva) next_bucket = eva; l2b = pmap_get_l2_bucket(pmap, sva); if (l2b == NULL) { sva = next_bucket; continue; } for (ptep = &l2b->l2b_kva[l2pte_index(sva)]; sva < next_bucket; sva += PAGE_SIZE, ptep++) { if ((pte = *ptep) == 0 || (m = PHYS_TO_VM_PAGE(l2pte_pa(pte))) == NULL || (m->oflags & VPO_UNMANAGED) != 0) continue; pv = pmap_find_pv(m, pmap, sva); if ((pv->pv_flags & PVF_WIRED) == 0) panic("pmap_unwire: pv %p isn't wired", pv); pv->pv_flags &= ~PVF_WIRED; pmap->pm_stats.wired_count--; } } rw_wunlock(&pvh_global_lock); PMAP_UNLOCK(pmap); } /* * Copy the range specified by src_addr/len * from the source map to the range dst_addr/len * in the destination map. * * This routine is only advisory and need not do anything. */ void pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len, vm_offset_t src_addr) { } /* * Routine: pmap_extract * Function: * Extract the physical page address associated * with the given map/virtual_address pair. */ vm_paddr_t pmap_extract(pmap_t pmap, vm_offset_t va) { vm_paddr_t pa; PMAP_LOCK(pmap); pa = pmap_extract_locked(pmap, va); PMAP_UNLOCK(pmap); return (pa); } static vm_paddr_t pmap_extract_locked(pmap_t pmap, vm_offset_t va) { struct l2_dtable *l2; pd_entry_t l1pd; pt_entry_t *ptep, pte; vm_paddr_t pa; u_int l1idx; if (pmap != kernel_pmap) PMAP_ASSERT_LOCKED(pmap); l1idx = L1_IDX(va); l1pd = pmap->pm_l1->l1_kva[l1idx]; if (l1pte_section_p(l1pd)) { /* * These should only happen for the kernel pmap. */ KASSERT(pmap == kernel_pmap, ("unexpected section")); /* XXX: what to do about the bits > 32 ? */ if (l1pd & L1_S_SUPERSEC) pa = (l1pd & L1_SUP_FRAME) | (va & L1_SUP_OFFSET); else pa = (l1pd & L1_S_FRAME) | (va & L1_S_OFFSET); } else { /* * Note that we can't rely on the validity of the L1 * descriptor as an indication that a mapping exists. * We have to look it up in the L2 dtable. */ l2 = pmap->pm_l2[L2_IDX(l1idx)]; if (l2 == NULL || (ptep = l2->l2_bucket[L2_BUCKET(l1idx)].l2b_kva) == NULL) return (0); pte = ptep[l2pte_index(va)]; if (pte == 0) return (0); switch (pte & L2_TYPE_MASK) { case L2_TYPE_L: pa = (pte & L2_L_FRAME) | (va & L2_L_OFFSET); break; default: pa = (pte & L2_S_FRAME) | (va & L2_S_OFFSET); break; } } return (pa); } /* * Atomically extract and hold the physical page with the given * pmap and virtual address pair if that mapping permits the given * protection. * */ vm_page_t pmap_extract_and_hold(pmap_t pmap, vm_offset_t va, vm_prot_t prot) { struct l2_dtable *l2; pd_entry_t l1pd; pt_entry_t *ptep, pte; vm_paddr_t pa, paddr; vm_page_t m = NULL; u_int l1idx; l1idx = L1_IDX(va); paddr = 0; PMAP_LOCK(pmap); retry: l1pd = pmap->pm_l1->l1_kva[l1idx]; if (l1pte_section_p(l1pd)) { /* * These should only happen for pmap_kernel() */ KASSERT(pmap == pmap_kernel(), ("huh")); /* XXX: what to do about the bits > 32 ? */ if (l1pd & L1_S_SUPERSEC) pa = (l1pd & L1_SUP_FRAME) | (va & L1_SUP_OFFSET); else pa = (l1pd & L1_S_FRAME) | (va & L1_S_OFFSET); if (vm_page_pa_tryrelock(pmap, pa & PG_FRAME, &paddr)) goto retry; if (l1pd & L1_S_PROT_W || (prot & VM_PROT_WRITE) == 0) { m = PHYS_TO_VM_PAGE(pa); vm_page_hold(m); } } else { /* * Note that we can't rely on the validity of the L1 * descriptor as an indication that a mapping exists. * We have to look it up in the L2 dtable. */ l2 = pmap->pm_l2[L2_IDX(l1idx)]; if (l2 == NULL || (ptep = l2->l2_bucket[L2_BUCKET(l1idx)].l2b_kva) == NULL) { PMAP_UNLOCK(pmap); return (NULL); } ptep = &ptep[l2pte_index(va)]; pte = *ptep; if (pte == 0) { PMAP_UNLOCK(pmap); return (NULL); } if (pte & L2_S_PROT_W || (prot & VM_PROT_WRITE) == 0) { switch (pte & L2_TYPE_MASK) { case L2_TYPE_L: pa = (pte & L2_L_FRAME) | (va & L2_L_OFFSET); break; default: pa = (pte & L2_S_FRAME) | (va & L2_S_OFFSET); break; } if (vm_page_pa_tryrelock(pmap, pa & PG_FRAME, &paddr)) goto retry; m = PHYS_TO_VM_PAGE(pa); vm_page_hold(m); } } PMAP_UNLOCK(pmap); PA_UNLOCK_COND(paddr); return (m); } /* * Initialize a preallocated and zeroed pmap structure, * such as one in a vmspace structure. */ int pmap_pinit(pmap_t pmap) { PDEBUG(1, printf("pmap_pinit: pmap = %08x\n", (uint32_t) pmap)); pmap_alloc_l1(pmap); bzero(pmap->pm_l2, sizeof(pmap->pm_l2)); CPU_ZERO(&pmap->pm_active); TAILQ_INIT(&pmap->pm_pvlist); bzero(&pmap->pm_stats, sizeof pmap->pm_stats); pmap->pm_stats.resident_count = 1; if (vector_page < KERNBASE) { pmap_enter(pmap, vector_page, PHYS_TO_VM_PAGE(systempage.pv_pa), VM_PROT_READ, PMAP_ENTER_WIRED | VM_PROT_READ, 0); } return (1); } /*************************************************** * page management routines. ***************************************************/ static void pmap_free_pv_entry(pv_entry_t pv) { pv_entry_count--; uma_zfree(pvzone, pv); } /* * get a new pv_entry, allocating a block from the system * when needed. * the memory allocation is performed bypassing the malloc code * because of the possibility of allocations at interrupt time. */ static pv_entry_t pmap_get_pv_entry(void) { pv_entry_t ret_value; pv_entry_count++; if (pv_entry_count > pv_entry_high_water) pagedaemon_wakeup(); ret_value = uma_zalloc(pvzone, M_NOWAIT); return ret_value; } /* * Remove the given range of addresses from the specified map. * * It is assumed that the start and end are properly * rounded to the page size. */ #define PMAP_REMOVE_CLEAN_LIST_SIZE 3 void pmap_remove(pmap_t pm, vm_offset_t sva, vm_offset_t eva) { struct l2_bucket *l2b; vm_offset_t next_bucket; pt_entry_t *ptep; u_int total; u_int mappings, is_exec, is_refd; int flushall = 0; /* * we lock in the pmap => pv_head direction */ rw_wlock(&pvh_global_lock); PMAP_LOCK(pm); total = 0; while (sva < eva) { /* * Do one L2 bucket's worth at a time. */ next_bucket = L2_NEXT_BUCKET(sva); if (next_bucket > eva) next_bucket = eva; l2b = pmap_get_l2_bucket(pm, sva); if (l2b == NULL) { sva = next_bucket; continue; } ptep = &l2b->l2b_kva[l2pte_index(sva)]; mappings = 0; while (sva < next_bucket) { struct vm_page *pg; pt_entry_t pte; vm_paddr_t pa; pte = *ptep; if (pte == 0) { /* * Nothing here, move along */ sva += PAGE_SIZE; ptep++; continue; } pm->pm_stats.resident_count--; pa = l2pte_pa(pte); is_exec = 0; is_refd = 1; /* * Update flags. In a number of circumstances, * we could cluster a lot of these and do a * number of sequential pages in one go. */ if ((pg = PHYS_TO_VM_PAGE(pa)) != NULL) { struct pv_entry *pve; pve = pmap_remove_pv(pg, pm, sva); if (pve) { is_exec = PV_BEEN_EXECD(pve->pv_flags); is_refd = PV_BEEN_REFD(pve->pv_flags); pmap_free_pv_entry(pve); } } if (l2pte_valid(pte) && pmap_is_current(pm)) { if (total < PMAP_REMOVE_CLEAN_LIST_SIZE) { total++; if (is_exec) { cpu_idcache_wbinv_range(sva, PAGE_SIZE); cpu_l2cache_wbinv_range(sva, PAGE_SIZE); cpu_tlb_flushID_SE(sva); } else if (is_refd) { cpu_dcache_wbinv_range(sva, PAGE_SIZE); cpu_l2cache_wbinv_range(sva, PAGE_SIZE); cpu_tlb_flushD_SE(sva); } } else if (total == PMAP_REMOVE_CLEAN_LIST_SIZE) { /* flushall will also only get set for * for a current pmap */ cpu_idcache_wbinv_all(); cpu_l2cache_wbinv_all(); flushall = 1; total++; } } *ptep = 0; PTE_SYNC(ptep); sva += PAGE_SIZE; ptep++; mappings++; } pmap_free_l2_bucket(pm, l2b, mappings); } rw_wunlock(&pvh_global_lock); if (flushall) cpu_tlb_flushID(); PMAP_UNLOCK(pm); } /* * pmap_zero_page() * * Zero a given physical page by mapping it at a page hook point. * In doing the zero page op, the page we zero is mapped cachable, as with * StrongARM accesses to non-cached pages are non-burst making writing * _any_ bulk data very slow. */ #if ARM_MMU_GENERIC != 0 || defined(CPU_XSCALE_CORE3) void pmap_zero_page_generic(vm_paddr_t phys, int off, int size) { if (_arm_bzero && size >= _min_bzero_size && _arm_bzero((void *)(phys + off), size, IS_PHYSICAL) == 0) return; mtx_lock(&cmtx); /* * Hook in the page, zero it, invalidate the TLB as needed. * * Note the temporary zero-page mapping must be a non-cached page in * order to work without corruption when write-allocate is enabled. */ *cdst_pte = L2_S_PROTO | phys | L2_S_PROT(PTE_KERNEL, VM_PROT_WRITE); PTE_SYNC(cdst_pte); cpu_tlb_flushD_SE(cdstp); cpu_cpwait(); if (off || size != PAGE_SIZE) bzero((void *)(cdstp + off), size); else bzero_page(cdstp); mtx_unlock(&cmtx); } #endif /* ARM_MMU_GENERIC != 0 */ #if ARM_MMU_XSCALE == 1 void pmap_zero_page_xscale(vm_paddr_t phys, int off, int size) { if (_arm_bzero && size >= _min_bzero_size && _arm_bzero((void *)(phys + off), size, IS_PHYSICAL) == 0) return; mtx_lock(&cmtx); /* * Hook in the page, zero it, and purge the cache for that * zeroed page. Invalidate the TLB as needed. */ *cdst_pte = L2_S_PROTO | phys | L2_S_PROT(PTE_KERNEL, VM_PROT_WRITE) | L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X); /* mini-data */ PTE_SYNC(cdst_pte); cpu_tlb_flushD_SE(cdstp); cpu_cpwait(); if (off || size != PAGE_SIZE) bzero((void *)(cdstp + off), size); else bzero_page(cdstp); mtx_unlock(&cmtx); xscale_cache_clean_minidata(); } /* * Change the PTEs for the specified kernel mappings such that they * will use the mini data cache instead of the main data cache. */ void pmap_use_minicache(vm_offset_t va, vm_size_t size) { struct l2_bucket *l2b; pt_entry_t *ptep, *sptep, pte; vm_offset_t next_bucket, eva; #if (ARM_NMMUS > 1) || defined(CPU_XSCALE_CORE3) if (xscale_use_minidata == 0) return; #endif eva = va + size; while (va < eva) { next_bucket = L2_NEXT_BUCKET(va); if (next_bucket > eva) next_bucket = eva; l2b = pmap_get_l2_bucket(pmap_kernel(), va); sptep = ptep = &l2b->l2b_kva[l2pte_index(va)]; while (va < next_bucket) { pte = *ptep; if (!l2pte_minidata(pte)) { cpu_dcache_wbinv_range(va, PAGE_SIZE); cpu_tlb_flushD_SE(va); *ptep = pte & ~L2_B; } ptep++; va += PAGE_SIZE; } PTE_SYNC_RANGE(sptep, (u_int)(ptep - sptep)); } cpu_cpwait(); } #endif /* ARM_MMU_XSCALE == 1 */ /* * pmap_zero_page zeros the specified hardware page by mapping * the page into KVM and using bzero to clear its contents. */ void pmap_zero_page(vm_page_t m) { pmap_zero_page_func(VM_PAGE_TO_PHYS(m), 0, PAGE_SIZE); } /* * pmap_zero_page_area zeros the specified hardware page by mapping * the page into KVM and using bzero to clear its contents. * * off and size may not cover an area beyond a single hardware page. */ void pmap_zero_page_area(vm_page_t m, int off, int size) { pmap_zero_page_func(VM_PAGE_TO_PHYS(m), off, size); } /* * pmap_zero_page_idle zeros the specified hardware page by mapping * the page into KVM and using bzero to clear its contents. This * is intended to be called from the vm_pagezero process only and * outside of Giant. */ void pmap_zero_page_idle(vm_page_t m) { pmap_zero_page(m); } #if 0 /* * pmap_clean_page() * * This is a local function used to work out the best strategy to clean * a single page referenced by its entry in the PV table. It should be used by * pmap_copy_page, pmap_zero page and maybe some others later on. * * Its policy is effectively: * o If there are no mappings, we don't bother doing anything with the cache. * o If there is one mapping, we clean just that page. * o If there are multiple mappings, we clean the entire cache. * * So that some functions can be further optimised, it returns 0 if it didn't * clean the entire cache, or 1 if it did. * * XXX One bug in this routine is that if the pv_entry has a single page * mapped at 0x00000000 a whole cache clean will be performed rather than * just the 1 page. Since this should not occur in everyday use and if it does * it will just result in not the most efficient clean for the page. * * We don't yet use this function but may want to. */ static int pmap_clean_page(struct pv_entry *pv, boolean_t is_src) { pmap_t pm, pm_to_clean = NULL; struct pv_entry *npv; u_int cache_needs_cleaning = 0; u_int flags = 0; vm_offset_t page_to_clean = 0; if (pv == NULL) { /* nothing mapped in so nothing to flush */ return (0); } /* * Since we flush the cache each time we change to a different * user vmspace, we only need to flush the page if it is in the * current pmap. */ if (curthread) pm = vmspace_pmap(curproc->p_vmspace); else pm = pmap_kernel(); for (npv = pv; npv; npv = TAILQ_NEXT(npv, pv_list)) { if (npv->pv_pmap == pmap_kernel() || npv->pv_pmap == pm) { flags |= npv->pv_flags; /* * The page is mapped non-cacheable in * this map. No need to flush the cache. */ if (npv->pv_flags & PVF_NC) { #ifdef DIAGNOSTIC if (cache_needs_cleaning) panic("pmap_clean_page: " "cache inconsistency"); #endif break; } else if (is_src && (npv->pv_flags & PVF_WRITE) == 0) continue; if (cache_needs_cleaning) { page_to_clean = 0; break; } else { page_to_clean = npv->pv_va; pm_to_clean = npv->pv_pmap; } cache_needs_cleaning = 1; } } if (page_to_clean) { if (PV_BEEN_EXECD(flags)) pmap_idcache_wbinv_range(pm_to_clean, page_to_clean, PAGE_SIZE); else pmap_dcache_wb_range(pm_to_clean, page_to_clean, PAGE_SIZE, !is_src, (flags & PVF_WRITE) == 0); } else if (cache_needs_cleaning) { if (PV_BEEN_EXECD(flags)) pmap_idcache_wbinv_all(pm); else pmap_dcache_wbinv_all(pm); return (1); } return (0); } #endif /* * pmap_copy_page copies the specified (machine independent) * page by mapping the page into virtual memory and using * bcopy to copy the page, one machine dependent page at a * time. */ /* * pmap_copy_page() * * Copy one physical page into another, by mapping the pages into * hook points. The same comment regarding cachability as in * pmap_zero_page also applies here. */ #if ARM_MMU_GENERIC != 0 || defined (CPU_XSCALE_CORE3) void pmap_copy_page_generic(vm_paddr_t src, vm_paddr_t dst) { #if 0 struct vm_page *src_pg = PHYS_TO_VM_PAGE(src); #endif /* * Clean the source page. Hold the source page's lock for * the duration of the copy so that no other mappings can * be created while we have a potentially aliased mapping. */ #if 0 /* * XXX: Not needed while we call cpu_dcache_wbinv_all() in * pmap_copy_page(). */ (void) pmap_clean_page(TAILQ_FIRST(&src_pg->md.pv_list), TRUE); #endif /* * Map the pages into the page hook points, copy them, and purge * the cache for the appropriate page. Invalidate the TLB * as required. */ mtx_lock(&cmtx); *csrc_pte = L2_S_PROTO | src | L2_S_PROT(PTE_KERNEL, VM_PROT_READ) | pte_l2_s_cache_mode; PTE_SYNC(csrc_pte); *cdst_pte = L2_S_PROTO | dst | L2_S_PROT(PTE_KERNEL, VM_PROT_WRITE) | pte_l2_s_cache_mode; PTE_SYNC(cdst_pte); cpu_tlb_flushD_SE(csrcp); cpu_tlb_flushD_SE(cdstp); cpu_cpwait(); bcopy_page(csrcp, cdstp); mtx_unlock(&cmtx); cpu_dcache_inv_range(csrcp, PAGE_SIZE); cpu_dcache_wbinv_range(cdstp, PAGE_SIZE); cpu_l2cache_inv_range(csrcp, PAGE_SIZE); cpu_l2cache_wbinv_range(cdstp, PAGE_SIZE); } void pmap_copy_page_offs_generic(vm_paddr_t a_phys, vm_offset_t a_offs, vm_paddr_t b_phys, vm_offset_t b_offs, int cnt) { mtx_lock(&cmtx); *csrc_pte = L2_S_PROTO | a_phys | L2_S_PROT(PTE_KERNEL, VM_PROT_READ) | pte_l2_s_cache_mode; PTE_SYNC(csrc_pte); *cdst_pte = L2_S_PROTO | b_phys | L2_S_PROT(PTE_KERNEL, VM_PROT_WRITE) | pte_l2_s_cache_mode; PTE_SYNC(cdst_pte); cpu_tlb_flushD_SE(csrcp); cpu_tlb_flushD_SE(cdstp); cpu_cpwait(); bcopy((char *)csrcp + a_offs, (char *)cdstp + b_offs, cnt); mtx_unlock(&cmtx); cpu_dcache_inv_range(csrcp + a_offs, cnt); cpu_dcache_wbinv_range(cdstp + b_offs, cnt); cpu_l2cache_inv_range(csrcp + a_offs, cnt); cpu_l2cache_wbinv_range(cdstp + b_offs, cnt); } #endif /* ARM_MMU_GENERIC != 0 */ #if ARM_MMU_XSCALE == 1 void pmap_copy_page_xscale(vm_paddr_t src, vm_paddr_t dst) { #if 0 /* XXX: Only needed for pmap_clean_page(), which is commented out. */ struct vm_page *src_pg = PHYS_TO_VM_PAGE(src); #endif /* * Clean the source page. Hold the source page's lock for * the duration of the copy so that no other mappings can * be created while we have a potentially aliased mapping. */ #if 0 /* * XXX: Not needed while we call cpu_dcache_wbinv_all() in * pmap_copy_page(). */ (void) pmap_clean_page(TAILQ_FIRST(&src_pg->md.pv_list), TRUE); #endif /* * Map the pages into the page hook points, copy them, and purge * the cache for the appropriate page. Invalidate the TLB * as required. */ mtx_lock(&cmtx); *csrc_pte = L2_S_PROTO | src | L2_S_PROT(PTE_KERNEL, VM_PROT_READ) | L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X); /* mini-data */ PTE_SYNC(csrc_pte); *cdst_pte = L2_S_PROTO | dst | L2_S_PROT(PTE_KERNEL, VM_PROT_WRITE) | L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X); /* mini-data */ PTE_SYNC(cdst_pte); cpu_tlb_flushD_SE(csrcp); cpu_tlb_flushD_SE(cdstp); cpu_cpwait(); bcopy_page(csrcp, cdstp); mtx_unlock(&cmtx); xscale_cache_clean_minidata(); } void pmap_copy_page_offs_xscale(vm_paddr_t a_phys, vm_offset_t a_offs, vm_paddr_t b_phys, vm_offset_t b_offs, int cnt) { mtx_lock(&cmtx); *csrc_pte = L2_S_PROTO | a_phys | L2_S_PROT(PTE_KERNEL, VM_PROT_READ) | L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X); PTE_SYNC(csrc_pte); *cdst_pte = L2_S_PROTO | b_phys | L2_S_PROT(PTE_KERNEL, VM_PROT_WRITE) | L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X); PTE_SYNC(cdst_pte); cpu_tlb_flushD_SE(csrcp); cpu_tlb_flushD_SE(cdstp); cpu_cpwait(); bcopy((char *)csrcp + a_offs, (char *)cdstp + b_offs, cnt); mtx_unlock(&cmtx); xscale_cache_clean_minidata(); } #endif /* ARM_MMU_XSCALE == 1 */ void pmap_copy_page(vm_page_t src, vm_page_t dst) { cpu_dcache_wbinv_all(); cpu_l2cache_wbinv_all(); if (_arm_memcpy && PAGE_SIZE >= _min_memcpy_size && _arm_memcpy((void *)VM_PAGE_TO_PHYS(dst), (void *)VM_PAGE_TO_PHYS(src), PAGE_SIZE, IS_PHYSICAL) == 0) return; pmap_copy_page_func(VM_PAGE_TO_PHYS(src), VM_PAGE_TO_PHYS(dst)); } -int unmapped_buf_allowed = 1; +/* + * We have code to do unmapped I/O. However, it isn't quite right + * an causes un-page-aligned I/O to devices to fail (most notably + * newfs or fsck). We give up a little performance to do this, but + * we trade that for rock-solid stability so it is a good trade. + */ +int unmapped_buf_allowed = 0; void pmap_copy_pages(vm_page_t ma[], vm_offset_t a_offset, vm_page_t mb[], vm_offset_t b_offset, int xfersize) { vm_page_t a_pg, b_pg; vm_offset_t a_pg_offset, b_pg_offset; int cnt; cpu_dcache_wbinv_all(); cpu_l2cache_wbinv_all(); while (xfersize > 0) { a_pg = ma[a_offset >> PAGE_SHIFT]; a_pg_offset = a_offset & PAGE_MASK; cnt = min(xfersize, PAGE_SIZE - a_pg_offset); b_pg = mb[b_offset >> PAGE_SHIFT]; b_pg_offset = b_offset & PAGE_MASK; cnt = min(cnt, PAGE_SIZE - b_pg_offset); pmap_copy_page_offs_func(VM_PAGE_TO_PHYS(a_pg), a_pg_offset, VM_PAGE_TO_PHYS(b_pg), b_pg_offset, cnt); xfersize -= cnt; a_offset += cnt; b_offset += cnt; } } /* * this routine returns true if a physical page resides * in the given pmap. */ boolean_t pmap_page_exists_quick(pmap_t pmap, vm_page_t m) { pv_entry_t pv; int loops = 0; boolean_t rv; KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_page_exists_quick: page %p is not managed", m)); rv = FALSE; rw_wlock(&pvh_global_lock); TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { if (pv->pv_pmap == pmap) { rv = TRUE; break; } loops++; if (loops >= 16) break; } rw_wunlock(&pvh_global_lock); return (rv); } /* * pmap_page_wired_mappings: * * Return the number of managed mappings to the given physical page * that are wired. */ int pmap_page_wired_mappings(vm_page_t m) { pv_entry_t pv; int count; count = 0; if ((m->oflags & VPO_UNMANAGED) != 0) return (count); rw_wlock(&pvh_global_lock); TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) if ((pv->pv_flags & PVF_WIRED) != 0) count++; rw_wunlock(&pvh_global_lock); return (count); } /* * This function is advisory. */ void pmap_advise(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, int advice) { } /* * pmap_ts_referenced: * * Return the count of reference bits for a page, clearing all of them. */ int pmap_ts_referenced(vm_page_t m) { KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_ts_referenced: page %p is not managed", m)); return (pmap_clearbit(m, PVF_REF)); } boolean_t pmap_is_modified(vm_page_t m) { KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_modified: page %p is not managed", m)); if (m->md.pvh_attrs & PVF_MOD) return (TRUE); return(FALSE); } /* * Clear the modify bits on the specified physical page. */ void pmap_clear_modify(vm_page_t m) { KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_clear_modify: page %p is not managed", m)); VM_OBJECT_ASSERT_WLOCKED(m->object); KASSERT(!vm_page_xbusied(m), ("pmap_clear_modify: page %p is exclusive busied", m)); /* * If the page is not PGA_WRITEABLE, then no mappings can be modified. * If the object containing the page is locked and the page is not * exclusive busied, then PGA_WRITEABLE cannot be concurrently set. */ if ((m->aflags & PGA_WRITEABLE) == 0) return; if (m->md.pvh_attrs & PVF_MOD) pmap_clearbit(m, PVF_MOD); } /* * pmap_is_referenced: * * Return whether or not the specified physical page was referenced * in any physical maps. */ boolean_t pmap_is_referenced(vm_page_t m) { KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_is_referenced: page %p is not managed", m)); return ((m->md.pvh_attrs & PVF_REF) != 0); } /* * Clear the write and modified bits in each of the given page's mappings. */ void pmap_remove_write(vm_page_t m) { KASSERT((m->oflags & VPO_UNMANAGED) == 0, ("pmap_remove_write: page %p is not managed", m)); /* * If the page is not exclusive busied, then PGA_WRITEABLE cannot be * set by another thread while the object is locked. Thus, * if PGA_WRITEABLE is clear, no page table entries need updating. */ VM_OBJECT_ASSERT_WLOCKED(m->object); if (vm_page_xbusied(m) || (m->aflags & PGA_WRITEABLE) != 0) pmap_clearbit(m, PVF_WRITE); } /* * perform the pmap work for mincore */ int pmap_mincore(pmap_t pmap, vm_offset_t addr, vm_paddr_t *locked_pa) { struct l2_bucket *l2b; pt_entry_t *ptep, pte; vm_paddr_t pa; vm_page_t m; int val; boolean_t managed; PMAP_LOCK(pmap); retry: l2b = pmap_get_l2_bucket(pmap, addr); if (l2b == NULL) { val = 0; goto out; } ptep = &l2b->l2b_kva[l2pte_index(addr)]; pte = *ptep; if (!l2pte_valid(pte)) { val = 0; goto out; } val = MINCORE_INCORE; if (pte & L2_S_PROT_W) val |= MINCORE_MODIFIED | MINCORE_MODIFIED_OTHER; managed = false; pa = l2pte_pa(pte); m = PHYS_TO_VM_PAGE(pa); if (m != NULL && !(m->oflags & VPO_UNMANAGED)) managed = true; if (managed) { /* * The ARM pmap tries to maintain a per-mapping * reference bit. The trouble is that it's kept in * the PV entry, not the PTE, so it's costly to access * here. You would need to acquire the pvh global * lock, call pmap_find_pv(), and introduce a custom * version of vm_page_pa_tryrelock() that releases and * reacquires the pvh global lock. In the end, I * doubt it's worthwhile. This may falsely report * the given address as referenced. */ if ((m->md.pvh_attrs & PVF_REF) != 0) val |= MINCORE_REFERENCED | MINCORE_REFERENCED_OTHER; } if ((val & (MINCORE_MODIFIED_OTHER | MINCORE_REFERENCED_OTHER)) != (MINCORE_MODIFIED_OTHER | MINCORE_REFERENCED_OTHER) && managed) { /* Ensure that "PHYS_TO_VM_PAGE(pa)->object" doesn't change. */ if (vm_page_pa_tryrelock(pmap, pa, locked_pa)) goto retry; } else out: PA_UNLOCK_COND(*locked_pa); PMAP_UNLOCK(pmap); return (val); } void pmap_sync_icache(pmap_t pm, vm_offset_t va, vm_size_t sz) { } /* * Increase the starting virtual address of the given mapping if a * different alignment might result in more superpage mappings. */ void pmap_align_superpage(vm_object_t object, vm_ooffset_t offset, vm_offset_t *addr, vm_size_t size) { } #define BOOTSTRAP_DEBUG /* * pmap_map_section: * * Create a single section mapping. */ void pmap_map_section(vm_offset_t l1pt, vm_offset_t va, vm_offset_t pa, int prot, int cache) { pd_entry_t *pde = (pd_entry_t *) l1pt; pd_entry_t fl; KASSERT(((va | pa) & L1_S_OFFSET) == 0, ("ouin2")); switch (cache) { case PTE_NOCACHE: default: fl = 0; break; case PTE_CACHE: fl = pte_l1_s_cache_mode; break; case PTE_PAGETABLE: fl = pte_l1_s_cache_mode_pt; break; } pde[va >> L1_S_SHIFT] = L1_S_PROTO | pa | L1_S_PROT(PTE_KERNEL, prot) | fl | L1_S_DOM(PMAP_DOMAIN_KERNEL); PTE_SYNC(&pde[va >> L1_S_SHIFT]); } /* * pmap_link_l2pt: * * Link the L2 page table specified by l2pv.pv_pa into the L1 * page table at the slot for "va". */ void pmap_link_l2pt(vm_offset_t l1pt, vm_offset_t va, struct pv_addr *l2pv) { pd_entry_t *pde = (pd_entry_t *) l1pt, proto; u_int slot = va >> L1_S_SHIFT; proto = L1_S_DOM(PMAP_DOMAIN_KERNEL) | L1_C_PROTO; #ifdef VERBOSE_INIT_ARM printf("pmap_link_l2pt: pa=0x%x va=0x%x\n", l2pv->pv_pa, l2pv->pv_va); #endif pde[slot + 0] = proto | (l2pv->pv_pa + 0x000); PTE_SYNC(&pde[slot]); SLIST_INSERT_HEAD(&kernel_pt_list, l2pv, pv_list); } /* * pmap_map_entry * * Create a single page mapping. */ void pmap_map_entry(vm_offset_t l1pt, vm_offset_t va, vm_offset_t pa, int prot, int cache) { pd_entry_t *pde = (pd_entry_t *) l1pt; pt_entry_t fl; pt_entry_t *pte; KASSERT(((va | pa) & PAGE_MASK) == 0, ("ouin")); switch (cache) { case PTE_NOCACHE: default: fl = 0; break; case PTE_CACHE: fl = pte_l2_s_cache_mode; break; case PTE_PAGETABLE: fl = pte_l2_s_cache_mode_pt; break; } if ((pde[va >> L1_S_SHIFT] & L1_TYPE_MASK) != L1_TYPE_C) panic("pmap_map_entry: no L2 table for VA 0x%08x", va); pte = (pt_entry_t *) kernel_pt_lookup(pde[L1_IDX(va)] & L1_C_ADDR_MASK); if (pte == NULL) panic("pmap_map_entry: can't find L2 table for VA 0x%08x", va); pte[l2pte_index(va)] = L2_S_PROTO | pa | L2_S_PROT(PTE_KERNEL, prot) | fl; PTE_SYNC(&pte[l2pte_index(va)]); } /* * pmap_map_chunk: * * Map a chunk of memory using the most efficient mappings * possible (section. large page, small page) into the * provided L1 and L2 tables at the specified virtual address. */ vm_size_t pmap_map_chunk(vm_offset_t l1pt, vm_offset_t va, vm_offset_t pa, vm_size_t size, int prot, int cache) { pd_entry_t *pde = (pd_entry_t *) l1pt; pt_entry_t *pte, f1, f2s, f2l; vm_size_t resid; int i; resid = (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); if (l1pt == 0) panic("pmap_map_chunk: no L1 table provided"); #ifdef VERBOSE_INIT_ARM printf("pmap_map_chunk: pa=0x%x va=0x%x size=0x%x resid=0x%x " "prot=0x%x cache=%d\n", pa, va, size, resid, prot, cache); #endif switch (cache) { case PTE_NOCACHE: default: f1 = 0; f2l = 0; f2s = 0; break; case PTE_CACHE: f1 = pte_l1_s_cache_mode; f2l = pte_l2_l_cache_mode; f2s = pte_l2_s_cache_mode; break; case PTE_PAGETABLE: f1 = pte_l1_s_cache_mode_pt; f2l = pte_l2_l_cache_mode_pt; f2s = pte_l2_s_cache_mode_pt; break; } size = resid; while (resid > 0) { /* See if we can use a section mapping. */ if (L1_S_MAPPABLE_P(va, pa, resid)) { #ifdef VERBOSE_INIT_ARM printf("S"); #endif pde[va >> L1_S_SHIFT] = L1_S_PROTO | pa | L1_S_PROT(PTE_KERNEL, prot) | f1 | L1_S_DOM(PMAP_DOMAIN_KERNEL); PTE_SYNC(&pde[va >> L1_S_SHIFT]); va += L1_S_SIZE; pa += L1_S_SIZE; resid -= L1_S_SIZE; continue; } /* * Ok, we're going to use an L2 table. Make sure * one is actually in the corresponding L1 slot * for the current VA. */ if ((pde[va >> L1_S_SHIFT] & L1_TYPE_MASK) != L1_TYPE_C) panic("pmap_map_chunk: no L2 table for VA 0x%08x", va); pte = (pt_entry_t *) kernel_pt_lookup( pde[L1_IDX(va)] & L1_C_ADDR_MASK); if (pte == NULL) panic("pmap_map_chunk: can't find L2 table for VA" "0x%08x", va); /* See if we can use a L2 large page mapping. */ if (L2_L_MAPPABLE_P(va, pa, resid)) { #ifdef VERBOSE_INIT_ARM printf("L"); #endif for (i = 0; i < 16; i++) { pte[l2pte_index(va) + i] = L2_L_PROTO | pa | L2_L_PROT(PTE_KERNEL, prot) | f2l; PTE_SYNC(&pte[l2pte_index(va) + i]); } va += L2_L_SIZE; pa += L2_L_SIZE; resid -= L2_L_SIZE; continue; } /* Use a small page mapping. */ #ifdef VERBOSE_INIT_ARM printf("P"); #endif pte[l2pte_index(va)] = L2_S_PROTO | pa | L2_S_PROT(PTE_KERNEL, prot) | f2s; PTE_SYNC(&pte[l2pte_index(va)]); va += PAGE_SIZE; pa += PAGE_SIZE; resid -= PAGE_SIZE; } #ifdef VERBOSE_INIT_ARM printf("\n"); #endif return (size); } void pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma) { /* * Remember the memattr in a field that gets used to set the appropriate * bits in the PTEs as mappings are established. */ m->md.pv_memattr = ma; /* * It appears that this function can only be called before any mappings * for the page are established on ARM. If this ever changes, this code * will need to walk the pv_list and make each of the existing mappings * uncacheable, being careful to sync caches and PTEs (and maybe * invalidate TLB?) for any current mapping it modifies. */ if (m->md.pv_kva != 0 || TAILQ_FIRST(&m->md.pv_list) != NULL) panic("Can't change memattr on page with existing mappings"); } Index: projects/ci20_mips/sys/arm/conf/ALPINE =================================================================== --- projects/ci20_mips/sys/arm/conf/ALPINE (nonexistent) +++ projects/ci20_mips/sys/arm/conf/ALPINE (revision 283031) @@ -0,0 +1,83 @@ +# Kernel configuration for Alpine Board. +# +# For more information on this file, please read the config(5) manual page, +# and/or the handbook section on Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ + +ident ALPINE + +include "std.armv6" +include "../annapurna/alpine/std.alpine" + +makeoptions MODULES_OVERRIDE="" +makeoptions WERROR="-Werror" + +options HZ=100 +options SCHED_4BSD # 4BSD scheduler +options SMP # Enable multiple cores + +# Debugging +makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols +options BREAK_TO_DEBUGGER +options KDB +options DDB #Enable the kernel debugger + +# NFS support +options NFSCL #Network Filesystem Client +options NFSLOCKD #Network Lock Manager +options NFS_ROOT #NFS usable as /, requires NFSCLIENT + +# Interrupt controller +device gic + +# Pseudo devices +device loop +device random +device pty +device md +device gpio + +# ATA controllers +device ahci # AHCI-compatible SATA controllers +device ata # Legacy ATA/SATA controllers +options ATA_STATIC_ID # Static device numbering + +# ATA/SCSI peripherals +device scbus # SCSI bus (required for ATA/SCSI) +device ch # SCSI media changers +device da # Direct Access (disks) +device sa # Sequential Access (tape etc) +device cd # CD +device pass # Passthrough device (direct ATA/SCSI access) +device ses # Enclosure Services (SES and SAF-TE) +#device ctl # CAM Target Layer + +# Serial ports +device uart + +# Ethernet +device ether +device mii +device bpf +options DEVICE_POLLING + +# USB ethernet support, requires miibus +device miibus + +#FDT +options FDT +options FDT_DTB_STATIC +makeoptions FDT_DTS_FILE=annapurna-alpine.dts Property changes on: projects/ci20_mips/sys/arm/conf/ALPINE ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Index: projects/ci20_mips/sys/arm/include/cpu-v6.h =================================================================== --- projects/ci20_mips/sys/arm/include/cpu-v6.h (revision 283030) +++ projects/ci20_mips/sys/arm/include/cpu-v6.h (revision 283031) @@ -1,509 +1,525 @@ /*- * Copyright 2014 Svatopluk Kraus * Copyright 2014 Michal Meloun * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef MACHINE_CPU_V6_H #define MACHINE_CPU_V6_H /* There are no user serviceable parts here, they may change without notice */ #ifndef _KERNEL #error Only include this file in the kernel #else #include "machine/atomic.h" #include "machine/cpufunc.h" #include "machine/cpuinfo.h" #include "machine/sysreg.h" - #define CPU_ASID_KERNEL 0 vm_offset_t dcache_wb_pou_checked(vm_offset_t, vm_size_t); vm_offset_t icache_inv_pou_checked(vm_offset_t, vm_size_t); /* * Macros to generate CP15 (system control processor) read/write functions. */ #define _FX(s...) #s #define _RF0(fname, aname...) \ static __inline register_t \ fname(void) \ { \ register_t reg; \ __asm __volatile("mrc\t" _FX(aname): "=r" (reg)); \ return(reg); \ } #define _R64F0(fname, aname) \ static __inline uint64_t \ fname(void) \ { \ uint64_t reg; \ __asm __volatile("mrrc\t" _FX(aname): "=r" (reg)); \ return(reg); \ } #define _WF0(fname, aname...) \ static __inline void \ fname(void) \ { \ __asm __volatile("mcr\t" _FX(aname)); \ } #define _WF1(fname, aname...) \ static __inline void \ fname(register_t reg) \ { \ __asm __volatile("mcr\t" _FX(aname):: "r" (reg)); \ } #define _W64F1(fname, aname...) \ static __inline void \ fname(uint64_t reg) \ { \ __asm __volatile("mcrr\t" _FX(aname):: "r" (reg)); \ } /* * Raw CP15 maintenance operations * !!! not for external use !!! */ /* TLB */ _WF0(_CP15_TLBIALL, CP15_TLBIALL) /* Invalidate entire unified TLB */ #if __ARM_ARCH >= 7 && defined SMP _WF0(_CP15_TLBIALLIS, CP15_TLBIALLIS) /* Invalidate entire unified TLB IS */ #endif _WF1(_CP15_TLBIASID, CP15_TLBIASID(%0)) /* Invalidate unified TLB by ASID */ #if __ARM_ARCH >= 7 && defined SMP _WF1(_CP15_TLBIASIDIS, CP15_TLBIASIDIS(%0)) /* Invalidate unified TLB by ASID IS */ #endif _WF1(_CP15_TLBIMVAA, CP15_TLBIMVAA(%0)) /* Invalidate unified TLB by MVA, all ASID */ #if __ARM_ARCH >= 7 && defined SMP _WF1(_CP15_TLBIMVAAIS, CP15_TLBIMVAAIS(%0)) /* Invalidate unified TLB by MVA, all ASID IS */ #endif _WF1(_CP15_TLBIMVA, CP15_TLBIMVA(%0)) /* Invalidate unified TLB by MVA */ _WF1(_CP15_TTB_SET, CP15_TTBR0(%0)) /* Cache and Branch predictor */ _WF0(_CP15_BPIALL, CP15_BPIALL) /* Branch predictor invalidate all */ #if __ARM_ARCH >= 7 && defined SMP _WF0(_CP15_BPIALLIS, CP15_BPIALLIS) /* Branch predictor invalidate all IS */ #endif _WF1(_CP15_BPIMVA, CP15_BPIMVA(%0)) /* Branch predictor invalidate by MVA */ _WF1(_CP15_DCCIMVAC, CP15_DCCIMVAC(%0)) /* Data cache clean and invalidate by MVA PoC */ _WF1(_CP15_DCCISW, CP15_DCCISW(%0)) /* Data cache clean and invalidate by set/way */ _WF1(_CP15_DCCMVAC, CP15_DCCMVAC(%0)) /* Data cache clean by MVA PoC */ #if __ARM_ARCH >= 7 _WF1(_CP15_DCCMVAU, CP15_DCCMVAU(%0)) /* Data cache clean by MVA PoU */ #endif _WF1(_CP15_DCCSW, CP15_DCCSW(%0)) /* Data cache clean by set/way */ _WF1(_CP15_DCIMVAC, CP15_DCIMVAC(%0)) /* Data cache invalidate by MVA PoC */ _WF1(_CP15_DCISW, CP15_DCISW(%0)) /* Data cache invalidate by set/way */ _WF0(_CP15_ICIALLU, CP15_ICIALLU) /* Instruction cache invalidate all PoU */ #if __ARM_ARCH >= 7 && defined SMP _WF0(_CP15_ICIALLUIS, CP15_ICIALLUIS) /* Instruction cache invalidate all PoU IS */ #endif _WF1(_CP15_ICIMVAU, CP15_ICIMVAU(%0)) /* Instruction cache invalidate */ /* * Publicly accessible functions */ /* Various control registers */ _RF0(cp15_dfsr_get, CP15_DFSR(%0)) _RF0(cp15_ifsr_get, CP15_IFSR(%0)) _WF1(cp15_prrr_set, CP15_PRRR(%0)) _WF1(cp15_nmrr_set, CP15_NMRR(%0)) _RF0(cp15_ttbr_get, CP15_TTBR0(%0)) _RF0(cp15_dfar_get, CP15_DFAR(%0)) #if __ARM_ARCH >= 7 _RF0(cp15_ifar_get, CP15_IFAR(%0)) _RF0(cp15_l2ctlr_get, CP15_L2CTLR(%0)) #endif #if __ARM_ARCH >= 6 _RF0(cp15_actlr_get, CP15_ACTLR(%0)) _WF1(cp15_ats1cpr_set, CP15_ATS1CPR(%0)); _RF0(cp15_par_get, CP15_PAR); _RF0(cp15_sctlr_get, CP15_SCTLR(%0)) #endif /*CPU id registers */ _RF0(cp15_midr_get, CP15_MIDR(%0)) _RF0(cp15_ctr_get, CP15_CTR(%0)) _RF0(cp15_tcmtr_get, CP15_TCMTR(%0)) _RF0(cp15_tlbtr_get, CP15_TLBTR(%0)) _RF0(cp15_mpidr_get, CP15_MPIDR(%0)) _RF0(cp15_revidr_get, CP15_REVIDR(%0)) _RF0(cp15_aidr_get, CP15_AIDR(%0)) _RF0(cp15_id_pfr0_get, CP15_ID_PFR0(%0)) _RF0(cp15_id_pfr1_get, CP15_ID_PFR1(%0)) _RF0(cp15_id_dfr0_get, CP15_ID_DFR0(%0)) _RF0(cp15_id_afr0_get, CP15_ID_AFR0(%0)) _RF0(cp15_id_mmfr0_get, CP15_ID_MMFR0(%0)) _RF0(cp15_id_mmfr1_get, CP15_ID_MMFR1(%0)) _RF0(cp15_id_mmfr2_get, CP15_ID_MMFR2(%0)) _RF0(cp15_id_mmfr3_get, CP15_ID_MMFR3(%0)) _RF0(cp15_id_isar0_get, CP15_ID_ISAR0(%0)) _RF0(cp15_id_isar1_get, CP15_ID_ISAR1(%0)) _RF0(cp15_id_isar2_get, CP15_ID_ISAR2(%0)) _RF0(cp15_id_isar3_get, CP15_ID_ISAR3(%0)) _RF0(cp15_id_isar4_get, CP15_ID_ISAR4(%0)) _RF0(cp15_id_isar5_get, CP15_ID_ISAR5(%0)) _RF0(cp15_cbar_get, CP15_CBAR(%0)) /* Performance Monitor registers */ #if __ARM_ARCH == 6 && defined(CPU_ARM1176) _RF0(cp15_pmccntr_get, CP15_PMCCNTR(%0)) _WF1(cp15_pmccntr_set, CP15_PMCCNTR(%0)) #elif __ARM_ARCH > 6 _RF0(cp15_pmcr_get, CP15_PMCR(%0)) _WF1(cp15_pmcr_set, CP15_PMCR(%0)) _RF0(cp15_pmcnten_get, CP15_PMCNTENSET(%0)) _WF1(cp15_pmcnten_set, CP15_PMCNTENSET(%0)) _WF1(cp15_pmcnten_clr, CP15_PMCNTENCLR(%0)) _RF0(cp15_pmovsr_get, CP15_PMOVSR(%0)) _WF1(cp15_pmovsr_set, CP15_PMOVSR(%0)) _WF1(cp15_pmswinc_set, CP15_PMSWINC(%0)) _RF0(cp15_pmselr_get, CP15_PMSELR(%0)) _WF1(cp15_pmselr_set, CP15_PMSELR(%0)) _RF0(cp15_pmccntr_get, CP15_PMCCNTR(%0)) _WF1(cp15_pmccntr_set, CP15_PMCCNTR(%0)) _RF0(cp15_pmxevtyper_get, CP15_PMXEVTYPER(%0)) _WF1(cp15_pmxevtyper_set, CP15_PMXEVTYPER(%0)) _RF0(cp15_pmxevcntr_get, CP15_PMXEVCNTRR(%0)) _WF1(cp15_pmxevcntr_set, CP15_PMXEVCNTRR(%0)) _RF0(cp15_pmuserenr_get, CP15_PMUSERENR(%0)) _WF1(cp15_pmuserenr_set, CP15_PMUSERENR(%0)) _RF0(cp15_pminten_get, CP15_PMINTENSET(%0)) _WF1(cp15_pminten_set, CP15_PMINTENSET(%0)) _WF1(cp15_pminten_clr, CP15_PMINTENCLR(%0)) #endif _RF0(cp15_tpidrurw_get, CP15_TPIDRURW(%0)) _WF1(cp15_tpidrurw_set, CP15_TPIDRURW(%0)) _RF0(cp15_tpidruro_get, CP15_TPIDRURO(%0)) _WF1(cp15_tpidruro_set, CP15_TPIDRURO(%0)) _RF0(cp15_tpidrpwr_get, CP15_TPIDRPRW(%0)) _WF1(cp15_tpidrpwr_set, CP15_TPIDRPRW(%0)) /* Generic Timer registers - only use when you know the hardware is available */ _RF0(cp15_cntfrq_get, CP15_CNTFRQ(%0)) _WF1(cp15_cntfrq_set, CP15_CNTFRQ(%0)) _RF0(cp15_cntkctl_get, CP15_CNTKCTL(%0)) _WF1(cp15_cntkctl_set, CP15_CNTKCTL(%0)) _RF0(cp15_cntp_tval_get, CP15_CNTP_TVAL(%0)) _WF1(cp15_cntp_tval_set, CP15_CNTP_TVAL(%0)) _RF0(cp15_cntp_ctl_get, CP15_CNTP_CTL(%0)) _WF1(cp15_cntp_ctl_set, CP15_CNTP_CTL(%0)) _RF0(cp15_cntv_tval_get, CP15_CNTV_TVAL(%0)) _WF1(cp15_cntv_tval_set, CP15_CNTV_TVAL(%0)) _RF0(cp15_cntv_ctl_get, CP15_CNTV_CTL(%0)) _WF1(cp15_cntv_ctl_set, CP15_CNTV_CTL(%0)) _RF0(cp15_cnthctl_get, CP15_CNTHCTL(%0)) _WF1(cp15_cnthctl_set, CP15_CNTHCTL(%0)) _RF0(cp15_cnthp_tval_get, CP15_CNTHP_TVAL(%0)) _WF1(cp15_cnthp_tval_set, CP15_CNTHP_TVAL(%0)) _RF0(cp15_cnthp_ctl_get, CP15_CNTHP_CTL(%0)) _WF1(cp15_cnthp_ctl_set, CP15_CNTHP_CTL(%0)) _R64F0(cp15_cntpct_get, CP15_CNTPCT(%Q0, %R0)) _R64F0(cp15_cntvct_get, CP15_CNTVCT(%Q0, %R0)) _R64F0(cp15_cntp_cval_get, CP15_CNTP_CVAL(%Q0, %R0)) _W64F1(cp15_cntp_cval_set, CP15_CNTP_CVAL(%Q0, %R0)) _R64F0(cp15_cntv_cval_get, CP15_CNTV_CVAL(%Q0, %R0)) _W64F1(cp15_cntv_cval_set, CP15_CNTV_CVAL(%Q0, %R0)) _R64F0(cp15_cntvoff_get, CP15_CNTVOFF(%Q0, %R0)) _W64F1(cp15_cntvoff_set, CP15_CNTVOFF(%Q0, %R0)) _R64F0(cp15_cnthp_cval_get, CP15_CNTHP_CVAL(%Q0, %R0)) _W64F1(cp15_cnthp_cval_set, CP15_CNTHP_CVAL(%Q0, %R0)) #undef _FX #undef _RF0 #undef _WF0 #undef _WF1 /* * TLB maintenance operations. */ /* Local (i.e. not broadcasting ) operations. */ /* Flush all TLB entries (even global). */ static __inline void tlb_flush_all_local(void) { dsb(); _CP15_TLBIALL(); dsb(); } /* Flush all not global TLB entries. */ static __inline void tlb_flush_all_ng_local(void) { dsb(); _CP15_TLBIASID(CPU_ASID_KERNEL); dsb(); } /* Flush single TLB entry (even global). */ static __inline void -tlb_flush_local(vm_offset_t sva) +tlb_flush_local(vm_offset_t va) { + KASSERT((va & PAGE_MASK) == 0, ("%s: va %#x not aligned", __func__, va)); + dsb(); - _CP15_TLBIMVA((sva & ~PAGE_MASK ) | CPU_ASID_KERNEL); + _CP15_TLBIMVA(va | CPU_ASID_KERNEL); dsb(); } /* Flush range of TLB entries (even global). */ static __inline void -tlb_flush_range_local(vm_offset_t sva, vm_size_t size) +tlb_flush_range_local(vm_offset_t va, vm_size_t size) { - vm_offset_t va; - vm_offset_t eva = sva + size; + vm_offset_t eva = va + size; + KASSERT((va & PAGE_MASK) == 0, ("%s: va %#x not aligned", __func__, va)); + KASSERT((size & PAGE_MASK) == 0, ("%s: size %#x not aligned", __func__, + size)); + dsb(); - for (va = sva; va < eva; va += PAGE_SIZE) - _CP15_TLBIMVA((va & ~PAGE_MASK ) | CPU_ASID_KERNEL); + for (; va < eva; va += PAGE_SIZE) + _CP15_TLBIMVA(va | CPU_ASID_KERNEL); dsb(); } /* Broadcasting operations. */ #if __ARM_ARCH >= 7 && defined SMP static __inline void tlb_flush_all(void) { dsb(); _CP15_TLBIALLIS(); dsb(); } static __inline void tlb_flush_all_ng(void) { dsb(); _CP15_TLBIASIDIS(CPU_ASID_KERNEL); dsb(); } static __inline void -tlb_flush(vm_offset_t sva) +tlb_flush(vm_offset_t va) { + KASSERT((va & PAGE_MASK) == 0, ("%s: va %#x not aligned", __func__, va)); + dsb(); - _CP15_TLBIMVAAIS(sva); + _CP15_TLBIMVAAIS(va); dsb(); } static __inline void -tlb_flush_range(vm_offset_t sva, vm_size_t size) +tlb_flush_range(vm_offset_t va, vm_size_t size) { - vm_offset_t va; - vm_offset_t eva = sva + size; + vm_offset_t eva = va + size; + KASSERT((va & PAGE_MASK) == 0, ("%s: va %#x not aligned", __func__, va)); + KASSERT((size & PAGE_MASK) == 0, ("%s: size %#x not aligned", __func__, + size)); + dsb(); - for (va = sva; va < eva; va += PAGE_SIZE) + for (; va < eva; va += PAGE_SIZE) _CP15_TLBIMVAAIS(va); dsb(); } #else /* SMP */ #define tlb_flush_all() tlb_flush_all_local() #define tlb_flush_all_ng() tlb_flush_all_ng_local() -#define tlb_flush(sva) tlb_flush_local(sva) -#define tlb_flush_range(sva, size) tlb_flush_range_local(sva, size) +#define tlb_flush(va) tlb_flush_local(va) +#define tlb_flush_range(va, size) tlb_flush_range_local(va, size) #endif /* SMP */ /* * Cache maintenance operations. */ /* Sync I and D caches to PoU */ static __inline void -icache_sync(vm_offset_t sva, vm_size_t size) +icache_sync(vm_offset_t va, vm_size_t size) { - vm_offset_t va; - vm_offset_t eva = sva + size; + vm_offset_t eva = va + size; dsb(); - for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { + va &= ~cpuinfo.dcache_line_mask; + for ( ; va < eva; va += cpuinfo.dcache_line_size) { #if __ARM_ARCH >= 7 && defined SMP _CP15_DCCMVAU(va); #else _CP15_DCCMVAC(va); #endif } dsb(); #if __ARM_ARCH >= 7 && defined SMP _CP15_ICIALLUIS(); #else _CP15_ICIALLU(); #endif dsb(); isb(); } /* Invalidate I cache */ static __inline void icache_inv_all(void) { #if __ARM_ARCH >= 7 && defined SMP _CP15_ICIALLUIS(); #else _CP15_ICIALLU(); #endif dsb(); isb(); } /* Invalidate branch predictor buffer */ static __inline void bpb_inv_all(void) { #if __ARM_ARCH >= 7 && defined SMP _CP15_BPIALLIS(); #else _CP15_BPIALL(); #endif dsb(); isb(); } /* Write back D-cache to PoU */ static __inline void -dcache_wb_pou(vm_offset_t sva, vm_size_t size) +dcache_wb_pou(vm_offset_t va, vm_size_t size) { - vm_offset_t va; - vm_offset_t eva = sva + size; + vm_offset_t eva = va + size; dsb(); - for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { + va &= ~cpuinfo.dcache_line_mask; + for ( ; va < eva; va += cpuinfo.dcache_line_size) { #if __ARM_ARCH >= 7 && defined SMP _CP15_DCCMVAU(va); #else _CP15_DCCMVAC(va); #endif } dsb(); } -/* Invalidate D-cache to PoC */ +/* + * Invalidate D-cache to PoC + * + * Caches are invalidated from outermost to innermost as fresh cachelines + * flow in this direction. In given range, if there was no dirty cacheline + * in any cache before, no stale cacheline should remain in them after this + * operation finishes. + */ static __inline void -dcache_inv_poc(vm_offset_t sva, vm_paddr_t pa, vm_size_t size) +dcache_inv_poc(vm_offset_t va, vm_paddr_t pa, vm_size_t size) { - vm_offset_t va; - vm_offset_t eva = sva + size; + vm_offset_t eva = va + size; - /* invalidate L1 first */ - for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { - _CP15_DCIMVAC(va); - } dsb(); + /* invalidate L2 first */ + cpu_l2cache_inv_range(pa, size); - /* then L2 */ - cpu_l2cache_inv_range(pa, size); - dsb(); - - /* then L1 again */ - for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { + /* then L1 */ + va &= ~cpuinfo.dcache_line_mask; + for ( ; va < eva; va += cpuinfo.dcache_line_size) { _CP15_DCIMVAC(va); } dsb(); } -/* Write back D-cache to PoC */ +/* + * Write back D-cache to PoC + * + * Caches are written back from innermost to outermost as dirty cachelines + * flow in this direction. In given range, no dirty cacheline should remain + * in any cache after this operation finishes. + */ static __inline void -dcache_wb_poc(vm_offset_t sva, vm_paddr_t pa, vm_size_t size) +dcache_wb_poc(vm_offset_t va, vm_paddr_t pa, vm_size_t size) { - vm_offset_t va; - vm_offset_t eva = sva + size; + vm_offset_t eva = va + size; dsb(); - - for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { + va &= ~cpuinfo.dcache_line_mask; + for ( ; va < eva; va += cpuinfo.dcache_line_size) { _CP15_DCCMVAC(va); } dsb(); cpu_l2cache_wb_range(pa, size); } /* Write back and invalidate D-cache to PoC */ static __inline void dcache_wbinv_poc(vm_offset_t sva, vm_paddr_t pa, vm_size_t size) { vm_offset_t va; vm_offset_t eva = sva + size; dsb(); - /* write back L1 first */ - for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { + va = sva & ~cpuinfo.dcache_line_mask; + for ( ; va < eva; va += cpuinfo.dcache_line_size) { _CP15_DCCMVAC(va); } dsb(); /* then write back and invalidate L2 */ cpu_l2cache_wbinv_range(pa, size); /* then invalidate L1 */ - for (va = sva; va < eva; va += cpuinfo.dcache_line_size) { + va = sva & ~cpuinfo.dcache_line_mask; + for ( ; va < eva; va += cpuinfo.dcache_line_size) { _CP15_DCIMVAC(va); } dsb(); } /* Set TTB0 register */ static __inline void cp15_ttbr_set(uint32_t reg) { dsb(); _CP15_TTB_SET(reg); dsb(); _CP15_BPIALL(); dsb(); isb(); tlb_flush_all_ng_local(); } #endif /* _KERNEL */ #endif /* !MACHINE_CPU_V6_H */ Index: projects/ci20_mips/sys/arm/include/cpufunc.h =================================================================== --- projects/ci20_mips/sys/arm/include/cpufunc.h (revision 283030) +++ projects/ci20_mips/sys/arm/include/cpufunc.h (revision 283031) @@ -1,622 +1,621 @@ /* $NetBSD: cpufunc.h,v 1.29 2003/09/06 09:08:35 rearnsha Exp $ */ /*- * Copyright (c) 1997 Mark Brinicombe. * Copyright (c) 1997 Causality Limited * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Causality Limited. * 4. The name of Causality Limited may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * RiscBSD kernel project * * cpufunc.h * * Prototypes for cpu, mmu and tlb related functions. * * $FreeBSD$ */ #ifndef _MACHINE_CPUFUNC_H_ #define _MACHINE_CPUFUNC_H_ #ifdef _KERNEL #include #include #include /* For in[bwl] and out[bwl] */ static __inline void breakpoint(void) { __asm(".word 0xe7ffffff"); } struct cpu_functions { /* CPU functions */ u_int (*cf_id) (void); void (*cf_cpwait) (void); /* MMU functions */ u_int (*cf_control) (u_int bic, u_int eor); void (*cf_domains) (u_int domains); void (*cf_setttb) (u_int ttb); u_int (*cf_faultstatus) (void); u_int (*cf_faultaddress) (void); /* TLB functions */ void (*cf_tlb_flushID) (void); void (*cf_tlb_flushID_SE) (u_int va); void (*cf_tlb_flushI) (void); void (*cf_tlb_flushI_SE) (u_int va); void (*cf_tlb_flushD) (void); void (*cf_tlb_flushD_SE) (u_int va); /* * Cache operations: * * We define the following primitives: * * icache_sync_all Synchronize I-cache * icache_sync_range Synchronize I-cache range * * dcache_wbinv_all Write-back and Invalidate D-cache * dcache_wbinv_range Write-back and Invalidate D-cache range * dcache_inv_range Invalidate D-cache range * dcache_wb_range Write-back D-cache range * * idcache_wbinv_all Write-back and Invalidate D-cache, * Invalidate I-cache * idcache_wbinv_range Write-back and Invalidate D-cache, * Invalidate I-cache range * * Note that the ARM term for "write-back" is "clean". We use * the term "write-back" since it's a more common way to describe * the operation. * * There are some rules that must be followed: * * ID-cache Invalidate All: * Unlike other functions, this one must never write back. * It is used to intialize the MMU when it is in an unknown * state (such as when it may have lines tagged as valid * that belong to a previous set of mappings). * * I-cache Synch (all or range): * The goal is to synchronize the instruction stream, * so you may beed to write-back dirty D-cache blocks * first. If a range is requested, and you can't * synchronize just a range, you have to hit the whole * thing. * * D-cache Write-Back and Invalidate range: * If you can't WB-Inv a range, you must WB-Inv the * entire D-cache. * * D-cache Invalidate: * If you can't Inv the D-cache, you must Write-Back * and Invalidate. Code that uses this operation * MUST NOT assume that the D-cache will not be written * back to memory. * * D-cache Write-Back: * If you can't Write-back without doing an Inv, * that's fine. Then treat this as a WB-Inv. * Skipping the invalidate is merely an optimization. * * All operations: * Valid virtual addresses must be passed to each * cache operation. */ void (*cf_icache_sync_all) (void); void (*cf_icache_sync_range) (vm_offset_t, vm_size_t); void (*cf_dcache_wbinv_all) (void); void (*cf_dcache_wbinv_range) (vm_offset_t, vm_size_t); void (*cf_dcache_inv_range) (vm_offset_t, vm_size_t); void (*cf_dcache_wb_range) (vm_offset_t, vm_size_t); void (*cf_idcache_inv_all) (void); void (*cf_idcache_wbinv_all) (void); void (*cf_idcache_wbinv_range) (vm_offset_t, vm_size_t); void (*cf_l2cache_wbinv_all) (void); void (*cf_l2cache_wbinv_range) (vm_offset_t, vm_size_t); void (*cf_l2cache_inv_range) (vm_offset_t, vm_size_t); void (*cf_l2cache_wb_range) (vm_offset_t, vm_size_t); void (*cf_l2cache_drain_writebuf) (void); /* Other functions */ void (*cf_flush_prefetchbuf) (void); void (*cf_drain_writebuf) (void); void (*cf_flush_brnchtgt_C) (void); void (*cf_flush_brnchtgt_E) (u_int va); void (*cf_sleep) (int mode); /* Soft functions */ int (*cf_dataabt_fixup) (void *arg); int (*cf_prefetchabt_fixup) (void *arg); void (*cf_context_switch) (void); void (*cf_setup) (void); }; extern struct cpu_functions cpufuncs; extern u_int cputype; #define cpu_ident() cpufuncs.cf_id() #define cpu_cpwait() cpufuncs.cf_cpwait() #define cpu_control(c, e) cpufuncs.cf_control(c, e) #define cpu_domains(d) cpufuncs.cf_domains(d) #define cpu_setttb(t) cpufuncs.cf_setttb(t) #define cpu_faultstatus() cpufuncs.cf_faultstatus() #define cpu_faultaddress() cpufuncs.cf_faultaddress() #ifndef SMP #define cpu_tlb_flushID() cpufuncs.cf_tlb_flushID() #define cpu_tlb_flushID_SE(e) cpufuncs.cf_tlb_flushID_SE(e) #define cpu_tlb_flushI() cpufuncs.cf_tlb_flushI() #define cpu_tlb_flushI_SE(e) cpufuncs.cf_tlb_flushI_SE(e) #define cpu_tlb_flushD() cpufuncs.cf_tlb_flushD() #define cpu_tlb_flushD_SE(e) cpufuncs.cf_tlb_flushD_SE(e) #else void tlb_broadcast(int); #if defined(CPU_CORTEXA) || defined(CPU_MV_PJ4B) || defined(CPU_KRAIT) #define TLB_BROADCAST /* No need to explicitely send an IPI */ #else #define TLB_BROADCAST tlb_broadcast(7) #endif #define cpu_tlb_flushID() do { \ cpufuncs.cf_tlb_flushID(); \ TLB_BROADCAST; \ } while(0) #define cpu_tlb_flushID_SE(e) do { \ cpufuncs.cf_tlb_flushID_SE(e); \ TLB_BROADCAST; \ } while(0) #define cpu_tlb_flushI() do { \ cpufuncs.cf_tlb_flushI(); \ TLB_BROADCAST; \ } while(0) #define cpu_tlb_flushI_SE(e) do { \ cpufuncs.cf_tlb_flushI_SE(e); \ TLB_BROADCAST; \ } while(0) #define cpu_tlb_flushD() do { \ cpufuncs.cf_tlb_flushD(); \ TLB_BROADCAST; \ } while(0) #define cpu_tlb_flushD_SE(e) do { \ cpufuncs.cf_tlb_flushD_SE(e); \ TLB_BROADCAST; \ } while(0) #endif #define cpu_icache_sync_all() cpufuncs.cf_icache_sync_all() #define cpu_icache_sync_range(a, s) cpufuncs.cf_icache_sync_range((a), (s)) #define cpu_dcache_wbinv_all() cpufuncs.cf_dcache_wbinv_all() #define cpu_dcache_wbinv_range(a, s) cpufuncs.cf_dcache_wbinv_range((a), (s)) #define cpu_dcache_inv_range(a, s) cpufuncs.cf_dcache_inv_range((a), (s)) #define cpu_dcache_wb_range(a, s) cpufuncs.cf_dcache_wb_range((a), (s)) #define cpu_idcache_inv_all() cpufuncs.cf_idcache_inv_all() #define cpu_idcache_wbinv_all() cpufuncs.cf_idcache_wbinv_all() #define cpu_idcache_wbinv_range(a, s) cpufuncs.cf_idcache_wbinv_range((a), (s)) #define cpu_l2cache_wbinv_all() cpufuncs.cf_l2cache_wbinv_all() #define cpu_l2cache_wb_range(a, s) cpufuncs.cf_l2cache_wb_range((a), (s)) #define cpu_l2cache_inv_range(a, s) cpufuncs.cf_l2cache_inv_range((a), (s)) #define cpu_l2cache_wbinv_range(a, s) cpufuncs.cf_l2cache_wbinv_range((a), (s)) #define cpu_l2cache_drain_writebuf() cpufuncs.cf_l2cache_drain_writebuf() #define cpu_flush_prefetchbuf() cpufuncs.cf_flush_prefetchbuf() #define cpu_drain_writebuf() cpufuncs.cf_drain_writebuf() #define cpu_flush_brnchtgt_C() cpufuncs.cf_flush_brnchtgt_C() #define cpu_flush_brnchtgt_E(e) cpufuncs.cf_flush_brnchtgt_E(e) #define cpu_sleep(m) cpufuncs.cf_sleep(m) #define cpu_dataabt_fixup(a) cpufuncs.cf_dataabt_fixup(a) #define cpu_prefetchabt_fixup(a) cpufuncs.cf_prefetchabt_fixup(a) #define ABORT_FIXUP_OK 0 /* fixup succeeded */ #define ABORT_FIXUP_FAILED 1 /* fixup failed */ #define ABORT_FIXUP_RETURN 2 /* abort handler should return */ #define cpu_setup() cpufuncs.cf_setup() int set_cpufuncs (void); #define ARCHITECTURE_NOT_PRESENT 1 /* known but not configured */ #define ARCHITECTURE_NOT_SUPPORTED 2 /* not known */ void cpufunc_nullop (void); int cpufunc_null_fixup (void *); int early_abort_fixup (void *); int late_abort_fixup (void *); u_int cpufunc_id (void); u_int cpufunc_cpuid (void); u_int cpufunc_control (u_int clear, u_int bic); void cpufunc_domains (u_int domains); u_int cpufunc_faultstatus (void); u_int cpufunc_faultaddress (void); u_int cpu_pfr (int); #if defined(CPU_FA526) void fa526_setup (void); void fa526_setttb (u_int ttb); void fa526_context_switch (void); void fa526_cpu_sleep (int); void fa526_tlb_flushI_SE (u_int); void fa526_tlb_flushID_SE (u_int); void fa526_flush_prefetchbuf (void); void fa526_flush_brnchtgt_E (u_int); void fa526_icache_sync_all (void); void fa526_icache_sync_range(vm_offset_t start, vm_size_t end); void fa526_dcache_wbinv_all (void); void fa526_dcache_wbinv_range(vm_offset_t start, vm_size_t end); void fa526_dcache_inv_range (vm_offset_t start, vm_size_t end); void fa526_dcache_wb_range (vm_offset_t start, vm_size_t end); void fa526_idcache_wbinv_all(void); void fa526_idcache_wbinv_range(vm_offset_t start, vm_size_t end); #endif #ifdef CPU_ARM9 void arm9_setttb (u_int); void arm9_tlb_flushID_SE (u_int va); void arm9_icache_sync_all (void); void arm9_icache_sync_range (vm_offset_t, vm_size_t); void arm9_dcache_wbinv_all (void); void arm9_dcache_wbinv_range (vm_offset_t, vm_size_t); void arm9_dcache_inv_range (vm_offset_t, vm_size_t); void arm9_dcache_wb_range (vm_offset_t, vm_size_t); void arm9_idcache_wbinv_all (void); void arm9_idcache_wbinv_range (vm_offset_t, vm_size_t); void arm9_context_switch (void); void arm9_setup (void); extern unsigned arm9_dcache_sets_max; extern unsigned arm9_dcache_sets_inc; extern unsigned arm9_dcache_index_max; extern unsigned arm9_dcache_index_inc; #endif #if defined(CPU_ARM9E) void arm10_tlb_flushID_SE (u_int); void arm10_tlb_flushI_SE (u_int); void arm10_context_switch (void); void arm10_setup (void); u_int sheeva_control_ext (u_int, u_int); void sheeva_cpu_sleep (int); void sheeva_setttb (u_int); void sheeva_dcache_wbinv_range (vm_offset_t, vm_size_t); void sheeva_dcache_inv_range (vm_offset_t, vm_size_t); void sheeva_dcache_wb_range (vm_offset_t, vm_size_t); void sheeva_idcache_wbinv_range (vm_offset_t, vm_size_t); void sheeva_l2cache_wbinv_range (vm_offset_t, vm_size_t); void sheeva_l2cache_inv_range (vm_offset_t, vm_size_t); void sheeva_l2cache_wb_range (vm_offset_t, vm_size_t); void sheeva_l2cache_wbinv_all (void); #endif #if defined(CPU_MV_PJ4B) void armv6_idcache_wbinv_all (void); #endif #if defined(CPU_MV_PJ4B) || defined(CPU_CORTEXA) || defined(CPU_KRAIT) void armv7_setttb (u_int); void armv7_tlb_flushID (void); void armv7_tlb_flushID_SE (u_int); void armv7_icache_sync_all (void); void armv7_icache_sync_range (vm_offset_t, vm_size_t); void armv7_idcache_wbinv_range (vm_offset_t, vm_size_t); void armv7_idcache_inv_all (void); void armv7_dcache_wbinv_all (void); void armv7_idcache_wbinv_all (void); void armv7_dcache_wbinv_range (vm_offset_t, vm_size_t); void armv7_dcache_inv_range (vm_offset_t, vm_size_t); void armv7_dcache_wb_range (vm_offset_t, vm_size_t); void armv7_cpu_sleep (int); void armv7_setup (void); void armv7_context_switch (void); void armv7_drain_writebuf (void); void armv7_sev (void); -void armv7_sleep (int unused); u_int armv7_auxctrl (u_int, u_int); void armadaxp_idcache_wbinv_all (void); void cortexa_setup (void); #endif #if defined(CPU_MV_PJ4B) void pj4b_config (void); void pj4bv7_setup (void); #endif #if defined(CPU_ARM1176) void arm11_tlb_flushID (void); void arm11_tlb_flushID_SE (u_int); void arm11_tlb_flushI (void); void arm11_tlb_flushI_SE (u_int); void arm11_tlb_flushD (void); void arm11_tlb_flushD_SE (u_int va); void arm11_context_switch (void); void arm11_drain_writebuf (void); void armv6_dcache_wbinv_range (vm_offset_t, vm_size_t); void armv6_dcache_inv_range (vm_offset_t, vm_size_t); void armv6_dcache_wb_range (vm_offset_t, vm_size_t); void armv6_idcache_inv_all (void); void arm11x6_setttb (u_int); void arm11x6_idcache_wbinv_all (void); void arm11x6_dcache_wbinv_all (void); void arm11x6_icache_sync_all (void); void arm11x6_flush_prefetchbuf (void); void arm11x6_icache_sync_range (vm_offset_t, vm_size_t); void arm11x6_idcache_wbinv_range (vm_offset_t, vm_size_t); void arm11x6_setup (void); void arm11x6_sleep (int); /* no ref. for errata */ #endif #if defined(CPU_ARM9E) void armv5_ec_setttb(u_int); void armv5_ec_icache_sync_all(void); void armv5_ec_icache_sync_range(vm_offset_t, vm_size_t); void armv5_ec_dcache_wbinv_all(void); void armv5_ec_dcache_wbinv_range(vm_offset_t, vm_size_t); void armv5_ec_dcache_inv_range(vm_offset_t, vm_size_t); void armv5_ec_dcache_wb_range(vm_offset_t, vm_size_t); void armv5_ec_idcache_wbinv_all(void); void armv5_ec_idcache_wbinv_range(vm_offset_t, vm_size_t); #endif #if defined(CPU_ARM9) || defined(CPU_ARM9E) || \ defined(CPU_XSCALE_80321) || \ defined(CPU_FA526) || \ defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425) || \ defined(CPU_XSCALE_80219) || defined(CPU_XSCALE_81342) void armv4_tlb_flushID (void); void armv4_tlb_flushI (void); void armv4_tlb_flushD (void); void armv4_tlb_flushD_SE (u_int va); void armv4_drain_writebuf (void); void armv4_idcache_inv_all (void); #endif #if defined(CPU_XSCALE_80321) || \ defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425) || \ defined(CPU_XSCALE_80219) || defined(CPU_XSCALE_81342) void xscale_cpwait (void); void xscale_cpu_sleep (int mode); u_int xscale_control (u_int clear, u_int bic); void xscale_setttb (u_int ttb); void xscale_tlb_flushID_SE (u_int va); void xscale_cache_flushID (void); void xscale_cache_flushI (void); void xscale_cache_flushD (void); void xscale_cache_flushD_SE (u_int entry); void xscale_cache_cleanID (void); void xscale_cache_cleanD (void); void xscale_cache_cleanD_E (u_int entry); void xscale_cache_clean_minidata (void); void xscale_cache_purgeID (void); void xscale_cache_purgeID_E (u_int entry); void xscale_cache_purgeD (void); void xscale_cache_purgeD_E (u_int entry); void xscale_cache_syncI (void); void xscale_cache_cleanID_rng (vm_offset_t start, vm_size_t end); void xscale_cache_cleanD_rng (vm_offset_t start, vm_size_t end); void xscale_cache_purgeID_rng (vm_offset_t start, vm_size_t end); void xscale_cache_purgeD_rng (vm_offset_t start, vm_size_t end); void xscale_cache_syncI_rng (vm_offset_t start, vm_size_t end); void xscale_cache_flushD_rng (vm_offset_t start, vm_size_t end); void xscale_context_switch (void); void xscale_setup (void); #endif /* CPU_XSCALE_80321 || CPU_XSCALE_PXA2X0 || CPU_XSCALE_IXP425 CPU_XSCALE_80219 */ #ifdef CPU_XSCALE_81342 void xscalec3_l2cache_purge (void); void xscalec3_cache_purgeID (void); void xscalec3_cache_purgeD (void); void xscalec3_cache_cleanID (void); void xscalec3_cache_cleanD (void); void xscalec3_cache_syncI (void); void xscalec3_cache_purgeID_rng (vm_offset_t start, vm_size_t end); void xscalec3_cache_purgeD_rng (vm_offset_t start, vm_size_t end); void xscalec3_cache_cleanID_rng (vm_offset_t start, vm_size_t end); void xscalec3_cache_cleanD_rng (vm_offset_t start, vm_size_t end); void xscalec3_cache_syncI_rng (vm_offset_t start, vm_size_t end); void xscalec3_l2cache_flush_rng (vm_offset_t, vm_size_t); void xscalec3_l2cache_clean_rng (vm_offset_t start, vm_size_t end); void xscalec3_l2cache_purge_rng (vm_offset_t start, vm_size_t end); void xscalec3_setttb (u_int ttb); void xscalec3_context_switch (void); #endif /* CPU_XSCALE_81342 */ #define setttb cpu_setttb #define drain_writebuf cpu_drain_writebuf /* * Macros for manipulating CPU interrupts */ static __inline u_int32_t __set_cpsr_c(u_int bic, u_int eor) __attribute__((__unused__)); static __inline u_int32_t __set_cpsr_c(u_int bic, u_int eor) { u_int32_t tmp, ret; __asm __volatile( "mrs %0, cpsr\n" /* Get the CPSR */ "bic %1, %0, %2\n" /* Clear bits */ "eor %1, %1, %3\n" /* XOR bits */ "msr cpsr_c, %1\n" /* Set the control field of CPSR */ : "=&r" (ret), "=&r" (tmp) : "r" (bic), "r" (eor) : "memory"); return ret; } #define ARM_CPSR_F32 (1 << 6) /* FIQ disable */ #define ARM_CPSR_I32 (1 << 7) /* IRQ disable */ #define disable_interrupts(mask) \ (__set_cpsr_c((mask) & (ARM_CPSR_I32 | ARM_CPSR_F32), \ (mask) & (ARM_CPSR_I32 | ARM_CPSR_F32))) #define enable_interrupts(mask) \ (__set_cpsr_c((mask) & (ARM_CPSR_I32 | ARM_CPSR_F32), 0)) #define restore_interrupts(old_cpsr) \ (__set_cpsr_c((ARM_CPSR_I32 | ARM_CPSR_F32), \ (old_cpsr) & (ARM_CPSR_I32 | ARM_CPSR_F32))) static __inline register_t intr_disable(void) { register_t s; s = disable_interrupts(ARM_CPSR_I32 | ARM_CPSR_F32); return (s); } static __inline void intr_restore(register_t s) { restore_interrupts(s); } /* Functions to manipulate the CPSR. */ u_int SetCPSR(u_int bic, u_int eor); u_int GetCPSR(void); /* * Functions to manipulate cpu r13 * (in arm/arm32/setstack.S) */ void set_stackptr (u_int mode, u_int address); u_int get_stackptr (u_int mode); /* * Miscellany */ int get_pc_str_offset (void); /* * CPU functions from locore.S */ void cpu_reset (void) __attribute__((__noreturn__)); /* * Cache info variables. */ /* PRIMARY CACHE VARIABLES */ extern int arm_picache_size; extern int arm_picache_line_size; extern int arm_picache_ways; extern int arm_pdcache_size; /* and unified */ extern int arm_pdcache_line_size; extern int arm_pdcache_ways; extern int arm_pcache_type; extern int arm_pcache_unified; extern int arm_dcache_align; extern int arm_dcache_align_mask; extern u_int arm_cache_level; extern u_int arm_cache_loc; extern u_int arm_cache_type[14]; #endif /* _KERNEL */ #endif /* _MACHINE_CPUFUNC_H_ */ /* End of cpufunc.h */ Index: projects/ci20_mips/sys/boot/arm/uboot/Makefile =================================================================== --- projects/ci20_mips/sys/boot/arm/uboot/Makefile (revision 283030) +++ projects/ci20_mips/sys/boot/arm/uboot/Makefile (revision 283031) @@ -1,158 +1,158 @@ # $FreeBSD$ .include FILES= ubldr ubldr.bin NEWVERSWHAT= "U-Boot loader" ${MACHINE_ARCH} BINDIR?= /boot INSTALLFLAGS= -b WARNS?= 1 # Address at which ubldr will be loaded. # This varies for different boards and SOCs. UBLDR_LOADADDR?= 0x1000000 # Architecture-specific loader code SRCS= start.S conf.c self_reloc.c vers.c .if !defined(LOADER_NO_DISK_SUPPORT) LOADER_DISK_SUPPORT?= yes .else LOADER_DISK_SUPPORT= no .endif LOADER_UFS_SUPPORT?= yes LOADER_CD9660_SUPPORT?= no LOADER_EXT2FS_SUPPORT?= no .if ${MK_NAND} != "no" LOADER_NANDFS_SUPPORT?= yes .else LOADER_NANDFS_SUPPORT?= no .endif LOADER_NET_SUPPORT?= yes LOADER_NFS_SUPPORT?= yes LOADER_TFTP_SUPPORT?= no LOADER_GZIP_SUPPORT?= no LOADER_BZIP2_SUPPORT?= no .if ${MK_FDT} != "no" LOADER_FDT_SUPPORT= yes .else LOADER_FDT_SUPPORT= no .endif .if ${LOADER_DISK_SUPPORT} == "yes" CFLAGS+= -DLOADER_DISK_SUPPORT .endif .if ${LOADER_UFS_SUPPORT} == "yes" CFLAGS+= -DLOADER_UFS_SUPPORT .endif .if ${LOADER_CD9660_SUPPORT} == "yes" CFLAGS+= -DLOADER_CD9660_SUPPORT .endif .if ${LOADER_EXT2FS_SUPPORT} == "yes" CFLAGS+= -DLOADER_EXT2FS_SUPPORT .endif .if ${LOADER_NANDFS_SUPPORT} == "yes" CFLAGS+= -DLOADER_NANDFS_SUPPORT .endif .if ${LOADER_GZIP_SUPPORT} == "yes" CFLAGS+= -DLOADER_GZIP_SUPPORT .endif .if ${LOADER_BZIP2_SUPPORT} == "yes" CFLAGS+= -DLOADER_BZIP2_SUPPORT .endif .if ${LOADER_NET_SUPPORT} == "yes" CFLAGS+= -DLOADER_NET_SUPPORT .endif .if ${LOADER_NFS_SUPPORT} == "yes" CFLAGS+= -DLOADER_NFS_SUPPORT .endif .if ${LOADER_TFTP_SUPPORT} == "yes" CFLAGS+= -DLOADER_TFTP_SUPPORT .endif .if ${LOADER_FDT_SUPPORT} == "yes" CFLAGS+= -I${.CURDIR}/../../fdt CFLAGS+= -I${.OBJDIR}/../../fdt CFLAGS+= -DLOADER_FDT_SUPPORT LIBUBOOT_FDT= ${.OBJDIR}/../../uboot/fdt/libuboot_fdt.a LIBFDT= ${.OBJDIR}/../../fdt/libfdt.a .endif .if ${MK_FORTH} != "no" # Enable BootForth BOOT_FORTH= yes CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/arm LIBFICL= ${.OBJDIR}/../../ficl/libficl.a .endif # Always add MI sources .PATH: ${.CURDIR}/../../common .include "${.CURDIR}/../../common/Makefile.inc" CFLAGS+= -I${.CURDIR}/../../common CFLAGS+= -I. CLEANFILES+= vers.c loader.help CFLAGS+= -ffreestanding -msoft-float LDFLAGS= -nostdlib -static -T ${.CURDIR}/ldscript.${MACHINE_CPUARCH} # Pull in common loader code .PATH: ${.CURDIR}/../../uboot/common .include "${.CURDIR}/../../uboot/common/Makefile.inc" CFLAGS+= -I${.CURDIR}/../../uboot/common # U-Boot standalone support library LIBUBOOT= ${.OBJDIR}/../../uboot/lib/libuboot.a CFLAGS+= -I${.CURDIR}/../../uboot/lib CFLAGS+= -I${.OBJDIR}/../../uboot/lib # where to get libstand from CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/ # clang doesn't understand %D as a specifier to printf NO_WERROR.clang= DPADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} ${LIBSTAND} LDADD= ${LIBFICL} ${LIBUBOOT} ${LIBFDT} ${LIBUBOOT_FDT} -lstand OBJS+= ${SRCS:N*.h:R:S/$/.o/g} vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT} loader.help: help.common help.uboot ${.CURDIR}/../../fdt/help.fdt cat ${.ALLSRC} | \ awk -f ${.CURDIR}/../../common/merge_help.awk > ${.TARGET} ldscript.abs: echo "UBLDR_LOADADDR = ${UBLDR_LOADADDR};" >${.TARGET} ldscript.pie: echo "UBLDR_LOADADDR = 0;" >${.TARGET} -ubldr: ${OBJS} ldscript.abs ${.CURDIR}/ldscript.${MACHINE_CPUARCH} +ubldr: ${OBJS} ldscript.abs ${.CURDIR}/ldscript.${MACHINE_CPUARCH} ${DPADD} ${CC} ${CFLAGS} -T ldscript.abs ${LDFLAGS} \ -o ${.TARGET} ${OBJS} ${LDADD} -ubldr.pie: ${OBJS} ldscript.pie ${.CURDIR}/ldscript.${MACHINE_CPUARCH} +ubldr.pie: ${OBJS} ldscript.pie ${.CURDIR}/ldscript.${MACHINE_CPUARCH} ${DPADD} ${CC} ${CFLAGS} -T ldscript.pie ${LDFLAGS} -pie -Wl,-Bsymbolic \ -o ${.TARGET} ${OBJS} ${LDADD} ubldr.bin: ubldr.pie ${OBJCOPY} -S -O binary ubldr.pie ${.TARGET} CLEANFILES+= ldscript.abs ldscript.pie ubldr ubldr.pie ubldr.bin .if !defined(LOADER_ONLY) .PATH: ${.CURDIR}/../../forth .include "${.CURDIR}/../../forth/Makefile.inc" # Put sample loader.rc and menu.rc on disk but don't enable them # by default. FILES+= loader.rc FILESNAME_loader.rc= loader.rc.sample FILES+= menu.rc FILESNAME_menu.rc= menu.rc.sample .endif .include Index: projects/ci20_mips/sys/boot/fdt/dts/arm/annapurna-alpine.dts =================================================================== --- projects/ci20_mips/sys/boot/fdt/dts/arm/annapurna-alpine.dts (nonexistent) +++ projects/ci20_mips/sys/boot/fdt/dts/arm/annapurna-alpine.dts (revision 283031) @@ -0,0 +1,244 @@ +/*- + * Copyright (c) 2013 Ruslan Bukin + * Copyright (c) 2015 Semihalf + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/dts-v1/; + +/ { + model = "annapurna,alpine"; + #address-cells = <1>; + #size-cells = <1>; + + aliases { + serial0 = &serial0; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x0>; + d-cache-line-size = <64>; // 64 bytes + i-cache-line-size = <64>; // 64 bytes + d-cache-size = <0x8000>; // L1, 32K + i-cache-size = <0x8000>; // L1, 32K + timebase-frequency = <0>; + bus-frequency = <375000000>; + clock-frequency = <0>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x0>; + d-cache-line-size = <64>; // 64 bytes + i-cache-line-size = <64>; // 64 bytes + d-cache-size = <0x8000>; // L1, 32K + i-cache-size = <0x8000>; // L1, 32K + timebase-frequency = <0>; + bus-frequency = <375000000>; + clock-frequency = <0>; + }; + + cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x0>; + d-cache-line-size = <64>; // 64 bytes + i-cache-line-size = <64>; // 64 bytes + d-cache-size = <0x8000>; // L1, 32K + i-cache-size = <0x8000>; // L1, 32K + timebase-frequency = <0>; + bus-frequency = <375000000>; + clock-frequency = <0>; + }; + + cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x0>; + d-cache-line-size = <64>; // 64 bytes + i-cache-line-size = <64>; // 64 bytes + d-cache-size = <0x8000>; // L1, 32K + i-cache-size = <0x8000>; // L1, 32K + timebase-frequency = <0>; + bus-frequency = <375000000>; + clock-frequency = <0>; + }; + }; + + memory { + device_type = "memory"; + reg = <0x00100000 0x7ff00000>; // 2047MB at 1MB + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0x0 0xfb000000 0x03000000>; + bus-frequency = <0>; + + MPIC: interrupt-controller { + compatible = "arm,gic"; + reg = < 0x1000 0x1000 >, /* Distributor Registers */ + < 0x2000 0x2000 >; /* CPU Interface Registers */ + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <3>; + + // In intr[2], bits[3:0] are trigger type and level flags. + // 1 = low-to-high edge triggered + // 2 = high-to-low edge triggered + // 4 = active high level-sensitive + // 8 = active low level-sensitive + // The hardware only supports active-high-level or rising-edge. + + }; + + generic_timer { + compatible = "arm,sp804"; + reg = <0x02890000 0x1000>; + interrupts = <0 9 4>; + interrupt-parent = <&MPIC>; + clock-frequency = <375000000>; + }; + + cpu_resume { + compatible = "annapurna-labs,al-cpu-resume"; + reg = <0x00ff5ec0 0x30>; + }; + + nb_service { + compatible = "annapurna-labs,al-nb-service"; + reg = <0x00070000 0x10000>; + interrupts = <0 32 4>, + <0 33 4>, + <0 34 4>, + <0 35 4>; + interrupt-parent = <&MPIC>; + }; + + wdt0 { + compatible = "arm,sp805", "arm,primecell"; + reg = <0x288c000 0x1000>; + interrupt-parent = <&MPIC>; + }; + + serial0: serial@2883000 { + compatible = "ns16550"; + reg = <0x2883000 0x20>; + reg-shift = <2>; + current-speed = <115200>; + clock-frequency = <375000000>; + interrupts = <0 17 4>; + interrupt-parent = <&MPIC>; + }; + }; + + pcie-internal { + compatible = "annapurna-labs,al-internal-pcie"; + device_type = "pci"; + #size-cells = <2>; + #address-cells = <3>; + interrupt-parent = <&MPIC>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = <0x3000 0 0 1 &MPIC 0 32 4>, // USB adapter + <0x3800 0 0 1 &MPIC 0 36 4>, + <0x4000 0 0 1 &MPIC 0 43 4>, // SATA 0 (PCIe expander) + <0x4800 0 0 1 &MPIC 0 44 1>; // SATA 1 (onboard) + + // ranges: + // - ECAM - non prefetchable config space + // - 32 bit non prefetchable memory space + ranges = <0x00000000 0x0 0xfbc00000 0xfbc00000 0x0 0x100000 + 0x02000000 0x0 0xfe000000 0xfe000000 0x0 0x1000000>; + + bus-range = <0x00 0x00>; + }; + +// WORKAROUND: enabling PCIe controller when no card is plugged in +// leads to kernel panic because u-boot disables PCIe controller if no link +// is detected. Just be kind and compatible with Linux +/* // External PCIe Controller 0 + pcie-external0 { + compatible = "annapurna-labs,al-external-pcie"; + reg = <0xfd800000 0x00020000>; + device_type = "pci"; + #size-cells = <2>; + #address-cells = <3>; + interrupt-parent = <&MPIC>; + interrupt-map-mask = <0x00 0 0 7>; + interrupt-map = <0x0000 0 0 1 &MPIC 0 40 4>; + + // ranges: + // Controller 0: + // - ECAM - non prefetchable config space: 2MB + // - IO - IO port space 64KB, reserve 64KB from target memory windows + // real IO address on the pci bus starts at 0x10000 + // - 32 bit non prefetchable memory space: 128MB - 64KB + + ranges = <0x00000000 0x0 0xfb600000 0xfb600000 0x0 0x00200000 + 0x01000000 0x0 0x00010000 0xe0000000 0x0 0x00010000 + 0x02000000 0x0 0xe1000000 0xe1000000 0x0 0x06f00000>; + + bus-range = <0x00 0xff>; + }; + + // External PCIe Controllers 1 + pcie-external1 { + compatible = "annapurna-labs,al-external-pcie"; + reg = <0xfd820000 0x00020000>; + device_type = "pci"; + #size-cells = <2>; + #address-cells = <3>; + interrupt-parent = <&MPIC>; + interrupt-map-mask = <0x0 0 0 7>; + interrupt-map = <0x0000 0 0 1 &MPIC 0 41 4>; + + // ranges: + // - ECAM - non prefetchable config space: 2MB + // - IO - IO port space 64KB, reserve 64KB from target memory windows + // real IO address on the pci bus starts at 0x20000 + // - 32 bit non prefetchable memory space: 64MB - 64KB + ranges = <0x00000000 0x0 0xfb800000 0xfb800000 0x0 0x00200000 + 0x01000000 0x0 0x00020000 0xe8000000 0x0 0x00010000 + 0x02000000 0x0 0xe8100000 0xe8100000 0x0 0x02ff0000>; + + bus-range = <0x00 0xff>; + }; */ + + chosen { + stdin = "serial0"; + stdout = "serial0"; + stddbg = "serial0"; + }; +}; Property changes on: projects/ci20_mips/sys/boot/fdt/dts/arm/annapurna-alpine.dts ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/sys/boot/i386/boot0/boot0.S =================================================================== --- projects/ci20_mips/sys/boot/i386/boot0/boot0.S (revision 283030) +++ projects/ci20_mips/sys/boot/i386/boot0/boot0.S (revision 283031) @@ -1,682 +1,682 @@ /* * Copyright (c) 2008 Luigi Rizzo (mostly documentation) * Copyright (c) 2002 Bruce M. Simpson * Copyright (c) 1998 Robert Nordier * All rights reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this * paragraph and the following disclaimer are duplicated in all * such forms. * * This software is provided "AS IS" and without any express or * implied warranties, including, without limitation, the implied * warranties of merchantability and fitness for a particular * purpose. * * $FreeBSD$ */ /* build options: */ #ifdef SIO /* use serial console on COM1. */ #endif #ifdef PXE /* enable PXE/INT18 booting with F6 */ #define SAVE_MORE_MEMORY #endif #ifdef CHECK_DRIVE /* make sure we boot from a HD. */ #endif #ifdef ONLY_F_KEYS /* Only F1..F6, no digits on console */ #endif #ifdef VOLUME_SERIAL /* support Volume serial number */ #define B0_BASE 0x1ae /* move the internal data area */ #define SAVE_MEMORY #else #define B0_BASE 0x1b2 #endif #ifdef TEST /* enable some test code */ #define SAVE_MEMORY #define SAVE_MORE_MEMORY #endif /* * Note - this code uses many tricks to save space and fit in one sector. * This includes using side effects of certain instructions, reusing * register values from previous operations, etc. * Be extremely careful when changing the code, even for simple things. */ /* * BOOT BLOCK STRUCTURE * * This code implements a Master Boot Record (MBR) for an Intel/PC disk. * It is 512 bytes long and it is normally loaded by the BIOS (or another * bootloader) at 0:0x7c00. This code depends on %cs:%ip being 0:0x7c00 * * The initial chunk of instructions is used as a signature by external * tools (e.g. boot0cfg) which can manipulate the block itself. * * The area at offset 0x1b2 contains a magic string ('Drive '), also * used as a signature to detect the block, and some variables that can * be updated by boot0cfg (and optionally written back to the disk). * These variables control the operation of the bootloader itself, * e.g. which partitions to enable, the timeout, the use of LBA * (called 'packet') or CHS mode, whether to force a drive number, * and whether to write back the user's selection back to disk. * * As in every Master Boot Record, the partition table is at 0x1be, * made of four 16-byte entries each containing: * * OFF SIZE DESCRIPTION * 0 1 status (0x80: bootable, 0: non bootable) * 1 3 start sector CHS * 8:head, 6:sector, 2:cyl bit 9..8, 8:cyl bit 7..0 * 4 1 partition type * 5 3 end sector CHS * 8 4 LBA of first sector * 12 4 partition size in sectors * * and followed by the two bytes 0x55, 0xAA (MBR signature). */ /* * BOOT BLOCK OPERATION * * On entry, the registers contain the following values: * * %cs:%ip 0:0x7c00 * %dl drive number (0x80, 0x81, ... ) * %si pointer to the partition table from which we were loaded. * Some boot code (e.g. syslinux) use this info to relocate * themselves, so we want to pass a valid one to the next stage. * NOTE: the use of %si is not a standard. * * This boot block first relocates itself at a different address (0:0x600), * to free the space at 0:0x7c00 for the next stage boot block. * * It then initializes some memory at 0:0x800 and above (pointed by %bp) * to store the original drive number (%dl) passed to us, and to construct a * fake partition entry. The latter is used by the disk I/O routine and, * in some cases, passed in %si to the next stage boot code. * * The variables at 0x1b2 are accessed as negative offsets from %bp. * * After the relocation, the code scans the partition table printing * out enabled partition or disks, and waits for user input. * * When a partition is selected, or a timeout expires, the currently * selected partition is used to load the next stage boot code, * %dl and %si are set appropriately as when we were called, and * control is transferred to the newly loaded code at 0:0x7c00. */ /* * CONSTANTS * * NHRDRV is the address in segment 0 where the BIOS writes the * total number of hard disks in the system. * LOAD is the original load address and cannot be changed. * ORIGIN is the relocation address. If you change it, you also need * to change the value passed to the linker in the Makefile * PRT_OFF is the location of the partition table (from the MBR standard). * B0_OFF is the location of the data area, known to boot0cfg so * it cannot be changed. Computed as a negative offset from 0x200 * MAGIC is the signature of a boot block. */ .set NHRDRV,0x475 # Number of hard drives .set ORIGIN,0x600 # Execution address .set LOAD,0x7c00 # Load address .set PRT_OFF,0x1be # Partition table .set B0_OFF,(B0_BASE-0x200) # Offset of boot0 data .set MAGIC,0xaa55 # Magic: bootable .set KEY_ENTER,0x1c # Enter key scan code .set KEY_F1,0x3b # F1 key scan code .set KEY_1,0x02 # #1 key scan code .set ASCII_BEL,'#' # ASCII code for .set ASCII_CR,0x0D # ASCII code for /* * Offsets of variables in the block at B0_OFF, and in the volatile * data area, computed as displacement from %bp. * We need to define them as constant as the assembler cannot * compute them in its single pass. */ .set _NXTDRV, B0_OFF+6 # Next drive .set _OPT, B0_OFF+7 # Default option .set _SETDRV, B0_OFF+8 # Drive to force .set _FLAGS, B0_OFF+9 # Flags .set SETDRV, 0x20 # the 'setdrv' flag .set NOUPDATE, 0x40 # the 'noupdate' flag .set USEPACKET, 0x80 # the 'packet' flag /* ticks is at a fixed position */ .set _TICKS, (PRT_OFF - 0x200 - 2) # Timeout ticks .set _MNUOPT, 0x10 # Saved menu entries .set TLEN, (desc_ofs - bootable_ids) # size of bootable ids .globl start # Entry point .code16 # This runs in real mode /* * MAIN ENTRY POINT * Initialise segments and registers to known values. * segments start at 0. * The stack is immediately below the address we were loaded to. * NOTE: the initial section of the code (up to movw $LOAD,%sp) * is used by boot0cfg, together with the 'Drive ' string and * the 0x55, 0xaa at the end, as an identifier for version 1.0 * of the boot code. Do not change it. * In version 1.0 the parameter table (_NEXTDRV etc) is at 0x1b9 */ start: cld # String ops inc xorw %ax,%ax # Zero movw %ax,%es # Address movw %ax,%ds # data movw %ax,%ss # Set up movw $LOAD,%sp # stack /* * Copy this code to the address it was linked for, 0x600 by default. */ movw %sp,%si # Source movw $start,%di # Destination movw $0x100,%cx # Word count rep # Relocate movsw # code /* * After the code, (i.e. at %di+0, 0x800) create a partition entry, * initialized to LBA 0 / CHS 0:0:1. * Set %bp to point to the partition and also, with negative offsets, * to the variables embedded in the bootblock (nextdrv and so on). */ movw %di,%bp # Address variables movb $0x8,%cl # Words to clear rep # Zero stosw # them incb -0xe(%di) # Set the S field to 1 jmp main-LOAD+ORIGIN # Jump to relocated code main: #if defined(SIO) && COMSPEED != 0 /* * Init the serial port. bioscom preserves the driver number in DX. */ movw $COMSPEED,%ax # defined by Makefile callw bioscom #endif /* * If the 'setdrv' flag is set in the boot sector, use the drive * number from the boot sector at 'setdrv_num'. * Optionally, do the same if the BIOS gives us an invalid number * (note though that the override prevents booting from a floppy * or a ZIP/flash drive in floppy emulation). * The test costs 4 bytes of code so it is disabled by default. */ testb $SETDRV,_FLAGS(%bp) # Set drive number? #ifndef CHECK_DRIVE /* disable drive checks */ jz save_curdrive # no, use the default #else jnz disable_update # Yes testb %dl,%dl # Drive number valid? js save_curdrive # Possibly (0x80 set) #endif /* * Disable updates if the drive number is forced. */ disable_update: orb $NOUPDATE,_FLAGS(%bp) # Disable updates movb _SETDRV(%bp),%dl # Use stored drive number /* * Whatever drive we decided to use, store it at (%bp). The byte * is normally used for the state of the partition (0x80 or 0x00), * but we abuse it as it is very convenient to access at offset 0. * The value is read back after 'check_selection' */ save_curdrive: movb %dl, (%bp) # Save drive number pushw %dx # Also in the stack #ifdef TEST /* test code, print internal bios drive */ rolb $1, %dl movw $drive, %si call putkey #endif callw putn # Print a newline /* * Start out with a pointer to the 4th byte of the first table entry * so that after 4 iterations it's beyond the end of the sector * and beyond a 256 byte boundary. We use the latter trick to check for * end of the loop without using an extra register (see start.5). */ movw $(partbl+0x4),%bx # Partition table (+4) xorw %dx,%dx # Item number /* * Loop around on the partition table, printing values until we * pass a 256 byte boundary. */ read_entry: movb %ch,-0x4(%bx) # Zero active flag (ch == 0) btw %dx,_FLAGS(%bp) # Entry enabled? jnc next_entry # No movb (%bx),%al # Load type test %al, %al # skip empty partition jz next_entry /* * Scan the table of bootable ids, which starts at %di and has * length TLEN. On a match, %di points to the element following the * match; the corresponding offset to the description is $(TLEN-1) * bytes ahead. We use a count of TLEN+1 so if we don't find a match * within the first TLEN entries, we hit the 'unknown' entry. */ movw $bootable_ids,%di # Lookup tables movb $(TLEN+1),%cl # Number of entries repne # Locate scasb # type /* * Get the matching element in the next array. * The byte at $(TLEN-1)(%di) contains the offset of the description * string from %di, so we add the number and print the string. */ addw $(TLEN-1), %di # Adjust movb (%di),%cl # Partition addw %cx,%di # description callw putx # Display it next_entry: incw %dx # Next item addb $0x10,%bl # Next entry jnc read_entry # Till done /* * We are past a 256 byte boundary: the partition table is finished. * Add one to the drive number and check it is valid. * Note that if we started from a floppy, %dl was 0 so we still * get an entry for the next drive, which is the first Hard Disk. */ popw %ax # Drive number subb $0x80-0x1,%al # Does next cmpb NHRDRV,%al # drive exist? (from BIOS?) jb print_drive # Yes /* * If this is the only drive, don't display it as an option. */ decw %ax # Already drive 0? jz print_prompt # Yes /* * If it was illegal or we cycled through them, go back to drive 0. */ xorb %al,%al # Drive 0 /* * Whatever drive we selected, make it an ascii digit and save it * back to the "nxtdrv" location in case we want to save it to disk. * This digit is also part of the printed drive string, so add 0x80 * to indicate end of string. */ print_drive: addb $'0'|0x80,%al # Save next movb %al,_NXTDRV(%bp) # drive number movw $drive,%di # Display callw putx # item /* * Menu is complete, display a prompt followed by current selection. * 'decw %si' makes the register point to the space after 'Boot: ' * so we do not see an extra CRLF on the screen. */ print_prompt: movw $prompt,%si # Display callw putstr # prompt movb _OPT(%bp),%dl # Display decw %si # default callw putkey # key jmp start_input # Skip beep /* * Here we have the code waiting for user input or a timeout. */ beep: movb $ASCII_BEL,%al # Input error, print or beep callw putchr start_input: /* * Actual Start of input loop. Take note of time */ xorb %ah,%ah # BIOS: Get int $0x1a # system time movw %dx,%di # Ticks when addw _TICKS(%bp),%di # timeout read_key: /* * Busy loop, looking for keystrokes but keeping one eye on the time. */ #ifndef SIO movb $0x1,%ah # BIOS: Check int $0x16 # for keypress #else /* SIO */ movb $0x03,%ah # BIOS: Read COM call bioscom testb $0x01,%ah # Check line status # (bit 1 indicates input) #endif /* SIO */ jnz got_key # Have input xorb %ah,%ah # BIOS: int 0x1a, 00 int $0x1a # get system time cmpw %di,%dx # Timeout? jb read_key # No /* * Timed out or default selection */ use_default: movb _OPT(%bp),%al # Load default orb $NOUPDATE,_FLAGS(%bp) # Disable updates jmp check_selection # Join common code /* * Get the keystroke. * ENTER or CR confirm the current selection (same as a timeout). * Otherwise convert F1..F6 (or '1'..'6') to 0..5 and check if the * selection is valid. * The SIO code uses ascii chars, the console code uses scancodes. */ got_key: #ifndef SIO xorb %ah,%ah # BIOS: int 0x16, 00 int $0x16 # get keypress movb %ah,%al # move scan code to %al cmpb $KEY_ENTER,%al #else movb $0x02,%ah # BIOS: Receive call bioscom cmpb $ASCII_CR,%al #endif je use_default # enter -> default /* * Check if the key is acceptable, and loop back if not. * The console (non-SIO) code looks at scancodes and accepts * both F1..F6 and 1..6 (the latter costs 6 bytes of code), * relying on the fact that F1..F6 have higher scancodes than 1..6 * The SIO code only takes 1..6 */ #ifdef SIO /* SIO mode, use ascii values */ subb $'1',%al # Subtract '1' ascii code #else /* console mode -- use scancodes */ subb $KEY_F1,%al /* Subtract F1 scan code */ #if !defined(ONLY_F_KEYS) cmpb $0x5,%al # F1..F6 jna 3f # Yes subb $(KEY_1 - KEY_F1),%al # Less #1 scan code 3: #endif /* ONLY_F_KEYS */ #endif /* SIO */ check_selection: cmpb $0x5,%al # F1..F6 or 1..6 ? #ifdef PXE /* enable PXE/INT18 using F6 */ jne 1f; int $0x18 # found F6, try INT18 1: #endif /* PXE */ jae beep # Not in F1..F5, beep /* * We have a selection. If it's a bad selection go back to complain. * The bits in MNUOPT were set when the options were printed. * Anything not printed is not an option. */ cbtw # Extend (%ah=0 used later) btw %ax,_MNUOPT(%bp) # Option enabled? jnc beep # No /* * Save the info in the original tables * for rewriting to the disk. */ movb %al,_OPT(%bp) # Save option /* * Make %si and %bx point to the fake partition at LBA 0 (CHS 0:0:1). * Because the correct address is already in %bp, just use it. * Set %dl with the drive number saved in byte 0. * If we have pressed F5 or 5, then this is a good, fake value * to present to the next stage boot code. */ movw %bp,%si # Partition for write movb (%si),%dl # Drive number, saved above movw %si,%bx # Partition for read cmpb $0x4,%al # F5/#5 pressed? pushf # Save results for later je 1f # Yes, F5 /* * F1..F4 was pressed, so make %bx point to the currently * selected partition, and leave the drive number unchanged. */ shlb $0x4,%al # Point to addw $partbl,%ax # selected xchgw %bx,%ax # partition movb $0x80,(%bx) # Flag active /* * If not asked to do a write-back (flags 0x40) don't do one. * Around the call, save the partition pointer to %bx and * restore to %si which is where the next stage expects it. */ 1: pushw %bx # Save testb $NOUPDATE,_FLAGS(%bp) # No updates? jnz 2f # skip update movw $start,%bx # Data to write movb $0x3,%ah # Write sector callw intx13 # to disk 2: popw %si # Restore /* * If going to next drive, replace drive with selected one. * Remember to un-ascii it. Hey 0x80 is already set, cool! */ popf # Restore %al test results jne 3f # If not F5/#5 movb _NXTDRV(%bp),%dl # Next drive subb $'0',%dl # number /* * Load selected bootsector to the LOAD location in RAM. If read * fails or there is no 0x55aa marker, treat it as a bad selection. */ 3: movw $LOAD,%bx # Address for read movb $0x2,%ah # Read sector callw intx13 # from disk jc beep # If error cmpw $MAGIC,0x1fe(%bx) # Bootable? jne beep # No pushw %si # Save ptr to selected part. callw putn # Leave some space popw %si # Restore, next stage uses it jmp *%bx # Invoke bootstrap /* * Display routines * putkey prints the option selected in %dl (F1..F5 or 1..5) followed by * the string at %si * putx: print the option in %dl followed by the string at %di * also record the drive as valid. * putn: print a crlf * putstr: print the string at %si * putchr: print the char in al */ /* * Display the option and record the drive as valid in the options. * That last point is done using the btsw instruction which does * a test and set. We don't care for the test part. */ putx: btsw %dx,_MNUOPT(%bp) # Enable menu option movw $item,%si # Display callw putkey # key movw %di,%si # Display the rest callw putstr # Display string putn: movw $crlf,%si # To next line jmp putstr putkey: #ifndef SIO movb $'F',%al # Display callw putchr # 'F' #endif movb $'1',%al # Prepare addb %dl,%al # digit putstr.1: callw putchr # Display char putstr: lodsb # Get byte testb $0x80,%al # End of string? jz putstr.1 # No andb $~0x80,%al # Clear MSB then print last putchr: #ifndef SIO pushw %bx # Save movw $0x7,%bx # Page:attribute movb $0xe,%ah # BIOS: Display int $0x10 # character popw %bx # Restore #else /* SIO */ - movb $0x01,%ah # BIOS: Send + movb $0x01,%ah # BIOS: Send character bioscom: pushw %dx # Save xorw %dx,%dx # Use COM1 - int $0x14 # Character + int $0x14 # BIOS: Serial I/O popw %dx # Restore #endif /* SIO */ retw # To caller /* One-sector disk I/O routine */ /* * %dl: drive, %si partition entry, %es:%bx transfer buffer. * Load the CHS values and possibly the LBA address from the block * at %si, and use the appropriate method to load the sector. * Don't use packet mode for a floppy. */ intx13: # Prepare CHS parameters movb 0x1(%si),%dh # Load head movw 0x2(%si),%cx # Load cylinder:sector movb $0x1,%al # Sector count pushw %si # Save movw %sp,%di # Save #ifndef CHECK_DRIVE /* floppy support */ testb %dl, %dl # is this a floppy ? jz 1f # Yes, use CHS mode #endif testb $USEPACKET,_FLAGS(%bp) # Use packet interface? jz 1f # No pushl $0x0 # Set the pushl 0x8(%si) # LBA address pushw %es # Set the transfer pushw %bx # buffer address push $0x1 # Block count push $0x10 # Packet size movw %sp,%si # Packet pointer decw %ax # Verify off orb $0x40,%ah # Use disk packet 1: int $0x13 # BIOS: Disk I/O movw %di,%sp # Restore popw %si # Restore retw # To caller /* * Various menu strings. 'item' goes after 'prompt' to save space. * Also use shorter versions to make room for the PXE/INT18 code. */ prompt: #ifdef PXE .ascii "\nF6 PXE\r" #endif .ascii "\nBoot:" item: .ascii " "; .byte ' '|0x80 crlf: .ascii "\r"; .byte '\n'|0x80 /* Partition type tables */ bootable_ids: /* * These values indicate bootable types we know about. * Corresponding descriptions are at desc_ofs: * Entries don't need to be sorted. */ .byte 0x83, 0xa5, 0xa6, 0xa9, 0x06, 0x07, 0x0b #ifndef SAVE_MORE_MEMORY .byte 0x05 # extended partition #endif #ifndef SAVE_MEMORY /* other DOS partitions */ .byte 0x01 # FAT12 .byte 0x04 # FAT16 < 32M #endif desc_ofs: /* * Offsets that match the known types above, used to point to the * actual partition name. The last entry must point to os_misc, * which is used for non-matching names. */ .byte os_linux-. # 131, Linux .byte os_freebsd-. # 165, FreeBSD .byte os_bsd-. # 166, OpenBSD .byte os_bsd-. # 169, NetBSD .byte os_dos-. # 6, FAT16 >= 32M .byte os_win-. # 7, NTFS .byte os_win-. # 11, FAT32 #ifndef SAVE_MORE_MEMORY .byte os_ext-. # 5, DOS Ext #endif #ifndef SAVE_MEMORY .byte os_dos-. # 1, FAT12 DOS .byte os_dos-. # 4, FAT16 <32M #endif .byte os_misc-. # Unknown /* * And here are the strings themselves. The last byte of * the string has bit 7 set. */ os_misc: .byte '?'|0x80 os_dos: #ifndef SAVE_MORE_MEMORY /* 'DOS' remapped to 'WIN' if no room */ .ascii "DO"; .byte 'S'|0x80 #endif os_win: .ascii "Wi"; .byte 'n'|0x80 os_linux: .ascii "Linu"; .byte 'x'|0x80 os_freebsd: .ascii "Free" os_bsd: .ascii "BS"; .byte 'D'|0x80 #ifndef SAVE_MORE_MEMORY os_ext: .ascii "EX"; .byte 'T'|0x80 #endif .org (0x200 + B0_OFF),0x90 /* * The boot0 version 1.0 parameter table. * Do not move it nor change the "Drive " string, boot0cfg * uses its offset and content to identify the boot sector. * The other fields are sometimes changed before writing back to the drive * Be especially careful that nxtdrv: must come after drive:, as it * is part of the same string. */ drive: .ascii "Drive " nxtdrv: .byte 0x0 # Next drive number opt: .byte 0x0 # Option setdrv_num: .byte 0x80 # Drive to force flags: .byte FLAGS # Flags #ifdef VOLUME_SERIAL .byte 0xa8,0xa8,0xa8,0xa8 # Volume Serial Number #endif ticks: .word TICKS # Delay .org PRT_OFF /* * Here is the 64 byte partition table that fdisk would fiddle with. */ partbl: .fill 0x40,0x1,0x0 # Partition table .word MAGIC # Magic number .org 0x200 # again, safety check endblock: Index: projects/ci20_mips/sys/boot =================================================================== --- projects/ci20_mips/sys/boot (revision 283030) +++ projects/ci20_mips/sys/boot (revision 283031) Property changes on: projects/ci20_mips/sys/boot ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys/boot:r282931-283030 Index: projects/ci20_mips/sys/dev/acpi_support/acpi_ibm.c =================================================================== --- projects/ci20_mips/sys/dev/acpi_support/acpi_ibm.c (revision 283030) +++ projects/ci20_mips/sys/dev/acpi_support/acpi_ibm.c (revision 283031) @@ -1,1256 +1,1256 @@ /*- * Copyright (c) 2004 Takanori Watanabe * Copyright (c) 2005 Markus Brueffer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Driver for extra ACPI-controlled gadgets found on IBM ThinkPad laptops. * Inspired by the ibm-acpi and tpb projects which implement these features * on Linux. * * acpi-ibm: * tpb: */ #include "opt_acpi.h" #include #include #include #include #include #include #include "acpi_if.h" #include #include #include #include #include #include #include #define _COMPONENT ACPI_OEM ACPI_MODULE_NAME("IBM") /* Internal methods */ #define ACPI_IBM_METHOD_EVENTS 1 #define ACPI_IBM_METHOD_EVENTMASK 2 #define ACPI_IBM_METHOD_HOTKEY 3 #define ACPI_IBM_METHOD_BRIGHTNESS 4 #define ACPI_IBM_METHOD_VOLUME 5 #define ACPI_IBM_METHOD_MUTE 6 #define ACPI_IBM_METHOD_THINKLIGHT 7 #define ACPI_IBM_METHOD_BLUETOOTH 8 #define ACPI_IBM_METHOD_WLAN 9 #define ACPI_IBM_METHOD_FANSPEED 10 #define ACPI_IBM_METHOD_FANLEVEL 11 #define ACPI_IBM_METHOD_FANSTATUS 12 #define ACPI_IBM_METHOD_THERMAL 13 #define ACPI_IBM_METHOD_HANDLEREVENTS 14 /* Hotkeys/Buttons */ #define IBM_RTC_HOTKEY1 0x64 #define IBM_RTC_MASK_HOME (1 << 0) #define IBM_RTC_MASK_SEARCH (1 << 1) #define IBM_RTC_MASK_MAIL (1 << 2) #define IBM_RTC_MASK_WLAN (1 << 5) #define IBM_RTC_HOTKEY2 0x65 #define IBM_RTC_MASK_THINKPAD (1 << 3) #define IBM_RTC_MASK_ZOOM (1 << 5) #define IBM_RTC_MASK_VIDEO (1 << 6) #define IBM_RTC_MASK_HIBERNATE (1 << 7) #define IBM_RTC_THINKLIGHT 0x66 #define IBM_RTC_MASK_THINKLIGHT (1 << 4) #define IBM_RTC_SCREENEXPAND 0x67 #define IBM_RTC_MASK_SCREENEXPAND (1 << 5) #define IBM_RTC_BRIGHTNESS 0x6c #define IBM_RTC_MASK_BRIGHTNESS (1 << 5) #define IBM_RTC_VOLUME 0x6e #define IBM_RTC_MASK_VOLUME (1 << 7) /* Embedded Controller registers */ #define IBM_EC_BRIGHTNESS 0x31 #define IBM_EC_MASK_BRI 0x7 #define IBM_EC_VOLUME 0x30 #define IBM_EC_MASK_VOL 0xf #define IBM_EC_MASK_MUTE (1 << 6) #define IBM_EC_FANSTATUS 0x2F #define IBM_EC_MASK_FANLEVEL 0x3f #define IBM_EC_MASK_FANDISENGAGED (1 << 6) #define IBM_EC_MASK_FANSTATUS (1 << 7) #define IBM_EC_FANSPEED 0x84 /* CMOS Commands */ #define IBM_CMOS_VOLUME_DOWN 0 #define IBM_CMOS_VOLUME_UP 1 #define IBM_CMOS_VOLUME_MUTE 2 #define IBM_CMOS_BRIGHTNESS_UP 4 #define IBM_CMOS_BRIGHTNESS_DOWN 5 /* ACPI methods */ #define IBM_NAME_KEYLIGHT "KBLT" #define IBM_NAME_WLAN_BT_GET "GBDC" #define IBM_NAME_WLAN_BT_SET "SBDC" #define IBM_NAME_MASK_BT (1 << 1) #define IBM_NAME_MASK_WLAN (1 << 2) #define IBM_NAME_THERMAL_GET "TMP7" #define IBM_NAME_THERMAL_UPDT "UPDT" #define IBM_NAME_EVENTS_STATUS_GET "DHKC" #define IBM_NAME_EVENTS_MASK_GET "DHKN" #define IBM_NAME_EVENTS_STATUS_SET "MHKC" #define IBM_NAME_EVENTS_MASK_SET "MHKM" #define IBM_NAME_EVENTS_GET "MHKP" #define IBM_NAME_EVENTS_AVAILMASK "MHKA" /* Event Code */ #define IBM_EVENT_LCD_BACKLIGHT 0x03 #define IBM_EVENT_SUSPEND_TO_RAM 0x04 #define IBM_EVENT_BLUETOOTH 0x05 #define IBM_EVENT_SCREEN_EXPAND 0x07 #define IBM_EVENT_SUSPEND_TO_DISK 0x0c #define IBM_EVENT_BRIGHTNESS_UP 0x10 #define IBM_EVENT_BRIGHTNESS_DOWN 0x11 #define IBM_EVENT_THINKLIGHT 0x12 #define IBM_EVENT_ZOOM 0x14 #define IBM_EVENT_VOLUME_UP 0x15 #define IBM_EVENT_VOLUME_DOWN 0x16 #define IBM_EVENT_MUTE 0x17 #define IBM_EVENT_ACCESS_IBM_BUTTON 0x18 #define ABS(x) (((x) < 0)? -(x) : (x)) struct acpi_ibm_softc { device_t dev; ACPI_HANDLE handle; /* Embedded controller */ device_t ec_dev; ACPI_HANDLE ec_handle; /* CMOS */ ACPI_HANDLE cmos_handle; /* Fan status */ ACPI_HANDLE fan_handle; int fan_levels; /* Keylight commands and states */ ACPI_HANDLE light_handle; int light_cmd_on; int light_cmd_off; int light_val; int light_get_supported; int light_set_supported; /* led(4) interface */ struct cdev *led_dev; int led_busy; int led_state; int wlan_bt_flags; int thermal_updt_supported; unsigned int events_availmask; unsigned int events_initialmask; int events_mask_supported; int events_enable; unsigned int handler_events; struct sysctl_ctx_list *sysctl_ctx; struct sysctl_oid *sysctl_tree; }; static struct { char *name; int method; char *description; int flag_rdonly; } acpi_ibm_sysctls[] = { { .name = "events", .method = ACPI_IBM_METHOD_EVENTS, .description = "ACPI events enable", }, { .name = "eventmask", .method = ACPI_IBM_METHOD_EVENTMASK, .description = "ACPI eventmask", }, { .name = "hotkey", .method = ACPI_IBM_METHOD_HOTKEY, .description = "Key Status", .flag_rdonly = 1 }, { .name = "lcd_brightness", .method = ACPI_IBM_METHOD_BRIGHTNESS, .description = "LCD Brightness", }, { .name = "volume", .method = ACPI_IBM_METHOD_VOLUME, .description = "Volume", }, { .name = "mute", .method = ACPI_IBM_METHOD_MUTE, .description = "Mute", }, { .name = "thinklight", .method = ACPI_IBM_METHOD_THINKLIGHT, .description = "Thinklight enable", }, { .name = "bluetooth", .method = ACPI_IBM_METHOD_BLUETOOTH, .description = "Bluetooth enable", }, { .name = "wlan", .method = ACPI_IBM_METHOD_WLAN, .description = "WLAN enable", .flag_rdonly = 1 }, { .name = "fan_speed", .method = ACPI_IBM_METHOD_FANSPEED, .description = "Fan speed", .flag_rdonly = 1 }, { .name = "fan_level", .method = ACPI_IBM_METHOD_FANLEVEL, .description = "Fan level", }, { .name = "fan", .method = ACPI_IBM_METHOD_FANSTATUS, .description = "Fan enable", }, { NULL, 0, NULL, 0 } }; ACPI_SERIAL_DECL(ibm, "ACPI IBM extras"); static int acpi_ibm_probe(device_t dev); static int acpi_ibm_attach(device_t dev); static int acpi_ibm_detach(device_t dev); static int acpi_ibm_resume(device_t dev); static void ibm_led(void *softc, int onoff); static void ibm_led_task(struct acpi_ibm_softc *sc, int pending __unused); static int acpi_ibm_sysctl(SYSCTL_HANDLER_ARGS); static int acpi_ibm_sysctl_init(struct acpi_ibm_softc *sc, int method); static int acpi_ibm_sysctl_get(struct acpi_ibm_softc *sc, int method); static int acpi_ibm_sysctl_set(struct acpi_ibm_softc *sc, int method, int val); static int acpi_ibm_eventmask_set(struct acpi_ibm_softc *sc, int val); static int acpi_ibm_thermal_sysctl(SYSCTL_HANDLER_ARGS); static int acpi_ibm_handlerevents_sysctl(SYSCTL_HANDLER_ARGS); static void acpi_ibm_notify(ACPI_HANDLE h, UINT32 notify, void *context); static int acpi_ibm_brightness_set(struct acpi_ibm_softc *sc, int arg); static int acpi_ibm_bluetooth_set(struct acpi_ibm_softc *sc, int arg); static int acpi_ibm_thinklight_set(struct acpi_ibm_softc *sc, int arg); static int acpi_ibm_volume_set(struct acpi_ibm_softc *sc, int arg); static int acpi_ibm_mute_set(struct acpi_ibm_softc *sc, int arg); static device_method_t acpi_ibm_methods[] = { /* Device interface */ DEVMETHOD(device_probe, acpi_ibm_probe), DEVMETHOD(device_attach, acpi_ibm_attach), DEVMETHOD(device_detach, acpi_ibm_detach), DEVMETHOD(device_resume, acpi_ibm_resume), DEVMETHOD_END }; static driver_t acpi_ibm_driver = { "acpi_ibm", acpi_ibm_methods, sizeof(struct acpi_ibm_softc), }; static devclass_t acpi_ibm_devclass; DRIVER_MODULE(acpi_ibm, acpi, acpi_ibm_driver, acpi_ibm_devclass, 0, 0); MODULE_DEPEND(acpi_ibm, acpi, 1, 1, 1); static char *ibm_ids[] = {"IBM0068", "LEN0068", NULL}; static void ibm_led(void *softc, int onoff) { struct acpi_ibm_softc* sc = (struct acpi_ibm_softc*) softc; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); if (sc->led_busy) return; sc->led_busy = 1; sc->led_state = onoff; AcpiOsExecute(OSL_NOTIFY_HANDLER, (void *)ibm_led_task, sc); } static void ibm_led_task(struct acpi_ibm_softc *sc, int pending __unused) { ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); ACPI_SERIAL_BEGIN(ibm); acpi_ibm_sysctl_set(sc, ACPI_IBM_METHOD_THINKLIGHT, sc->led_state); ACPI_SERIAL_END(ibm); sc->led_busy = 0; } static int acpi_ibm_probe(device_t dev) { if (acpi_disabled("ibm") || ACPI_ID_PROBE(device_get_parent(dev), dev, ibm_ids) == NULL || device_get_unit(dev) != 0) return (ENXIO); device_set_desc(dev, "IBM ThinkPad ACPI Extras"); return (0); } static int acpi_ibm_attach(device_t dev) { struct acpi_ibm_softc *sc; devclass_t ec_devclass; ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); sc = device_get_softc(dev); sc->dev = dev; sc->handle = acpi_get_handle(dev); /* Look for the first embedded controller */ if (!(ec_devclass = devclass_find ("acpi_ec"))) { if (bootverbose) device_printf(dev, "Couldn't find acpi_ec devclass\n"); return (EINVAL); } if (!(sc->ec_dev = devclass_get_device(ec_devclass, 0))) { if (bootverbose) device_printf(dev, "Couldn't find acpi_ec device\n"); return (EINVAL); } sc->ec_handle = acpi_get_handle(sc->ec_dev); /* Get the sysctl tree */ sc->sysctl_ctx = device_get_sysctl_ctx(dev); sc->sysctl_tree = device_get_sysctl_tree(dev); /* Look for event mask and hook up the nodes */ sc->events_mask_supported = ACPI_SUCCESS(acpi_GetInteger(sc->handle, IBM_NAME_EVENTS_MASK_GET, &sc->events_initialmask)); if (sc->events_mask_supported) { SYSCTL_ADD_UINT(sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "initialmask", CTLFLAG_RD, &sc->events_initialmask, 0, "Initial eventmask"); /* The availmask is the bitmask of supported events */ if (ACPI_FAILURE(acpi_GetInteger(sc->handle, IBM_NAME_EVENTS_AVAILMASK, &sc->events_availmask))) sc->events_availmask = 0xffffffff; SYSCTL_ADD_UINT(sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "availmask", CTLFLAG_RD, &sc->events_availmask, 0, "Mask of supported events"); } /* Hook up proc nodes */ for (int i = 0; acpi_ibm_sysctls[i].name != NULL; i++) { if (!acpi_ibm_sysctl_init(sc, acpi_ibm_sysctls[i].method)) continue; if (acpi_ibm_sysctls[i].flag_rdonly != 0) { SYSCTL_ADD_PROC(sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, acpi_ibm_sysctls[i].name, CTLTYPE_INT | CTLFLAG_RD, sc, i, acpi_ibm_sysctl, "I", acpi_ibm_sysctls[i].description); } else { SYSCTL_ADD_PROC(sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, acpi_ibm_sysctls[i].name, CTLTYPE_INT | CTLFLAG_RW, sc, i, acpi_ibm_sysctl, "I", acpi_ibm_sysctls[i].description); } } /* Hook up thermal node */ if (acpi_ibm_sysctl_init(sc, ACPI_IBM_METHOD_THERMAL)) { SYSCTL_ADD_PROC(sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "thermal", CTLTYPE_INT | CTLFLAG_RD, sc, 0, acpi_ibm_thermal_sysctl, "I", "Thermal zones"); } /* Hook up handlerevents node */ if (acpi_ibm_sysctl_init(sc, ACPI_IBM_METHOD_HANDLEREVENTS)) { SYSCTL_ADD_PROC(sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "handlerevents", CTLTYPE_STRING | CTLFLAG_RW, sc, 0, acpi_ibm_handlerevents_sysctl, "I", "devd(8) events handled by acpi_ibm"); } /* Handle notifies */ AcpiInstallNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, acpi_ibm_notify, dev); /* Hook up light to led(4) */ if (sc->light_set_supported) sc->led_dev = led_create_state(ibm_led, sc, "thinklight", sc->light_val); return (0); } static int acpi_ibm_detach(device_t dev) { ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); struct acpi_ibm_softc *sc = device_get_softc(dev); /* Disable events and restore eventmask */ ACPI_SERIAL_BEGIN(ibm); acpi_ibm_sysctl_set(sc, ACPI_IBM_METHOD_EVENTS, 0); acpi_ibm_sysctl_set(sc, ACPI_IBM_METHOD_EVENTMASK, sc->events_initialmask); ACPI_SERIAL_END(ibm); AcpiRemoveNotifyHandler(sc->handle, ACPI_DEVICE_NOTIFY, acpi_ibm_notify); if (sc->led_dev != NULL) led_destroy(sc->led_dev); return (0); } static int acpi_ibm_resume(device_t dev) { struct acpi_ibm_softc *sc = device_get_softc(dev); ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); ACPI_SERIAL_BEGIN(ibm); for (int i = 0; acpi_ibm_sysctls[i].name != NULL; i++) { int val; val = acpi_ibm_sysctl_get(sc, i); if (acpi_ibm_sysctls[i].flag_rdonly != 0) continue; acpi_ibm_sysctl_set(sc, i, val); } ACPI_SERIAL_END(ibm); return (0); } static int acpi_ibm_eventmask_set(struct acpi_ibm_softc *sc, int val) { ACPI_OBJECT arg[2]; ACPI_OBJECT_LIST args; ACPI_STATUS status; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); ACPI_SERIAL_ASSERT(ibm); args.Count = 2; args.Pointer = arg; arg[0].Type = ACPI_TYPE_INTEGER; arg[1].Type = ACPI_TYPE_INTEGER; for (int i = 0; i < 32; ++i) { arg[0].Integer.Value = i+1; arg[1].Integer.Value = (((1 << i) & val) != 0); status = AcpiEvaluateObject(sc->handle, IBM_NAME_EVENTS_MASK_SET, &args, NULL); if (ACPI_FAILURE(status)) return (status); } return (0); } static int acpi_ibm_sysctl(SYSCTL_HANDLER_ARGS) { struct acpi_ibm_softc *sc; int arg; int error = 0; int function; int method; - + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); sc = (struct acpi_ibm_softc *)oidp->oid_arg1; function = oidp->oid_arg2; method = acpi_ibm_sysctls[function].method; ACPI_SERIAL_BEGIN(ibm); arg = acpi_ibm_sysctl_get(sc, method); error = sysctl_handle_int(oidp, &arg, 0, req); /* Sanity check */ if (error != 0 || req->newptr == NULL) goto out; /* Update */ error = acpi_ibm_sysctl_set(sc, method, arg); out: ACPI_SERIAL_END(ibm); return (error); } static int acpi_ibm_sysctl_get(struct acpi_ibm_softc *sc, int method) { UINT64 val_ec; int val = 0, key; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); ACPI_SERIAL_ASSERT(ibm); switch (method) { case ACPI_IBM_METHOD_EVENTS: acpi_GetInteger(sc->handle, IBM_NAME_EVENTS_STATUS_GET, &val); break; case ACPI_IBM_METHOD_EVENTMASK: if (sc->events_mask_supported) acpi_GetInteger(sc->handle, IBM_NAME_EVENTS_MASK_GET, &val); break; case ACPI_IBM_METHOD_HOTKEY: /* * Construct the hotkey as a bitmask as illustrated below. * Note that whenever a key was pressed, the respecting bit * toggles and nothing else changes. * +--+--+-+-+-+-+-+-+-+-+-+-+ * |11|10|9|8|7|6|5|4|3|2|1|0| * +--+--+-+-+-+-+-+-+-+-+-+-+ * | | | | | | | | | | | | * | | | | | | | | | | | +- Home Button * | | | | | | | | | | +--- Search Button * | | | | | | | | | +----- Mail Button * | | | | | | | | +------- Thinkpad Button * | | | | | | | +--------- Zoom (Fn + Space) * | | | | | | +----------- WLAN Button * | | | | | +------------- Video Button * | | | | +--------------- Hibernate Button * | | | +----------------- Thinklight Button * | | +------------------- Screen expand (Fn + F8) * | +--------------------- Brightness * +------------------------ Volume/Mute */ key = rtcin(IBM_RTC_HOTKEY1); val = (IBM_RTC_MASK_HOME | IBM_RTC_MASK_SEARCH | IBM_RTC_MASK_MAIL | IBM_RTC_MASK_WLAN) & key; key = rtcin(IBM_RTC_HOTKEY2); val |= (IBM_RTC_MASK_THINKPAD | IBM_RTC_MASK_VIDEO | IBM_RTC_MASK_HIBERNATE) & key; val |= (IBM_RTC_MASK_ZOOM & key) >> 1; key = rtcin(IBM_RTC_THINKLIGHT); val |= (IBM_RTC_MASK_THINKLIGHT & key) << 4; key = rtcin(IBM_RTC_SCREENEXPAND); val |= (IBM_RTC_MASK_THINKLIGHT & key) << 4; key = rtcin(IBM_RTC_BRIGHTNESS); val |= (IBM_RTC_MASK_BRIGHTNESS & key) << 5; key = rtcin(IBM_RTC_VOLUME); val |= (IBM_RTC_MASK_VOLUME & key) << 4; break; case ACPI_IBM_METHOD_BRIGHTNESS: ACPI_EC_READ(sc->ec_dev, IBM_EC_BRIGHTNESS, &val_ec, 1); val = val_ec & IBM_EC_MASK_BRI; break; case ACPI_IBM_METHOD_VOLUME: ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1); val = val_ec & IBM_EC_MASK_VOL; break; case ACPI_IBM_METHOD_MUTE: ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1); val = ((val_ec & IBM_EC_MASK_MUTE) == IBM_EC_MASK_MUTE); break; case ACPI_IBM_METHOD_THINKLIGHT: if (sc->light_get_supported) acpi_GetInteger(sc->ec_handle, IBM_NAME_KEYLIGHT, &val); else val = sc->light_val; break; case ACPI_IBM_METHOD_BLUETOOTH: acpi_GetInteger(sc->handle, IBM_NAME_WLAN_BT_GET, &val); sc->wlan_bt_flags = val; val = ((val & IBM_NAME_MASK_BT) != 0); break; case ACPI_IBM_METHOD_WLAN: acpi_GetInteger(sc->handle, IBM_NAME_WLAN_BT_GET, &val); sc->wlan_bt_flags = val; val = ((val & IBM_NAME_MASK_WLAN) != 0); break; case ACPI_IBM_METHOD_FANSPEED: if (sc->fan_handle) { if(ACPI_FAILURE(acpi_GetInteger(sc->fan_handle, NULL, &val))) val = -1; } else { ACPI_EC_READ(sc->ec_dev, IBM_EC_FANSPEED, &val_ec, 2); val = val_ec; } break; case ACPI_IBM_METHOD_FANLEVEL: /* * The IBM_EC_FANSTATUS register works as follows: * Bit 0-5 indicate the level at which the fan operates. Only * values between 0 and 7 have an effect. Everything * above 7 is treated the same as level 7 * Bit 6 overrides the fan speed limit if set to 1 * Bit 7 indicates at which mode the fan operates: * manual (0) or automatic (1) */ if (!sc->fan_handle) { ACPI_EC_READ(sc->ec_dev, IBM_EC_FANSTATUS, &val_ec, 1); val = val_ec & IBM_EC_MASK_FANLEVEL; } break; case ACPI_IBM_METHOD_FANSTATUS: if (!sc->fan_handle) { ACPI_EC_READ(sc->ec_dev, IBM_EC_FANSTATUS, &val_ec, 1); val = (val_ec & IBM_EC_MASK_FANSTATUS) == IBM_EC_MASK_FANSTATUS; } else val = -1; break; } return (val); } static int acpi_ibm_sysctl_set(struct acpi_ibm_softc *sc, int method, int arg) { int val; UINT64 val_ec; ACPI_STATUS status; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); ACPI_SERIAL_ASSERT(ibm); switch (method) { case ACPI_IBM_METHOD_EVENTS: if (arg < 0 || arg > 1) return (EINVAL); status = acpi_SetInteger(sc->handle, IBM_NAME_EVENTS_STATUS_SET, arg); if (ACPI_FAILURE(status)) return (status); if (sc->events_mask_supported) return acpi_ibm_eventmask_set(sc, sc->events_availmask); break; case ACPI_IBM_METHOD_EVENTMASK: if (sc->events_mask_supported) return acpi_ibm_eventmask_set(sc, arg); break; case ACPI_IBM_METHOD_BRIGHTNESS: return acpi_ibm_brightness_set(sc, arg); break; case ACPI_IBM_METHOD_VOLUME: return acpi_ibm_volume_set(sc, arg); break; case ACPI_IBM_METHOD_MUTE: return acpi_ibm_mute_set(sc, arg); break; case ACPI_IBM_METHOD_THINKLIGHT: return acpi_ibm_thinklight_set(sc, arg); break; case ACPI_IBM_METHOD_BLUETOOTH: return acpi_ibm_bluetooth_set(sc, arg); break; case ACPI_IBM_METHOD_FANLEVEL: if (arg < 0 || arg > 7) return (EINVAL); if (!sc->fan_handle) { /* Read the current fanstatus */ ACPI_EC_READ(sc->ec_dev, IBM_EC_FANSTATUS, &val_ec, 1); val = val_ec & (~IBM_EC_MASK_FANLEVEL); return ACPI_EC_WRITE(sc->ec_dev, IBM_EC_FANSTATUS, val | arg, 1); } break; case ACPI_IBM_METHOD_FANSTATUS: if (arg < 0 || arg > 1) return (EINVAL); if (!sc->fan_handle) { /* Read the current fanstatus */ ACPI_EC_READ(sc->ec_dev, IBM_EC_FANSTATUS, &val_ec, 1); return ACPI_EC_WRITE(sc->ec_dev, IBM_EC_FANSTATUS, (arg == 1) ? (val_ec | IBM_EC_MASK_FANSTATUS) : (val_ec & (~IBM_EC_MASK_FANSTATUS)), 1); } break; } return (0); } static int acpi_ibm_sysctl_init(struct acpi_ibm_softc *sc, int method) { int dummy; ACPI_OBJECT_TYPE cmos_t; ACPI_HANDLE ledb_handle; switch (method) { case ACPI_IBM_METHOD_EVENTS: /* Events are disabled by default */ return (TRUE); case ACPI_IBM_METHOD_EVENTMASK: return (sc->events_mask_supported); case ACPI_IBM_METHOD_HOTKEY: case ACPI_IBM_METHOD_BRIGHTNESS: case ACPI_IBM_METHOD_VOLUME: case ACPI_IBM_METHOD_MUTE: /* EC is required here, which was aready checked before */ return (TRUE); case ACPI_IBM_METHOD_THINKLIGHT: sc->cmos_handle = NULL; sc->light_get_supported = ACPI_SUCCESS(acpi_GetInteger( sc->ec_handle, IBM_NAME_KEYLIGHT, &sc->light_val)); if ((ACPI_SUCCESS(AcpiGetHandle(sc->handle, "\\UCMS", &sc->light_handle)) || ACPI_SUCCESS(AcpiGetHandle(sc->handle, "\\CMOS", &sc->light_handle)) || ACPI_SUCCESS(AcpiGetHandle(sc->handle, "\\CMS", &sc->light_handle))) && ACPI_SUCCESS(AcpiGetType(sc->light_handle, &cmos_t)) && cmos_t == ACPI_TYPE_METHOD) { sc->light_cmd_on = 0x0c; sc->light_cmd_off = 0x0d; sc->cmos_handle = sc->light_handle; } else if (ACPI_SUCCESS(AcpiGetHandle(sc->handle, "\\LGHT", &sc->light_handle))) { sc->light_cmd_on = 1; sc->light_cmd_off = 0; } else sc->light_handle = NULL; sc->light_set_supported = (sc->light_handle && ACPI_FAILURE(AcpiGetHandle(sc->ec_handle, "LEDB", &ledb_handle))); if (sc->light_get_supported) return (TRUE); if (sc->light_set_supported) { sc->light_val = 0; return (TRUE); } return (FALSE); case ACPI_IBM_METHOD_BLUETOOTH: case ACPI_IBM_METHOD_WLAN: if (ACPI_SUCCESS(acpi_GetInteger(sc->handle, IBM_NAME_WLAN_BT_GET, &dummy))) return (TRUE); return (FALSE); case ACPI_IBM_METHOD_FANSPEED: - /* + /* * Some models report the fan speed in levels from 0-7 * Newer models report it contiguously */ sc->fan_levels = (ACPI_SUCCESS(AcpiGetHandle(sc->handle, "GFAN", &sc->fan_handle)) || ACPI_SUCCESS(AcpiGetHandle(sc->handle, "\\FSPD", &sc->fan_handle))); return (TRUE); case ACPI_IBM_METHOD_FANLEVEL: case ACPI_IBM_METHOD_FANSTATUS: - /* + /* * Fan status is only supported on those models, * which report fan RPM contiguously, not in levels */ if (sc->fan_levels) return (FALSE); return (TRUE); case ACPI_IBM_METHOD_THERMAL: if (ACPI_SUCCESS(acpi_GetInteger(sc->ec_handle, IBM_NAME_THERMAL_GET, &dummy))) { sc->thermal_updt_supported = ACPI_SUCCESS(acpi_GetInteger(sc->ec_handle, IBM_NAME_THERMAL_UPDT, &dummy)); return (TRUE); } return (FALSE); case ACPI_IBM_METHOD_HANDLEREVENTS: return (TRUE); } return (FALSE); } static int acpi_ibm_thermal_sysctl(SYSCTL_HANDLER_ARGS) { struct acpi_ibm_softc *sc; int error = 0; char temp_cmd[] = "TMP0"; int temp[8]; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); sc = (struct acpi_ibm_softc *)oidp->oid_arg1; ACPI_SERIAL_BEGIN(ibm); for (int i = 0; i < 8; ++i) { temp_cmd[3] = '0' + i; - - /* + + /* * The TMPx methods seem to return +/- 128 or 0 - * when the respecting sensor is not available + * when the respecting sensor is not available */ if (ACPI_FAILURE(acpi_GetInteger(sc->ec_handle, temp_cmd, &temp[i])) || ABS(temp[i]) == 128 || temp[i] == 0) temp[i] = -1; else if (sc->thermal_updt_supported) /* Temperature is reported in tenth of Kelvin */ temp[i] = (temp[i] - 2732 + 5) / 10; } error = sysctl_handle_opaque(oidp, &temp, 8*sizeof(int), req); ACPI_SERIAL_END(ibm); return (error); } static int acpi_ibm_handlerevents_sysctl(SYSCTL_HANDLER_ARGS) { struct acpi_ibm_softc *sc; int error = 0; struct sbuf sb; char *cp, *ep; int l, val; unsigned int handler_events; char temp[128]; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); sc = (struct acpi_ibm_softc *)oidp->oid_arg1; if (sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND) == NULL) return (ENOMEM); ACPI_SERIAL_BEGIN(ibm); /* Get old values if this is a get request. */ if (req->newptr == NULL) { for (int i = 0; i < 8 * sizeof(sc->handler_events); i++) if (sc->handler_events & (1 << i)) sbuf_printf(&sb, "0x%02x ", i + 1); if (sbuf_len(&sb) == 0) sbuf_printf(&sb, "NONE"); } sbuf_trim(&sb); sbuf_finish(&sb); strlcpy(temp, sbuf_data(&sb), sizeof(temp)); sbuf_delete(&sb); error = sysctl_handle_string(oidp, temp, sizeof(temp), req); /* Check for error or no change */ if (error != 0 || req->newptr == NULL) goto out; /* If the user is setting a string, parse it. */ handler_events = 0; cp = temp; while (*cp) { if (isspace(*cp)) { cp++; continue; } ep = cp; while (*ep && !isspace(*ep)) ep++; l = ep - cp; if (l == 0) break; if (strncmp(cp, "NONE", 4) == 0) { cp = ep; continue; } if (l >= 3 && cp[0] == '0' && (cp[1] == 'X' || cp[1] == 'x')) val = strtoul(cp, &ep, 16); else val = strtoul(cp, &ep, 10); if (val == 0 || ep == cp || val >= 8 * sizeof(handler_events)) { cp[l] = '\0'; device_printf(sc->dev, "invalid event code: %s\n", cp); error = EINVAL; goto out; } handler_events |= 1 << (val - 1); cp = ep; } sc->handler_events = handler_events; out: ACPI_SERIAL_END(ibm); return (error); } static int acpi_ibm_brightness_set(struct acpi_ibm_softc *sc, int arg) { int val, step; UINT64 val_ec; ACPI_OBJECT Arg; ACPI_OBJECT_LIST Args; ACPI_STATUS status; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); ACPI_SERIAL_ASSERT(ibm); if (arg < 0 || arg > 7) return (EINVAL); /* Read the current brightness */ status = ACPI_EC_READ(sc->ec_dev, IBM_EC_BRIGHTNESS, &val_ec, 1); if (ACPI_FAILURE(status)) return (status); if (sc->cmos_handle) { val = val_ec & IBM_EC_MASK_BRI; Args.Count = 1; Args.Pointer = &Arg; Arg.Type = ACPI_TYPE_INTEGER; Arg.Integer.Value = (arg > val) ? IBM_CMOS_BRIGHTNESS_UP : IBM_CMOS_BRIGHTNESS_DOWN; step = (arg > val) ? 1 : -1; for (int i = val; i != arg; i += step) { status = AcpiEvaluateObject(sc->cmos_handle, NULL, &Args, NULL); if (ACPI_FAILURE(status)) { /* Record the last value */ if (i != val) { ACPI_EC_WRITE(sc->ec_dev, IBM_EC_BRIGHTNESS, i - step, 1); } return (status); } } } return ACPI_EC_WRITE(sc->ec_dev, IBM_EC_BRIGHTNESS, arg, 1); } static int acpi_ibm_bluetooth_set(struct acpi_ibm_softc *sc, int arg) { int val; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); ACPI_SERIAL_ASSERT(ibm); if (arg < 0 || arg > 1) return (EINVAL); val = (arg == 1) ? sc->wlan_bt_flags | IBM_NAME_MASK_BT : sc->wlan_bt_flags & (~IBM_NAME_MASK_BT); return acpi_SetInteger(sc->handle, IBM_NAME_WLAN_BT_SET, val); } static int acpi_ibm_thinklight_set(struct acpi_ibm_softc *sc, int arg) { ACPI_OBJECT Arg; ACPI_OBJECT_LIST Args; ACPI_STATUS status; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); ACPI_SERIAL_ASSERT(ibm); if (arg < 0 || arg > 1) return (EINVAL); if (sc->light_set_supported) { Args.Count = 1; Args.Pointer = &Arg; Arg.Type = ACPI_TYPE_INTEGER; Arg.Integer.Value = arg ? sc->light_cmd_on : sc->light_cmd_off; status = AcpiEvaluateObject(sc->light_handle, NULL, &Args, NULL); if (ACPI_SUCCESS(status)) sc->light_val = arg; return (status); } return (0); } static int acpi_ibm_volume_set(struct acpi_ibm_softc *sc, int arg) { int val, step; UINT64 val_ec; ACPI_OBJECT Arg; ACPI_OBJECT_LIST Args; ACPI_STATUS status; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); ACPI_SERIAL_ASSERT(ibm); if (arg < 0 || arg > 14) return (EINVAL); /* Read the current volume */ status = ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1); if (ACPI_FAILURE(status)) return (status); if (sc->cmos_handle) { val = val_ec & IBM_EC_MASK_VOL; Args.Count = 1; Args.Pointer = &Arg; Arg.Type = ACPI_TYPE_INTEGER; Arg.Integer.Value = (arg > val) ? IBM_CMOS_VOLUME_UP : IBM_CMOS_VOLUME_DOWN; step = (arg > val) ? 1 : -1; for (int i = val; i != arg; i += step) { status = AcpiEvaluateObject(sc->cmos_handle, NULL, &Args, NULL); if (ACPI_FAILURE(status)) { /* Record the last value */ if (i != val) { val_ec = i - step + (val_ec & (~IBM_EC_MASK_VOL)); ACPI_EC_WRITE(sc->ec_dev, IBM_EC_VOLUME, val_ec, 1); } return (status); } } } val_ec = arg + (val_ec & (~IBM_EC_MASK_VOL)); return ACPI_EC_WRITE(sc->ec_dev, IBM_EC_VOLUME, val_ec, 1); } static int acpi_ibm_mute_set(struct acpi_ibm_softc *sc, int arg) { UINT64 val_ec; ACPI_OBJECT Arg; ACPI_OBJECT_LIST Args; ACPI_STATUS status; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); ACPI_SERIAL_ASSERT(ibm); if (arg < 0 || arg > 1) return (EINVAL); status = ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1); if (ACPI_FAILURE(status)) return (status); if (sc->cmos_handle) { Args.Count = 1; Args.Pointer = &Arg; Arg.Type = ACPI_TYPE_INTEGER; Arg.Integer.Value = IBM_CMOS_VOLUME_MUTE; status = AcpiEvaluateObject(sc->cmos_handle, NULL, &Args, NULL); if (ACPI_FAILURE(status)) return (status); } val_ec = (arg == 1) ? val_ec | IBM_EC_MASK_MUTE : val_ec & (~IBM_EC_MASK_MUTE); return ACPI_EC_WRITE(sc->ec_dev, IBM_EC_VOLUME, val_ec, 1); } static void acpi_ibm_eventhandler(struct acpi_ibm_softc *sc, int arg) { int val; UINT64 val_ec; ACPI_STATUS status; ACPI_SERIAL_BEGIN(ibm); switch (arg) { case IBM_EVENT_SUSPEND_TO_RAM: power_pm_suspend(POWER_SLEEP_STATE_SUSPEND); break; case IBM_EVENT_BLUETOOTH: acpi_ibm_bluetooth_set(sc, (sc->wlan_bt_flags == 0)); break; case IBM_EVENT_BRIGHTNESS_UP: case IBM_EVENT_BRIGHTNESS_DOWN: /* Read the current brightness */ status = ACPI_EC_READ(sc->ec_dev, IBM_EC_BRIGHTNESS, &val_ec, 1); if (ACPI_FAILURE(status)) return; val = val_ec & IBM_EC_MASK_BRI; val = (arg == IBM_EVENT_BRIGHTNESS_UP) ? val + 1 : val - 1; acpi_ibm_brightness_set(sc, val); break; case IBM_EVENT_THINKLIGHT: acpi_ibm_thinklight_set(sc, (sc->light_val == 0)); break; case IBM_EVENT_VOLUME_UP: case IBM_EVENT_VOLUME_DOWN: /* Read the current volume */ status = ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1); if (ACPI_FAILURE(status)) return; val = val_ec & IBM_EC_MASK_VOL; val = (arg == IBM_EVENT_VOLUME_UP) ? val + 1 : val - 1; acpi_ibm_volume_set(sc, val); break; case IBM_EVENT_MUTE: /* Read the current value */ status = ACPI_EC_READ(sc->ec_dev, IBM_EC_VOLUME, &val_ec, 1); if (ACPI_FAILURE(status)) return; val = ((val_ec & IBM_EC_MASK_MUTE) == IBM_EC_MASK_MUTE); acpi_ibm_mute_set(sc, (val == 0)); break; default: break; } ACPI_SERIAL_END(ibm); } static void acpi_ibm_notify(ACPI_HANDLE h, UINT32 notify, void *context) { int event, arg, type; device_t dev = context; struct acpi_ibm_softc *sc = device_get_softc(dev); ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); if (notify != 0x80) device_printf(dev, "Unknown notify\n"); for (;;) { acpi_GetInteger(acpi_get_handle(dev), IBM_NAME_EVENTS_GET, &event); if (event == 0) break; type = (event >> 12) & 0xf; arg = event & 0xfff; switch (type) { case 1: if (!(sc->events_availmask & (1 << (arg - 1)))) { device_printf(dev, "Unknown key %d\n", arg); break; } /* Execute event handler */ if (sc->handler_events & (1 << (arg - 1))) acpi_ibm_eventhandler(sc, (arg & 0xff)); /* Notify devd(8) */ acpi_UserNotify("IBM", h, (arg & 0xff)); break; default: break; } } } Index: projects/ci20_mips/sys/dev/fdt/simplebus.c =================================================================== --- projects/ci20_mips/sys/dev/fdt/simplebus.c (revision 283030) +++ projects/ci20_mips/sys/dev/fdt/simplebus.c (revision 283031) @@ -1,423 +1,423 @@ /*- * Copyright (c) 2013 Nathan Whitehorn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include /* * Bus interface. */ static int simplebus_probe(device_t dev); static int simplebus_attach(device_t dev); static struct resource *simplebus_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); static void simplebus_probe_nomatch(device_t bus, device_t child); static int simplebus_print_child(device_t bus, device_t child); static device_t simplebus_add_child(device_t dev, u_int order, const char *name, int unit); static struct resource_list *simplebus_get_resource_list(device_t bus, device_t child); /* * ofw_bus interface */ static const struct ofw_bus_devinfo *simplebus_get_devinfo(device_t bus, device_t child); /* * local methods */ static int simplebus_fill_ranges(phandle_t node, struct simplebus_softc *sc); /* * Driver methods. */ static device_method_t simplebus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, simplebus_probe), DEVMETHOD(device_attach, simplebus_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_add_child, simplebus_add_child), DEVMETHOD(bus_print_child, simplebus_print_child), DEVMETHOD(bus_probe_nomatch, simplebus_probe_nomatch), DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_alloc_resource, simplebus_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), DEVMETHOD(bus_get_resource_list, simplebus_get_resource_list), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, simplebus_get_devinfo), DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), DEVMETHOD_END }; DEFINE_CLASS_0(simplebus, simplebus_driver, simplebus_methods, sizeof(struct simplebus_softc)); static devclass_t simplebus_devclass; EARLY_DRIVER_MODULE(simplebus, ofwbus, simplebus_driver, simplebus_devclass, 0, 0, BUS_PASS_BUS); EARLY_DRIVER_MODULE(simplebus, simplebus, simplebus_driver, simplebus_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); static int simplebus_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); /* * FDT data puts a "simple-bus" compatible string on many things that * have children but aren't really busses in our world. Without a * ranges property we will fail to attach, so just fail to probe too. */ if (!(ofw_bus_is_compatible(dev, "simple-bus") && ofw_bus_has_prop(dev, "ranges")) && (ofw_bus_get_type(dev) == NULL || strcmp(ofw_bus_get_type(dev), "soc") != 0)) return (ENXIO); device_set_desc(dev, "Flattened device tree simple bus"); return (BUS_PROBE_GENERIC); } static int simplebus_attach(device_t dev) { struct simplebus_softc *sc; phandle_t node; sc = device_get_softc(dev); simplebus_init(dev, 0); if (simplebus_fill_ranges(sc->node, sc) < 0) { device_printf(dev, "could not get ranges\n"); return (ENXIO); } /* * In principle, simplebus could have an interrupt map, but ignore that * for now */ for (node = OF_child(sc->node); node > 0; node = OF_peer(node)) simplebus_add_device(dev, node, 0, NULL, -1, NULL); return (bus_generic_attach(dev)); } void simplebus_init(device_t dev, phandle_t node) { struct simplebus_softc *sc; sc = device_get_softc(dev); if (node == 0) node = ofw_bus_get_node(dev); sc->dev = dev; sc->node = node; /* * Some important numbers */ sc->acells = 2; OF_getencprop(node, "#address-cells", &sc->acells, sizeof(sc->acells)); sc->scells = 1; OF_getencprop(node, "#size-cells", &sc->scells, sizeof(sc->scells)); } static int simplebus_fill_ranges(phandle_t node, struct simplebus_softc *sc) { int host_address_cells; cell_t *base_ranges; ssize_t nbase_ranges; int err; int i, j, k; err = OF_searchencprop(OF_parent(node), "#address-cells", &host_address_cells, sizeof(host_address_cells)); if (err <= 0) return (-1); nbase_ranges = OF_getproplen(node, "ranges"); if (nbase_ranges < 0) return (-1); sc->nranges = nbase_ranges / sizeof(cell_t) / (sc->acells + host_address_cells + sc->scells); if (sc->nranges == 0) return (0); sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]), M_DEVBUF, M_WAITOK); base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK); OF_getencprop(node, "ranges", base_ranges, nbase_ranges); for (i = 0, j = 0; i < sc->nranges; i++) { sc->ranges[i].bus = 0; for (k = 0; k < sc->acells; k++) { sc->ranges[i].bus <<= 32; sc->ranges[i].bus |= base_ranges[j++]; } sc->ranges[i].host = 0; for (k = 0; k < host_address_cells; k++) { sc->ranges[i].host <<= 32; sc->ranges[i].host |= base_ranges[j++]; } sc->ranges[i].size = 0; for (k = 0; k < sc->scells; k++) { sc->ranges[i].size <<= 32; sc->ranges[i].size |= base_ranges[j++]; } } free(base_ranges, M_DEVBUF); return (sc->nranges); } struct simplebus_devinfo * simplebus_setup_dinfo(device_t dev, phandle_t node, struct simplebus_devinfo *di) { struct simplebus_softc *sc; struct simplebus_devinfo *ndi; sc = device_get_softc(dev); if (di == NULL) ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); else ndi = di; if (ofw_bus_gen_setup_devinfo(&ndi->obdinfo, node) != 0) { if (di == NULL) free(ndi, M_DEVBUF); return (NULL); } resource_list_init(&ndi->rl); ofw_bus_reg_to_rl(dev, node, sc->acells, sc->scells, &ndi->rl); - ofw_bus_intr_to_rl(dev, node, &ndi->rl); + ofw_bus_intr_to_rl(dev, node, &ndi->rl, NULL); return (ndi); } device_t simplebus_add_device(device_t dev, phandle_t node, u_int order, const char *name, int unit, struct simplebus_devinfo *di) { struct simplebus_devinfo *ndi; device_t cdev; if ((ndi = simplebus_setup_dinfo(dev, node, di)) == NULL) return (NULL); cdev = device_add_child_ordered(dev, order, name, unit); if (cdev == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", ndi->obdinfo.obd_name); resource_list_free(&ndi->rl); ofw_bus_gen_destroy_devinfo(&ndi->obdinfo); if (di == NULL) free(ndi, M_DEVBUF); return (NULL); } device_set_ivars(cdev, ndi); return(cdev); } static device_t simplebus_add_child(device_t dev, u_int order, const char *name, int unit) { device_t cdev; struct simplebus_devinfo *ndi; cdev = device_add_child_ordered(dev, order, name, unit); if (cdev == NULL) return (NULL); ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); ndi->obdinfo.obd_node = -1; resource_list_init(&ndi->rl); device_set_ivars(cdev, ndi); return (cdev); } static const struct ofw_bus_devinfo * simplebus_get_devinfo(device_t bus __unused, device_t child) { struct simplebus_devinfo *ndi; ndi = device_get_ivars(child); return (&ndi->obdinfo); } static struct resource_list * simplebus_get_resource_list(device_t bus __unused, device_t child) { struct simplebus_devinfo *ndi; ndi = device_get_ivars(child); return (&ndi->rl); } static struct resource * simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct simplebus_softc *sc; struct simplebus_devinfo *di; struct resource_list_entry *rle; int j; sc = device_get_softc(bus); /* * Request for the default allocation with a given rid: use resource * list stored in the local device info. */ if ((start == 0UL) && (end == ~0UL)) { if ((di = device_get_ivars(child)) == NULL) return (NULL); if (type == SYS_RES_IOPORT) type = SYS_RES_MEMORY; rle = resource_list_find(&di->rl, type, *rid); if (rle == NULL) { if (bootverbose) device_printf(bus, "no default resources for " "rid = %d, type = %d\n", *rid, type); return (NULL); } start = rle->start; end = rle->end; count = rle->count; } if (type == SYS_RES_MEMORY) { /* Remap through ranges property */ for (j = 0; j < sc->nranges; j++) { if (start >= sc->ranges[j].bus && end < sc->ranges[j].bus + sc->ranges[j].size) { start -= sc->ranges[j].bus; start += sc->ranges[j].host; end -= sc->ranges[j].bus; end += sc->ranges[j].host; break; } } if (j == sc->nranges && sc->nranges != 0) { if (bootverbose) device_printf(bus, "Could not map resource " "%#lx-%#lx\n", start, end); return (NULL); } } return (bus_generic_alloc_resource(bus, child, type, rid, start, end, count, flags)); } static int simplebus_print_res(struct simplebus_devinfo *di) { int rv; rv = 0; rv += resource_list_print_type(&di->rl, "mem", SYS_RES_MEMORY, "%#lx"); rv += resource_list_print_type(&di->rl, "irq", SYS_RES_IRQ, "%ld"); return (rv); } static void simplebus_probe_nomatch(device_t bus, device_t child) { const char *name, *type, *compat; if (!bootverbose) return; compat = ofw_bus_get_compat(child); if (compat == NULL) return; name = ofw_bus_get_name(child); type = ofw_bus_get_type(child); device_printf(bus, "<%s>", name != NULL ? name : "unknown"); simplebus_print_res(device_get_ivars(child)); if (!ofw_bus_status_okay(child)) printf(" disabled"); if (type) printf(" type %s", type); printf(" compat %s (no driver attached)\n", compat); } static int simplebus_print_child(device_t bus, device_t child) { int rv; rv = bus_print_child_header(bus, child); rv += simplebus_print_res(device_get_ivars(child)); if (!ofw_bus_status_okay(child)) rv += printf(" disabled"); rv += bus_print_child_footer(bus, child); return (rv); } Index: projects/ci20_mips/sys/dev/gpio/ofw_gpiobus.c =================================================================== --- projects/ci20_mips/sys/dev/gpio/ofw_gpiobus.c (revision 283030) +++ projects/ci20_mips/sys/dev/gpio/ofw_gpiobus.c (revision 283031) @@ -1,412 +1,412 @@ /*- * Copyright (c) 2009, Nathan Whitehorn * Copyright (c) 2013, Luiz Otavio O Souza * Copyright (c) 2013 The FreeBSD Foundation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include "gpiobus_if.h" static struct ofw_gpiobus_devinfo *ofw_gpiobus_setup_devinfo(device_t, device_t, phandle_t); static void ofw_gpiobus_destroy_devinfo(device_t, struct ofw_gpiobus_devinfo *); static int ofw_gpiobus_parse_gpios_impl(device_t, phandle_t, char *, struct gpiobus_softc *, struct gpiobus_pin **); device_t ofw_gpiobus_add_fdt_child(device_t bus, const char *drvname, phandle_t child) { device_t childdev; int i; struct gpiobus_ivar *devi; struct ofw_gpiobus_devinfo *dinfo; /* * Set up the GPIO child and OFW bus layer devinfo and add it to bus. */ childdev = device_add_child(bus, drvname, -1); if (childdev == NULL) return (NULL); dinfo = ofw_gpiobus_setup_devinfo(bus, childdev, child); if (dinfo == NULL) { device_delete_child(bus, childdev); return (NULL); } if (device_probe_and_attach(childdev) != 0) { ofw_gpiobus_destroy_devinfo(bus, dinfo); device_delete_child(bus, childdev); return (NULL); } /* Use the child name as pin name. */ devi = &dinfo->opd_dinfo; for (i = 0; i < devi->npins; i++) GPIOBUS_PIN_SETNAME(bus, devi->pins[i], device_get_nameunit(childdev)); return (childdev); } int ofw_gpiobus_parse_gpios(device_t consumer, char *pname, struct gpiobus_pin **pins) { return (ofw_gpiobus_parse_gpios_impl(consumer, ofw_bus_get_node(consumer), pname, NULL, pins)); } void ofw_gpiobus_register_provider(device_t provider) { phandle_t node; node = ofw_bus_get_node(provider); OF_device_register_xref(OF_xref_from_node(node), provider); } void ofw_gpiobus_unregister_provider(device_t provider) { phandle_t node; node = ofw_bus_get_node(provider); OF_device_register_xref(OF_xref_from_node(node), NULL); } static struct ofw_gpiobus_devinfo * ofw_gpiobus_setup_devinfo(device_t bus, device_t child, phandle_t node) { int i, npins; struct gpiobus_ivar *devi; struct gpiobus_pin *pins; struct gpiobus_softc *sc; struct ofw_gpiobus_devinfo *dinfo; sc = device_get_softc(bus); dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_NOWAIT | M_ZERO); if (dinfo == NULL) return (NULL); if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, node) != 0) { free(dinfo, M_DEVBUF); return (NULL); } /* Parse the gpios property for the child. */ npins = ofw_gpiobus_parse_gpios_impl(child, node, "gpios", sc, &pins); if (npins <= 0) { ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo); free(dinfo, M_DEVBUF); return (NULL); } /* Initialize the irq resource list. */ resource_list_init(&dinfo->opd_dinfo.rl); /* Allocate the child ivars and copy the parsed pin data. */ devi = &dinfo->opd_dinfo; devi->npins = (uint32_t)npins; if (gpiobus_alloc_ivars(devi) != 0) { free(pins, M_DEVBUF); ofw_gpiobus_destroy_devinfo(bus, dinfo); return (NULL); } for (i = 0; i < devi->npins; i++) { devi->flags[i] = pins[i].flags; devi->pins[i] = pins[i].pin; } free(pins, M_DEVBUF); /* Parse the interrupt resources. */ - if (ofw_bus_intr_to_rl(bus, node, &dinfo->opd_dinfo.rl) != 0) { + if (ofw_bus_intr_to_rl(bus, node, &dinfo->opd_dinfo.rl, NULL) != 0) { ofw_gpiobus_destroy_devinfo(bus, dinfo); return (NULL); } device_set_ivars(child, dinfo); return (dinfo); } static void ofw_gpiobus_destroy_devinfo(device_t bus, struct ofw_gpiobus_devinfo *dinfo) { int i; struct gpiobus_ivar *devi; struct gpiobus_softc *sc; sc = device_get_softc(bus); devi = &dinfo->opd_dinfo; for (i = 0; i < devi->npins; i++) { if (devi->pins[i] > sc->sc_npins) continue; sc->sc_pins[devi->pins[i]].mapped = 0; } gpiobus_free_ivars(devi); resource_list_free(&dinfo->opd_dinfo.rl); ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo); free(dinfo, M_DEVBUF); } static int ofw_gpiobus_parse_gpios_impl(device_t consumer, phandle_t cnode, char *pname, struct gpiobus_softc *bussc, struct gpiobus_pin **pins) { int gpiocells, i, j, ncells, npins; pcell_t *gpios; phandle_t gpio; ncells = OF_getencprop_alloc(cnode, pname, sizeof(*gpios), (void **)&gpios); if (ncells == -1) { device_printf(consumer, "Warning: No %s specified in fdt data; " "device may not function.\n", pname); return (-1); } /* * The gpio-specifier is controller independent, the first pcell has * the reference to the GPIO controller phandler. * Count the number of encoded gpio-specifiers on the first pass. */ i = 0; npins = 0; while (i < ncells) { /* Allow NULL specifiers. */ if (gpios[i] == 0) { npins++; i++; continue; } gpio = OF_node_from_xref(gpios[i]); /* If we have bussc, ignore devices from other gpios. */ if (bussc != NULL) if (ofw_bus_get_node(bussc->sc_dev) != gpio) return (0); /* * Check for gpio-controller property and read the #gpio-cells * for this GPIO controller. */ if (!OF_hasprop(gpio, "gpio-controller") || OF_getencprop(gpio, "#gpio-cells", &gpiocells, sizeof(gpiocells)) < 0) { device_printf(consumer, "gpio reference is not a gpio-controller.\n"); free(gpios, M_OFWPROP); return (-1); } if (ncells - i < gpiocells + 1) { device_printf(consumer, "%s cells doesn't match #gpio-cells.\n", pname); return (-1); } npins++; i += gpiocells + 1; } if (npins == 0 || pins == NULL) { if (npins == 0) device_printf(consumer, "no pin specified in %s.\n", pname); free(gpios, M_OFWPROP); return (npins); } *pins = malloc(sizeof(struct gpiobus_pin) * npins, M_DEVBUF, M_NOWAIT | M_ZERO); if (*pins == NULL) { free(gpios, M_OFWPROP); return (-1); } /* Decode the gpio specifier on the second pass. */ i = 0; j = 0; while (i < ncells) { /* Allow NULL specifiers. */ if (gpios[i] == 0) { j++; i++; continue; } gpio = OF_node_from_xref(gpios[i]); /* Read gpio-cells property for this GPIO controller. */ if (OF_getencprop(gpio, "#gpio-cells", &gpiocells, sizeof(gpiocells)) < 0) { device_printf(consumer, "gpio does not have the #gpio-cells property.\n"); goto fail; } /* Return the device reference for the GPIO controller. */ (*pins)[j].dev = OF_device_from_xref(gpios[i]); if ((*pins)[j].dev == NULL) { device_printf(consumer, "no device registered for the gpio controller.\n"); goto fail; } /* * If the gpiobus softc is NULL we use the GPIO_GET_BUS() to * retrieve it. The GPIO_GET_BUS() method is only valid after * the child is probed and attached. */ if (bussc == NULL) { if (GPIO_GET_BUS((*pins)[j].dev) == NULL) { device_printf(consumer, "no gpiobus reference for %s.\n", device_get_nameunit((*pins)[j].dev)); goto fail; } bussc = device_get_softc(GPIO_GET_BUS((*pins)[j].dev)); } /* Get the GPIO pin number and flags. */ if (gpio_map_gpios((*pins)[j].dev, cnode, gpio, gpiocells, &gpios[i + 1], &(*pins)[j].pin, &(*pins)[j].flags) != 0) { device_printf(consumer, "cannot map the gpios specifier.\n"); goto fail; } /* Reserve the GPIO pin. */ if (gpiobus_map_pin(bussc->sc_busdev, (*pins)[j].pin) != 0) goto fail; j++; i += gpiocells + 1; } free(gpios, M_OFWPROP); return (npins); fail: free(gpios, M_OFWPROP); free(*pins, M_DEVBUF); return (-1); } static int ofw_gpiobus_probe(device_t dev) { if (ofw_bus_get_node(dev) == -1) return (ENXIO); device_set_desc(dev, "OFW GPIO bus"); return (0); } static int ofw_gpiobus_attach(device_t dev) { int err; phandle_t child; err = gpiobus_init_softc(dev); if (err != 0) return (err); bus_generic_probe(dev); bus_enumerate_hinted_children(dev); /* * Attach the children represented in the device tree. */ for (child = OF_child(ofw_bus_get_node(dev)); child != 0; child = OF_peer(child)) { if (!OF_hasprop(child, "gpios")) continue; if (ofw_gpiobus_add_fdt_child(dev, NULL, child) == NULL) continue; } return (bus_generic_attach(dev)); } static device_t ofw_gpiobus_add_child(device_t dev, u_int order, const char *name, int unit) { device_t child; struct ofw_gpiobus_devinfo *devi; child = device_add_child_ordered(dev, order, name, unit); if (child == NULL) return (child); devi = malloc(sizeof(struct ofw_gpiobus_devinfo), M_DEVBUF, M_NOWAIT | M_ZERO); if (devi == NULL) { device_delete_child(dev, child); return (0); } /* * NULL all the OFW-related parts of the ivars for non-OFW * children. */ devi->opd_obdinfo.obd_node = -1; devi->opd_obdinfo.obd_name = NULL; devi->opd_obdinfo.obd_compat = NULL; devi->opd_obdinfo.obd_type = NULL; devi->opd_obdinfo.obd_model = NULL; device_set_ivars(child, devi); return (child); } static const struct ofw_bus_devinfo * ofw_gpiobus_get_devinfo(device_t bus, device_t dev) { struct ofw_gpiobus_devinfo *dinfo; dinfo = device_get_ivars(dev); return (&dinfo->opd_obdinfo); } static device_method_t ofw_gpiobus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ofw_gpiobus_probe), DEVMETHOD(device_attach, ofw_gpiobus_attach), /* Bus interface */ DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), DEVMETHOD(bus_add_child, ofw_gpiobus_add_child), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, ofw_gpiobus_get_devinfo), DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), DEVMETHOD_END }; static devclass_t ofwgpiobus_devclass; DEFINE_CLASS_1(gpiobus, ofw_gpiobus_driver, ofw_gpiobus_methods, sizeof(struct gpiobus_softc), gpiobus_driver); DRIVER_MODULE(ofw_gpiobus, gpio, ofw_gpiobus_driver, ofwgpiobus_devclass, 0, 0); MODULE_VERSION(ofw_gpiobus, 1); MODULE_DEPEND(ofw_gpiobus, gpiobus, 1, 1, 1); Index: projects/ci20_mips/sys/dev/iscsi/icl_soft.c =================================================================== --- projects/ci20_mips/sys/dev/iscsi/icl_soft.c (revision 283030) +++ projects/ci20_mips/sys/dev/iscsi/icl_soft.c (revision 283031) @@ -1,1543 +1,1543 @@ /*- * Copyright (c) 2012 The FreeBSD Foundation * All rights reserved. * * This software was developed by Edward Tomasz Napierala under sponsorship * from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* * Software implementation of iSCSI Common Layer kobj(9) interface. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int coalesce = 1; SYSCTL_INT(_kern_icl, OID_AUTO, coalesce, CTLFLAG_RWTUN, &coalesce, 0, "Try to coalesce PDUs before sending"); static int partial_receive_len = 128 * 1024; SYSCTL_INT(_kern_icl, OID_AUTO, partial_receive_len, CTLFLAG_RWTUN, &partial_receive_len, 0, "Minimum read size for partially received " "data segment"); static int sendspace = 1048576; SYSCTL_INT(_kern_icl, OID_AUTO, sendspace, CTLFLAG_RWTUN, &sendspace, 0, "Default send socket buffer size"); static int recvspace = 1048576; SYSCTL_INT(_kern_icl, OID_AUTO, recvspace, CTLFLAG_RWTUN, &recvspace, 0, "Default receive socket buffer size"); static MALLOC_DEFINE(M_ICL_SOFT, "icl_soft", "iSCSI software backend"); static uma_zone_t icl_pdu_zone; static volatile u_int icl_ncons; #define ICL_CONN_LOCK(X) mtx_lock(X->ic_lock) #define ICL_CONN_UNLOCK(X) mtx_unlock(X->ic_lock) #define ICL_CONN_LOCK_ASSERT(X) mtx_assert(X->ic_lock, MA_OWNED) #define ICL_CONN_LOCK_ASSERT_NOT(X) mtx_assert(X->ic_lock, MA_NOTOWNED) STAILQ_HEAD(icl_pdu_stailq, icl_pdu); static icl_conn_new_pdu_t icl_soft_conn_new_pdu; static icl_conn_pdu_free_t icl_soft_conn_pdu_free; static icl_conn_pdu_data_segment_length_t icl_soft_conn_pdu_data_segment_length; static icl_conn_pdu_append_data_t icl_soft_conn_pdu_append_data; static icl_conn_pdu_get_data_t icl_soft_conn_pdu_get_data; static icl_conn_pdu_queue_t icl_soft_conn_pdu_queue; static icl_conn_handoff_t icl_soft_conn_handoff; static icl_conn_free_t icl_soft_conn_free; static icl_conn_close_t icl_soft_conn_close; static icl_conn_task_setup_t icl_soft_conn_task_setup; static icl_conn_task_done_t icl_soft_conn_task_done; static icl_conn_transfer_setup_t icl_soft_conn_transfer_setup; static icl_conn_transfer_done_t icl_soft_conn_transfer_done; static kobj_method_t icl_soft_methods[] = { KOBJMETHOD(icl_conn_new_pdu, icl_soft_conn_new_pdu), KOBJMETHOD(icl_conn_pdu_free, icl_soft_conn_pdu_free), KOBJMETHOD(icl_conn_pdu_data_segment_length, icl_soft_conn_pdu_data_segment_length), KOBJMETHOD(icl_conn_pdu_append_data, icl_soft_conn_pdu_append_data), KOBJMETHOD(icl_conn_pdu_get_data, icl_soft_conn_pdu_get_data), KOBJMETHOD(icl_conn_pdu_queue, icl_soft_conn_pdu_queue), KOBJMETHOD(icl_conn_handoff, icl_soft_conn_handoff), KOBJMETHOD(icl_conn_free, icl_soft_conn_free), KOBJMETHOD(icl_conn_close, icl_soft_conn_close), KOBJMETHOD(icl_conn_task_setup, icl_soft_conn_task_setup), KOBJMETHOD(icl_conn_task_done, icl_soft_conn_task_done), KOBJMETHOD(icl_conn_transfer_setup, icl_soft_conn_transfer_setup), KOBJMETHOD(icl_conn_transfer_done, icl_soft_conn_transfer_done), { 0, 0 } }; DEFINE_CLASS(icl_soft, icl_soft_methods, sizeof(struct icl_conn)); static void icl_conn_fail(struct icl_conn *ic) { if (ic->ic_socket == NULL) return; /* * XXX */ ic->ic_socket->so_error = EDOOFUS; (ic->ic_error)(ic); } static struct mbuf * icl_conn_receive(struct icl_conn *ic, size_t len) { struct uio uio; struct socket *so; struct mbuf *m; int error, flags; so = ic->ic_socket; memset(&uio, 0, sizeof(uio)); uio.uio_resid = len; flags = MSG_DONTWAIT; error = soreceive(so, NULL, &uio, &m, NULL, &flags); if (error != 0) { ICL_DEBUG("soreceive error %d", error); return (NULL); } if (uio.uio_resid != 0) { m_freem(m); ICL_DEBUG("short read"); return (NULL); } return (m); } static struct icl_pdu * icl_pdu_new_empty(struct icl_conn *ic, int flags) { struct icl_pdu *ip; #ifdef DIAGNOSTIC refcount_acquire(&ic->ic_outstanding_pdus); #endif ip = uma_zalloc(icl_pdu_zone, flags | M_ZERO); if (ip == NULL) { ICL_WARN("failed to allocate %zd bytes", sizeof(*ip)); #ifdef DIAGNOSTIC refcount_release(&ic->ic_outstanding_pdus); #endif return (NULL); } ip->ip_conn = ic; return (ip); } static void icl_pdu_free(struct icl_pdu *ip) { struct icl_conn *ic; ic = ip->ip_conn; m_freem(ip->ip_bhs_mbuf); m_freem(ip->ip_ahs_mbuf); m_freem(ip->ip_data_mbuf); uma_zfree(icl_pdu_zone, ip); #ifdef DIAGNOSTIC refcount_release(&ic->ic_outstanding_pdus); #endif } void icl_soft_conn_pdu_free(struct icl_conn *ic, struct icl_pdu *ip) { icl_pdu_free(ip); } /* * Allocate icl_pdu with empty BHS to fill up by the caller. */ struct icl_pdu * icl_soft_conn_new_pdu(struct icl_conn *ic, int flags) { struct icl_pdu *ip; ip = icl_pdu_new_empty(ic, flags); if (ip == NULL) return (NULL); ip->ip_bhs_mbuf = m_getm2(NULL, sizeof(struct iscsi_bhs), flags, MT_DATA, M_PKTHDR); if (ip->ip_bhs_mbuf == NULL) { ICL_WARN("failed to allocate %zd bytes", sizeof(*ip)); icl_pdu_free(ip); return (NULL); } ip->ip_bhs = mtod(ip->ip_bhs_mbuf, struct iscsi_bhs *); memset(ip->ip_bhs, 0, sizeof(struct iscsi_bhs)); ip->ip_bhs_mbuf->m_len = sizeof(struct iscsi_bhs); return (ip); } static int icl_pdu_ahs_length(const struct icl_pdu *request) { return (request->ip_bhs->bhs_total_ahs_len * 4); } static size_t icl_pdu_data_segment_length(const struct icl_pdu *request) { uint32_t len = 0; len += request->ip_bhs->bhs_data_segment_len[0]; len <<= 8; len += request->ip_bhs->bhs_data_segment_len[1]; len <<= 8; len += request->ip_bhs->bhs_data_segment_len[2]; return (len); } size_t icl_soft_conn_pdu_data_segment_length(struct icl_conn *ic, const struct icl_pdu *request) { return (icl_pdu_data_segment_length(request)); } static void icl_pdu_set_data_segment_length(struct icl_pdu *response, uint32_t len) { response->ip_bhs->bhs_data_segment_len[2] = len; response->ip_bhs->bhs_data_segment_len[1] = len >> 8; response->ip_bhs->bhs_data_segment_len[0] = len >> 16; } static size_t icl_pdu_padding(const struct icl_pdu *ip) { if ((ip->ip_data_len % 4) != 0) return (4 - (ip->ip_data_len % 4)); return (0); } static size_t icl_pdu_size(const struct icl_pdu *response) { size_t len; KASSERT(response->ip_ahs_len == 0, ("responding with AHS")); len = sizeof(struct iscsi_bhs) + response->ip_data_len + icl_pdu_padding(response); if (response->ip_conn->ic_header_crc32c) len += ISCSI_HEADER_DIGEST_SIZE; if (response->ip_data_len != 0 && response->ip_conn->ic_data_crc32c) len += ISCSI_DATA_DIGEST_SIZE; return (len); } static int icl_pdu_receive_bhs(struct icl_pdu *request, size_t *availablep) { struct mbuf *m; m = icl_conn_receive(request->ip_conn, sizeof(struct iscsi_bhs)); if (m == NULL) { ICL_DEBUG("failed to receive BHS"); return (-1); } request->ip_bhs_mbuf = m_pullup(m, sizeof(struct iscsi_bhs)); if (request->ip_bhs_mbuf == NULL) { ICL_WARN("m_pullup failed"); return (-1); } request->ip_bhs = mtod(request->ip_bhs_mbuf, struct iscsi_bhs *); /* * XXX: For architectures with strict alignment requirements * we may need to allocate ip_bhs and copy the data into it. * For some reason, though, not doing this doesn't seem * to cause problems; tested on sparc64. */ *availablep -= sizeof(struct iscsi_bhs); return (0); } static int icl_pdu_receive_ahs(struct icl_pdu *request, size_t *availablep) { request->ip_ahs_len = icl_pdu_ahs_length(request); if (request->ip_ahs_len == 0) return (0); request->ip_ahs_mbuf = icl_conn_receive(request->ip_conn, request->ip_ahs_len); if (request->ip_ahs_mbuf == NULL) { ICL_DEBUG("failed to receive AHS"); return (-1); } *availablep -= request->ip_ahs_len; return (0); } static uint32_t icl_mbuf_to_crc32c(const struct mbuf *m0) { uint32_t digest = 0xffffffff; const struct mbuf *m; for (m = m0; m != NULL; m = m->m_next) digest = calculate_crc32c(digest, mtod(m, const void *), m->m_len); digest = digest ^ 0xffffffff; return (digest); } static int icl_pdu_check_header_digest(struct icl_pdu *request, size_t *availablep) { struct mbuf *m; uint32_t received_digest, valid_digest; if (request->ip_conn->ic_header_crc32c == false) return (0); m = icl_conn_receive(request->ip_conn, ISCSI_HEADER_DIGEST_SIZE); if (m == NULL) { ICL_DEBUG("failed to receive header digest"); return (-1); } CTASSERT(sizeof(received_digest) == ISCSI_HEADER_DIGEST_SIZE); m_copydata(m, 0, ISCSI_HEADER_DIGEST_SIZE, (void *)&received_digest); m_freem(m); *availablep -= ISCSI_HEADER_DIGEST_SIZE; /* * XXX: Handle AHS. */ valid_digest = icl_mbuf_to_crc32c(request->ip_bhs_mbuf); if (received_digest != valid_digest) { ICL_WARN("header digest check failed; got 0x%x, " "should be 0x%x", received_digest, valid_digest); return (-1); } return (0); } /* * Return the number of bytes that should be waiting in the receive socket * before icl_pdu_receive_data_segment() gets called. */ static size_t icl_pdu_data_segment_receive_len(const struct icl_pdu *request) { size_t len; len = icl_pdu_data_segment_length(request); if (len == 0) return (0); /* * Account for the parts of data segment already read from * the socket buffer. */ KASSERT(len > request->ip_data_len, ("len <= request->ip_data_len")); len -= request->ip_data_len; /* * Don't always wait for the full data segment to be delivered * to the socket; this might badly affect performance due to * TCP window scaling. */ if (len > partial_receive_len) { #if 0 ICL_DEBUG("need %zd bytes of data, limiting to %zd", len, partial_receive_len)); #endif len = partial_receive_len; return (len); } /* * Account for padding. Note that due to the way code is written, * the icl_pdu_receive_data_segment() must always receive padding * along with the last part of data segment, because it would be * impossible to tell whether we've already received the full data * segment including padding, or without it. */ if ((len % 4) != 0) len += 4 - (len % 4); #if 0 ICL_DEBUG("need %zd bytes of data", len)); #endif return (len); } static int icl_pdu_receive_data_segment(struct icl_pdu *request, size_t *availablep, bool *more_neededp) { struct icl_conn *ic; size_t len, padding = 0; struct mbuf *m; ic = request->ip_conn; *more_neededp = false; ic->ic_receive_len = 0; len = icl_pdu_data_segment_length(request); if (len == 0) return (0); if ((len % 4) != 0) padding = 4 - (len % 4); /* * Account for already received parts of data segment. */ KASSERT(len > request->ip_data_len, ("len <= request->ip_data_len")); len -= request->ip_data_len; if (len + padding > *availablep) { /* * Not enough data in the socket buffer. Receive as much * as we can. Don't receive padding, since, obviously, it's * not the end of data segment yet. */ #if 0 ICL_DEBUG("limited from %zd to %zd", len + padding, *availablep - padding)); #endif len = *availablep - padding; *more_neededp = true; padding = 0; } /* * Must not try to receive padding without at least one byte * of actual data segment. */ if (len > 0) { m = icl_conn_receive(request->ip_conn, len + padding); if (m == NULL) { ICL_DEBUG("failed to receive data segment"); return (-1); } if (request->ip_data_mbuf == NULL) request->ip_data_mbuf = m; else m_cat(request->ip_data_mbuf, m); request->ip_data_len += len; *availablep -= len + padding; } else ICL_DEBUG("len 0"); if (*more_neededp) ic->ic_receive_len = icl_pdu_data_segment_receive_len(request); return (0); } static int icl_pdu_check_data_digest(struct icl_pdu *request, size_t *availablep) { struct mbuf *m; uint32_t received_digest, valid_digest; if (request->ip_conn->ic_data_crc32c == false) return (0); if (request->ip_data_len == 0) return (0); m = icl_conn_receive(request->ip_conn, ISCSI_DATA_DIGEST_SIZE); if (m == NULL) { ICL_DEBUG("failed to receive data digest"); return (-1); } CTASSERT(sizeof(received_digest) == ISCSI_DATA_DIGEST_SIZE); m_copydata(m, 0, ISCSI_DATA_DIGEST_SIZE, (void *)&received_digest); m_freem(m); *availablep -= ISCSI_DATA_DIGEST_SIZE; /* * Note that ip_data_mbuf also contains padding; since digest * calculation is supposed to include that, we iterate over * the entire ip_data_mbuf chain, not just ip_data_len bytes of it. */ valid_digest = icl_mbuf_to_crc32c(request->ip_data_mbuf); if (received_digest != valid_digest) { ICL_WARN("data digest check failed; got 0x%x, " "should be 0x%x", received_digest, valid_digest); return (-1); } return (0); } /* * Somewhat contrary to the name, this attempts to receive only one * "part" of PDU at a time; call it repeatedly until it returns non-NULL. */ static struct icl_pdu * icl_conn_receive_pdu(struct icl_conn *ic, size_t *availablep) { struct icl_pdu *request; struct socket *so; size_t len; int error; bool more_needed; so = ic->ic_socket; if (ic->ic_receive_state == ICL_CONN_STATE_BHS) { KASSERT(ic->ic_receive_pdu == NULL, ("ic->ic_receive_pdu != NULL")); request = icl_pdu_new_empty(ic, M_NOWAIT); if (request == NULL) { ICL_DEBUG("failed to allocate PDU; " "dropping connection"); icl_conn_fail(ic); return (NULL); } ic->ic_receive_pdu = request; } else { KASSERT(ic->ic_receive_pdu != NULL, ("ic->ic_receive_pdu == NULL")); request = ic->ic_receive_pdu; } if (*availablep < ic->ic_receive_len) { #if 0 ICL_DEBUG("not enough data; need %zd, " "have %zd", ic->ic_receive_len, *availablep); #endif return (NULL); } switch (ic->ic_receive_state) { case ICL_CONN_STATE_BHS: //ICL_DEBUG("receiving BHS"); error = icl_pdu_receive_bhs(request, availablep); if (error != 0) { ICL_DEBUG("failed to receive BHS; " "dropping connection"); break; } /* * We don't enforce any limit for AHS length; * its length is stored in 8 bit field. */ len = icl_pdu_data_segment_length(request); if (len > ic->ic_max_data_segment_length) { ICL_WARN("received data segment " "length %zd is larger than negotiated " "MaxDataSegmentLength %zd; " "dropping connection", len, ic->ic_max_data_segment_length); error = EINVAL; break; } ic->ic_receive_state = ICL_CONN_STATE_AHS; ic->ic_receive_len = icl_pdu_ahs_length(request); break; case ICL_CONN_STATE_AHS: //ICL_DEBUG("receiving AHS"); error = icl_pdu_receive_ahs(request, availablep); if (error != 0) { ICL_DEBUG("failed to receive AHS; " "dropping connection"); break; } ic->ic_receive_state = ICL_CONN_STATE_HEADER_DIGEST; if (ic->ic_header_crc32c == false) ic->ic_receive_len = 0; else ic->ic_receive_len = ISCSI_HEADER_DIGEST_SIZE; break; case ICL_CONN_STATE_HEADER_DIGEST: //ICL_DEBUG("receiving header digest"); error = icl_pdu_check_header_digest(request, availablep); if (error != 0) { ICL_DEBUG("header digest failed; " "dropping connection"); break; } ic->ic_receive_state = ICL_CONN_STATE_DATA; ic->ic_receive_len = icl_pdu_data_segment_receive_len(request); break; case ICL_CONN_STATE_DATA: //ICL_DEBUG("receiving data segment"); error = icl_pdu_receive_data_segment(request, availablep, &more_needed); if (error != 0) { ICL_DEBUG("failed to receive data segment;" "dropping connection"); break; } if (more_needed) break; ic->ic_receive_state = ICL_CONN_STATE_DATA_DIGEST; if (request->ip_data_len == 0 || ic->ic_data_crc32c == false) ic->ic_receive_len = 0; else ic->ic_receive_len = ISCSI_DATA_DIGEST_SIZE; break; case ICL_CONN_STATE_DATA_DIGEST: //ICL_DEBUG("receiving data digest"); error = icl_pdu_check_data_digest(request, availablep); if (error != 0) { ICL_DEBUG("data digest failed; " "dropping connection"); break; } /* * We've received complete PDU; reset the receive state machine * and return the PDU. */ ic->ic_receive_state = ICL_CONN_STATE_BHS; ic->ic_receive_len = sizeof(struct iscsi_bhs); ic->ic_receive_pdu = NULL; return (request); default: panic("invalid ic_receive_state %d\n", ic->ic_receive_state); } if (error != 0) { /* * Don't free the PDU; it's pointed to by ic->ic_receive_pdu * and will get freed in icl_soft_conn_close(). */ icl_conn_fail(ic); } return (NULL); } static void icl_conn_receive_pdus(struct icl_conn *ic, size_t available) { struct icl_pdu *response; struct socket *so; so = ic->ic_socket; /* * This can never happen; we're careful to only mess with ic->ic_socket * pointer when the send/receive threads are not running. */ KASSERT(so != NULL, ("NULL socket")); for (;;) { if (ic->ic_disconnecting) return; if (so->so_error != 0) { ICL_DEBUG("connection error %d; " "dropping connection", so->so_error); icl_conn_fail(ic); return; } /* * Loop until we have a complete PDU or there is not enough * data in the socket buffer. */ if (available < ic->ic_receive_len) { #if 0 ICL_DEBUG("not enough data; have %zd, " "need %zd", available, ic->ic_receive_len); #endif return; } response = icl_conn_receive_pdu(ic, &available); if (response == NULL) continue; if (response->ip_ahs_len > 0) { ICL_WARN("received PDU with unsupported " "AHS; opcode 0x%x; dropping connection", response->ip_bhs->bhs_opcode); icl_pdu_free(response); icl_conn_fail(ic); return; } (ic->ic_receive)(response); } } static void icl_receive_thread(void *arg) { struct icl_conn *ic; size_t available; struct socket *so; ic = arg; so = ic->ic_socket; - ICL_CONN_LOCK(ic); - ic->ic_receive_running = true; - ICL_CONN_UNLOCK(ic); - for (;;) { if (ic->ic_disconnecting) { //ICL_DEBUG("terminating"); break; } /* * Set the low watermark, to be checked by * soreadable() in icl_soupcall_receive() * to avoid unneccessary wakeups until there * is enough data received to read the PDU. */ SOCKBUF_LOCK(&so->so_rcv); available = sbavail(&so->so_rcv); if (available < ic->ic_receive_len) { so->so_rcv.sb_lowat = ic->ic_receive_len; cv_wait(&ic->ic_receive_cv, &so->so_rcv.sb_mtx); } else so->so_rcv.sb_lowat = so->so_rcv.sb_hiwat + 1; SOCKBUF_UNLOCK(&so->so_rcv); icl_conn_receive_pdus(ic, available); } ICL_CONN_LOCK(ic); ic->ic_receive_running = false; cv_signal(&ic->ic_send_cv); ICL_CONN_UNLOCK(ic); kthread_exit(); } static int icl_soupcall_receive(struct socket *so, void *arg, int waitflag) { struct icl_conn *ic; if (!soreadable(so)) return (SU_OK); ic = arg; cv_signal(&ic->ic_receive_cv); return (SU_OK); } static int icl_pdu_finalize(struct icl_pdu *request) { size_t padding, pdu_len; uint32_t digest, zero = 0; int ok; struct icl_conn *ic; ic = request->ip_conn; icl_pdu_set_data_segment_length(request, request->ip_data_len); pdu_len = icl_pdu_size(request); if (ic->ic_header_crc32c) { digest = icl_mbuf_to_crc32c(request->ip_bhs_mbuf); ok = m_append(request->ip_bhs_mbuf, sizeof(digest), (void *)&digest); if (ok != 1) { ICL_WARN("failed to append header digest"); return (1); } } if (request->ip_data_len != 0) { padding = icl_pdu_padding(request); if (padding > 0) { ok = m_append(request->ip_data_mbuf, padding, (void *)&zero); if (ok != 1) { ICL_WARN("failed to append padding"); return (1); } } if (ic->ic_data_crc32c) { digest = icl_mbuf_to_crc32c(request->ip_data_mbuf); ok = m_append(request->ip_data_mbuf, sizeof(digest), (void *)&digest); if (ok != 1) { ICL_WARN("failed to append data digest"); return (1); } } m_cat(request->ip_bhs_mbuf, request->ip_data_mbuf); request->ip_data_mbuf = NULL; } request->ip_bhs_mbuf->m_pkthdr.len = pdu_len; return (0); } static void icl_conn_send_pdus(struct icl_conn *ic, struct icl_pdu_stailq *queue) { struct icl_pdu *request, *request2; struct socket *so; size_t available, size, size2; int coalesced, error; ICL_CONN_LOCK_ASSERT_NOT(ic); so = ic->ic_socket; SOCKBUF_LOCK(&so->so_snd); /* * Check how much space do we have for transmit. We can't just * call sosend() and retry when we get EWOULDBLOCK or EMSGSIZE, * as it always frees the mbuf chain passed to it, even in case * of error. */ available = sbspace(&so->so_snd); /* * Notify the socket upcall that we don't need wakeups * for the time being. */ so->so_snd.sb_lowat = so->so_snd.sb_hiwat + 1; SOCKBUF_UNLOCK(&so->so_snd); while (!STAILQ_EMPTY(queue)) { request = STAILQ_FIRST(queue); size = icl_pdu_size(request); if (available < size) { /* * Set the low watermark, to be checked by * sowriteable() in icl_soupcall_send() * to avoid unneccessary wakeups until there * is enough space for the PDU to fit. */ SOCKBUF_LOCK(&so->so_snd); available = sbspace(&so->so_snd); if (available < size) { #if 1 ICL_DEBUG("no space to send; " "have %zd, need %zd", available, size); #endif so->so_snd.sb_lowat = size; SOCKBUF_UNLOCK(&so->so_snd); return; } SOCKBUF_UNLOCK(&so->so_snd); } STAILQ_REMOVE_HEAD(queue, ip_next); error = icl_pdu_finalize(request); if (error != 0) { ICL_DEBUG("failed to finalize PDU; " "dropping connection"); icl_conn_fail(ic); icl_pdu_free(request); return; } if (coalesce) { coalesced = 1; for (;;) { request2 = STAILQ_FIRST(queue); if (request2 == NULL) break; size2 = icl_pdu_size(request2); if (available < size + size2) break; STAILQ_REMOVE_HEAD(queue, ip_next); error = icl_pdu_finalize(request2); if (error != 0) { ICL_DEBUG("failed to finalize PDU; " "dropping connection"); icl_conn_fail(ic); icl_pdu_free(request); icl_pdu_free(request2); return; } m_cat(request->ip_bhs_mbuf, request2->ip_bhs_mbuf); request2->ip_bhs_mbuf = NULL; request->ip_bhs_mbuf->m_pkthdr.len += size2; size += size2; STAILQ_REMOVE_AFTER(queue, request, ip_next); icl_pdu_free(request2); coalesced++; } #if 0 if (coalesced > 1) { ICL_DEBUG("coalesced %d PDUs into %zd bytes", coalesced, size); } #endif } available -= size; error = sosend(so, NULL, NULL, request->ip_bhs_mbuf, NULL, MSG_DONTWAIT, curthread); request->ip_bhs_mbuf = NULL; /* Sosend consumes the mbuf. */ if (error != 0) { ICL_DEBUG("failed to send PDU, error %d; " "dropping connection", error); icl_conn_fail(ic); icl_pdu_free(request); return; } icl_pdu_free(request); } } static void icl_send_thread(void *arg) { struct icl_conn *ic; struct icl_pdu_stailq queue; ic = arg; STAILQ_INIT(&queue); ICL_CONN_LOCK(ic); - ic->ic_send_running = true; - for (;;) { for (;;) { /* * If the local queue is empty, populate it from * the main one. This way the icl_conn_send_pdus() * can go through all the queued PDUs without holding * any locks. */ if (STAILQ_EMPTY(&queue)) STAILQ_SWAP(&ic->ic_to_send, &queue, icl_pdu); ic->ic_check_send_space = false; ICL_CONN_UNLOCK(ic); icl_conn_send_pdus(ic, &queue); ICL_CONN_LOCK(ic); /* * The icl_soupcall_send() was called since the last * call to sbspace(); go around; */ if (ic->ic_check_send_space) continue; /* * Local queue is empty, but we still have PDUs * in the main one; go around. */ if (STAILQ_EMPTY(&queue) && !STAILQ_EMPTY(&ic->ic_to_send)) continue; /* * There might be some stuff in the local queue, * which didn't get sent due to not having enough send * space. Wait for socket upcall. */ break; } if (ic->ic_disconnecting) { //ICL_DEBUG("terminating"); break; } cv_wait(&ic->ic_send_cv, ic->ic_lock); } /* * We're exiting; move PDUs back to the main queue, so they can * get freed properly. At this point ordering doesn't matter. */ STAILQ_CONCAT(&ic->ic_to_send, &queue); ic->ic_send_running = false; cv_signal(&ic->ic_send_cv); ICL_CONN_UNLOCK(ic); kthread_exit(); } static int icl_soupcall_send(struct socket *so, void *arg, int waitflag) { struct icl_conn *ic; if (!sowriteable(so)) return (SU_OK); ic = arg; ICL_CONN_LOCK(ic); ic->ic_check_send_space = true; ICL_CONN_UNLOCK(ic); cv_signal(&ic->ic_send_cv); return (SU_OK); } static int icl_pdu_append_data(struct icl_pdu *request, const void *addr, size_t len, int flags) { struct mbuf *mb, *newmb; size_t copylen, off = 0; KASSERT(len > 0, ("len == 0")); newmb = m_getm2(NULL, len, flags, MT_DATA, M_PKTHDR); if (newmb == NULL) { ICL_WARN("failed to allocate mbuf for %zd bytes", len); return (ENOMEM); } for (mb = newmb; mb != NULL; mb = mb->m_next) { copylen = min(M_TRAILINGSPACE(mb), len - off); memcpy(mtod(mb, char *), (const char *)addr + off, copylen); mb->m_len = copylen; off += copylen; } KASSERT(off == len, ("%s: off != len", __func__)); if (request->ip_data_mbuf == NULL) { request->ip_data_mbuf = newmb; request->ip_data_len = len; } else { m_cat(request->ip_data_mbuf, newmb); request->ip_data_len += len; } return (0); } int icl_soft_conn_pdu_append_data(struct icl_conn *ic, struct icl_pdu *request, const void *addr, size_t len, int flags) { return (icl_pdu_append_data(request, addr, len, flags)); } static void icl_pdu_get_data(struct icl_pdu *ip, size_t off, void *addr, size_t len) { m_copydata(ip->ip_data_mbuf, off, len, addr); } void icl_soft_conn_pdu_get_data(struct icl_conn *ic, struct icl_pdu *ip, size_t off, void *addr, size_t len) { return (icl_pdu_get_data(ip, off, addr, len)); } static void icl_pdu_queue(struct icl_pdu *ip) { struct icl_conn *ic; ic = ip->ip_conn; ICL_CONN_LOCK_ASSERT(ic); if (ic->ic_disconnecting || ic->ic_socket == NULL) { ICL_DEBUG("icl_pdu_queue on closed connection"); icl_pdu_free(ip); return; } if (!STAILQ_EMPTY(&ic->ic_to_send)) { STAILQ_INSERT_TAIL(&ic->ic_to_send, ip, ip_next); /* * If the queue is not empty, someone else had already * signaled the send thread; no need to do that again, * just return. */ return; } STAILQ_INSERT_TAIL(&ic->ic_to_send, ip, ip_next); cv_signal(&ic->ic_send_cv); } void icl_soft_conn_pdu_queue(struct icl_conn *ic, struct icl_pdu *ip) { icl_pdu_queue(ip); } static struct icl_conn * icl_soft_new_conn(const char *name, struct mtx *lock) { struct icl_conn *ic; refcount_acquire(&icl_ncons); ic = (struct icl_conn *)kobj_create(&icl_soft_class, M_ICL_SOFT, M_WAITOK | M_ZERO); STAILQ_INIT(&ic->ic_to_send); ic->ic_lock = lock; cv_init(&ic->ic_send_cv, "icl_tx"); cv_init(&ic->ic_receive_cv, "icl_rx"); #ifdef DIAGNOSTIC refcount_init(&ic->ic_outstanding_pdus, 0); #endif ic->ic_max_data_segment_length = ICL_MAX_DATA_SEGMENT_LENGTH; ic->ic_name = name; ic->ic_offload = "None"; return (ic); } void icl_soft_conn_free(struct icl_conn *ic) { cv_destroy(&ic->ic_send_cv); cv_destroy(&ic->ic_receive_cv); kobj_delete((struct kobj *)ic, M_ICL_SOFT); refcount_release(&icl_ncons); } static int icl_conn_start(struct icl_conn *ic) { size_t minspace; struct sockopt opt; int error, one = 1; ICL_CONN_LOCK(ic); /* * XXX: Ugly hack. */ if (ic->ic_socket == NULL) { ICL_CONN_UNLOCK(ic); return (EINVAL); } ic->ic_receive_state = ICL_CONN_STATE_BHS; ic->ic_receive_len = sizeof(struct iscsi_bhs); ic->ic_disconnecting = false; ICL_CONN_UNLOCK(ic); /* * For sendspace, this is required because the current code cannot * send a PDU in pieces; thus, the minimum buffer size is equal * to the maximum PDU size. "+4" is to account for possible padding. * * What we should actually do here is to use autoscaling, but set * some minimal buffer size to "minspace". I don't know a way to do * that, though. */ minspace = sizeof(struct iscsi_bhs) + ic->ic_max_data_segment_length + ISCSI_HEADER_DIGEST_SIZE + ISCSI_DATA_DIGEST_SIZE + 4; if (sendspace < minspace) { ICL_WARN("kern.icl.sendspace too low; must be at least %zd", minspace); sendspace = minspace; } if (recvspace < minspace) { ICL_WARN("kern.icl.recvspace too low; must be at least %zd", minspace); recvspace = minspace; } error = soreserve(ic->ic_socket, sendspace, recvspace); if (error != 0) { ICL_WARN("soreserve failed with error %d", error); icl_soft_conn_close(ic); return (error); } ic->ic_socket->so_snd.sb_flags |= SB_AUTOSIZE; ic->ic_socket->so_rcv.sb_flags |= SB_AUTOSIZE; /* * Disable Nagle. */ bzero(&opt, sizeof(opt)); opt.sopt_dir = SOPT_SET; opt.sopt_level = IPPROTO_TCP; opt.sopt_name = TCP_NODELAY; opt.sopt_val = &one; opt.sopt_valsize = sizeof(one); error = sosetopt(ic->ic_socket, &opt); if (error != 0) { ICL_WARN("disabling TCP_NODELAY failed with error %d", error); icl_soft_conn_close(ic); return (error); } /* + * Register socket upcall, to get notified about incoming PDUs + * and free space to send outgoing ones. + */ + SOCKBUF_LOCK(&ic->ic_socket->so_snd); + soupcall_set(ic->ic_socket, SO_SND, icl_soupcall_send, ic); + SOCKBUF_UNLOCK(&ic->ic_socket->so_snd); + SOCKBUF_LOCK(&ic->ic_socket->so_rcv); + soupcall_set(ic->ic_socket, SO_RCV, icl_soupcall_receive, ic); + SOCKBUF_UNLOCK(&ic->ic_socket->so_rcv); + + /* * Start threads. */ + ICL_CONN_LOCK(ic); + ic->ic_send_running = ic->ic_receive_running = true; + ICL_CONN_UNLOCK(ic); error = kthread_add(icl_send_thread, ic, NULL, NULL, 0, 0, "%stx", ic->ic_name); if (error != 0) { ICL_WARN("kthread_add(9) failed with error %d", error); + ICL_CONN_LOCK(ic); + ic->ic_send_running = ic->ic_receive_running = false; + cv_signal(&ic->ic_send_cv); + ICL_CONN_UNLOCK(ic); icl_soft_conn_close(ic); return (error); } - error = kthread_add(icl_receive_thread, ic, NULL, NULL, 0, 0, "%srx", ic->ic_name); if (error != 0) { ICL_WARN("kthread_add(9) failed with error %d", error); + ICL_CONN_LOCK(ic); + ic->ic_receive_running = false; + cv_signal(&ic->ic_send_cv); + ICL_CONN_UNLOCK(ic); icl_soft_conn_close(ic); return (error); } - /* - * Register socket upcall, to get notified about incoming PDUs - * and free space to send outgoing ones. - */ - SOCKBUF_LOCK(&ic->ic_socket->so_snd); - soupcall_set(ic->ic_socket, SO_SND, icl_soupcall_send, ic); - SOCKBUF_UNLOCK(&ic->ic_socket->so_snd); - SOCKBUF_LOCK(&ic->ic_socket->so_rcv); - soupcall_set(ic->ic_socket, SO_RCV, icl_soupcall_receive, ic); - SOCKBUF_UNLOCK(&ic->ic_socket->so_rcv); - return (0); } int icl_soft_conn_handoff(struct icl_conn *ic, int fd) { struct file *fp; struct socket *so; cap_rights_t rights; int error; ICL_CONN_LOCK_ASSERT_NOT(ic); /* * Steal the socket from userland. */ error = fget(curthread, fd, cap_rights_init(&rights, CAP_SOCK_CLIENT), &fp); if (error != 0) return (error); if (fp->f_type != DTYPE_SOCKET) { fdrop(fp, curthread); return (EINVAL); } so = fp->f_data; if (so->so_type != SOCK_STREAM) { fdrop(fp, curthread); return (EINVAL); } ICL_CONN_LOCK(ic); if (ic->ic_socket != NULL) { ICL_CONN_UNLOCK(ic); fdrop(fp, curthread); return (EBUSY); } ic->ic_socket = fp->f_data; fp->f_ops = &badfileops; fp->f_data = NULL; fdrop(fp, curthread); ICL_CONN_UNLOCK(ic); error = icl_conn_start(ic); return (error); } void icl_soft_conn_close(struct icl_conn *ic) { struct icl_pdu *pdu; + struct socket *so; - ICL_CONN_LOCK_ASSERT_NOT(ic); - ICL_CONN_LOCK(ic); - if (ic->ic_socket == NULL) { - ICL_CONN_UNLOCK(ic); - return; - } /* - * Deregister socket upcalls. - */ - ICL_CONN_UNLOCK(ic); - SOCKBUF_LOCK(&ic->ic_socket->so_snd); - if (ic->ic_socket->so_snd.sb_upcall != NULL) - soupcall_clear(ic->ic_socket, SO_SND); - SOCKBUF_UNLOCK(&ic->ic_socket->so_snd); - SOCKBUF_LOCK(&ic->ic_socket->so_rcv); - if (ic->ic_socket->so_rcv.sb_upcall != NULL) - soupcall_clear(ic->ic_socket, SO_RCV); - SOCKBUF_UNLOCK(&ic->ic_socket->so_rcv); - ICL_CONN_LOCK(ic); - - ic->ic_disconnecting = true; - - /* * Wake up the threads, so they can properly terminate. */ + ic->ic_disconnecting = true; while (ic->ic_receive_running || ic->ic_send_running) { - //ICL_DEBUG("waiting for send/receive threads to terminate"); cv_signal(&ic->ic_receive_cv); cv_signal(&ic->ic_send_cv); cv_wait(&ic->ic_send_cv, ic->ic_lock); } - //ICL_DEBUG("send/receive threads terminated"); + /* Some other thread could close the connection same time. */ + so = ic->ic_socket; + if (so == NULL) { + ICL_CONN_UNLOCK(ic); + return; + } + ic->ic_socket = NULL; + + /* + * Deregister socket upcalls. + */ ICL_CONN_UNLOCK(ic); - soclose(ic->ic_socket); + SOCKBUF_LOCK(&so->so_snd); + if (so->so_snd.sb_upcall != NULL) + soupcall_clear(so, SO_SND); + SOCKBUF_UNLOCK(&so->so_snd); + SOCKBUF_LOCK(&so->so_rcv); + if (so->so_rcv.sb_upcall != NULL) + soupcall_clear(so, SO_RCV); + SOCKBUF_UNLOCK(&so->so_rcv); + soclose(so); ICL_CONN_LOCK(ic); - ic->ic_socket = NULL; if (ic->ic_receive_pdu != NULL) { //ICL_DEBUG("freeing partially received PDU"); icl_pdu_free(ic->ic_receive_pdu); ic->ic_receive_pdu = NULL; } /* * Remove any outstanding PDUs from the send queue. */ while (!STAILQ_EMPTY(&ic->ic_to_send)) { pdu = STAILQ_FIRST(&ic->ic_to_send); STAILQ_REMOVE_HEAD(&ic->ic_to_send, ip_next); icl_pdu_free(pdu); } KASSERT(STAILQ_EMPTY(&ic->ic_to_send), ("destroying session with non-empty send queue")); #ifdef DIAGNOSTIC KASSERT(ic->ic_outstanding_pdus == 0, ("destroying session with %d outstanding PDUs", ic->ic_outstanding_pdus)); #endif ICL_CONN_UNLOCK(ic); } int icl_soft_conn_task_setup(struct icl_conn *ic, struct ccb_scsiio *csio, uint32_t *task_tagp, void **prvp) { return (0); } void icl_soft_conn_task_done(struct icl_conn *ic, void *prv) { } int icl_soft_conn_transfer_setup(struct icl_conn *ic, union ctl_io *io, uint32_t *transfer_tag, void **prvp) { return (0); } void icl_soft_conn_transfer_done(struct icl_conn *ic, void *prv) { } static int icl_soft_limits(size_t *limitp) { *limitp = 128 * 1024; return (0); } #ifdef ICL_KERNEL_PROXY int icl_conn_handoff_sock(struct icl_conn *ic, struct socket *so) { int error; ICL_CONN_LOCK_ASSERT_NOT(ic); if (so->so_type != SOCK_STREAM) return (EINVAL); ICL_CONN_LOCK(ic); if (ic->ic_socket != NULL) { ICL_CONN_UNLOCK(ic); return (EBUSY); } ic->ic_socket = so; ICL_CONN_UNLOCK(ic); error = icl_conn_start(ic); return (error); } #endif /* ICL_KERNEL_PROXY */ static int icl_soft_load(void) { int error; icl_pdu_zone = uma_zcreate("icl_pdu", sizeof(struct icl_pdu), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); refcount_init(&icl_ncons, 0); /* * The reason we call this "none" is that to the user, * it's known as "offload driver"; "offload driver: soft" * doesn't make much sense. */ error = icl_register("none", 0, icl_soft_limits, icl_soft_new_conn); KASSERT(error == 0, ("failed to register")); return (error); } static int icl_soft_unload(void) { if (icl_ncons != 0) return (EBUSY); icl_unregister("none"); uma_zdestroy(icl_pdu_zone); return (0); } static int icl_soft_modevent(module_t mod, int what, void *arg) { switch (what) { case MOD_LOAD: return (icl_soft_load()); case MOD_UNLOAD: return (icl_soft_unload()); default: return (EINVAL); } } moduledata_t icl_soft_data = { "icl_soft", icl_soft_modevent, 0 }; DECLARE_MODULE(icl_soft, icl_soft_data, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); MODULE_DEPEND(icl_soft, icl, 1, 1, 1); MODULE_VERSION(icl_soft, 1); Index: projects/ci20_mips/sys/dev/iwn/if_iwn.c =================================================================== --- projects/ci20_mips/sys/dev/iwn/if_iwn.c (revision 283030) +++ projects/ci20_mips/sys/dev/iwn/if_iwn.c (revision 283031) @@ -1,8891 +1,8891 @@ /*- * Copyright (c) 2007-2009 Damien Bergamini * Copyright (c) 2008 Benjamin Close * Copyright (c) 2008 Sam Leffler, Errno Consulting * Copyright (c) 2011 Intel Corporation * Copyright (c) 2013 Cedric GROSS * Copyright (c) 2013 Adrian Chadd * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Driver for Intel WiFi Link 4965 and 1000/5000/6000 Series 802.11 network * adapters. */ #include __FBSDID("$FreeBSD$"); #include "opt_wlan.h" #include "opt_iwn.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct iwn_ident { uint16_t vendor; uint16_t device; const char *name; }; static const struct iwn_ident iwn_ident_table[] = { { 0x8086, IWN_DID_6x05_1, "Intel Centrino Advanced-N 6205" }, { 0x8086, IWN_DID_1000_1, "Intel Centrino Wireless-N 1000" }, { 0x8086, IWN_DID_1000_2, "Intel Centrino Wireless-N 1000" }, { 0x8086, IWN_DID_6x05_2, "Intel Centrino Advanced-N 6205" }, { 0x8086, IWN_DID_6050_1, "Intel Centrino Advanced-N + WiMAX 6250" }, { 0x8086, IWN_DID_6050_2, "Intel Centrino Advanced-N + WiMAX 6250" }, { 0x8086, IWN_DID_x030_1, "Intel Centrino Wireless-N 1030" }, { 0x8086, IWN_DID_x030_2, "Intel Centrino Wireless-N 1030" }, { 0x8086, IWN_DID_x030_3, "Intel Centrino Advanced-N 6230" }, { 0x8086, IWN_DID_x030_4, "Intel Centrino Advanced-N 6230" }, { 0x8086, IWN_DID_6150_1, "Intel Centrino Wireless-N + WiMAX 6150" }, { 0x8086, IWN_DID_6150_2, "Intel Centrino Wireless-N + WiMAX 6150" }, { 0x8086, IWN_DID_2x00_1, "Intel(R) Centrino(R) Wireless-N 2200 BGN" }, { 0x8086, IWN_DID_2x00_2, "Intel(R) Centrino(R) Wireless-N 2200 BGN" }, /* XXX 2200D is IWN_SDID_2x00_4; there's no way to express this here! */ { 0x8086, IWN_DID_2x30_1, "Intel Centrino Wireless-N 2230" }, { 0x8086, IWN_DID_2x30_2, "Intel Centrino Wireless-N 2230" }, { 0x8086, IWN_DID_130_1, "Intel Centrino Wireless-N 130" }, { 0x8086, IWN_DID_130_2, "Intel Centrino Wireless-N 130" }, { 0x8086, IWN_DID_100_1, "Intel Centrino Wireless-N 100" }, { 0x8086, IWN_DID_100_2, "Intel Centrino Wireless-N 100" }, { 0x8086, IWN_DID_105_1, "Intel Centrino Wireless-N 105" }, { 0x8086, IWN_DID_105_2, "Intel Centrino Wireless-N 105" }, { 0x8086, IWN_DID_135_1, "Intel Centrino Wireless-N 135" }, { 0x8086, IWN_DID_135_2, "Intel Centrino Wireless-N 135" }, { 0x8086, IWN_DID_4965_1, "Intel Wireless WiFi Link 4965" }, { 0x8086, IWN_DID_6x00_1, "Intel Centrino Ultimate-N 6300" }, { 0x8086, IWN_DID_6x00_2, "Intel Centrino Advanced-N 6200" }, { 0x8086, IWN_DID_4965_2, "Intel Wireless WiFi Link 4965" }, { 0x8086, IWN_DID_4965_3, "Intel Wireless WiFi Link 4965" }, { 0x8086, IWN_DID_5x00_1, "Intel WiFi Link 5100" }, { 0x8086, IWN_DID_4965_4, "Intel Wireless WiFi Link 4965" }, { 0x8086, IWN_DID_5x00_3, "Intel Ultimate N WiFi Link 5300" }, { 0x8086, IWN_DID_5x00_4, "Intel Ultimate N WiFi Link 5300" }, { 0x8086, IWN_DID_5x00_2, "Intel WiFi Link 5100" }, { 0x8086, IWN_DID_6x00_3, "Intel Centrino Ultimate-N 6300" }, { 0x8086, IWN_DID_6x00_4, "Intel Centrino Advanced-N 6200" }, { 0x8086, IWN_DID_5x50_1, "Intel WiMAX/WiFi Link 5350" }, { 0x8086, IWN_DID_5x50_2, "Intel WiMAX/WiFi Link 5350" }, { 0x8086, IWN_DID_5x50_3, "Intel WiMAX/WiFi Link 5150" }, { 0x8086, IWN_DID_5x50_4, "Intel WiMAX/WiFi Link 5150" }, { 0x8086, IWN_DID_6035_1, "Intel Centrino Advanced 6235" }, { 0x8086, IWN_DID_6035_2, "Intel Centrino Advanced 6235" }, { 0, 0, NULL } }; static int iwn_probe(device_t); static int iwn_attach(device_t); static int iwn4965_attach(struct iwn_softc *, uint16_t); static int iwn5000_attach(struct iwn_softc *, uint16_t); static int iwn_config_specific(struct iwn_softc *, uint16_t); static void iwn_radiotap_attach(struct iwn_softc *); static void iwn_sysctlattach(struct iwn_softc *); static struct ieee80211vap *iwn_vap_create(struct ieee80211com *, const char [IFNAMSIZ], int, enum ieee80211_opmode, int, const uint8_t [IEEE80211_ADDR_LEN], const uint8_t [IEEE80211_ADDR_LEN]); static void iwn_vap_delete(struct ieee80211vap *); static int iwn_detach(device_t); static int iwn_shutdown(device_t); static int iwn_suspend(device_t); static int iwn_resume(device_t); static int iwn_nic_lock(struct iwn_softc *); static int iwn_eeprom_lock(struct iwn_softc *); static int iwn_init_otprom(struct iwn_softc *); static int iwn_read_prom_data(struct iwn_softc *, uint32_t, void *, int); static void iwn_dma_map_addr(void *, bus_dma_segment_t *, int, int); static int iwn_dma_contig_alloc(struct iwn_softc *, struct iwn_dma_info *, void **, bus_size_t, bus_size_t); static void iwn_dma_contig_free(struct iwn_dma_info *); static int iwn_alloc_sched(struct iwn_softc *); static void iwn_free_sched(struct iwn_softc *); static int iwn_alloc_kw(struct iwn_softc *); static void iwn_free_kw(struct iwn_softc *); static int iwn_alloc_ict(struct iwn_softc *); static void iwn_free_ict(struct iwn_softc *); static int iwn_alloc_fwmem(struct iwn_softc *); static void iwn_free_fwmem(struct iwn_softc *); static int iwn_alloc_rx_ring(struct iwn_softc *, struct iwn_rx_ring *); static void iwn_reset_rx_ring(struct iwn_softc *, struct iwn_rx_ring *); static void iwn_free_rx_ring(struct iwn_softc *, struct iwn_rx_ring *); static int iwn_alloc_tx_ring(struct iwn_softc *, struct iwn_tx_ring *, int); static void iwn_reset_tx_ring(struct iwn_softc *, struct iwn_tx_ring *); static void iwn_free_tx_ring(struct iwn_softc *, struct iwn_tx_ring *); static void iwn5000_ict_reset(struct iwn_softc *); static int iwn_read_eeprom(struct iwn_softc *, uint8_t macaddr[IEEE80211_ADDR_LEN]); static void iwn4965_read_eeprom(struct iwn_softc *); #ifdef IWN_DEBUG static void iwn4965_print_power_group(struct iwn_softc *, int); #endif static void iwn5000_read_eeprom(struct iwn_softc *); static uint32_t iwn_eeprom_channel_flags(struct iwn_eeprom_chan *); static void iwn_read_eeprom_band(struct iwn_softc *, int); static void iwn_read_eeprom_ht40(struct iwn_softc *, int); static void iwn_read_eeprom_channels(struct iwn_softc *, int, uint32_t); static struct iwn_eeprom_chan *iwn_find_eeprom_channel(struct iwn_softc *, struct ieee80211_channel *); static int iwn_setregdomain(struct ieee80211com *, struct ieee80211_regdomain *, int, struct ieee80211_channel[]); static void iwn_read_eeprom_enhinfo(struct iwn_softc *); static struct ieee80211_node *iwn_node_alloc(struct ieee80211vap *, const uint8_t mac[IEEE80211_ADDR_LEN]); static void iwn_newassoc(struct ieee80211_node *, int); static int iwn_media_change(struct ifnet *); static int iwn_newstate(struct ieee80211vap *, enum ieee80211_state, int); static void iwn_calib_timeout(void *); static void iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); static void iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); static void iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); static void iwn5000_rx_calib_results(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); static void iwn_rx_statistics(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); static void iwn4965_tx_done(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); static void iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); static void iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *, int, uint8_t); static void iwn_ampdu_tx_done(struct iwn_softc *, int, int, int, int, void *); static void iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *); static void iwn_notif_intr(struct iwn_softc *); static void iwn_wakeup_intr(struct iwn_softc *); static void iwn_rftoggle_intr(struct iwn_softc *); static void iwn_fatal_intr(struct iwn_softc *); static void iwn_intr(void *); static void iwn4965_update_sched(struct iwn_softc *, int, int, uint8_t, uint16_t); static void iwn5000_update_sched(struct iwn_softc *, int, int, uint8_t, uint16_t); #ifdef notyet static void iwn5000_reset_sched(struct iwn_softc *, int, int); #endif static int iwn_tx_data(struct iwn_softc *, struct mbuf *, struct ieee80211_node *); static int iwn_tx_data_raw(struct iwn_softc *, struct mbuf *, struct ieee80211_node *, const struct ieee80211_bpf_params *params); static int iwn_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static void iwn_start(struct ifnet *); static void iwn_start_locked(struct ifnet *); static void iwn_watchdog(void *); static int iwn_ioctl(struct ifnet *, u_long, caddr_t); static int iwn_cmd(struct iwn_softc *, int, const void *, int, int); static int iwn4965_add_node(struct iwn_softc *, struct iwn_node_info *, int); static int iwn5000_add_node(struct iwn_softc *, struct iwn_node_info *, int); static int iwn_set_link_quality(struct iwn_softc *, struct ieee80211_node *); static int iwn_add_broadcast_node(struct iwn_softc *, int); static int iwn_updateedca(struct ieee80211com *); static void iwn_update_mcast(struct ifnet *); static void iwn_set_led(struct iwn_softc *, uint8_t, uint8_t, uint8_t); static int iwn_set_critical_temp(struct iwn_softc *); static int iwn_set_timing(struct iwn_softc *, struct ieee80211_node *); static void iwn4965_power_calibration(struct iwn_softc *, int); static int iwn4965_set_txpower(struct iwn_softc *, struct ieee80211_channel *, int); static int iwn5000_set_txpower(struct iwn_softc *, struct ieee80211_channel *, int); static int iwn4965_get_rssi(struct iwn_softc *, struct iwn_rx_stat *); static int iwn5000_get_rssi(struct iwn_softc *, struct iwn_rx_stat *); static int iwn_get_noise(const struct iwn_rx_general_stats *); static int iwn4965_get_temperature(struct iwn_softc *); static int iwn5000_get_temperature(struct iwn_softc *); static int iwn_init_sensitivity(struct iwn_softc *); static void iwn_collect_noise(struct iwn_softc *, const struct iwn_rx_general_stats *); static int iwn4965_init_gains(struct iwn_softc *); static int iwn5000_init_gains(struct iwn_softc *); static int iwn4965_set_gains(struct iwn_softc *); static int iwn5000_set_gains(struct iwn_softc *); static void iwn_tune_sensitivity(struct iwn_softc *, const struct iwn_rx_stats *); static void iwn_save_stats_counters(struct iwn_softc *, const struct iwn_stats *); static int iwn_send_sensitivity(struct iwn_softc *); static void iwn_check_rx_recovery(struct iwn_softc *, struct iwn_stats *); static int iwn_set_pslevel(struct iwn_softc *, int, int, int); static int iwn_send_btcoex(struct iwn_softc *); static int iwn_send_advanced_btcoex(struct iwn_softc *); static int iwn5000_runtime_calib(struct iwn_softc *); static int iwn_config(struct iwn_softc *); static int iwn_scan(struct iwn_softc *, struct ieee80211vap *, struct ieee80211_scan_state *, struct ieee80211_channel *); static int iwn_auth(struct iwn_softc *, struct ieee80211vap *vap); static int iwn_run(struct iwn_softc *, struct ieee80211vap *vap); static int iwn_ampdu_rx_start(struct ieee80211_node *, struct ieee80211_rx_ampdu *, int, int, int); static void iwn_ampdu_rx_stop(struct ieee80211_node *, struct ieee80211_rx_ampdu *); static int iwn_addba_request(struct ieee80211_node *, struct ieee80211_tx_ampdu *, int, int, int); static int iwn_addba_response(struct ieee80211_node *, struct ieee80211_tx_ampdu *, int, int, int); static int iwn_ampdu_tx_start(struct ieee80211com *, struct ieee80211_node *, uint8_t); static void iwn_ampdu_tx_stop(struct ieee80211_node *, struct ieee80211_tx_ampdu *); static void iwn4965_ampdu_tx_start(struct iwn_softc *, struct ieee80211_node *, int, uint8_t, uint16_t); static void iwn4965_ampdu_tx_stop(struct iwn_softc *, int, uint8_t, uint16_t); static void iwn5000_ampdu_tx_start(struct iwn_softc *, struct ieee80211_node *, int, uint8_t, uint16_t); static void iwn5000_ampdu_tx_stop(struct iwn_softc *, int, uint8_t, uint16_t); static int iwn5000_query_calibration(struct iwn_softc *); static int iwn5000_send_calibration(struct iwn_softc *); static int iwn5000_send_wimax_coex(struct iwn_softc *); static int iwn5000_crystal_calib(struct iwn_softc *); static int iwn5000_temp_offset_calib(struct iwn_softc *); static int iwn5000_temp_offset_calibv2(struct iwn_softc *); static int iwn4965_post_alive(struct iwn_softc *); static int iwn5000_post_alive(struct iwn_softc *); static int iwn4965_load_bootcode(struct iwn_softc *, const uint8_t *, int); static int iwn4965_load_firmware(struct iwn_softc *); static int iwn5000_load_firmware_section(struct iwn_softc *, uint32_t, const uint8_t *, int); static int iwn5000_load_firmware(struct iwn_softc *); static int iwn_read_firmware_leg(struct iwn_softc *, struct iwn_fw_info *); static int iwn_read_firmware_tlv(struct iwn_softc *, struct iwn_fw_info *, uint16_t); static int iwn_read_firmware(struct iwn_softc *); static int iwn_clock_wait(struct iwn_softc *); static int iwn_apm_init(struct iwn_softc *); static void iwn_apm_stop_master(struct iwn_softc *); static void iwn_apm_stop(struct iwn_softc *); static int iwn4965_nic_config(struct iwn_softc *); static int iwn5000_nic_config(struct iwn_softc *); static int iwn_hw_prepare(struct iwn_softc *); static int iwn_hw_init(struct iwn_softc *); static void iwn_hw_stop(struct iwn_softc *); static void iwn_radio_on(void *, int); static void iwn_radio_off(void *, int); static void iwn_panicked(void *, int); static void iwn_init_locked(struct iwn_softc *); static void iwn_init(void *); static void iwn_stop_locked(struct iwn_softc *); static void iwn_stop(struct iwn_softc *); static void iwn_scan_start(struct ieee80211com *); static void iwn_scan_end(struct ieee80211com *); static void iwn_set_channel(struct ieee80211com *); static void iwn_scan_curchan(struct ieee80211_scan_state *, unsigned long); static void iwn_scan_mindwell(struct ieee80211_scan_state *); static void iwn_hw_reset(void *, int); #ifdef IWN_DEBUG static char *iwn_get_csr_string(int); static void iwn_debug_register(struct iwn_softc *); #endif static device_method_t iwn_methods[] = { /* Device interface */ DEVMETHOD(device_probe, iwn_probe), DEVMETHOD(device_attach, iwn_attach), DEVMETHOD(device_detach, iwn_detach), DEVMETHOD(device_shutdown, iwn_shutdown), DEVMETHOD(device_suspend, iwn_suspend), DEVMETHOD(device_resume, iwn_resume), DEVMETHOD_END }; static driver_t iwn_driver = { "iwn", iwn_methods, sizeof(struct iwn_softc) }; static devclass_t iwn_devclass; DRIVER_MODULE(iwn, pci, iwn_driver, iwn_devclass, NULL, NULL); MODULE_VERSION(iwn, 1); MODULE_DEPEND(iwn, firmware, 1, 1, 1); MODULE_DEPEND(iwn, pci, 1, 1, 1); MODULE_DEPEND(iwn, wlan, 1, 1, 1); static int iwn_probe(device_t dev) { const struct iwn_ident *ident; for (ident = iwn_ident_table; ident->name != NULL; ident++) { if (pci_get_vendor(dev) == ident->vendor && pci_get_device(dev) == ident->device) { device_set_desc(dev, ident->name); return (BUS_PROBE_DEFAULT); } } return ENXIO; } static int iwn_is_3stream_device(struct iwn_softc *sc) { /* XXX for now only 5300, until the 5350 can be tested */ if (sc->hw_type == IWN_HW_REV_TYPE_5300) return (1); return (0); } static int iwn_attach(device_t dev) { struct iwn_softc *sc = (struct iwn_softc *)device_get_softc(dev); struct ieee80211com *ic; struct ifnet *ifp; int i, error, rid; uint8_t macaddr[IEEE80211_ADDR_LEN]; sc->sc_dev = dev; #ifdef IWN_DEBUG error = resource_int_value(device_get_name(sc->sc_dev), device_get_unit(sc->sc_dev), "debug", &(sc->sc_debug)); if (error != 0) sc->sc_debug = 0; #else sc->sc_debug = 0; #endif DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: begin\n",__func__); /* * Get the offset of the PCI Express Capability Structure in PCI * Configuration Space. */ error = pci_find_cap(dev, PCIY_EXPRESS, &sc->sc_cap_off); if (error != 0) { device_printf(dev, "PCIe capability structure not found!\n"); return error; } /* Clear device-specific "PCI retry timeout" register (41h). */ pci_write_config(dev, 0x41, 0, 1); /* Enable bus-mastering. */ pci_enable_busmaster(dev); rid = PCIR_BAR(0); sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem == NULL) { device_printf(dev, "can't map mem space\n"); error = ENOMEM; return error; } sc->sc_st = rman_get_bustag(sc->mem); sc->sc_sh = rman_get_bushandle(sc->mem); i = 1; rid = 0; if (pci_alloc_msi(dev, &i) == 0) rid = 1; /* Install interrupt handler. */ sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | (rid != 0 ? 0 : RF_SHAREABLE)); if (sc->irq == NULL) { device_printf(dev, "can't map interrupt\n"); error = ENOMEM; goto fail; } IWN_LOCK_INIT(sc); /* Read hardware revision and attach. */ sc->hw_type = (IWN_READ(sc, IWN_HW_REV) >> IWN_HW_REV_TYPE_SHIFT) & IWN_HW_REV_TYPE_MASK; sc->subdevice_id = pci_get_subdevice(dev); /* * 4965 versus 5000 and later have different methods. * Let's set those up first. */ if (sc->hw_type == IWN_HW_REV_TYPE_4965) error = iwn4965_attach(sc, pci_get_device(dev)); else error = iwn5000_attach(sc, pci_get_device(dev)); if (error != 0) { device_printf(dev, "could not attach device, error %d\n", error); goto fail; } /* * Next, let's setup the various parameters of each NIC. */ error = iwn_config_specific(sc, pci_get_device(dev)); if (error != 0) { device_printf(dev, "could not attach device, error %d\n", error); goto fail; } if ((error = iwn_hw_prepare(sc)) != 0) { device_printf(dev, "hardware not ready, error %d\n", error); goto fail; } /* Allocate DMA memory for firmware transfers. */ if ((error = iwn_alloc_fwmem(sc)) != 0) { device_printf(dev, "could not allocate memory for firmware, error %d\n", error); goto fail; } /* Allocate "Keep Warm" page. */ if ((error = iwn_alloc_kw(sc)) != 0) { device_printf(dev, "could not allocate keep warm page, error %d\n", error); goto fail; } /* Allocate ICT table for 5000 Series. */ if (sc->hw_type != IWN_HW_REV_TYPE_4965 && (error = iwn_alloc_ict(sc)) != 0) { device_printf(dev, "could not allocate ICT table, error %d\n", error); goto fail; } /* Allocate TX scheduler "rings". */ if ((error = iwn_alloc_sched(sc)) != 0) { device_printf(dev, "could not allocate TX scheduler rings, error %d\n", error); goto fail; } /* Allocate TX rings (16 on 4965AGN, 20 on >=5000). */ for (i = 0; i < sc->ntxqs; i++) { if ((error = iwn_alloc_tx_ring(sc, &sc->txq[i], i)) != 0) { device_printf(dev, "could not allocate TX ring %d, error %d\n", i, error); goto fail; } } /* Allocate RX ring. */ if ((error = iwn_alloc_rx_ring(sc, &sc->rxq)) != 0) { device_printf(dev, "could not allocate RX ring, error %d\n", error); goto fail; } /* Clear pending interrupts. */ IWN_WRITE(sc, IWN_INT, 0xffffffff); ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); if (ifp == NULL) { device_printf(dev, "can not allocate ifnet structure\n"); goto fail; } ic = ifp->if_l2com; ic->ic_ifp = ifp; ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ /* Set device capabilities. */ ic->ic_caps = IEEE80211_C_STA /* station mode supported */ | IEEE80211_C_MONITOR /* monitor mode supported */ | IEEE80211_C_BGSCAN /* background scanning */ | IEEE80211_C_TXPMGT /* tx power management */ | IEEE80211_C_SHSLOT /* short slot time supported */ | IEEE80211_C_WPA | IEEE80211_C_SHPREAMBLE /* short preamble supported */ #if 0 | IEEE80211_C_IBSS /* ibss/adhoc mode */ #endif | IEEE80211_C_WME /* WME */ | IEEE80211_C_PMGT /* Station-side power mgmt */ ; /* Read MAC address, channels, etc from EEPROM. */ if ((error = iwn_read_eeprom(sc, macaddr)) != 0) { device_printf(dev, "could not read EEPROM, error %d\n", error); goto fail; } /* Count the number of available chains. */ sc->ntxchains = ((sc->txchainmask >> 2) & 1) + ((sc->txchainmask >> 1) & 1) + ((sc->txchainmask >> 0) & 1); sc->nrxchains = ((sc->rxchainmask >> 2) & 1) + ((sc->rxchainmask >> 1) & 1) + ((sc->rxchainmask >> 0) & 1); if (bootverbose) { device_printf(dev, "MIMO %dT%dR, %.4s, address %6D\n", sc->ntxchains, sc->nrxchains, sc->eeprom_domain, macaddr, ":"); } if (sc->sc_flags & IWN_FLAG_HAS_11N) { ic->ic_rxstream = sc->nrxchains; ic->ic_txstream = sc->ntxchains; /* * Some of the 3 antenna devices (ie, the 4965) only supports * 2x2 operation. So correct the number of streams if * it's not a 3-stream device. */ if (! iwn_is_3stream_device(sc)) { if (ic->ic_rxstream > 2) ic->ic_rxstream = 2; if (ic->ic_txstream > 2) ic->ic_txstream = 2; } ic->ic_htcaps = IEEE80211_HTCAP_SMPS_OFF /* SMPS mode disabled */ | IEEE80211_HTCAP_SHORTGI20 /* short GI in 20MHz */ | IEEE80211_HTCAP_CHWIDTH40 /* 40MHz channel width*/ | IEEE80211_HTCAP_SHORTGI40 /* short GI in 40MHz */ #ifdef notyet | IEEE80211_HTCAP_GREENFIELD #if IWN_RBUF_SIZE == 8192 | IEEE80211_HTCAP_MAXAMSDU_7935 /* max A-MSDU length */ #else | IEEE80211_HTCAP_MAXAMSDU_3839 /* max A-MSDU length */ #endif #endif /* s/w capabilities */ | IEEE80211_HTC_HT /* HT operation */ | IEEE80211_HTC_AMPDU /* tx A-MPDU */ #ifdef notyet | IEEE80211_HTC_AMSDU /* tx A-MSDU */ #endif ; } if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_init = iwn_init; ifp->if_ioctl = iwn_ioctl; ifp->if_start = iwn_start; IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; IFQ_SET_READY(&ifp->if_snd); ieee80211_ifattach(ic, macaddr); ic->ic_vap_create = iwn_vap_create; ic->ic_vap_delete = iwn_vap_delete; ic->ic_raw_xmit = iwn_raw_xmit; ic->ic_node_alloc = iwn_node_alloc; sc->sc_ampdu_rx_start = ic->ic_ampdu_rx_start; ic->ic_ampdu_rx_start = iwn_ampdu_rx_start; sc->sc_ampdu_rx_stop = ic->ic_ampdu_rx_stop; ic->ic_ampdu_rx_stop = iwn_ampdu_rx_stop; sc->sc_addba_request = ic->ic_addba_request; ic->ic_addba_request = iwn_addba_request; sc->sc_addba_response = ic->ic_addba_response; ic->ic_addba_response = iwn_addba_response; sc->sc_addba_stop = ic->ic_addba_stop; ic->ic_addba_stop = iwn_ampdu_tx_stop; ic->ic_newassoc = iwn_newassoc; ic->ic_wme.wme_update = iwn_updateedca; ic->ic_update_mcast = iwn_update_mcast; ic->ic_scan_start = iwn_scan_start; ic->ic_scan_end = iwn_scan_end; ic->ic_set_channel = iwn_set_channel; ic->ic_scan_curchan = iwn_scan_curchan; ic->ic_scan_mindwell = iwn_scan_mindwell; ic->ic_setregdomain = iwn_setregdomain; iwn_radiotap_attach(sc); callout_init_mtx(&sc->calib_to, &sc->sc_mtx, 0); callout_init_mtx(&sc->watchdog_to, &sc->sc_mtx, 0); TASK_INIT(&sc->sc_reinit_task, 0, iwn_hw_reset, sc); TASK_INIT(&sc->sc_radioon_task, 0, iwn_radio_on, sc); TASK_INIT(&sc->sc_radiooff_task, 0, iwn_radio_off, sc); TASK_INIT(&sc->sc_panic_task, 0, iwn_panicked, sc); sc->sc_tq = taskqueue_create("iwn_taskq", M_WAITOK, taskqueue_thread_enqueue, &sc->sc_tq); error = taskqueue_start_threads(&sc->sc_tq, 1, 0, "iwn_taskq"); if (error != 0) { device_printf(dev, "can't start threads, error %d\n", error); goto fail; } iwn_sysctlattach(sc); /* * Hook our interrupt after all initialization is complete. */ error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, iwn_intr, sc, &sc->sc_ih); if (error != 0) { device_printf(dev, "can't establish interrupt, error %d\n", error); goto fail; } #if 0 device_printf(sc->sc_dev, "%s: rx_stats=%d, rx_stats_bt=%d\n", __func__, sizeof(struct iwn_stats), sizeof(struct iwn_stats_bt)); #endif if (bootverbose) ieee80211_announce(ic); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return 0; fail: iwn_detach(dev); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end in error\n",__func__); return error; } /* * Define specific configuration based on device id and subdevice id * pid : PCI device id */ static int iwn_config_specific(struct iwn_softc *sc, uint16_t pid) { switch (pid) { /* 4965 series */ case IWN_DID_4965_1: case IWN_DID_4965_2: case IWN_DID_4965_3: case IWN_DID_4965_4: sc->base_params = &iwn4965_base_params; sc->limits = &iwn4965_sensitivity_limits; sc->fwname = "iwn4965fw"; /* Override chains masks, ROM is known to be broken. */ sc->txchainmask = IWN_ANT_AB; sc->rxchainmask = IWN_ANT_ABC; /* Enable normal btcoex */ sc->sc_flags |= IWN_FLAG_BTCOEX; break; /* 1000 Series */ case IWN_DID_1000_1: case IWN_DID_1000_2: switch(sc->subdevice_id) { case IWN_SDID_1000_1: case IWN_SDID_1000_2: case IWN_SDID_1000_3: case IWN_SDID_1000_4: case IWN_SDID_1000_5: case IWN_SDID_1000_6: case IWN_SDID_1000_7: case IWN_SDID_1000_8: case IWN_SDID_1000_9: case IWN_SDID_1000_10: case IWN_SDID_1000_11: case IWN_SDID_1000_12: sc->limits = &iwn1000_sensitivity_limits; sc->base_params = &iwn1000_base_params; sc->fwname = "iwn1000fw"; break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" "0x%04x rev %d not supported (subdevice)\n", pid, sc->subdevice_id,sc->hw_type); return ENOTSUP; } break; /* 6x00 Series */ case IWN_DID_6x00_2: case IWN_DID_6x00_4: case IWN_DID_6x00_1: case IWN_DID_6x00_3: sc->fwname = "iwn6000fw"; sc->limits = &iwn6000_sensitivity_limits; switch(sc->subdevice_id) { case IWN_SDID_6x00_1: case IWN_SDID_6x00_2: case IWN_SDID_6x00_8: //iwl6000_3agn_cfg sc->base_params = &iwn_6000_base_params; break; case IWN_SDID_6x00_3: case IWN_SDID_6x00_6: case IWN_SDID_6x00_9: ////iwl6000i_2agn case IWN_SDID_6x00_4: case IWN_SDID_6x00_7: case IWN_SDID_6x00_10: //iwl6000i_2abg_cfg case IWN_SDID_6x00_5: //iwl6000i_2bg_cfg sc->base_params = &iwn_6000i_base_params; sc->sc_flags |= IWN_FLAG_INTERNAL_PA; sc->txchainmask = IWN_ANT_BC; sc->rxchainmask = IWN_ANT_BC; break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" "0x%04x rev %d not supported (subdevice)\n", pid, sc->subdevice_id,sc->hw_type); return ENOTSUP; } break; /* 6x05 Series */ case IWN_DID_6x05_1: case IWN_DID_6x05_2: switch(sc->subdevice_id) { case IWN_SDID_6x05_1: case IWN_SDID_6x05_4: case IWN_SDID_6x05_6: //iwl6005_2agn_cfg case IWN_SDID_6x05_2: case IWN_SDID_6x05_5: case IWN_SDID_6x05_7: //iwl6005_2abg_cfg case IWN_SDID_6x05_3: //iwl6005_2bg_cfg case IWN_SDID_6x05_8: case IWN_SDID_6x05_9: //iwl6005_2agn_sff_cfg case IWN_SDID_6x05_10: //iwl6005_2agn_d_cfg case IWN_SDID_6x05_11: //iwl6005_2agn_mow1_cfg case IWN_SDID_6x05_12: //iwl6005_2agn_mow2_cfg sc->fwname = "iwn6000g2afw"; sc->limits = &iwn6000_sensitivity_limits; sc->base_params = &iwn_6000g2_base_params; break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" "0x%04x rev %d not supported (subdevice)\n", pid, sc->subdevice_id,sc->hw_type); return ENOTSUP; } break; /* 6x35 Series */ case IWN_DID_6035_1: case IWN_DID_6035_2: switch(sc->subdevice_id) { case IWN_SDID_6035_1: case IWN_SDID_6035_2: case IWN_SDID_6035_3: case IWN_SDID_6035_4: sc->fwname = "iwn6000g2bfw"; sc->limits = &iwn6235_sensitivity_limits; sc->base_params = &iwn_6235_base_params; break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" "0x%04x rev %d not supported (subdevice)\n", pid, sc->subdevice_id,sc->hw_type); return ENOTSUP; } break; /* 6x50 WiFi/WiMax Series */ case IWN_DID_6050_1: case IWN_DID_6050_2: switch(sc->subdevice_id) { case IWN_SDID_6050_1: case IWN_SDID_6050_3: case IWN_SDID_6050_5: //iwl6050_2agn_cfg case IWN_SDID_6050_2: case IWN_SDID_6050_4: case IWN_SDID_6050_6: //iwl6050_2abg_cfg sc->fwname = "iwn6050fw"; sc->txchainmask = IWN_ANT_AB; sc->rxchainmask = IWN_ANT_AB; sc->limits = &iwn6000_sensitivity_limits; sc->base_params = &iwn_6050_base_params; break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" "0x%04x rev %d not supported (subdevice)\n", pid, sc->subdevice_id,sc->hw_type); return ENOTSUP; } break; /* 6150 WiFi/WiMax Series */ case IWN_DID_6150_1: case IWN_DID_6150_2: switch(sc->subdevice_id) { case IWN_SDID_6150_1: case IWN_SDID_6150_3: case IWN_SDID_6150_5: // iwl6150_bgn_cfg case IWN_SDID_6150_2: case IWN_SDID_6150_4: case IWN_SDID_6150_6: //iwl6150_bg_cfg sc->fwname = "iwn6050fw"; sc->limits = &iwn6000_sensitivity_limits; sc->base_params = &iwn_6150_base_params; break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" "0x%04x rev %d not supported (subdevice)\n", pid, sc->subdevice_id,sc->hw_type); return ENOTSUP; } break; /* 6030 Series and 1030 Series */ case IWN_DID_x030_1: case IWN_DID_x030_2: case IWN_DID_x030_3: case IWN_DID_x030_4: switch(sc->subdevice_id) { case IWN_SDID_x030_1: case IWN_SDID_x030_3: case IWN_SDID_x030_5: // iwl1030_bgn_cfg case IWN_SDID_x030_2: case IWN_SDID_x030_4: case IWN_SDID_x030_6: //iwl1030_bg_cfg case IWN_SDID_x030_7: case IWN_SDID_x030_10: case IWN_SDID_x030_14: //iwl6030_2agn_cfg case IWN_SDID_x030_8: case IWN_SDID_x030_11: case IWN_SDID_x030_15: // iwl6030_2bgn_cfg case IWN_SDID_x030_9: case IWN_SDID_x030_12: case IWN_SDID_x030_16: // iwl6030_2abg_cfg case IWN_SDID_x030_13: //iwl6030_2bg_cfg sc->fwname = "iwn6000g2bfw"; sc->limits = &iwn6000_sensitivity_limits; sc->base_params = &iwn_6000g2b_base_params; break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" "0x%04x rev %d not supported (subdevice)\n", pid, sc->subdevice_id,sc->hw_type); return ENOTSUP; } break; /* 130 Series WiFi */ /* XXX: This series will need adjustment for rate. * see rx_with_siso_diversity in linux kernel */ case IWN_DID_130_1: case IWN_DID_130_2: switch(sc->subdevice_id) { case IWN_SDID_130_1: case IWN_SDID_130_3: case IWN_SDID_130_5: //iwl130_bgn_cfg case IWN_SDID_130_2: case IWN_SDID_130_4: case IWN_SDID_130_6: //iwl130_bg_cfg sc->fwname = "iwn6000g2bfw"; sc->limits = &iwn6000_sensitivity_limits; sc->base_params = &iwn_6000g2b_base_params; break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" "0x%04x rev %d not supported (subdevice)\n", pid, sc->subdevice_id,sc->hw_type); return ENOTSUP; } break; /* 100 Series WiFi */ case IWN_DID_100_1: case IWN_DID_100_2: switch(sc->subdevice_id) { case IWN_SDID_100_1: case IWN_SDID_100_2: case IWN_SDID_100_3: case IWN_SDID_100_4: case IWN_SDID_100_5: case IWN_SDID_100_6: sc->limits = &iwn1000_sensitivity_limits; sc->base_params = &iwn1000_base_params; sc->fwname = "iwn100fw"; break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" "0x%04x rev %d not supported (subdevice)\n", pid, sc->subdevice_id,sc->hw_type); return ENOTSUP; } break; /* 105 Series */ /* XXX: This series will need adjustment for rate. * see rx_with_siso_diversity in linux kernel */ case IWN_DID_105_1: case IWN_DID_105_2: switch(sc->subdevice_id) { case IWN_SDID_105_1: case IWN_SDID_105_2: case IWN_SDID_105_3: //iwl105_bgn_cfg case IWN_SDID_105_4: //iwl105_bgn_d_cfg sc->limits = &iwn2030_sensitivity_limits; sc->base_params = &iwn2000_base_params; sc->fwname = "iwn105fw"; break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" "0x%04x rev %d not supported (subdevice)\n", pid, sc->subdevice_id,sc->hw_type); return ENOTSUP; } break; /* 135 Series */ /* XXX: This series will need adjustment for rate. * see rx_with_siso_diversity in linux kernel */ case IWN_DID_135_1: case IWN_DID_135_2: switch(sc->subdevice_id) { case IWN_SDID_135_1: case IWN_SDID_135_2: case IWN_SDID_135_3: sc->limits = &iwn2030_sensitivity_limits; sc->base_params = &iwn2030_base_params; sc->fwname = "iwn135fw"; break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" "0x%04x rev %d not supported (subdevice)\n", pid, sc->subdevice_id,sc->hw_type); return ENOTSUP; } break; /* 2x00 Series */ case IWN_DID_2x00_1: case IWN_DID_2x00_2: switch(sc->subdevice_id) { case IWN_SDID_2x00_1: case IWN_SDID_2x00_2: case IWN_SDID_2x00_3: //iwl2000_2bgn_cfg case IWN_SDID_2x00_4: //iwl2000_2bgn_d_cfg sc->limits = &iwn2030_sensitivity_limits; sc->base_params = &iwn2000_base_params; sc->fwname = "iwn2000fw"; break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" "0x%04x rev %d not supported (subdevice) \n", pid, sc->subdevice_id, sc->hw_type); return ENOTSUP; } break; /* 2x30 Series */ case IWN_DID_2x30_1: case IWN_DID_2x30_2: switch(sc->subdevice_id) { case IWN_SDID_2x30_1: case IWN_SDID_2x30_3: case IWN_SDID_2x30_5: //iwl100_bgn_cfg case IWN_SDID_2x30_2: case IWN_SDID_2x30_4: case IWN_SDID_2x30_6: //iwl100_bg_cfg sc->limits = &iwn2030_sensitivity_limits; sc->base_params = &iwn2030_base_params; sc->fwname = "iwn2030fw"; break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" "0x%04x rev %d not supported (subdevice)\n", pid, sc->subdevice_id,sc->hw_type); return ENOTSUP; } break; /* 5x00 Series */ case IWN_DID_5x00_1: case IWN_DID_5x00_2: case IWN_DID_5x00_3: case IWN_DID_5x00_4: sc->limits = &iwn5000_sensitivity_limits; sc->base_params = &iwn5000_base_params; sc->fwname = "iwn5000fw"; switch(sc->subdevice_id) { case IWN_SDID_5x00_1: case IWN_SDID_5x00_2: case IWN_SDID_5x00_3: case IWN_SDID_5x00_4: case IWN_SDID_5x00_9: case IWN_SDID_5x00_10: case IWN_SDID_5x00_11: case IWN_SDID_5x00_12: case IWN_SDID_5x00_17: case IWN_SDID_5x00_18: case IWN_SDID_5x00_19: case IWN_SDID_5x00_20: //iwl5100_agn_cfg sc->txchainmask = IWN_ANT_B; sc->rxchainmask = IWN_ANT_AB; break; case IWN_SDID_5x00_5: case IWN_SDID_5x00_6: case IWN_SDID_5x00_13: case IWN_SDID_5x00_14: case IWN_SDID_5x00_21: case IWN_SDID_5x00_22: //iwl5100_bgn_cfg sc->txchainmask = IWN_ANT_B; sc->rxchainmask = IWN_ANT_AB; break; case IWN_SDID_5x00_7: case IWN_SDID_5x00_8: case IWN_SDID_5x00_15: case IWN_SDID_5x00_16: case IWN_SDID_5x00_23: case IWN_SDID_5x00_24: //iwl5100_abg_cfg sc->txchainmask = IWN_ANT_B; sc->rxchainmask = IWN_ANT_AB; break; case IWN_SDID_5x00_25: case IWN_SDID_5x00_26: case IWN_SDID_5x00_27: case IWN_SDID_5x00_28: case IWN_SDID_5x00_29: case IWN_SDID_5x00_30: case IWN_SDID_5x00_31: case IWN_SDID_5x00_32: case IWN_SDID_5x00_33: case IWN_SDID_5x00_34: case IWN_SDID_5x00_35: case IWN_SDID_5x00_36: //iwl5300_agn_cfg sc->txchainmask = IWN_ANT_ABC; sc->rxchainmask = IWN_ANT_ABC; break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" "0x%04x rev %d not supported (subdevice)\n", pid, sc->subdevice_id,sc->hw_type); return ENOTSUP; } break; /* 5x50 Series */ case IWN_DID_5x50_1: case IWN_DID_5x50_2: case IWN_DID_5x50_3: case IWN_DID_5x50_4: sc->limits = &iwn5000_sensitivity_limits; sc->base_params = &iwn5000_base_params; sc->fwname = "iwn5000fw"; switch(sc->subdevice_id) { case IWN_SDID_5x50_1: case IWN_SDID_5x50_2: case IWN_SDID_5x50_3: //iwl5350_agn_cfg sc->limits = &iwn5000_sensitivity_limits; sc->base_params = &iwn5000_base_params; sc->fwname = "iwn5000fw"; break; case IWN_SDID_5x50_4: case IWN_SDID_5x50_5: case IWN_SDID_5x50_8: case IWN_SDID_5x50_9: case IWN_SDID_5x50_10: case IWN_SDID_5x50_11: //iwl5150_agn_cfg case IWN_SDID_5x50_6: case IWN_SDID_5x50_7: case IWN_SDID_5x50_12: case IWN_SDID_5x50_13: //iwl5150_abg_cfg sc->limits = &iwn5000_sensitivity_limits; sc->fwname = "iwn5150fw"; sc->base_params = &iwn_5x50_base_params; break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :" "0x%04x rev %d not supported (subdevice)\n", pid, sc->subdevice_id,sc->hw_type); return ENOTSUP; } break; default: device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id : 0x%04x" "rev 0x%08x not supported (device)\n", pid, sc->subdevice_id, sc->hw_type); return ENOTSUP; } return 0; } static int iwn4965_attach(struct iwn_softc *sc, uint16_t pid) { struct iwn_ops *ops = &sc->ops; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); ops->load_firmware = iwn4965_load_firmware; ops->read_eeprom = iwn4965_read_eeprom; ops->post_alive = iwn4965_post_alive; ops->nic_config = iwn4965_nic_config; ops->update_sched = iwn4965_update_sched; ops->get_temperature = iwn4965_get_temperature; ops->get_rssi = iwn4965_get_rssi; ops->set_txpower = iwn4965_set_txpower; ops->init_gains = iwn4965_init_gains; ops->set_gains = iwn4965_set_gains; ops->add_node = iwn4965_add_node; ops->tx_done = iwn4965_tx_done; ops->ampdu_tx_start = iwn4965_ampdu_tx_start; ops->ampdu_tx_stop = iwn4965_ampdu_tx_stop; sc->ntxqs = IWN4965_NTXQUEUES; sc->firstaggqueue = IWN4965_FIRSTAGGQUEUE; sc->ndmachnls = IWN4965_NDMACHNLS; sc->broadcast_id = IWN4965_ID_BROADCAST; sc->rxonsz = IWN4965_RXONSZ; sc->schedsz = IWN4965_SCHEDSZ; sc->fw_text_maxsz = IWN4965_FW_TEXT_MAXSZ; sc->fw_data_maxsz = IWN4965_FW_DATA_MAXSZ; sc->fwsz = IWN4965_FWSZ; sc->sched_txfact_addr = IWN4965_SCHED_TXFACT; sc->limits = &iwn4965_sensitivity_limits; sc->fwname = "iwn4965fw"; /* Override chains masks, ROM is known to be broken. */ sc->txchainmask = IWN_ANT_AB; sc->rxchainmask = IWN_ANT_ABC; /* Enable normal btcoex */ sc->sc_flags |= IWN_FLAG_BTCOEX; DPRINTF(sc, IWN_DEBUG_TRACE, "%s: end\n",__func__); return 0; } static int iwn5000_attach(struct iwn_softc *sc, uint16_t pid) { struct iwn_ops *ops = &sc->ops; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); ops->load_firmware = iwn5000_load_firmware; ops->read_eeprom = iwn5000_read_eeprom; ops->post_alive = iwn5000_post_alive; ops->nic_config = iwn5000_nic_config; ops->update_sched = iwn5000_update_sched; ops->get_temperature = iwn5000_get_temperature; ops->get_rssi = iwn5000_get_rssi; ops->set_txpower = iwn5000_set_txpower; ops->init_gains = iwn5000_init_gains; ops->set_gains = iwn5000_set_gains; ops->add_node = iwn5000_add_node; ops->tx_done = iwn5000_tx_done; ops->ampdu_tx_start = iwn5000_ampdu_tx_start; ops->ampdu_tx_stop = iwn5000_ampdu_tx_stop; sc->ntxqs = IWN5000_NTXQUEUES; sc->firstaggqueue = IWN5000_FIRSTAGGQUEUE; sc->ndmachnls = IWN5000_NDMACHNLS; sc->broadcast_id = IWN5000_ID_BROADCAST; sc->rxonsz = IWN5000_RXONSZ; sc->schedsz = IWN5000_SCHEDSZ; sc->fw_text_maxsz = IWN5000_FW_TEXT_MAXSZ; sc->fw_data_maxsz = IWN5000_FW_DATA_MAXSZ; sc->fwsz = IWN5000_FWSZ; sc->sched_txfact_addr = IWN5000_SCHED_TXFACT; sc->reset_noise_gain = IWN5000_PHY_CALIB_RESET_NOISE_GAIN; sc->noise_gain = IWN5000_PHY_CALIB_NOISE_GAIN; return 0; } /* * Attach the interface to 802.11 radiotap. */ static void iwn_radiotap_attach(struct iwn_softc *sc) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), IWN_TX_RADIOTAP_PRESENT, &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), IWN_RX_RADIOTAP_PRESENT); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); } static void iwn_sysctlattach(struct iwn_softc *sc) { #ifdef IWN_DEBUG struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "debug", CTLFLAG_RW, &sc->sc_debug, sc->sc_debug, "control debugging printfs"); #endif } static struct ieee80211vap * iwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, enum ieee80211_opmode opmode, int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { struct iwn_vap *ivp; struct ieee80211vap *vap; uint8_t mac1[IEEE80211_ADDR_LEN]; struct iwn_softc *sc = ic->ic_ifp->if_softc; if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ return NULL; IEEE80211_ADDR_COPY(mac1, mac); ivp = (struct iwn_vap *) malloc(sizeof(struct iwn_vap), M_80211_VAP, M_NOWAIT | M_ZERO); if (ivp == NULL) return NULL; vap = &ivp->iv_vap; ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac1); ivp->ctx = IWN_RXON_BSS_CTX; IEEE80211_ADDR_COPY(ivp->macaddr, mac1); vap->iv_bmissthreshold = 10; /* override default */ /* Override with driver methods. */ ivp->iv_newstate = vap->iv_newstate; vap->iv_newstate = iwn_newstate; sc->ivap[IWN_RXON_BSS_CTX] = vap; ieee80211_ratectl_init(vap); /* Complete setup. */ ieee80211_vap_attach(vap, iwn_media_change, ieee80211_media_status); ic->ic_opmode = opmode; return vap; } static void iwn_vap_delete(struct ieee80211vap *vap) { struct iwn_vap *ivp = IWN_VAP(vap); ieee80211_ratectl_deinit(vap); ieee80211_vap_detach(vap); free(ivp, M_80211_VAP); } static int iwn_detach(device_t dev) { struct iwn_softc *sc = device_get_softc(dev); struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic; int qid; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); if (ifp != NULL) { ic = ifp->if_l2com; ieee80211_draintask(ic, &sc->sc_reinit_task); ieee80211_draintask(ic, &sc->sc_radioon_task); ieee80211_draintask(ic, &sc->sc_radiooff_task); iwn_stop(sc); taskqueue_drain_all(sc->sc_tq); taskqueue_free(sc->sc_tq); callout_drain(&sc->watchdog_to); callout_drain(&sc->calib_to); ieee80211_ifdetach(ic); } /* Uninstall interrupt handler. */ if (sc->irq != NULL) { bus_teardown_intr(dev, sc->irq, sc->sc_ih); bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq), sc->irq); pci_release_msi(dev); } /* Free DMA resources. */ iwn_free_rx_ring(sc, &sc->rxq); for (qid = 0; qid < sc->ntxqs; qid++) iwn_free_tx_ring(sc, &sc->txq[qid]); iwn_free_sched(sc); iwn_free_kw(sc); if (sc->ict != NULL) iwn_free_ict(sc); iwn_free_fwmem(sc); if (sc->mem != NULL) bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem), sc->mem); if (ifp != NULL) if_free(ifp); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n", __func__); IWN_LOCK_DESTROY(sc); return 0; } static int iwn_shutdown(device_t dev) { struct iwn_softc *sc = device_get_softc(dev); iwn_stop(sc); return 0; } static int iwn_suspend(device_t dev) { struct iwn_softc *sc = device_get_softc(dev); struct ieee80211com *ic = sc->sc_ifp->if_l2com; ieee80211_suspend_all(ic); return 0; } static int iwn_resume(device_t dev) { struct iwn_softc *sc = device_get_softc(dev); struct ieee80211com *ic = sc->sc_ifp->if_l2com; /* Clear device-specific "PCI retry timeout" register (41h). */ pci_write_config(dev, 0x41, 0, 1); ieee80211_resume_all(ic); return 0; } static int iwn_nic_lock(struct iwn_softc *sc) { int ntries; /* Request exclusive access to NIC. */ IWN_SETBITS(sc, IWN_GP_CNTRL, IWN_GP_CNTRL_MAC_ACCESS_REQ); /* Spin until we actually get the lock. */ for (ntries = 0; ntries < 1000; ntries++) { if ((IWN_READ(sc, IWN_GP_CNTRL) & (IWN_GP_CNTRL_MAC_ACCESS_ENA | IWN_GP_CNTRL_SLEEP)) == IWN_GP_CNTRL_MAC_ACCESS_ENA) return 0; DELAY(10); } return ETIMEDOUT; } static __inline void iwn_nic_unlock(struct iwn_softc *sc) { IWN_CLRBITS(sc, IWN_GP_CNTRL, IWN_GP_CNTRL_MAC_ACCESS_REQ); } static __inline uint32_t iwn_prph_read(struct iwn_softc *sc, uint32_t addr) { IWN_WRITE(sc, IWN_PRPH_RADDR, IWN_PRPH_DWORD | addr); IWN_BARRIER_READ_WRITE(sc); return IWN_READ(sc, IWN_PRPH_RDATA); } static __inline void iwn_prph_write(struct iwn_softc *sc, uint32_t addr, uint32_t data) { IWN_WRITE(sc, IWN_PRPH_WADDR, IWN_PRPH_DWORD | addr); IWN_BARRIER_WRITE(sc); IWN_WRITE(sc, IWN_PRPH_WDATA, data); } static __inline void iwn_prph_setbits(struct iwn_softc *sc, uint32_t addr, uint32_t mask) { iwn_prph_write(sc, addr, iwn_prph_read(sc, addr) | mask); } static __inline void iwn_prph_clrbits(struct iwn_softc *sc, uint32_t addr, uint32_t mask) { iwn_prph_write(sc, addr, iwn_prph_read(sc, addr) & ~mask); } static __inline void iwn_prph_write_region_4(struct iwn_softc *sc, uint32_t addr, const uint32_t *data, int count) { for (; count > 0; count--, data++, addr += 4) iwn_prph_write(sc, addr, *data); } static __inline uint32_t iwn_mem_read(struct iwn_softc *sc, uint32_t addr) { IWN_WRITE(sc, IWN_MEM_RADDR, addr); IWN_BARRIER_READ_WRITE(sc); return IWN_READ(sc, IWN_MEM_RDATA); } static __inline void iwn_mem_write(struct iwn_softc *sc, uint32_t addr, uint32_t data) { IWN_WRITE(sc, IWN_MEM_WADDR, addr); IWN_BARRIER_WRITE(sc); IWN_WRITE(sc, IWN_MEM_WDATA, data); } static __inline void iwn_mem_write_2(struct iwn_softc *sc, uint32_t addr, uint16_t data) { uint32_t tmp; tmp = iwn_mem_read(sc, addr & ~3); if (addr & 3) tmp = (tmp & 0x0000ffff) | data << 16; else tmp = (tmp & 0xffff0000) | data; iwn_mem_write(sc, addr & ~3, tmp); } static __inline void iwn_mem_read_region_4(struct iwn_softc *sc, uint32_t addr, uint32_t *data, int count) { for (; count > 0; count--, addr += 4) *data++ = iwn_mem_read(sc, addr); } static __inline void iwn_mem_set_region_4(struct iwn_softc *sc, uint32_t addr, uint32_t val, int count) { for (; count > 0; count--, addr += 4) iwn_mem_write(sc, addr, val); } static int iwn_eeprom_lock(struct iwn_softc *sc) { int i, ntries; for (i = 0; i < 100; i++) { /* Request exclusive access to EEPROM. */ IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_EEPROM_LOCKED); /* Spin until we actually get the lock. */ for (ntries = 0; ntries < 100; ntries++) { if (IWN_READ(sc, IWN_HW_IF_CONFIG) & IWN_HW_IF_CONFIG_EEPROM_LOCKED) return 0; DELAY(10); } } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end timeout\n", __func__); return ETIMEDOUT; } static __inline void iwn_eeprom_unlock(struct iwn_softc *sc) { IWN_CLRBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_EEPROM_LOCKED); } /* * Initialize access by host to One Time Programmable ROM. * NB: This kind of ROM can be found on 1000 or 6000 Series only. */ static int iwn_init_otprom(struct iwn_softc *sc) { uint16_t prev, base, next; int count, error; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); /* Wait for clock stabilization before accessing prph. */ if ((error = iwn_clock_wait(sc)) != 0) return error; if ((error = iwn_nic_lock(sc)) != 0) return error; iwn_prph_setbits(sc, IWN_APMG_PS, IWN_APMG_PS_RESET_REQ); DELAY(5); iwn_prph_clrbits(sc, IWN_APMG_PS, IWN_APMG_PS_RESET_REQ); iwn_nic_unlock(sc); /* Set auto clock gate disable bit for HW with OTP shadow RAM. */ if (sc->base_params->shadow_ram_support) { IWN_SETBITS(sc, IWN_DBG_LINK_PWR_MGMT, IWN_RESET_LINK_PWR_MGMT_DIS); } IWN_CLRBITS(sc, IWN_EEPROM_GP, IWN_EEPROM_GP_IF_OWNER); /* Clear ECC status. */ IWN_SETBITS(sc, IWN_OTP_GP, IWN_OTP_GP_ECC_CORR_STTS | IWN_OTP_GP_ECC_UNCORR_STTS); /* * Find the block before last block (contains the EEPROM image) * for HW without OTP shadow RAM. */ if (! sc->base_params->shadow_ram_support) { /* Switch to absolute addressing mode. */ IWN_CLRBITS(sc, IWN_OTP_GP, IWN_OTP_GP_RELATIVE_ACCESS); base = prev = 0; for (count = 0; count < sc->base_params->max_ll_items; count++) { error = iwn_read_prom_data(sc, base, &next, 2); if (error != 0) return error; if (next == 0) /* End of linked-list. */ break; prev = base; base = le16toh(next); } if (count == 0 || count == sc->base_params->max_ll_items) return EIO; /* Skip "next" word. */ sc->prom_base = prev + 1; } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); return 0; } static int iwn_read_prom_data(struct iwn_softc *sc, uint32_t addr, void *data, int count) { uint8_t *out = data; uint32_t val, tmp; int ntries; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); addr += sc->prom_base; for (; count > 0; count -= 2, addr++) { IWN_WRITE(sc, IWN_EEPROM, addr << 2); for (ntries = 0; ntries < 10; ntries++) { val = IWN_READ(sc, IWN_EEPROM); if (val & IWN_EEPROM_READ_VALID) break; DELAY(5); } if (ntries == 10) { device_printf(sc->sc_dev, "timeout reading ROM at 0x%x\n", addr); return ETIMEDOUT; } if (sc->sc_flags & IWN_FLAG_HAS_OTPROM) { /* OTPROM, check for ECC errors. */ tmp = IWN_READ(sc, IWN_OTP_GP); if (tmp & IWN_OTP_GP_ECC_UNCORR_STTS) { device_printf(sc->sc_dev, "OTPROM ECC error at 0x%x\n", addr); return EIO; } if (tmp & IWN_OTP_GP_ECC_CORR_STTS) { /* Correctable ECC error, clear bit. */ IWN_SETBITS(sc, IWN_OTP_GP, IWN_OTP_GP_ECC_CORR_STTS); } } *out++ = val >> 16; if (count > 1) *out++ = val >> 24; } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); return 0; } static void iwn_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { if (error != 0) return; KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs)); *(bus_addr_t *)arg = segs[0].ds_addr; } static int iwn_dma_contig_alloc(struct iwn_softc *sc, struct iwn_dma_info *dma, void **kvap, bus_size_t size, bus_size_t alignment) { int error; dma->tag = NULL; dma->size = size; error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), alignment, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, size, 1, size, BUS_DMA_NOWAIT, NULL, NULL, &dma->tag); if (error != 0) goto fail; error = bus_dmamem_alloc(dma->tag, (void **)&dma->vaddr, BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, &dma->map); if (error != 0) goto fail; error = bus_dmamap_load(dma->tag, dma->map, dma->vaddr, size, iwn_dma_map_addr, &dma->paddr, BUS_DMA_NOWAIT); if (error != 0) goto fail; bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); if (kvap != NULL) *kvap = dma->vaddr; return 0; fail: iwn_dma_contig_free(dma); return error; } static void iwn_dma_contig_free(struct iwn_dma_info *dma) { if (dma->vaddr != NULL) { bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(dma->tag, dma->map); bus_dmamem_free(dma->tag, dma->vaddr, dma->map); dma->vaddr = NULL; } if (dma->tag != NULL) { bus_dma_tag_destroy(dma->tag); dma->tag = NULL; } } static int iwn_alloc_sched(struct iwn_softc *sc) { /* TX scheduler rings must be aligned on a 1KB boundary. */ return iwn_dma_contig_alloc(sc, &sc->sched_dma, (void **)&sc->sched, sc->schedsz, 1024); } static void iwn_free_sched(struct iwn_softc *sc) { iwn_dma_contig_free(&sc->sched_dma); } static int iwn_alloc_kw(struct iwn_softc *sc) { /* "Keep Warm" page must be aligned on a 4KB boundary. */ return iwn_dma_contig_alloc(sc, &sc->kw_dma, NULL, 4096, 4096); } static void iwn_free_kw(struct iwn_softc *sc) { iwn_dma_contig_free(&sc->kw_dma); } static int iwn_alloc_ict(struct iwn_softc *sc) { /* ICT table must be aligned on a 4KB boundary. */ return iwn_dma_contig_alloc(sc, &sc->ict_dma, (void **)&sc->ict, IWN_ICT_SIZE, 4096); } static void iwn_free_ict(struct iwn_softc *sc) { iwn_dma_contig_free(&sc->ict_dma); } static int iwn_alloc_fwmem(struct iwn_softc *sc) { /* Must be aligned on a 16-byte boundary. */ return iwn_dma_contig_alloc(sc, &sc->fw_dma, NULL, sc->fwsz, 16); } static void iwn_free_fwmem(struct iwn_softc *sc) { iwn_dma_contig_free(&sc->fw_dma); } static int iwn_alloc_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) { bus_size_t size; int i, error; ring->cur = 0; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); /* Allocate RX descriptors (256-byte aligned). */ size = IWN_RX_RING_COUNT * sizeof (uint32_t); error = iwn_dma_contig_alloc(sc, &ring->desc_dma, (void **)&ring->desc, size, 256); if (error != 0) { device_printf(sc->sc_dev, "%s: could not allocate RX ring DMA memory, error %d\n", __func__, error); goto fail; } /* Allocate RX status area (16-byte aligned). */ error = iwn_dma_contig_alloc(sc, &ring->stat_dma, (void **)&ring->stat, sizeof (struct iwn_rx_status), 16); if (error != 0) { device_printf(sc->sc_dev, "%s: could not allocate RX status DMA memory, error %d\n", __func__, error); goto fail; } /* Create RX buffer DMA tag. */ error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, IWN_RBUF_SIZE, 1, IWN_RBUF_SIZE, BUS_DMA_NOWAIT, NULL, NULL, &ring->data_dmat); if (error != 0) { device_printf(sc->sc_dev, "%s: could not create RX buf DMA tag, error %d\n", __func__, error); goto fail; } /* * Allocate and map RX buffers. */ for (i = 0; i < IWN_RX_RING_COUNT; i++) { struct iwn_rx_data *data = &ring->data[i]; bus_addr_t paddr; error = bus_dmamap_create(ring->data_dmat, 0, &data->map); if (error != 0) { device_printf(sc->sc_dev, "%s: could not create RX buf DMA map, error %d\n", __func__, error); goto fail; } data->m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, IWN_RBUF_SIZE); if (data->m == NULL) { device_printf(sc->sc_dev, "%s: could not allocate RX mbuf\n", __func__); error = ENOBUFS; goto fail; } error = bus_dmamap_load(ring->data_dmat, data->map, mtod(data->m, void *), IWN_RBUF_SIZE, iwn_dma_map_addr, &paddr, BUS_DMA_NOWAIT); if (error != 0 && error != EFBIG) { device_printf(sc->sc_dev, - "%s: can't not map mbuf, error %d\n", __func__, + "%s: can't map mbuf, error %d\n", __func__, error); goto fail; } /* Set physical address of RX buffer (256-byte aligned). */ ring->desc[i] = htole32(paddr >> 8); } bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return 0; fail: iwn_free_rx_ring(sc, ring); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end in error\n",__func__); return error; } static void iwn_reset_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) { int ntries; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); if (iwn_nic_lock(sc) == 0) { IWN_WRITE(sc, IWN_FH_RX_CONFIG, 0); for (ntries = 0; ntries < 1000; ntries++) { if (IWN_READ(sc, IWN_FH_RX_STATUS) & IWN_FH_RX_STATUS_IDLE) break; DELAY(10); } iwn_nic_unlock(sc); } ring->cur = 0; sc->last_rx_valid = 0; } static void iwn_free_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring) { int i; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s \n", __func__); iwn_dma_contig_free(&ring->desc_dma); iwn_dma_contig_free(&ring->stat_dma); for (i = 0; i < IWN_RX_RING_COUNT; i++) { struct iwn_rx_data *data = &ring->data[i]; if (data->m != NULL) { bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD); bus_dmamap_unload(ring->data_dmat, data->map); m_freem(data->m); data->m = NULL; } if (data->map != NULL) bus_dmamap_destroy(ring->data_dmat, data->map); } if (ring->data_dmat != NULL) { bus_dma_tag_destroy(ring->data_dmat); ring->data_dmat = NULL; } } static int iwn_alloc_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring, int qid) { bus_addr_t paddr; bus_size_t size; int i, error; ring->qid = qid; ring->queued = 0; ring->cur = 0; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); /* Allocate TX descriptors (256-byte aligned). */ size = IWN_TX_RING_COUNT * sizeof (struct iwn_tx_desc); error = iwn_dma_contig_alloc(sc, &ring->desc_dma, (void **)&ring->desc, size, 256); if (error != 0) { device_printf(sc->sc_dev, "%s: could not allocate TX ring DMA memory, error %d\n", __func__, error); goto fail; } size = IWN_TX_RING_COUNT * sizeof (struct iwn_tx_cmd); error = iwn_dma_contig_alloc(sc, &ring->cmd_dma, (void **)&ring->cmd, size, 4); if (error != 0) { device_printf(sc->sc_dev, "%s: could not allocate TX cmd DMA memory, error %d\n", __func__, error); goto fail; } error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, IWN_MAX_SCATTER - 1, MCLBYTES, BUS_DMA_NOWAIT, NULL, NULL, &ring->data_dmat); if (error != 0) { device_printf(sc->sc_dev, "%s: could not create TX buf DMA tag, error %d\n", __func__, error); goto fail; } paddr = ring->cmd_dma.paddr; for (i = 0; i < IWN_TX_RING_COUNT; i++) { struct iwn_tx_data *data = &ring->data[i]; data->cmd_paddr = paddr; data->scratch_paddr = paddr + 12; paddr += sizeof (struct iwn_tx_cmd); error = bus_dmamap_create(ring->data_dmat, 0, &data->map); if (error != 0) { device_printf(sc->sc_dev, "%s: could not create TX buf DMA map, error %d\n", __func__, error); goto fail; } } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); return 0; fail: iwn_free_tx_ring(sc, ring); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end in error\n", __func__); return error; } static void iwn_reset_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring) { int i; DPRINTF(sc, IWN_DEBUG_TRACE, "->doing %s \n", __func__); for (i = 0; i < IWN_TX_RING_COUNT; i++) { struct iwn_tx_data *data = &ring->data[i]; if (data->m != NULL) { bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ring->data_dmat, data->map); m_freem(data->m); data->m = NULL; } + if (data->ni != NULL) { + ieee80211_free_node(data->ni); + data->ni = NULL; + } } /* Clear TX descriptors. */ memset(ring->desc, 0, ring->desc_dma.size); bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); sc->qfullmsk &= ~(1 << ring->qid); ring->queued = 0; ring->cur = 0; } static void iwn_free_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring) { int i; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s \n", __func__); iwn_dma_contig_free(&ring->desc_dma); iwn_dma_contig_free(&ring->cmd_dma); for (i = 0; i < IWN_TX_RING_COUNT; i++) { struct iwn_tx_data *data = &ring->data[i]; if (data->m != NULL) { bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ring->data_dmat, data->map); m_freem(data->m); } if (data->map != NULL) bus_dmamap_destroy(ring->data_dmat, data->map); } if (ring->data_dmat != NULL) { bus_dma_tag_destroy(ring->data_dmat); ring->data_dmat = NULL; } } static void iwn5000_ict_reset(struct iwn_softc *sc) { /* Disable interrupts. */ IWN_WRITE(sc, IWN_INT_MASK, 0); /* Reset ICT table. */ memset(sc->ict, 0, IWN_ICT_SIZE); sc->ict_cur = 0; /* Set physical address of ICT table (4KB aligned). */ DPRINTF(sc, IWN_DEBUG_RESET, "%s: enabling ICT\n", __func__); IWN_WRITE(sc, IWN_DRAM_INT_TBL, IWN_DRAM_INT_TBL_ENABLE | IWN_DRAM_INT_TBL_WRAP_CHECK | sc->ict_dma.paddr >> 12); /* Enable periodic RX interrupt. */ sc->int_mask |= IWN_INT_RX_PERIODIC; /* Switch to ICT interrupt mode in driver. */ sc->sc_flags |= IWN_FLAG_USE_ICT; /* Re-enable interrupts. */ IWN_WRITE(sc, IWN_INT, 0xffffffff); IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); } static int iwn_read_eeprom(struct iwn_softc *sc, uint8_t macaddr[IEEE80211_ADDR_LEN]) { struct iwn_ops *ops = &sc->ops; uint16_t val; int error; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); /* Check whether adapter has an EEPROM or an OTPROM. */ if (sc->hw_type >= IWN_HW_REV_TYPE_1000 && (IWN_READ(sc, IWN_OTP_GP) & IWN_OTP_GP_DEV_SEL_OTP)) sc->sc_flags |= IWN_FLAG_HAS_OTPROM; DPRINTF(sc, IWN_DEBUG_RESET, "%s found\n", (sc->sc_flags & IWN_FLAG_HAS_OTPROM) ? "OTPROM" : "EEPROM"); /* Adapter has to be powered on for EEPROM access to work. */ if ((error = iwn_apm_init(sc)) != 0) { device_printf(sc->sc_dev, "%s: could not power ON adapter, error %d\n", __func__, error); return error; } if ((IWN_READ(sc, IWN_EEPROM_GP) & 0x7) == 0) { device_printf(sc->sc_dev, "%s: bad ROM signature\n", __func__); return EIO; } if ((error = iwn_eeprom_lock(sc)) != 0) { device_printf(sc->sc_dev, "%s: could not lock ROM, error %d\n", __func__, error); return error; } if (sc->sc_flags & IWN_FLAG_HAS_OTPROM) { if ((error = iwn_init_otprom(sc)) != 0) { device_printf(sc->sc_dev, "%s: could not initialize OTPROM, error %d\n", __func__, error); return error; } } iwn_read_prom_data(sc, IWN_EEPROM_SKU_CAP, &val, 2); DPRINTF(sc, IWN_DEBUG_RESET, "SKU capabilities=0x%04x\n", le16toh(val)); /* Check if HT support is bonded out. */ if (val & htole16(IWN_EEPROM_SKU_CAP_11N)) sc->sc_flags |= IWN_FLAG_HAS_11N; iwn_read_prom_data(sc, IWN_EEPROM_RFCFG, &val, 2); sc->rfcfg = le16toh(val); DPRINTF(sc, IWN_DEBUG_RESET, "radio config=0x%04x\n", sc->rfcfg); /* Read Tx/Rx chains from ROM unless it's known to be broken. */ if (sc->txchainmask == 0) sc->txchainmask = IWN_RFCFG_TXANTMSK(sc->rfcfg); if (sc->rxchainmask == 0) sc->rxchainmask = IWN_RFCFG_RXANTMSK(sc->rfcfg); /* Read MAC address. */ iwn_read_prom_data(sc, IWN_EEPROM_MAC, macaddr, 6); /* Read adapter-specific information from EEPROM. */ ops->read_eeprom(sc); iwn_apm_stop(sc); /* Power OFF adapter. */ iwn_eeprom_unlock(sc); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); return 0; } static void iwn4965_read_eeprom(struct iwn_softc *sc) { uint32_t addr; uint16_t val; int i; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); /* Read regulatory domain (4 ASCII characters). */ iwn_read_prom_data(sc, IWN4965_EEPROM_DOMAIN, sc->eeprom_domain, 4); /* Read the list of authorized channels (20MHz ones only). */ for (i = 0; i < IWN_NBANDS - 1; i++) { addr = iwn4965_regulatory_bands[i]; iwn_read_eeprom_channels(sc, i, addr); } /* Read maximum allowed TX power for 2GHz and 5GHz bands. */ iwn_read_prom_data(sc, IWN4965_EEPROM_MAXPOW, &val, 2); sc->maxpwr2GHz = val & 0xff; sc->maxpwr5GHz = val >> 8; /* Check that EEPROM values are within valid range. */ if (sc->maxpwr5GHz < 20 || sc->maxpwr5GHz > 50) sc->maxpwr5GHz = 38; if (sc->maxpwr2GHz < 20 || sc->maxpwr2GHz > 50) sc->maxpwr2GHz = 38; DPRINTF(sc, IWN_DEBUG_RESET, "maxpwr 2GHz=%d 5GHz=%d\n", sc->maxpwr2GHz, sc->maxpwr5GHz); /* Read samples for each TX power group. */ iwn_read_prom_data(sc, IWN4965_EEPROM_BANDS, sc->bands, sizeof sc->bands); /* Read voltage at which samples were taken. */ iwn_read_prom_data(sc, IWN4965_EEPROM_VOLTAGE, &val, 2); sc->eeprom_voltage = (int16_t)le16toh(val); DPRINTF(sc, IWN_DEBUG_RESET, "voltage=%d (in 0.3V)\n", sc->eeprom_voltage); #ifdef IWN_DEBUG /* Print samples. */ if (sc->sc_debug & IWN_DEBUG_ANY) { for (i = 0; i < IWN_NBANDS - 1; i++) iwn4965_print_power_group(sc, i); } #endif DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); } #ifdef IWN_DEBUG static void iwn4965_print_power_group(struct iwn_softc *sc, int i) { struct iwn4965_eeprom_band *band = &sc->bands[i]; struct iwn4965_eeprom_chan_samples *chans = band->chans; int j, c; printf("===band %d===\n", i); printf("chan lo=%d, chan hi=%d\n", band->lo, band->hi); printf("chan1 num=%d\n", chans[0].num); for (c = 0; c < 2; c++) { for (j = 0; j < IWN_NSAMPLES; j++) { printf("chain %d, sample %d: temp=%d gain=%d " "power=%d pa_det=%d\n", c, j, chans[0].samples[c][j].temp, chans[0].samples[c][j].gain, chans[0].samples[c][j].power, chans[0].samples[c][j].pa_det); } } printf("chan2 num=%d\n", chans[1].num); for (c = 0; c < 2; c++) { for (j = 0; j < IWN_NSAMPLES; j++) { printf("chain %d, sample %d: temp=%d gain=%d " "power=%d pa_det=%d\n", c, j, chans[1].samples[c][j].temp, chans[1].samples[c][j].gain, chans[1].samples[c][j].power, chans[1].samples[c][j].pa_det); } } } #endif static void iwn5000_read_eeprom(struct iwn_softc *sc) { struct iwn5000_eeprom_calib_hdr hdr; int32_t volt; uint32_t base, addr; uint16_t val; int i; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); /* Read regulatory domain (4 ASCII characters). */ iwn_read_prom_data(sc, IWN5000_EEPROM_REG, &val, 2); base = le16toh(val); iwn_read_prom_data(sc, base + IWN5000_EEPROM_DOMAIN, sc->eeprom_domain, 4); /* Read the list of authorized channels (20MHz ones only). */ for (i = 0; i < IWN_NBANDS - 1; i++) { addr = base + sc->base_params->regulatory_bands[i]; iwn_read_eeprom_channels(sc, i, addr); } /* Read enhanced TX power information for 6000 Series. */ if (sc->base_params->enhanced_TX_power) iwn_read_eeprom_enhinfo(sc); iwn_read_prom_data(sc, IWN5000_EEPROM_CAL, &val, 2); base = le16toh(val); iwn_read_prom_data(sc, base, &hdr, sizeof hdr); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: calib version=%u pa type=%u voltage=%u\n", __func__, hdr.version, hdr.pa_type, le16toh(hdr.volt)); sc->calib_ver = hdr.version; if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2) { sc->eeprom_voltage = le16toh(hdr.volt); iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2); sc->eeprom_temp_high=le16toh(val); iwn_read_prom_data(sc, base + IWN5000_EEPROM_VOLT, &val, 2); sc->eeprom_temp = le16toh(val); } if (sc->hw_type == IWN_HW_REV_TYPE_5150) { /* Compute temperature offset. */ iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2); sc->eeprom_temp = le16toh(val); iwn_read_prom_data(sc, base + IWN5000_EEPROM_VOLT, &val, 2); volt = le16toh(val); sc->temp_off = sc->eeprom_temp - (volt / -5); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "temp=%d volt=%d offset=%dK\n", sc->eeprom_temp, volt, sc->temp_off); } else { /* Read crystal calibration. */ iwn_read_prom_data(sc, base + IWN5000_EEPROM_CRYSTAL, &sc->eeprom_crystal, sizeof (uint32_t)); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "crystal calibration 0x%08x\n", le32toh(sc->eeprom_crystal)); } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); } /* * Translate EEPROM flags to net80211. */ static uint32_t iwn_eeprom_channel_flags(struct iwn_eeprom_chan *channel) { uint32_t nflags; nflags = 0; if ((channel->flags & IWN_EEPROM_CHAN_ACTIVE) == 0) nflags |= IEEE80211_CHAN_PASSIVE; if ((channel->flags & IWN_EEPROM_CHAN_IBSS) == 0) nflags |= IEEE80211_CHAN_NOADHOC; if (channel->flags & IWN_EEPROM_CHAN_RADAR) { nflags |= IEEE80211_CHAN_DFS; /* XXX apparently IBSS may still be marked */ nflags |= IEEE80211_CHAN_NOADHOC; } return nflags; } static void iwn_read_eeprom_band(struct iwn_softc *sc, int n) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct iwn_eeprom_chan *channels = sc->eeprom_channels[n]; const struct iwn_chan_band *band = &iwn_bands[n]; struct ieee80211_channel *c; uint8_t chan; int i, nflags; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); for (i = 0; i < band->nchan; i++) { if (!(channels[i].flags & IWN_EEPROM_CHAN_VALID)) { DPRINTF(sc, IWN_DEBUG_RESET, "skip chan %d flags 0x%x maxpwr %d\n", band->chan[i], channels[i].flags, channels[i].maxpwr); continue; } chan = band->chan[i]; nflags = iwn_eeprom_channel_flags(&channels[i]); c = &ic->ic_channels[ic->ic_nchans++]; c->ic_ieee = chan; c->ic_maxregpower = channels[i].maxpwr; c->ic_maxpower = 2*c->ic_maxregpower; if (n == 0) { /* 2GHz band */ c->ic_freq = ieee80211_ieee2mhz(chan, IEEE80211_CHAN_G); /* G =>'s B is supported */ c->ic_flags = IEEE80211_CHAN_B | nflags; c = &ic->ic_channels[ic->ic_nchans++]; c[0] = c[-1]; c->ic_flags = IEEE80211_CHAN_G | nflags; } else { /* 5GHz band */ c->ic_freq = ieee80211_ieee2mhz(chan, IEEE80211_CHAN_A); c->ic_flags = IEEE80211_CHAN_A | nflags; } /* Save maximum allowed TX power for this channel. */ sc->maxpwr[chan] = channels[i].maxpwr; DPRINTF(sc, IWN_DEBUG_RESET, "add chan %d flags 0x%x maxpwr %d\n", chan, channels[i].flags, channels[i].maxpwr); if (sc->sc_flags & IWN_FLAG_HAS_11N) { /* add HT20, HT40 added separately */ c = &ic->ic_channels[ic->ic_nchans++]; c[0] = c[-1]; c->ic_flags |= IEEE80211_CHAN_HT20; } } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); } static void iwn_read_eeprom_ht40(struct iwn_softc *sc, int n) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct iwn_eeprom_chan *channels = sc->eeprom_channels[n]; const struct iwn_chan_band *band = &iwn_bands[n]; struct ieee80211_channel *c, *cent, *extc; uint8_t chan; int i, nflags; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s start\n", __func__); if (!(sc->sc_flags & IWN_FLAG_HAS_11N)) { DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end no 11n\n", __func__); return; } for (i = 0; i < band->nchan; i++) { if (!(channels[i].flags & IWN_EEPROM_CHAN_VALID)) { DPRINTF(sc, IWN_DEBUG_RESET, "skip chan %d flags 0x%x maxpwr %d\n", band->chan[i], channels[i].flags, channels[i].maxpwr); continue; } chan = band->chan[i]; nflags = iwn_eeprom_channel_flags(&channels[i]); /* * Each entry defines an HT40 channel pair; find the * center channel, then the extension channel above. */ cent = ieee80211_find_channel_byieee(ic, chan, (n == 5 ? IEEE80211_CHAN_G : IEEE80211_CHAN_A)); if (cent == NULL) { /* XXX shouldn't happen */ device_printf(sc->sc_dev, "%s: no entry for channel %d\n", __func__, chan); continue; } extc = ieee80211_find_channel(ic, cent->ic_freq+20, (n == 5 ? IEEE80211_CHAN_G : IEEE80211_CHAN_A)); if (extc == NULL) { DPRINTF(sc, IWN_DEBUG_RESET, "%s: skip chan %d, extension channel not found\n", __func__, chan); continue; } DPRINTF(sc, IWN_DEBUG_RESET, "add ht40 chan %d flags 0x%x maxpwr %d\n", chan, channels[i].flags, channels[i].maxpwr); c = &ic->ic_channels[ic->ic_nchans++]; c[0] = cent[0]; c->ic_extieee = extc->ic_ieee; c->ic_flags &= ~IEEE80211_CHAN_HT; c->ic_flags |= IEEE80211_CHAN_HT40U | nflags; c = &ic->ic_channels[ic->ic_nchans++]; c[0] = extc[0]; c->ic_extieee = cent->ic_ieee; c->ic_flags &= ~IEEE80211_CHAN_HT; c->ic_flags |= IEEE80211_CHAN_HT40D | nflags; } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); } static void iwn_read_eeprom_channels(struct iwn_softc *sc, int n, uint32_t addr) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; iwn_read_prom_data(sc, addr, &sc->eeprom_channels[n], iwn_bands[n].nchan * sizeof (struct iwn_eeprom_chan)); if (n < 5) iwn_read_eeprom_band(sc, n); else iwn_read_eeprom_ht40(sc, n); ieee80211_sort_channels(ic->ic_channels, ic->ic_nchans); } static struct iwn_eeprom_chan * iwn_find_eeprom_channel(struct iwn_softc *sc, struct ieee80211_channel *c) { int band, chan, i, j; if (IEEE80211_IS_CHAN_HT40(c)) { band = IEEE80211_IS_CHAN_5GHZ(c) ? 6 : 5; if (IEEE80211_IS_CHAN_HT40D(c)) chan = c->ic_extieee; else chan = c->ic_ieee; for (i = 0; i < iwn_bands[band].nchan; i++) { if (iwn_bands[band].chan[i] == chan) return &sc->eeprom_channels[band][i]; } } else { for (j = 0; j < 5; j++) { for (i = 0; i < iwn_bands[j].nchan; i++) { if (iwn_bands[j].chan[i] == c->ic_ieee) return &sc->eeprom_channels[j][i]; } } } return NULL; } /* * Enforce flags read from EEPROM. */ static int iwn_setregdomain(struct ieee80211com *ic, struct ieee80211_regdomain *rd, int nchan, struct ieee80211_channel chans[]) { struct iwn_softc *sc = ic->ic_ifp->if_softc; int i; for (i = 0; i < nchan; i++) { struct ieee80211_channel *c = &chans[i]; struct iwn_eeprom_chan *channel; channel = iwn_find_eeprom_channel(sc, c); if (channel == NULL) { if_printf(ic->ic_ifp, "%s: invalid channel %u freq %u/0x%x\n", __func__, c->ic_ieee, c->ic_freq, c->ic_flags); return EINVAL; } c->ic_flags |= iwn_eeprom_channel_flags(channel); } return 0; } static void iwn_read_eeprom_enhinfo(struct iwn_softc *sc) { struct iwn_eeprom_enhinfo enhinfo[35]; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_channel *c; uint16_t val, base; int8_t maxpwr; uint8_t flags; int i, j; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); iwn_read_prom_data(sc, IWN5000_EEPROM_REG, &val, 2); base = le16toh(val); iwn_read_prom_data(sc, base + IWN6000_EEPROM_ENHINFO, enhinfo, sizeof enhinfo); for (i = 0; i < nitems(enhinfo); i++) { flags = enhinfo[i].flags; if (!(flags & IWN_ENHINFO_VALID)) continue; /* Skip invalid entries. */ maxpwr = 0; if (sc->txchainmask & IWN_ANT_A) maxpwr = MAX(maxpwr, enhinfo[i].chain[0]); if (sc->txchainmask & IWN_ANT_B) maxpwr = MAX(maxpwr, enhinfo[i].chain[1]); if (sc->txchainmask & IWN_ANT_C) maxpwr = MAX(maxpwr, enhinfo[i].chain[2]); if (sc->ntxchains == 2) maxpwr = MAX(maxpwr, enhinfo[i].mimo2); else if (sc->ntxchains == 3) maxpwr = MAX(maxpwr, enhinfo[i].mimo3); for (j = 0; j < ic->ic_nchans; j++) { c = &ic->ic_channels[j]; if ((flags & IWN_ENHINFO_5GHZ)) { if (!IEEE80211_IS_CHAN_A(c)) continue; } else if ((flags & IWN_ENHINFO_OFDM)) { if (!IEEE80211_IS_CHAN_G(c)) continue; } else if (!IEEE80211_IS_CHAN_B(c)) continue; if ((flags & IWN_ENHINFO_HT40)) { if (!IEEE80211_IS_CHAN_HT40(c)) continue; } else { if (IEEE80211_IS_CHAN_HT40(c)) continue; } if (enhinfo[i].chan != 0 && enhinfo[i].chan != c->ic_ieee) continue; DPRINTF(sc, IWN_DEBUG_RESET, "channel %d(%x), maxpwr %d\n", c->ic_ieee, c->ic_flags, maxpwr / 2); c->ic_maxregpower = maxpwr / 2; c->ic_maxpower = maxpwr; } } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end\n", __func__); } static struct ieee80211_node * iwn_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) { return malloc(sizeof (struct iwn_node), M_80211_NODE,M_NOWAIT | M_ZERO); } static __inline int rate2plcp(int rate) { switch (rate & 0xff) { case 12: return 0xd; case 18: return 0xf; case 24: return 0x5; case 36: return 0x7; case 48: return 0x9; case 72: return 0xb; case 96: return 0x1; case 108: return 0x3; case 2: return 10; case 4: return 20; case 11: return 55; case 22: return 110; } return 0; } static int iwn_get_1stream_tx_antmask(struct iwn_softc *sc) { return IWN_LSB(sc->txchainmask); } static int iwn_get_2stream_tx_antmask(struct iwn_softc *sc) { int tx; /* * The '2 stream' setup is a bit .. odd. * * For NICs that support only 1 antenna, default to IWN_ANT_AB or * the firmware panics (eg Intel 5100.) * * For NICs that support two antennas, we use ANT_AB. * * For NICs that support three antennas, we use the two that * wasn't the default one. * * XXX TODO: if bluetooth (full concurrent) is enabled, restrict * this to only one antenna. */ /* Default - transmit on the other antennas */ tx = (sc->txchainmask & ~IWN_LSB(sc->txchainmask)); /* Now, if it's zero, set it to IWN_ANT_AB, so to not panic firmware */ if (tx == 0) tx = IWN_ANT_AB; /* * If the NIC is a two-stream TX NIC, configure the TX mask to * the default chainmask */ else if (sc->ntxchains == 2) tx = sc->txchainmask; return (tx); } /* * Calculate the required PLCP value from the given rate, * to the given node. * * This will take the node configuration (eg 11n, rate table * setup, etc) into consideration. */ static uint32_t iwn_rate_to_plcp(struct iwn_softc *sc, struct ieee80211_node *ni, uint8_t rate) { #define RV(v) ((v) & IEEE80211_RATE_VAL) struct ieee80211com *ic = ni->ni_ic; uint32_t plcp = 0; int ridx; /* * If it's an MCS rate, let's set the plcp correctly * and set the relevant flags based on the node config. */ if (rate & IEEE80211_RATE_MCS) { /* * Set the initial PLCP value to be between 0->31 for * MCS 0 -> MCS 31, then set the "I'm an MCS rate!" * flag. */ plcp = RV(rate) | IWN_RFLAG_MCS; /* * XXX the following should only occur if both * the local configuration _and_ the remote node * advertise these capabilities. Thus this code * may need fixing! */ /* * Set the channel width and guard interval. */ if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { plcp |= IWN_RFLAG_HT40; if (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) plcp |= IWN_RFLAG_SGI; } else if (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) { plcp |= IWN_RFLAG_SGI; } /* * Ensure the selected rate matches the link quality * table entries being used. */ if (rate > 0x8f) plcp |= IWN_RFLAG_ANT(sc->txchainmask); else if (rate > 0x87) plcp |= IWN_RFLAG_ANT(iwn_get_2stream_tx_antmask(sc)); else plcp |= IWN_RFLAG_ANT(iwn_get_1stream_tx_antmask(sc)); } else { /* * Set the initial PLCP - fine for both * OFDM and CCK rates. */ plcp = rate2plcp(rate); /* Set CCK flag if it's CCK */ /* XXX It would be nice to have a method * to map the ridx -> phy table entry * so we could just query that, rather than * this hack to check against IWN_RIDX_OFDM6. */ ridx = ieee80211_legacy_rate_lookup(ic->ic_rt, rate & IEEE80211_RATE_VAL); if (ridx < IWN_RIDX_OFDM6 && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) plcp |= IWN_RFLAG_CCK; /* Set antenna configuration */ /* XXX TODO: is this the right antenna to use for legacy? */ plcp |= IWN_RFLAG_ANT(iwn_get_1stream_tx_antmask(sc)); } DPRINTF(sc, IWN_DEBUG_TXRATE, "%s: rate=0x%02x, plcp=0x%08x\n", __func__, rate, plcp); return (htole32(plcp)); #undef RV } static void iwn_newassoc(struct ieee80211_node *ni, int isnew) { /* Doesn't do anything at the moment */ } static int iwn_media_change(struct ifnet *ifp) { int error; error = ieee80211_media_change(ifp); /* NB: only the fixed rate can change and that doesn't need a reset */ return (error == ENETRESET ? 0 : error); } static int iwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct iwn_vap *ivp = IWN_VAP(vap); struct ieee80211com *ic = vap->iv_ic; struct iwn_softc *sc = ic->ic_ifp->if_softc; int error = 0; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); DPRINTF(sc, IWN_DEBUG_STATE, "%s: %s -> %s\n", __func__, ieee80211_state_name[vap->iv_state], ieee80211_state_name[nstate]); IEEE80211_UNLOCK(ic); IWN_LOCK(sc); callout_stop(&sc->calib_to); sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; switch (nstate) { case IEEE80211_S_ASSOC: if (vap->iv_state != IEEE80211_S_RUN) break; /* FALLTHROUGH */ case IEEE80211_S_AUTH: if (vap->iv_state == IEEE80211_S_AUTH) break; /* * !AUTH -> AUTH transition requires state reset to handle * reassociations correctly. */ sc->rxon->associd = 0; sc->rxon->filter &= ~htole32(IWN_FILTER_BSS); sc->calib.state = IWN_CALIB_STATE_INIT; if ((error = iwn_auth(sc, vap)) != 0) { device_printf(sc->sc_dev, "%s: could not move to auth state\n", __func__); } break; case IEEE80211_S_RUN: /* * RUN -> RUN transition; Just restart the timers. */ if (vap->iv_state == IEEE80211_S_RUN) { sc->calib_cnt = 0; break; } /* * !RUN -> RUN requires setting the association id * which is done with a firmware cmd. We also defer * starting the timers until that work is done. */ if ((error = iwn_run(sc, vap)) != 0) { device_printf(sc->sc_dev, "%s: could not move to run state\n", __func__); } break; case IEEE80211_S_INIT: sc->calib.state = IWN_CALIB_STATE_INIT; break; default: break; } IWN_UNLOCK(sc); IEEE80211_LOCK(ic); if (error != 0){ DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end in error\n", __func__); return error; } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return ivp->iv_newstate(vap, nstate, arg); } static void iwn_calib_timeout(void *arg) { struct iwn_softc *sc = arg; IWN_LOCK_ASSERT(sc); /* Force automatic TX power calibration every 60 secs. */ if (++sc->calib_cnt >= 120) { uint32_t flags = 0; DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s\n", "sending request for statistics"); (void)iwn_cmd(sc, IWN_CMD_GET_STATISTICS, &flags, sizeof flags, 1); sc->calib_cnt = 0; } callout_reset(&sc->calib_to, msecs_to_ticks(500), iwn_calib_timeout, sc); } /* * Process an RX_PHY firmware notification. This is usually immediately * followed by an MPDU_RX_DONE notification. */ static void iwn_rx_phy(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn_rx_stat *stat = (struct iwn_rx_stat *)(desc + 1); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: received PHY stats\n", __func__); bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); /* Save RX statistics, they will be used on MPDU_RX_DONE. */ memcpy(&sc->last_rx_stat, stat, sizeof (*stat)); sc->last_rx_valid = 1; } /* * Process an RX_DONE (4965AGN only) or MPDU_RX_DONE firmware notification. * Each MPDU_RX_DONE notification must be preceded by an RX_PHY one. */ static void iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct iwn_rx_ring *ring = &sc->rxq; struct ieee80211_frame *wh; struct ieee80211_node *ni; struct mbuf *m, *m1; struct iwn_rx_stat *stat; caddr_t head; bus_addr_t paddr; uint32_t flags; int error, len, rssi, nf; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); if (desc->type == IWN_MPDU_RX_DONE) { /* Check for prior RX_PHY notification. */ if (!sc->last_rx_valid) { DPRINTF(sc, IWN_DEBUG_ANY, "%s: missing RX_PHY\n", __func__); return; } stat = &sc->last_rx_stat; } else stat = (struct iwn_rx_stat *)(desc + 1); bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD); if (stat->cfg_phy_len > IWN_STAT_MAXLEN) { device_printf(sc->sc_dev, "%s: invalid RX statistic header, len %d\n", __func__, stat->cfg_phy_len); return; } if (desc->type == IWN_MPDU_RX_DONE) { struct iwn_rx_mpdu *mpdu = (struct iwn_rx_mpdu *)(desc + 1); head = (caddr_t)(mpdu + 1); len = le16toh(mpdu->len); } else { head = (caddr_t)(stat + 1) + stat->cfg_phy_len; len = le16toh(stat->len); } flags = le32toh(*(uint32_t *)(head + len)); /* Discard frames with a bad FCS early. */ if ((flags & IWN_RX_NOERROR) != IWN_RX_NOERROR) { DPRINTF(sc, IWN_DEBUG_RECV, "%s: RX flags error %x\n", __func__, flags); if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } /* Discard frames that are too short. */ - if (len < sizeof (*wh)) { + if (len < sizeof (struct ieee80211_frame_ack)) { DPRINTF(sc, IWN_DEBUG_RECV, "%s: frame too short: %d\n", __func__, len); if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } m1 = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, IWN_RBUF_SIZE); if (m1 == NULL) { DPRINTF(sc, IWN_DEBUG_ANY, "%s: no mbuf to restock ring\n", __func__); if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } bus_dmamap_unload(ring->data_dmat, data->map); error = bus_dmamap_load(ring->data_dmat, data->map, mtod(m1, void *), IWN_RBUF_SIZE, iwn_dma_map_addr, &paddr, BUS_DMA_NOWAIT); if (error != 0 && error != EFBIG) { device_printf(sc->sc_dev, "%s: bus_dmamap_load failed, error %d\n", __func__, error); m_freem(m1); /* Try to reload the old mbuf. */ error = bus_dmamap_load(ring->data_dmat, data->map, mtod(data->m, void *), IWN_RBUF_SIZE, iwn_dma_map_addr, &paddr, BUS_DMA_NOWAIT); if (error != 0 && error != EFBIG) { panic("%s: could not load old RX mbuf", __func__); } /* Physical address may have changed. */ ring->desc[ring->cur] = htole32(paddr >> 8); bus_dmamap_sync(ring->data_dmat, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); return; } m = data->m; data->m = m1; /* Update RX descriptor. */ ring->desc[ring->cur] = htole32(paddr >> 8); bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); /* Finalize mbuf. */ m->m_pkthdr.rcvif = ifp; m->m_data = head; m->m_pkthdr.len = m->m_len = len; /* Grab a reference to the source node. */ wh = mtod(m, struct ieee80211_frame *); - ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); + if (len >= sizeof(struct ieee80211_frame_min)) + ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); + else + ni = NULL; nf = (ni != NULL && ni->ni_vap->iv_state == IEEE80211_S_RUN && (ic->ic_flags & IEEE80211_F_SCAN) == 0) ? sc->noise : -95; rssi = ops->get_rssi(sc, stat); if (ieee80211_radiotap_active(ic)) { struct iwn_rx_radiotap_header *tap = &sc->sc_rxtap; tap->wr_flags = 0; if (stat->flags & htole16(IWN_STAT_FLAG_SHPREAMBLE)) tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; tap->wr_dbm_antsignal = (int8_t)rssi; tap->wr_dbm_antnoise = (int8_t)nf; tap->wr_tsft = stat->tstamp; switch (stat->rate) { /* CCK rates. */ case 10: tap->wr_rate = 2; break; case 20: tap->wr_rate = 4; break; case 55: tap->wr_rate = 11; break; case 110: tap->wr_rate = 22; break; /* OFDM rates. */ case 0xd: tap->wr_rate = 12; break; case 0xf: tap->wr_rate = 18; break; case 0x5: tap->wr_rate = 24; break; case 0x7: tap->wr_rate = 36; break; case 0x9: tap->wr_rate = 48; break; case 0xb: tap->wr_rate = 72; break; case 0x1: tap->wr_rate = 96; break; case 0x3: tap->wr_rate = 108; break; /* Unknown rate: should not happen. */ default: tap->wr_rate = 0; } } IWN_UNLOCK(sc); /* Send the frame to the 802.11 layer. */ if (ni != NULL) { if (ni->ni_flags & IEEE80211_NODE_HT) m->m_flags |= M_AMPDU; (void)ieee80211_input(ni, m, rssi - nf, nf); /* Node is no longer needed. */ ieee80211_free_node(ni); } else (void)ieee80211_input_all(ic, m, rssi - nf, nf); IWN_LOCK(sc); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); } /* Process an incoming Compressed BlockAck. */ static void iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct iwn_node *wn; struct ieee80211_node *ni; struct iwn_compressed_ba *ba = (struct iwn_compressed_ba *)(desc + 1); struct iwn_tx_ring *txq; struct iwn_tx_data *txdata; struct ieee80211_tx_ampdu *tap; struct mbuf *m; uint64_t bitmap; uint16_t ssn; uint8_t tid; int ackfailcnt = 0, i, lastidx, qid, *res, shift; int tx_ok = 0, tx_err = 0; DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, "->%s begin\n", __func__); bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); qid = le16toh(ba->qid); txq = &sc->txq[ba->qid]; tap = sc->qid2tap[ba->qid]; tid = tap->txa_tid; wn = (void *)tap->txa_ni; res = NULL; ssn = 0; if (!IEEE80211_AMPDU_RUNNING(tap)) { res = tap->txa_private; ssn = tap->txa_start & 0xfff; } for (lastidx = le16toh(ba->ssn) & 0xff; txq->read != lastidx;) { txdata = &txq->data[txq->read]; /* Unmap and free mbuf. */ bus_dmamap_sync(txq->data_dmat, txdata->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(txq->data_dmat, txdata->map); m = txdata->m, txdata->m = NULL; ni = txdata->ni, txdata->ni = NULL; KASSERT(ni != NULL, ("no node")); KASSERT(m != NULL, ("no mbuf")); DPRINTF(sc, IWN_DEBUG_XMIT, "%s: freeing m=%p\n", __func__, m); ieee80211_tx_complete(ni, m, 1); txq->queued--; txq->read = (txq->read + 1) % IWN_TX_RING_COUNT; } if (txq->queued == 0 && res != NULL) { iwn_nic_lock(sc); ops->ampdu_tx_stop(sc, qid, tid, ssn); iwn_nic_unlock(sc); sc->qid2tap[qid] = NULL; free(res, M_DEVBUF); return; } if (wn->agg[tid].bitmap == 0) return; shift = wn->agg[tid].startidx - ((le16toh(ba->seq) >> 4) & 0xff); if (shift < 0) shift += 0x100; if (wn->agg[tid].nframes > (64 - shift)) return; /* * Walk the bitmap and calculate how many successful and failed * attempts are made. * * Yes, the rate control code doesn't know these are A-MPDU * subframes and that it's okay to fail some of these. */ ni = tap->txa_ni; bitmap = (le64toh(ba->bitmap) >> shift) & wn->agg[tid].bitmap; for (i = 0; bitmap; i++) { if ((bitmap & 1) == 0) { if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); tx_err ++; ieee80211_ratectl_tx_complete(ni->ni_vap, ni, IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); } else { if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); tx_ok ++; ieee80211_ratectl_tx_complete(ni->ni_vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); } bitmap >>= 1; } DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, "->%s: end; %d ok; %d err\n",__func__, tx_ok, tx_err); } /* * Process a CALIBRATION_RESULT notification sent by the initialization * firmware on response to a CMD_CALIB_CONFIG command (5000 only). */ static void iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn_phy_calib *calib = (struct iwn_phy_calib *)(desc + 1); int len, idx = -1; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); /* Runtime firmware should not send such a notification. */ if (sc->sc_flags & IWN_FLAG_CALIB_DONE){ DPRINTF(sc, IWN_DEBUG_TRACE, "->%s received after clib done\n", __func__); return; } len = (le32toh(desc->len) & 0x3fff) - 4; bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); switch (calib->code) { case IWN5000_PHY_CALIB_DC: if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_DC) idx = 0; break; case IWN5000_PHY_CALIB_LO: if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_LO) idx = 1; break; case IWN5000_PHY_CALIB_TX_IQ: if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TX_IQ) idx = 2; break; case IWN5000_PHY_CALIB_TX_IQ_PERIODIC: if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TX_IQ_PERIODIC) idx = 3; break; case IWN5000_PHY_CALIB_BASE_BAND: if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_BASE_BAND) idx = 4; break; } if (idx == -1) /* Ignore other results. */ return; /* Save calibration result. */ if (sc->calibcmd[idx].buf != NULL) free(sc->calibcmd[idx].buf, M_DEVBUF); sc->calibcmd[idx].buf = malloc(len, M_DEVBUF, M_NOWAIT); if (sc->calibcmd[idx].buf == NULL) { DPRINTF(sc, IWN_DEBUG_CALIBRATE, "not enough memory for calibration result %d\n", calib->code); return; } DPRINTF(sc, IWN_DEBUG_CALIBRATE, "saving calibration result idx=%d, code=%d len=%d\n", idx, calib->code, len); sc->calibcmd[idx].len = len; memcpy(sc->calibcmd[idx].buf, calib, len); } static void iwn_stats_update(struct iwn_softc *sc, struct iwn_calib_state *calib, struct iwn_stats *stats, int len) { struct iwn_stats_bt *stats_bt; struct iwn_stats *lstats; /* * First - check whether the length is the bluetooth or normal. * * If it's normal - just copy it and bump out. * Otherwise we have to convert things. */ if (len == sizeof(struct iwn_stats) + 4) { memcpy(&sc->last_stat, stats, sizeof(struct iwn_stats)); sc->last_stat_valid = 1; return; } /* * If it's not the bluetooth size - log, then just copy. */ if (len != sizeof(struct iwn_stats_bt) + 4) { DPRINTF(sc, IWN_DEBUG_STATS, "%s: size of rx statistics (%d) not an expected size!\n", __func__, len); memcpy(&sc->last_stat, stats, sizeof(struct iwn_stats)); sc->last_stat_valid = 1; return; } /* * Ok. Time to copy. */ stats_bt = (struct iwn_stats_bt *) stats; lstats = &sc->last_stat; /* flags */ lstats->flags = stats_bt->flags; /* rx_bt */ memcpy(&lstats->rx.ofdm, &stats_bt->rx_bt.ofdm, sizeof(struct iwn_rx_phy_stats)); memcpy(&lstats->rx.cck, &stats_bt->rx_bt.cck, sizeof(struct iwn_rx_phy_stats)); memcpy(&lstats->rx.general, &stats_bt->rx_bt.general_bt.common, sizeof(struct iwn_rx_general_stats)); memcpy(&lstats->rx.ht, &stats_bt->rx_bt.ht, sizeof(struct iwn_rx_ht_phy_stats)); /* tx */ memcpy(&lstats->tx, &stats_bt->tx, sizeof(struct iwn_tx_stats)); /* general */ memcpy(&lstats->general, &stats_bt->general, sizeof(struct iwn_general_stats)); /* XXX TODO: Squirrel away the extra bluetooth stats somewhere */ sc->last_stat_valid = 1; } /* * Process an RX_STATISTICS or BEACON_STATISTICS firmware notification. * The latter is sent by the firmware after each received beacon. */ static void iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct iwn_calib_state *calib = &sc->calib; struct iwn_stats *stats = (struct iwn_stats *)(desc + 1); struct iwn_stats *lstats; int temp; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); /* Ignore statistics received during a scan. */ if (vap->iv_state != IEEE80211_S_RUN || (ic->ic_flags & IEEE80211_F_SCAN)){ DPRINTF(sc, IWN_DEBUG_TRACE, "->%s received during calib\n", __func__); return; } bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_STATS, "%s: received statistics, cmd %d, len %d\n", __func__, desc->type, le16toh(desc->len)); sc->calib_cnt = 0; /* Reset TX power calibration timeout. */ /* * Collect/track general statistics for reporting. * * This takes care of ensuring that the bluetooth sized message * will be correctly converted to the legacy sized message. */ iwn_stats_update(sc, calib, stats, le16toh(desc->len)); /* * And now, let's take a reference of it to use! */ lstats = &sc->last_stat; /* Test if temperature has changed. */ if (lstats->general.temp != sc->rawtemp) { /* Convert "raw" temperature to degC. */ sc->rawtemp = stats->general.temp; temp = ops->get_temperature(sc); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: temperature %d\n", __func__, temp); /* Update TX power if need be (4965AGN only). */ if (sc->hw_type == IWN_HW_REV_TYPE_4965) iwn4965_power_calibration(sc, temp); } if (desc->type != IWN_BEACON_STATISTICS) return; /* Reply to a statistics request. */ sc->noise = iwn_get_noise(&lstats->rx.general); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: noise %d\n", __func__, sc->noise); /* Test that RSSI and noise are present in stats report. */ if (le32toh(lstats->rx.general.flags) != 1) { DPRINTF(sc, IWN_DEBUG_ANY, "%s\n", "received statistics without RSSI"); return; } if (calib->state == IWN_CALIB_STATE_ASSOC) iwn_collect_noise(sc, &lstats->rx.general); else if (calib->state == IWN_CALIB_STATE_RUN) { iwn_tune_sensitivity(sc, &lstats->rx); /* * XXX TODO: Only run the RX recovery if we're associated! */ iwn_check_rx_recovery(sc, lstats); iwn_save_stats_counters(sc, lstats); } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); } /* * Save the relevant statistic counters for the next calibration * pass. */ static void iwn_save_stats_counters(struct iwn_softc *sc, const struct iwn_stats *rs) { struct iwn_calib_state *calib = &sc->calib; /* Save counters values for next call. */ calib->bad_plcp_cck = le32toh(rs->rx.cck.bad_plcp); calib->fa_cck = le32toh(rs->rx.cck.fa); calib->bad_plcp_ht = le32toh(rs->rx.ht.bad_plcp); calib->bad_plcp_ofdm = le32toh(rs->rx.ofdm.bad_plcp); calib->fa_ofdm = le32toh(rs->rx.ofdm.fa); /* Last time we received these tick values */ sc->last_calib_ticks = ticks; } /* * Process a TX_DONE firmware notification. Unfortunately, the 4965AGN * and 5000 adapters have different incompatible TX status formats. */ static void iwn4965_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn4965_tx_stat *stat = (struct iwn4965_tx_stat *)(desc + 1); struct iwn_tx_ring *ring; int qid; qid = desc->qid & 0xf; ring = &sc->txq[qid]; DPRINTF(sc, IWN_DEBUG_XMIT, "%s: " "qid %d idx %d RTS retries %d ACK retries %d nkill %d rate %x duration %d status %x\n", __func__, desc->qid, desc->idx, stat->rtsfailcnt, stat->ackfailcnt, stat->btkillcnt, stat->rate, le16toh(stat->duration), le32toh(stat->status)); bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD); if (qid >= sc->firstaggqueue) { iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes, stat->ackfailcnt, &stat->status); } else { iwn_tx_done(sc, desc, stat->ackfailcnt, le32toh(stat->status) & 0xff); } } static void iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, struct iwn_rx_data *data) { struct iwn5000_tx_stat *stat = (struct iwn5000_tx_stat *)(desc + 1); struct iwn_tx_ring *ring; int qid; qid = desc->qid & 0xf; ring = &sc->txq[qid]; DPRINTF(sc, IWN_DEBUG_XMIT, "%s: " "qid %d idx %d RTS retries %d ACK retries %d nkill %d rate %x duration %d status %x\n", __func__, desc->qid, desc->idx, stat->rtsfailcnt, stat->ackfailcnt, stat->btkillcnt, stat->rate, le16toh(stat->duration), le32toh(stat->status)); #ifdef notyet /* Reset TX scheduler slot. */ iwn5000_reset_sched(sc, desc->qid & 0xf, desc->idx); #endif bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD); if (qid >= sc->firstaggqueue) { iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes, stat->ackfailcnt, &stat->status); } else { iwn_tx_done(sc, desc, stat->ackfailcnt, le16toh(stat->status) & 0xff); } } /* * Adapter-independent backend for TX_DONE firmware notifications. */ static void iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int ackfailcnt, uint8_t status) { struct ifnet *ifp = sc->sc_ifp; struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf]; struct iwn_tx_data *data = &ring->data[desc->idx]; struct mbuf *m; struct ieee80211_node *ni; struct ieee80211vap *vap; KASSERT(data->ni != NULL, ("no node")); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); /* Unmap and free mbuf. */ bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ring->data_dmat, data->map); m = data->m, data->m = NULL; ni = data->ni, data->ni = NULL; vap = ni->ni_vap; /* * Update rate control statistics for the node. */ if (status & IWN_TX_FAIL) { if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); } else { if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); } /* * Channels marked for "radar" require traffic to be received * to unlock before we can transmit. Until traffic is seen * any attempt to transmit is returned immediately with status * set to IWN_TX_FAIL_TX_LOCKED. Unfortunately this can easily * happen on first authenticate after scanning. To workaround * this we ignore a failure of this sort in AUTH state so the * 802.11 layer will fall back to using a timeout to wait for * the AUTH reply. This allows the firmware time to see * traffic so a subsequent retry of AUTH succeeds. It's * unclear why the firmware does not maintain state for * channels recently visited as this would allow immediate * use of the channel after a scan (where we see traffic). */ if (status == IWN_TX_FAIL_TX_LOCKED && ni->ni_vap->iv_state == IEEE80211_S_AUTH) ieee80211_tx_complete(ni, m, 0); else ieee80211_tx_complete(ni, m, (status & IWN_TX_FAIL) != 0); sc->sc_tx_timer = 0; if (--ring->queued < IWN_TX_RING_LOMARK) { sc->qfullmsk &= ~(1 << ring->qid); if (sc->qfullmsk == 0 && (ifp->if_drv_flags & IFF_DRV_OACTIVE)) { ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; iwn_start_locked(ifp); } } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); } /* * Process a "command done" firmware notification. This is where we wakeup * processes waiting for a synchronous command completion. */ static void iwn_cmd_done(struct iwn_softc *sc, struct iwn_rx_desc *desc) { struct iwn_tx_ring *ring; struct iwn_tx_data *data; int cmd_queue_num; if (sc->sc_flags & IWN_FLAG_PAN_SUPPORT) cmd_queue_num = IWN_PAN_CMD_QUEUE; else cmd_queue_num = IWN_CMD_QUEUE_NUM; if ((desc->qid & IWN_RX_DESC_QID_MSK) != cmd_queue_num) return; /* Not a command ack. */ ring = &sc->txq[cmd_queue_num]; data = &ring->data[desc->idx]; /* If the command was mapped in an mbuf, free it. */ if (data->m != NULL) { bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ring->data_dmat, data->map); m_freem(data->m); data->m = NULL; } wakeup(&ring->desc[desc->idx]); } static void iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes, int ackfailcnt, void *stat) { struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct iwn_tx_ring *ring = &sc->txq[qid]; struct iwn_tx_data *data; struct mbuf *m; struct iwn_node *wn; struct ieee80211_node *ni; struct ieee80211_tx_ampdu *tap; uint64_t bitmap; uint32_t *status = stat; uint16_t *aggstatus = stat; uint16_t ssn; uint8_t tid; int bit, i, lastidx, *res, seqno, shift, start; /* XXX TODO: status is le16 field! Grr */ DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); DPRINTF(sc, IWN_DEBUG_XMIT, "%s: nframes=%d, status=0x%08x\n", __func__, nframes, *status); tap = sc->qid2tap[qid]; tid = tap->txa_tid; wn = (void *)tap->txa_ni; ni = tap->txa_ni; /* * XXX TODO: ACK and RTS failures would be nice here! */ /* * A-MPDU single frame status - if we failed to transmit it * in A-MPDU, then it may be a permanent failure. * * XXX TODO: check what the Linux iwlwifi driver does here; * there's some permanent and temporary failures that may be * handled differently. */ if (nframes == 1) { if ((*status & 0xff) != 1 && (*status & 0xff) != 2) { #ifdef NOT_YET printf("ieee80211_send_bar()\n"); #endif /* * If we completely fail a transmit, make sure a * notification is pushed up to the rate control * layer. */ ieee80211_ratectl_tx_complete(ni->ni_vap, ni, IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); } else { /* * If nframes=1, then we won't be getting a BA for * this frame. Ensure that we correctly update the * rate control code with how many retries were * needed to send it. */ ieee80211_ratectl_tx_complete(ni->ni_vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); } } bitmap = 0; start = idx; for (i = 0; i < nframes; i++) { if (le16toh(aggstatus[i * 2]) & 0xc) continue; idx = le16toh(aggstatus[2*i + 1]) & 0xff; bit = idx - start; shift = 0; if (bit >= 64) { shift = 0x100 - idx + start; bit = 0; start = idx; } else if (bit <= -64) bit = 0x100 - start + idx; else if (bit < 0) { shift = start - idx; start = idx; bit = 0; } bitmap = bitmap << shift; bitmap |= 1ULL << bit; } tap = sc->qid2tap[qid]; tid = tap->txa_tid; wn = (void *)tap->txa_ni; wn->agg[tid].bitmap = bitmap; wn->agg[tid].startidx = start; wn->agg[tid].nframes = nframes; res = NULL; ssn = 0; if (!IEEE80211_AMPDU_RUNNING(tap)) { res = tap->txa_private; ssn = tap->txa_start & 0xfff; } /* This is going nframes DWORDS into the descriptor? */ seqno = le32toh(*(status + nframes)) & 0xfff; for (lastidx = (seqno & 0xff); ring->read != lastidx;) { data = &ring->data[ring->read]; /* Unmap and free mbuf. */ bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ring->data_dmat, data->map); m = data->m, data->m = NULL; ni = data->ni, data->ni = NULL; KASSERT(ni != NULL, ("no node")); KASSERT(m != NULL, ("no mbuf")); DPRINTF(sc, IWN_DEBUG_XMIT, "%s: freeing m=%p\n", __func__, m); ieee80211_tx_complete(ni, m, 1); ring->queued--; ring->read = (ring->read + 1) % IWN_TX_RING_COUNT; } if (ring->queued == 0 && res != NULL) { iwn_nic_lock(sc); ops->ampdu_tx_stop(sc, qid, tid, ssn); iwn_nic_unlock(sc); sc->qid2tap[qid] = NULL; free(res, M_DEVBUF); return; } sc->sc_tx_timer = 0; if (ring->queued < IWN_TX_RING_LOMARK) { sc->qfullmsk &= ~(1 << ring->qid); if (sc->qfullmsk == 0 && (ifp->if_drv_flags & IFF_DRV_OACTIVE)) { ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; iwn_start_locked(ifp); } } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); } /* * Process an INT_FH_RX or INT_SW_RX interrupt. */ static void iwn_notif_intr(struct iwn_softc *sc) { struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); uint16_t hw; bus_dmamap_sync(sc->rxq.stat_dma.tag, sc->rxq.stat_dma.map, BUS_DMASYNC_POSTREAD); hw = le16toh(sc->rxq.stat->closed_count) & 0xfff; while (sc->rxq.cur != hw) { struct iwn_rx_data *data = &sc->rxq.data[sc->rxq.cur]; struct iwn_rx_desc *desc; bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); desc = mtod(data->m, struct iwn_rx_desc *); DPRINTF(sc, IWN_DEBUG_RECV, "%s: cur=%d; qid %x idx %d flags %x type %d(%s) len %d\n", __func__, sc->rxq.cur, desc->qid & 0xf, desc->idx, desc->flags, desc->type, iwn_intr_str(desc->type), le16toh(desc->len)); if (!(desc->qid & IWN_UNSOLICITED_RX_NOTIF)) /* Reply to a command. */ iwn_cmd_done(sc, desc); switch (desc->type) { case IWN_RX_PHY: iwn_rx_phy(sc, desc, data); break; case IWN_RX_DONE: /* 4965AGN only. */ case IWN_MPDU_RX_DONE: /* An 802.11 frame has been received. */ iwn_rx_done(sc, desc, data); break; case IWN_RX_COMPRESSED_BA: /* A Compressed BlockAck has been received. */ iwn_rx_compressed_ba(sc, desc, data); break; case IWN_TX_DONE: /* An 802.11 frame has been transmitted. */ ops->tx_done(sc, desc, data); break; case IWN_RX_STATISTICS: case IWN_BEACON_STATISTICS: iwn_rx_statistics(sc, desc, data); break; case IWN_BEACON_MISSED: { struct iwn_beacon_missed *miss = (struct iwn_beacon_missed *)(desc + 1); int misses; bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); misses = le32toh(miss->consecutive); DPRINTF(sc, IWN_DEBUG_STATE, "%s: beacons missed %d/%d\n", __func__, misses, le32toh(miss->total)); /* * If more than 5 consecutive beacons are missed, * reinitialize the sensitivity state machine. */ if (vap->iv_state == IEEE80211_S_RUN && (ic->ic_flags & IEEE80211_F_SCAN) == 0) { if (misses > 5) (void)iwn_init_sensitivity(sc); if (misses >= vap->iv_bmissthreshold) { IWN_UNLOCK(sc); ieee80211_beacon_miss(ic); IWN_LOCK(sc); } } break; } case IWN_UC_READY: { struct iwn_ucode_info *uc = (struct iwn_ucode_info *)(desc + 1); /* The microcontroller is ready. */ bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); DPRINTF(sc, IWN_DEBUG_RESET, "microcode alive notification version=%d.%d " "subtype=%x alive=%x\n", uc->major, uc->minor, uc->subtype, le32toh(uc->valid)); if (le32toh(uc->valid) != 1) { device_printf(sc->sc_dev, "microcontroller initialization failed"); break; } if (uc->subtype == IWN_UCODE_INIT) { /* Save microcontroller report. */ memcpy(&sc->ucode_info, uc, sizeof (*uc)); } /* Save the address of the error log in SRAM. */ sc->errptr = le32toh(uc->errptr); break; } case IWN_STATE_CHANGED: { /* * State change allows hardware switch change to be * noted. However, we handle this in iwn_intr as we * get both the enable/disble intr. */ bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); #ifdef IWN_DEBUG uint32_t *status = (uint32_t *)(desc + 1); DPRINTF(sc, IWN_DEBUG_INTR | IWN_DEBUG_STATE, "state changed to %x\n", le32toh(*status)); #endif break; } case IWN_START_SCAN: { bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); #ifdef IWN_DEBUG struct iwn_start_scan *scan = (struct iwn_start_scan *)(desc + 1); DPRINTF(sc, IWN_DEBUG_ANY, "%s: scanning channel %d status %x\n", __func__, scan->chan, le32toh(scan->status)); #endif break; } case IWN_STOP_SCAN: { bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); #ifdef IWN_DEBUG struct iwn_stop_scan *scan = (struct iwn_stop_scan *)(desc + 1); DPRINTF(sc, IWN_DEBUG_STATE | IWN_DEBUG_SCAN, "scan finished nchan=%d status=%d chan=%d\n", scan->nchan, scan->status, scan->chan); #endif sc->sc_is_scanning = 0; IWN_UNLOCK(sc); ieee80211_scan_next(vap); IWN_LOCK(sc); break; } case IWN5000_CALIBRATION_RESULT: iwn5000_rx_calib_results(sc, desc, data); break; case IWN5000_CALIBRATION_DONE: sc->sc_flags |= IWN_FLAG_CALIB_DONE; wakeup(sc); break; } sc->rxq.cur = (sc->rxq.cur + 1) % IWN_RX_RING_COUNT; } /* Tell the firmware what we have processed. */ hw = (hw == 0) ? IWN_RX_RING_COUNT - 1 : hw - 1; IWN_WRITE(sc, IWN_FH_RX_WPTR, hw & ~7); } /* * Process an INT_WAKEUP interrupt raised when the microcontroller wakes up * from power-down sleep mode. */ static void iwn_wakeup_intr(struct iwn_softc *sc) { int qid; DPRINTF(sc, IWN_DEBUG_RESET, "%s: ucode wakeup from power-down sleep\n", __func__); /* Wakeup RX and TX rings. */ IWN_WRITE(sc, IWN_FH_RX_WPTR, sc->rxq.cur & ~7); for (qid = 0; qid < sc->ntxqs; qid++) { struct iwn_tx_ring *ring = &sc->txq[qid]; IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | ring->cur); } } static void iwn_rftoggle_intr(struct iwn_softc *sc) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp = IWN_READ(sc, IWN_GP_CNTRL); IWN_LOCK_ASSERT(sc); device_printf(sc->sc_dev, "RF switch: radio %s\n", (tmp & IWN_GP_CNTRL_RFKILL) ? "enabled" : "disabled"); if (tmp & IWN_GP_CNTRL_RFKILL) ieee80211_runtask(ic, &sc->sc_radioon_task); else ieee80211_runtask(ic, &sc->sc_radiooff_task); } /* * Dump the error log of the firmware when a firmware panic occurs. Although * we can't debug the firmware because it is neither open source nor free, it * can help us to identify certain classes of problems. */ static void iwn_fatal_intr(struct iwn_softc *sc) { struct iwn_fw_dump dump; int i; IWN_LOCK_ASSERT(sc); /* Force a complete recalibration on next init. */ sc->sc_flags &= ~IWN_FLAG_CALIB_DONE; /* Check that the error log address is valid. */ if (sc->errptr < IWN_FW_DATA_BASE || sc->errptr + sizeof (dump) > IWN_FW_DATA_BASE + sc->fw_data_maxsz) { printf("%s: bad firmware error log address 0x%08x\n", __func__, sc->errptr); return; } if (iwn_nic_lock(sc) != 0) { printf("%s: could not read firmware error log\n", __func__); return; } /* Read firmware error log from SRAM. */ iwn_mem_read_region_4(sc, sc->errptr, (uint32_t *)&dump, sizeof (dump) / sizeof (uint32_t)); iwn_nic_unlock(sc); if (dump.valid == 0) { printf("%s: firmware error log is empty\n", __func__); return; } printf("firmware error log:\n"); printf(" error type = \"%s\" (0x%08X)\n", (dump.id < nitems(iwn_fw_errmsg)) ? iwn_fw_errmsg[dump.id] : "UNKNOWN", dump.id); printf(" program counter = 0x%08X\n", dump.pc); printf(" source line = 0x%08X\n", dump.src_line); printf(" error data = 0x%08X%08X\n", dump.error_data[0], dump.error_data[1]); printf(" branch link = 0x%08X%08X\n", dump.branch_link[0], dump.branch_link[1]); printf(" interrupt link = 0x%08X%08X\n", dump.interrupt_link[0], dump.interrupt_link[1]); printf(" time = %u\n", dump.time[0]); /* Dump driver status (TX and RX rings) while we're here. */ printf("driver status:\n"); for (i = 0; i < sc->ntxqs; i++) { struct iwn_tx_ring *ring = &sc->txq[i]; printf(" tx ring %2d: qid=%-2d cur=%-3d queued=%-3d\n", i, ring->qid, ring->cur, ring->queued); } printf(" rx ring: cur=%d\n", sc->rxq.cur); } static void iwn_intr(void *arg) { struct iwn_softc *sc = arg; struct ifnet *ifp = sc->sc_ifp; uint32_t r1, r2, tmp; IWN_LOCK(sc); /* Disable interrupts. */ IWN_WRITE(sc, IWN_INT_MASK, 0); /* Read interrupts from ICT (fast) or from registers (slow). */ if (sc->sc_flags & IWN_FLAG_USE_ICT) { tmp = 0; while (sc->ict[sc->ict_cur] != 0) { tmp |= sc->ict[sc->ict_cur]; sc->ict[sc->ict_cur] = 0; /* Acknowledge. */ sc->ict_cur = (sc->ict_cur + 1) % IWN_ICT_COUNT; } tmp = le32toh(tmp); if (tmp == 0xffffffff) /* Shouldn't happen. */ tmp = 0; else if (tmp & 0xc0000) /* Workaround a HW bug. */ tmp |= 0x8000; r1 = (tmp & 0xff00) << 16 | (tmp & 0xff); r2 = 0; /* Unused. */ } else { r1 = IWN_READ(sc, IWN_INT); - if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0) + if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0) { + IWN_UNLOCK(sc); return; /* Hardware gone! */ + } r2 = IWN_READ(sc, IWN_FH_INT); } DPRINTF(sc, IWN_DEBUG_INTR, "interrupt reg1=0x%08x reg2=0x%08x\n" , r1, r2); if (r1 == 0 && r2 == 0) goto done; /* Interrupt not for us. */ /* Acknowledge interrupts. */ IWN_WRITE(sc, IWN_INT, r1); if (!(sc->sc_flags & IWN_FLAG_USE_ICT)) IWN_WRITE(sc, IWN_FH_INT, r2); if (r1 & IWN_INT_RF_TOGGLED) { iwn_rftoggle_intr(sc); goto done; } if (r1 & IWN_INT_CT_REACHED) { device_printf(sc->sc_dev, "%s: critical temperature reached!\n", __func__); } if (r1 & (IWN_INT_SW_ERR | IWN_INT_HW_ERR)) { device_printf(sc->sc_dev, "%s: fatal firmware error\n", __func__); #ifdef IWN_DEBUG iwn_debug_register(sc); #endif /* Dump firmware error log and stop. */ iwn_fatal_intr(sc); taskqueue_enqueue(sc->sc_tq, &sc->sc_panic_task); goto done; } if ((r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX | IWN_INT_RX_PERIODIC)) || (r2 & IWN_FH_INT_RX)) { if (sc->sc_flags & IWN_FLAG_USE_ICT) { if (r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX)) IWN_WRITE(sc, IWN_FH_INT, IWN_FH_INT_RX); IWN_WRITE_1(sc, IWN_INT_PERIODIC, IWN_INT_PERIODIC_DIS); iwn_notif_intr(sc); if (r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX)) { IWN_WRITE_1(sc, IWN_INT_PERIODIC, IWN_INT_PERIODIC_ENA); } } else iwn_notif_intr(sc); } if ((r1 & IWN_INT_FH_TX) || (r2 & IWN_FH_INT_TX)) { if (sc->sc_flags & IWN_FLAG_USE_ICT) IWN_WRITE(sc, IWN_FH_INT, IWN_FH_INT_TX); wakeup(sc); /* FH DMA transfer completed. */ } if (r1 & IWN_INT_ALIVE) wakeup(sc); /* Firmware is alive. */ if (r1 & IWN_INT_WAKEUP) iwn_wakeup_intr(sc); done: /* Re-enable interrupts. */ if (ifp->if_flags & IFF_UP) IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); IWN_UNLOCK(sc); } /* * Update TX scheduler ring when transmitting an 802.11 frame (4965AGN and * 5000 adapters use a slightly different format). */ static void iwn4965_update_sched(struct iwn_softc *sc, int qid, int idx, uint8_t id, uint16_t len) { uint16_t *w = &sc->sched[qid * IWN4965_SCHED_COUNT + idx]; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); *w = htole16(len + 8); bus_dmamap_sync(sc->sched_dma.tag, sc->sched_dma.map, BUS_DMASYNC_PREWRITE); if (idx < IWN_SCHED_WINSZ) { *(w + IWN_TX_RING_COUNT) = *w; bus_dmamap_sync(sc->sched_dma.tag, sc->sched_dma.map, BUS_DMASYNC_PREWRITE); } } static void iwn5000_update_sched(struct iwn_softc *sc, int qid, int idx, uint8_t id, uint16_t len) { uint16_t *w = &sc->sched[qid * IWN5000_SCHED_COUNT + idx]; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); *w = htole16(id << 12 | (len + 8)); bus_dmamap_sync(sc->sched_dma.tag, sc->sched_dma.map, BUS_DMASYNC_PREWRITE); if (idx < IWN_SCHED_WINSZ) { *(w + IWN_TX_RING_COUNT) = *w; bus_dmamap_sync(sc->sched_dma.tag, sc->sched_dma.map, BUS_DMASYNC_PREWRITE); } } #ifdef notyet static void iwn5000_reset_sched(struct iwn_softc *sc, int qid, int idx) { uint16_t *w = &sc->sched[qid * IWN5000_SCHED_COUNT + idx]; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); *w = (*w & htole16(0xf000)) | htole16(1); bus_dmamap_sync(sc->sched_dma.tag, sc->sched_dma.map, BUS_DMASYNC_PREWRITE); if (idx < IWN_SCHED_WINSZ) { *(w + IWN_TX_RING_COUNT) = *w; bus_dmamap_sync(sc->sched_dma.tag, sc->sched_dma.map, BUS_DMASYNC_PREWRITE); } } #endif /* * Check whether OFDM 11g protection will be enabled for the given rate. * * The original driver code only enabled protection for OFDM rates. * It didn't check to see whether it was operating in 11a or 11bg mode. */ static int iwn_check_rate_needs_protection(struct iwn_softc *sc, struct ieee80211vap *vap, uint8_t rate) { struct ieee80211com *ic = vap->iv_ic; /* * Not in 2GHz mode? Then there's no need to enable OFDM * 11bg protection. */ if (! IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) { return (0); } /* * 11bg protection not enabled? Then don't use it. */ if ((ic->ic_flags & IEEE80211_F_USEPROT) == 0) return (0); /* * If it's an 11n rate - no protection. * We'll do it via a specific 11n check. */ if (rate & IEEE80211_RATE_MCS) { return (0); } /* * Do a rate table lookup. If the PHY is CCK, * don't do protection. */ if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_CCK) return (0); /* * Yup, enable protection. */ return (1); } /* * return a value between 0 and IWN_MAX_TX_RETRIES-1 as an index into * the link quality table that reflects this particular entry. */ static int iwn_tx_rate_to_linkq_offset(struct iwn_softc *sc, struct ieee80211_node *ni, uint8_t rate) { struct ieee80211_rateset *rs; int is_11n; int nr; int i; uint8_t cmp_rate; /* * Figure out if we're using 11n or not here. */ if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_htrates.rs_nrates > 0) is_11n = 1; else is_11n = 0; /* * Use the correct rate table. */ if (is_11n) { rs = (struct ieee80211_rateset *) &ni->ni_htrates; nr = ni->ni_htrates.rs_nrates; } else { rs = &ni->ni_rates; nr = rs->rs_nrates; } /* * Find the relevant link quality entry in the table. */ for (i = 0; i < nr && i < IWN_MAX_TX_RETRIES - 1 ; i++) { /* * The link quality table index starts at 0 == highest * rate, so we walk the rate table backwards. */ cmp_rate = rs->rs_rates[(nr - 1) - i]; if (rate & IEEE80211_RATE_MCS) cmp_rate |= IEEE80211_RATE_MCS; #if 0 DPRINTF(sc, IWN_DEBUG_XMIT, "%s: idx %d: nr=%d, rate=0x%02x, rateentry=0x%02x\n", __func__, i, nr, rate, cmp_rate); #endif if (cmp_rate == rate) return (i); } /* Failed? Start at the end */ return (IWN_MAX_TX_RETRIES - 1); } static int iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { struct iwn_ops *ops = &sc->ops; const struct ieee80211_txparam *tp; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct iwn_node *wn = (void *)ni; struct iwn_tx_ring *ring; struct iwn_tx_desc *desc; struct iwn_tx_data *data; struct iwn_tx_cmd *cmd; struct iwn_cmd_data *tx; struct ieee80211_frame *wh; struct ieee80211_key *k = NULL; struct mbuf *m1; uint32_t flags; uint16_t qos; u_int hdrlen; bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER]; uint8_t tid, type; int ac, i, totlen, error, pad, nsegs = 0, rate; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); IWN_LOCK_ASSERT(sc); wh = mtod(m, struct ieee80211_frame *); hdrlen = ieee80211_anyhdrsize(wh); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; /* Select EDCA Access Category and TX ring for this frame. */ if (IEEE80211_QOS_HAS_SEQ(wh)) { qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; tid = qos & IEEE80211_QOS_TID; } else { qos = 0; tid = 0; } ac = M_WME_GETAC(m); if (m->m_flags & M_AMPDU_MPDU) { uint16_t seqno; struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac]; if (!IEEE80211_AMPDU_RUNNING(tap)) { m_freem(m); return EINVAL; } /* * Queue this frame to the hardware ring that we've * negotiated AMPDU TX on. * * Note that the sequence number must match the TX slot * being used! */ ac = *(int *)tap->txa_private; seqno = ni->ni_txseqs[tid]; *(uint16_t *)wh->i_seq = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); ring = &sc->txq[ac]; if ((seqno % 256) != ring->cur) { device_printf(sc->sc_dev, "%s: m=%p: seqno (%d) (%d) != ring index (%d) !\n", __func__, m, seqno, seqno % 256, ring->cur); } ni->ni_txseqs[tid]++; } ring = &sc->txq[ac]; desc = &ring->desc[ring->cur]; data = &ring->data[ring->cur]; /* Choose a TX rate index. */ tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; if (type == IEEE80211_FC0_TYPE_MGT) rate = tp->mgmtrate; else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) rate = tp->mcastrate; else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) rate = tp->ucastrate; else if (m->m_flags & M_EAPOL) rate = tp->mgmtrate; else { /* XXX pass pktlen */ (void) ieee80211_ratectl_rate(ni, NULL, 0); rate = ni->ni_txrate; } /* Encrypt the frame if need be. */ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { /* Retrieve key for TX. */ k = ieee80211_crypto_encap(ni, m); if (k == NULL) { m_freem(m); return ENOBUFS; } /* 802.11 header may have moved. */ wh = mtod(m, struct ieee80211_frame *); } totlen = m->m_pkthdr.len; if (ieee80211_radiotap_active_vap(vap)) { struct iwn_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; tap->wt_rate = rate; if (k != NULL) tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; ieee80211_radiotap_tx(vap, m); } /* Prepare TX firmware command. */ cmd = &ring->cmd[ring->cur]; cmd->code = IWN_CMD_TX_DATA; cmd->flags = 0; cmd->qid = ring->qid; cmd->idx = ring->cur; tx = (struct iwn_cmd_data *)cmd->data; /* NB: No need to clear tx, all fields are reinitialized here. */ tx->scratch = 0; /* clear "scratch" area */ flags = 0; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { /* Unicast frame, check if an ACK is expected. */ if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != IEEE80211_QOS_ACKPOLICY_NOACK) flags |= IWN_TX_NEED_ACK; } if ((wh->i_fc[0] & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == (IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR)) flags |= IWN_TX_IMM_BA; /* Cannot happen yet. */ if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) flags |= IWN_TX_MORE_FRAG; /* Cannot happen yet. */ /* Check if frame must be protected using RTS/CTS or CTS-to-self. */ if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { /* NB: Group frames are sent using CCK in 802.11b/g. */ if (totlen + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) { flags |= IWN_TX_NEED_RTS; } else if (iwn_check_rate_needs_protection(sc, vap, rate)) { if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) flags |= IWN_TX_NEED_CTS; else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) flags |= IWN_TX_NEED_RTS; } else if ((rate & IEEE80211_RATE_MCS) && (ic->ic_htprotmode == IEEE80211_PROT_RTSCTS)) { flags |= IWN_TX_NEED_RTS; } /* XXX HT protection? */ if (flags & (IWN_TX_NEED_RTS | IWN_TX_NEED_CTS)) { if (sc->hw_type != IWN_HW_REV_TYPE_4965) { /* 5000 autoselects RTS/CTS or CTS-to-self. */ flags &= ~(IWN_TX_NEED_RTS | IWN_TX_NEED_CTS); flags |= IWN_TX_NEED_PROTECTION; } else flags |= IWN_TX_FULL_TXOP; } } if (IEEE80211_IS_MULTICAST(wh->i_addr1) || type != IEEE80211_FC0_TYPE_DATA) tx->id = sc->broadcast_id; else tx->id = wn->id; if (type == IEEE80211_FC0_TYPE_MGT) { uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; /* Tell HW to set timestamp in probe responses. */ if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) flags |= IWN_TX_INSERT_TSTAMP; if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ || subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) tx->timeout = htole16(3); else tx->timeout = htole16(2); } else tx->timeout = htole16(0); if (hdrlen & 3) { /* First segment length must be a multiple of 4. */ flags |= IWN_TX_NEED_PADDING; pad = 4 - (hdrlen & 3); } else pad = 0; tx->len = htole16(totlen); tx->tid = tid; tx->rts_ntries = 60; tx->data_ntries = 15; tx->lifetime = htole32(IWN_LIFETIME_INFINITE); tx->rate = iwn_rate_to_plcp(sc, ni, rate); if (tx->id == sc->broadcast_id) { /* Group or management frame. */ tx->linkq = 0; } else { tx->linkq = iwn_tx_rate_to_linkq_offset(sc, ni, rate); flags |= IWN_TX_LINKQ; /* enable MRR */ } /* Set physical address of "scratch area". */ tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr)); tx->hiaddr = IWN_HIADDR(data->scratch_paddr); /* Copy 802.11 header in TX command. */ memcpy((uint8_t *)(tx + 1), wh, hdrlen); /* Trim 802.11 header. */ m_adj(m, hdrlen); tx->security = 0; tx->flags = htole32(flags); error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { if (error != EFBIG) { device_printf(sc->sc_dev, "%s: can't map mbuf (error %d)\n", __func__, error); m_freem(m); return error; } /* Too many DMA segments, linearize mbuf. */ - m1 = m_collapse(m, M_NOWAIT, IWN_MAX_SCATTER); + m1 = m_collapse(m, M_NOWAIT, IWN_MAX_SCATTER - 1); if (m1 == NULL) { device_printf(sc->sc_dev, "%s: could not defrag mbuf\n", __func__); m_freem(m); return ENOBUFS; } m = m1; error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { device_printf(sc->sc_dev, "%s: can't map mbuf (error %d)\n", __func__, error); m_freem(m); return error; } } data->m = m; data->ni = ni; DPRINTF(sc, IWN_DEBUG_XMIT, "%s: qid %d idx %d len %d nsegs %d flags 0x%08x rate 0x%04x plcp 0x%08x\n", __func__, ring->qid, ring->cur, m->m_pkthdr.len, nsegs, flags, rate, tx->rate); /* Fill TX descriptor. */ desc->nsegs = 1; if (m->m_len != 0) desc->nsegs += nsegs; /* First DMA segment is used by the TX command. */ desc->segs[0].addr = htole32(IWN_LOADDR(data->cmd_paddr)); desc->segs[0].len = htole16(IWN_HIADDR(data->cmd_paddr) | (4 + sizeof (*tx) + hdrlen + pad) << 4); /* Other DMA segments are for data payload. */ seg = &segs[0]; for (i = 1; i <= nsegs; i++) { desc->segs[i].addr = htole32(IWN_LOADDR(seg->ds_addr)); desc->segs[i].len = htole16(IWN_HIADDR(seg->ds_addr) | seg->ds_len << 4); seg++; } bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(ring->data_dmat, ring->cmd_dma.map, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); /* Update TX scheduler. */ if (ring->qid >= sc->firstaggqueue) ops->update_sched(sc, ring->qid, ring->cur, tx->id, totlen); /* Kick TX ring. */ ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT; IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); /* Mark TX ring as full if we reach a certain threshold. */ if (++ring->queued > IWN_TX_RING_HIMARK) sc->qfullmsk |= 1 << ring->qid; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return 0; } static int iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { struct iwn_ops *ops = &sc->ops; // struct ifnet *ifp = sc->sc_ifp; struct ieee80211vap *vap = ni->ni_vap; // struct ieee80211com *ic = ifp->if_l2com; struct iwn_tx_cmd *cmd; struct iwn_cmd_data *tx; struct ieee80211_frame *wh; struct iwn_tx_ring *ring; struct iwn_tx_desc *desc; struct iwn_tx_data *data; struct mbuf *m1; bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER]; uint32_t flags; u_int hdrlen; int ac, totlen, error, pad, nsegs = 0, i, rate; uint8_t type; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); IWN_LOCK_ASSERT(sc); wh = mtod(m, struct ieee80211_frame *); hdrlen = ieee80211_anyhdrsize(wh); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; ac = params->ibp_pri & 3; ring = &sc->txq[ac]; desc = &ring->desc[ring->cur]; data = &ring->data[ring->cur]; /* Choose a TX rate. */ rate = params->ibp_rate0; totlen = m->m_pkthdr.len; /* Prepare TX firmware command. */ cmd = &ring->cmd[ring->cur]; cmd->code = IWN_CMD_TX_DATA; cmd->flags = 0; cmd->qid = ring->qid; cmd->idx = ring->cur; tx = (struct iwn_cmd_data *)cmd->data; /* NB: No need to clear tx, all fields are reinitialized here. */ tx->scratch = 0; /* clear "scratch" area */ flags = 0; if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) flags |= IWN_TX_NEED_ACK; if (params->ibp_flags & IEEE80211_BPF_RTS) { if (sc->hw_type != IWN_HW_REV_TYPE_4965) { /* 5000 autoselects RTS/CTS or CTS-to-self. */ flags &= ~IWN_TX_NEED_RTS; flags |= IWN_TX_NEED_PROTECTION; } else flags |= IWN_TX_NEED_RTS | IWN_TX_FULL_TXOP; } if (params->ibp_flags & IEEE80211_BPF_CTS) { if (sc->hw_type != IWN_HW_REV_TYPE_4965) { /* 5000 autoselects RTS/CTS or CTS-to-self. */ flags &= ~IWN_TX_NEED_CTS; flags |= IWN_TX_NEED_PROTECTION; } else flags |= IWN_TX_NEED_CTS | IWN_TX_FULL_TXOP; } if (type == IEEE80211_FC0_TYPE_MGT) { uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; /* Tell HW to set timestamp in probe responses. */ if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) flags |= IWN_TX_INSERT_TSTAMP; if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ || subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) tx->timeout = htole16(3); else tx->timeout = htole16(2); } else tx->timeout = htole16(0); if (hdrlen & 3) { /* First segment length must be a multiple of 4. */ flags |= IWN_TX_NEED_PADDING; pad = 4 - (hdrlen & 3); } else pad = 0; if (ieee80211_radiotap_active_vap(vap)) { struct iwn_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; tap->wt_rate = rate; ieee80211_radiotap_tx(vap, m); } tx->len = htole16(totlen); tx->tid = 0; tx->id = sc->broadcast_id; tx->rts_ntries = params->ibp_try1; tx->data_ntries = params->ibp_try0; tx->lifetime = htole32(IWN_LIFETIME_INFINITE); tx->rate = iwn_rate_to_plcp(sc, ni, rate); /* Group or management frame. */ tx->linkq = 0; /* Set physical address of "scratch area". */ tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr)); tx->hiaddr = IWN_HIADDR(data->scratch_paddr); /* Copy 802.11 header in TX command. */ memcpy((uint8_t *)(tx + 1), wh, hdrlen); /* Trim 802.11 header. */ m_adj(m, hdrlen); tx->security = 0; tx->flags = htole32(flags); error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { if (error != EFBIG) { device_printf(sc->sc_dev, "%s: can't map mbuf (error %d)\n", __func__, error); m_freem(m); return error; } /* Too many DMA segments, linearize mbuf. */ - m1 = m_collapse(m, M_NOWAIT, IWN_MAX_SCATTER); + m1 = m_collapse(m, M_NOWAIT, IWN_MAX_SCATTER - 1); if (m1 == NULL) { device_printf(sc->sc_dev, "%s: could not defrag mbuf\n", __func__); m_freem(m); return ENOBUFS; } m = m1; error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { device_printf(sc->sc_dev, "%s: can't map mbuf (error %d)\n", __func__, error); m_freem(m); return error; } } data->m = m; data->ni = ni; DPRINTF(sc, IWN_DEBUG_XMIT, "%s: qid %d idx %d len %d nsegs %d\n", __func__, ring->qid, ring->cur, m->m_pkthdr.len, nsegs); /* Fill TX descriptor. */ desc->nsegs = 1; if (m->m_len != 0) desc->nsegs += nsegs; /* First DMA segment is used by the TX command. */ desc->segs[0].addr = htole32(IWN_LOADDR(data->cmd_paddr)); desc->segs[0].len = htole16(IWN_HIADDR(data->cmd_paddr) | (4 + sizeof (*tx) + hdrlen + pad) << 4); /* Other DMA segments are for data payload. */ seg = &segs[0]; for (i = 1; i <= nsegs; i++) { desc->segs[i].addr = htole32(IWN_LOADDR(seg->ds_addr)); desc->segs[i].len = htole16(IWN_HIADDR(seg->ds_addr) | seg->ds_len << 4); seg++; } bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(ring->data_dmat, ring->cmd_dma.map, BUS_DMASYNC_PREWRITE); bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); /* Update TX scheduler. */ if (ring->qid >= sc->firstaggqueue) ops->update_sched(sc, ring->qid, ring->cur, tx->id, totlen); /* Kick TX ring. */ ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT; IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); /* Mark TX ring as full if we reach a certain threshold. */ if (++ring->queued > IWN_TX_RING_HIMARK) sc->qfullmsk |= 1 << ring->qid; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return 0; } static int iwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { struct ieee80211com *ic = ni->ni_ic; struct ifnet *ifp = ic->ic_ifp; struct iwn_softc *sc = ifp->if_softc; int error = 0; DPRINTF(sc, IWN_DEBUG_XMIT | IWN_DEBUG_TRACE, "->%s begin\n", __func__); if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { ieee80211_free_node(ni); m_freem(m); return ENETDOWN; } IWN_LOCK(sc); if (params == NULL) { /* * Legacy path; interpret frame contents to decide * precisely how to send the frame. */ error = iwn_tx_data(sc, m, ni); } else { /* * Caller supplied explicit parameters to use in * sending the frame. */ error = iwn_tx_data_raw(sc, m, ni, params); } if (error != 0) { /* NB: m is reclaimed on tx failure */ ieee80211_free_node(ni); if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - } - sc->sc_tx_timer = 5; + } else + sc->sc_tx_timer = 5; IWN_UNLOCK(sc); DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, "->%s: end\n",__func__); return error; } static void iwn_start(struct ifnet *ifp) { struct iwn_softc *sc = ifp->if_softc; IWN_LOCK(sc); iwn_start_locked(ifp); IWN_UNLOCK(sc); } static void iwn_start_locked(struct ifnet *ifp) { struct iwn_softc *sc = ifp->if_softc; struct ieee80211_node *ni; struct mbuf *m; IWN_LOCK_ASSERT(sc); DPRINTF(sc, IWN_DEBUG_XMIT, "%s: called\n", __func__); if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || (ifp->if_drv_flags & IFF_DRV_OACTIVE)) return; for (;;) { if (sc->qfullmsk != 0) { ifp->if_drv_flags |= IFF_DRV_OACTIVE; break; } IFQ_DRV_DEQUEUE(&ifp->if_snd, m); if (m == NULL) break; ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; if (iwn_tx_data(sc, m, ni) != 0) { ieee80211_free_node(ni); if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - continue; - } - sc->sc_tx_timer = 5; + } else + sc->sc_tx_timer = 5; } DPRINTF(sc, IWN_DEBUG_XMIT, "%s: done\n", __func__); } static void iwn_watchdog(void *arg) { struct iwn_softc *sc = arg; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; IWN_LOCK_ASSERT(sc); KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, ("not running")); DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); if (sc->sc_tx_timer > 0) { if (--sc->sc_tx_timer == 0) { if_printf(ifp, "device timeout\n"); ieee80211_runtask(ic, &sc->sc_reinit_task); return; } } callout_reset(&sc->watchdog_to, hz, iwn_watchdog, sc); } static int iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct iwn_softc *sc = ifp->if_softc; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); struct ifreq *ifr = (struct ifreq *) data; int error = 0, startall = 0, stop = 0; switch (cmd) { case SIOCGIFADDR: error = ether_ioctl(ifp, cmd, data); break; case SIOCSIFFLAGS: IWN_LOCK(sc); if (ifp->if_flags & IFF_UP) { if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { iwn_init_locked(sc); if (IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_RFKILL) startall = 1; else stop = 1; } } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) iwn_stop_locked(sc); } IWN_UNLOCK(sc); if (startall) ieee80211_start_all(ic); else if (vap != NULL && stop) ieee80211_stop(vap); break; case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); break; case SIOCGIWNSTATS: IWN_LOCK(sc); /* XXX validate permissions/memory/etc? */ error = copyout(&sc->last_stat, ifr->ifr_data, sizeof(struct iwn_stats)); IWN_UNLOCK(sc); break; case SIOCZIWNSTATS: IWN_LOCK(sc); memset(&sc->last_stat, 0, sizeof(struct iwn_stats)); IWN_UNLOCK(sc); - error = 0; break; default: error = EINVAL; break; } return error; } /* * Send a command to the firmware. */ static int iwn_cmd(struct iwn_softc *sc, int code, const void *buf, int size, int async) { struct iwn_tx_ring *ring; struct iwn_tx_desc *desc; struct iwn_tx_data *data; struct iwn_tx_cmd *cmd; struct mbuf *m; bus_addr_t paddr; int totlen, error; int cmd_queue_num; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); if (async == 0) IWN_LOCK_ASSERT(sc); if (sc->sc_flags & IWN_FLAG_PAN_SUPPORT) cmd_queue_num = IWN_PAN_CMD_QUEUE; else cmd_queue_num = IWN_CMD_QUEUE_NUM; ring = &sc->txq[cmd_queue_num]; desc = &ring->desc[ring->cur]; data = &ring->data[ring->cur]; totlen = 4 + size; if (size > sizeof cmd->data) { /* Command is too large to fit in a descriptor. */ if (totlen > MCLBYTES) return EINVAL; m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE); if (m == NULL) return ENOMEM; cmd = mtod(m, struct iwn_tx_cmd *); error = bus_dmamap_load(ring->data_dmat, data->map, cmd, totlen, iwn_dma_map_addr, &paddr, BUS_DMA_NOWAIT); if (error != 0) { m_freem(m); return error; } data->m = m; } else { cmd = &ring->cmd[ring->cur]; paddr = data->cmd_paddr; } cmd->code = code; cmd->flags = 0; cmd->qid = ring->qid; cmd->idx = ring->cur; memcpy(cmd->data, buf, size); desc->nsegs = 1; desc->segs[0].addr = htole32(IWN_LOADDR(paddr)); desc->segs[0].len = htole16(IWN_HIADDR(paddr) | totlen << 4); DPRINTF(sc, IWN_DEBUG_CMD, "%s: %s (0x%x) flags %d qid %d idx %d\n", __func__, iwn_intr_str(cmd->code), cmd->code, cmd->flags, cmd->qid, cmd->idx); if (size > sizeof cmd->data) { bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE); } else { bus_dmamap_sync(ring->data_dmat, ring->cmd_dma.map, BUS_DMASYNC_PREWRITE); } bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, BUS_DMASYNC_PREWRITE); /* Kick command ring. */ ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT; IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return async ? 0 : msleep(desc, &sc->sc_mtx, PCATCH, "iwncmd", hz); } static int iwn4965_add_node(struct iwn_softc *sc, struct iwn_node_info *node, int async) { struct iwn4965_node_info hnode; caddr_t src, dst; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* * We use the node structure for 5000 Series internally (it is * a superset of the one for 4965AGN). We thus copy the common * fields before sending the command. */ src = (caddr_t)node; dst = (caddr_t)&hnode; memcpy(dst, src, 48); /* Skip TSC, RX MIC and TX MIC fields from ``src''. */ memcpy(dst + 48, src + 72, 20); return iwn_cmd(sc, IWN_CMD_ADD_NODE, &hnode, sizeof hnode, async); } static int iwn5000_add_node(struct iwn_softc *sc, struct iwn_node_info *node, int async) { DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* Direct mapping. */ return iwn_cmd(sc, IWN_CMD_ADD_NODE, node, sizeof (*node), async); } static int iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni) { #define RV(v) ((v) & IEEE80211_RATE_VAL) struct iwn_node *wn = (void *)ni; struct ieee80211_rateset *rs; struct iwn_cmd_link_quality linkq; int i, rate, txrate; int is_11n; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); memset(&linkq, 0, sizeof linkq); linkq.id = wn->id; linkq.antmsk_1stream = iwn_get_1stream_tx_antmask(sc); linkq.antmsk_2stream = iwn_get_2stream_tx_antmask(sc); linkq.ampdu_max = 32; /* XXX negotiated? */ linkq.ampdu_threshold = 3; linkq.ampdu_limit = htole16(4000); /* 4ms */ DPRINTF(sc, IWN_DEBUG_XMIT, "%s: 1stream antenna=0x%02x, 2stream antenna=0x%02x, ntxstreams=%d\n", __func__, linkq.antmsk_1stream, linkq.antmsk_2stream, sc->ntxchains); /* * Are we using 11n rates? Ensure the channel is * 11n _and_ we have some 11n rates, or don't * try. */ if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_htrates.rs_nrates > 0) { rs = (struct ieee80211_rateset *) &ni->ni_htrates; is_11n = 1; } else { rs = &ni->ni_rates; is_11n = 0; } /* Start at highest available bit-rate. */ /* * XXX this is all very dirty! */ if (is_11n) txrate = ni->ni_htrates.rs_nrates - 1; else txrate = rs->rs_nrates - 1; for (i = 0; i < IWN_MAX_TX_RETRIES; i++) { uint32_t plcp; /* * XXX TODO: ensure the last two slots are the two lowest * rate entries, just for now. */ if (i == 14 || i == 15) txrate = 0; if (is_11n) rate = IEEE80211_RATE_MCS | rs->rs_rates[txrate]; else rate = RV(rs->rs_rates[txrate]); /* Do rate -> PLCP config mapping */ plcp = iwn_rate_to_plcp(sc, ni, rate); linkq.retry[i] = plcp; DPRINTF(sc, IWN_DEBUG_XMIT, "%s: i=%d, txrate=%d, rate=0x%02x, plcp=0x%08x\n", __func__, i, txrate, rate, le32toh(plcp)); /* * The mimo field is an index into the table which * indicates the first index where it and subsequent entries * will not be using MIMO. * * Since we're filling linkq from 0..15 and we're filling * from the higest MCS rates to the lowest rates, if we * _are_ doing a dual-stream rate, set mimo to idx+1 (ie, * the next entry.) That way if the next entry is a non-MIMO * entry, we're already pointing at it. */ if ((le32toh(plcp) & IWN_RFLAG_MCS) && RV(le32toh(plcp)) > 7) linkq.mimo = i + 1; /* Next retry at immediate lower bit-rate. */ if (txrate > 0) txrate--; } /* * If we reached the end of the list and indeed we hit * all MIMO rates (eg 5300 doing MCS23-15) then yes, * set mimo to 15. Setting it to 16 panics the firmware. */ if (linkq.mimo > 15) linkq.mimo = 15; DPRINTF(sc, IWN_DEBUG_XMIT, "%s: mimo = %d\n", __func__, linkq.mimo); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, 1); #undef RV } /* * Broadcast node is used to send group-addressed and management frames. */ static int iwn_add_broadcast_node(struct iwn_softc *sc, int async) { struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct iwn_node_info node; struct iwn_cmd_link_quality linkq; uint8_t txant; int i, error; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; memset(&node, 0, sizeof node); IEEE80211_ADDR_COPY(node.macaddr, ifp->if_broadcastaddr); node.id = sc->broadcast_id; DPRINTF(sc, IWN_DEBUG_RESET, "%s: adding broadcast node\n", __func__); if ((error = ops->add_node(sc, &node, async)) != 0) return error; /* Use the first valid TX antenna. */ txant = IWN_LSB(sc->txchainmask); memset(&linkq, 0, sizeof linkq); linkq.id = sc->broadcast_id; linkq.antmsk_1stream = iwn_get_1stream_tx_antmask(sc); linkq.antmsk_2stream = iwn_get_2stream_tx_antmask(sc); linkq.ampdu_max = 64; linkq.ampdu_threshold = 3; linkq.ampdu_limit = htole16(4000); /* 4ms */ /* Use lowest mandatory bit-rate. */ /* XXX rate table lookup? */ if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) linkq.retry[0] = htole32(0xd); else linkq.retry[0] = htole32(10 | IWN_RFLAG_CCK); linkq.retry[0] |= htole32(IWN_RFLAG_ANT(txant)); /* Use same bit-rate for all TX retries. */ for (i = 1; i < IWN_MAX_TX_RETRIES; i++) { linkq.retry[i] = linkq.retry[0]; } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, async); } static int iwn_updateedca(struct ieee80211com *ic) { #define IWN_EXP2(x) ((1 << (x)) - 1) /* CWmin = 2^ECWmin - 1 */ struct iwn_softc *sc = ic->ic_ifp->if_softc; struct iwn_edca_params cmd; int aci; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); memset(&cmd, 0, sizeof cmd); cmd.flags = htole32(IWN_EDCA_UPDATE); for (aci = 0; aci < WME_NUM_AC; aci++) { const struct wmeParams *ac = &ic->ic_wme.wme_chanParams.cap_wmeParams[aci]; cmd.ac[aci].aifsn = ac->wmep_aifsn; cmd.ac[aci].cwmin = htole16(IWN_EXP2(ac->wmep_logcwmin)); cmd.ac[aci].cwmax = htole16(IWN_EXP2(ac->wmep_logcwmax)); cmd.ac[aci].txoplimit = htole16(IEEE80211_TXOP_TO_US(ac->wmep_txopLimit)); } IEEE80211_UNLOCK(ic); IWN_LOCK(sc); (void)iwn_cmd(sc, IWN_CMD_EDCA_PARAMS, &cmd, sizeof cmd, 1); IWN_UNLOCK(sc); IEEE80211_LOCK(ic); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return 0; #undef IWN_EXP2 } static void iwn_update_mcast(struct ifnet *ifp) { /* Ignore */ } static void iwn_set_led(struct iwn_softc *sc, uint8_t which, uint8_t off, uint8_t on) { struct iwn_cmd_led led; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); #if 0 /* XXX don't set LEDs during scan? */ if (sc->sc_is_scanning) return; #endif /* Clear microcode LED ownership. */ IWN_CLRBITS(sc, IWN_LED, IWN_LED_BSM_CTRL); led.which = which; led.unit = htole32(10000); /* on/off in unit of 100ms */ led.off = off; led.on = on; (void)iwn_cmd(sc, IWN_CMD_SET_LED, &led, sizeof led, 1); } /* * Set the critical temperature at which the firmware will stop the radio * and notify us. */ static int iwn_set_critical_temp(struct iwn_softc *sc) { struct iwn_critical_temp crit; int32_t temp; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_CTEMP_STOP_RF); if (sc->hw_type == IWN_HW_REV_TYPE_5150) temp = (IWN_CTOK(110) - sc->temp_off) * -5; else if (sc->hw_type == IWN_HW_REV_TYPE_4965) temp = IWN_CTOK(110); else temp = 110; memset(&crit, 0, sizeof crit); crit.tempR = htole32(temp); DPRINTF(sc, IWN_DEBUG_RESET, "setting critical temp to %d\n", temp); return iwn_cmd(sc, IWN_CMD_SET_CRITICAL_TEMP, &crit, sizeof crit, 0); } static int iwn_set_timing(struct iwn_softc *sc, struct ieee80211_node *ni) { struct iwn_cmd_timing cmd; uint64_t val, mod; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); memset(&cmd, 0, sizeof cmd); memcpy(&cmd.tstamp, ni->ni_tstamp.data, sizeof (uint64_t)); cmd.bintval = htole16(ni->ni_intval); cmd.lintval = htole16(10); /* Compute remaining time until next beacon. */ val = (uint64_t)ni->ni_intval * IEEE80211_DUR_TU; mod = le64toh(cmd.tstamp) % val; cmd.binitval = htole32((uint32_t)(val - mod)); DPRINTF(sc, IWN_DEBUG_RESET, "timing bintval=%u tstamp=%ju, init=%u\n", ni->ni_intval, le64toh(cmd.tstamp), (uint32_t)(val - mod)); return iwn_cmd(sc, IWN_CMD_TIMING, &cmd, sizeof cmd, 1); } static void iwn4965_power_calibration(struct iwn_softc *sc, int temp) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* Adjust TX power if need be (delta >= 3 degC). */ DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: temperature %d->%d\n", __func__, sc->temp, temp); if (abs(temp - sc->temp) >= 3) { /* Record temperature of last calibration. */ sc->temp = temp; (void)iwn4965_set_txpower(sc, ic->ic_bsschan, 1); } } /* * Set TX power for current channel (each rate has its own power settings). * This function takes into account the regulatory information from EEPROM, * the current temperature and the current voltage. */ static int iwn4965_set_txpower(struct iwn_softc *sc, struct ieee80211_channel *ch, int async) { /* Fixed-point arithmetic division using a n-bit fractional part. */ #define fdivround(a, b, n) \ ((((1 << n) * (a)) / (b) + (1 << n) / 2) / (1 << n)) /* Linear interpolation. */ #define interpolate(x, x1, y1, x2, y2, n) \ ((y1) + fdivround(((int)(x) - (x1)) * ((y2) - (y1)), (x2) - (x1), n)) static const int tdiv[IWN_NATTEN_GROUPS] = { 9, 8, 8, 8, 6 }; struct iwn_ucode_info *uc = &sc->ucode_info; struct iwn4965_cmd_txpower cmd; struct iwn4965_eeprom_chan_samples *chans; const uint8_t *rf_gain, *dsp_gain; int32_t vdiff, tdiff; int i, c, grp, maxpwr; uint8_t chan; sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; /* Retrieve current channel from last RXON. */ chan = sc->rxon->chan; DPRINTF(sc, IWN_DEBUG_RESET, "setting TX power for channel %d\n", chan); memset(&cmd, 0, sizeof cmd); cmd.band = IEEE80211_IS_CHAN_5GHZ(ch) ? 0 : 1; cmd.chan = chan; if (IEEE80211_IS_CHAN_5GHZ(ch)) { maxpwr = sc->maxpwr5GHz; rf_gain = iwn4965_rf_gain_5ghz; dsp_gain = iwn4965_dsp_gain_5ghz; } else { maxpwr = sc->maxpwr2GHz; rf_gain = iwn4965_rf_gain_2ghz; dsp_gain = iwn4965_dsp_gain_2ghz; } /* Compute voltage compensation. */ vdiff = ((int32_t)le32toh(uc->volt) - sc->eeprom_voltage) / 7; if (vdiff > 0) vdiff *= 2; if (abs(vdiff) > 2) vdiff = 0; DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_TXPOW, "%s: voltage compensation=%d (UCODE=%d, EEPROM=%d)\n", __func__, vdiff, le32toh(uc->volt), sc->eeprom_voltage); /* Get channel attenuation group. */ if (chan <= 20) /* 1-20 */ grp = 4; else if (chan <= 43) /* 34-43 */ grp = 0; else if (chan <= 70) /* 44-70 */ grp = 1; else if (chan <= 124) /* 71-124 */ grp = 2; else /* 125-200 */ grp = 3; DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_TXPOW, "%s: chan %d, attenuation group=%d\n", __func__, chan, grp); /* Get channel sub-band. */ for (i = 0; i < IWN_NBANDS; i++) if (sc->bands[i].lo != 0 && sc->bands[i].lo <= chan && chan <= sc->bands[i].hi) break; if (i == IWN_NBANDS) /* Can't happen in real-life. */ return EINVAL; chans = sc->bands[i].chans; DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_TXPOW, "%s: chan %d sub-band=%d\n", __func__, chan, i); for (c = 0; c < 2; c++) { uint8_t power, gain, temp; int maxchpwr, pwr, ridx, idx; power = interpolate(chan, chans[0].num, chans[0].samples[c][1].power, chans[1].num, chans[1].samples[c][1].power, 1); gain = interpolate(chan, chans[0].num, chans[0].samples[c][1].gain, chans[1].num, chans[1].samples[c][1].gain, 1); temp = interpolate(chan, chans[0].num, chans[0].samples[c][1].temp, chans[1].num, chans[1].samples[c][1].temp, 1); DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_TXPOW, "%s: Tx chain %d: power=%d gain=%d temp=%d\n", __func__, c, power, gain, temp); /* Compute temperature compensation. */ tdiff = ((sc->temp - temp) * 2) / tdiv[grp]; DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_TXPOW, "%s: temperature compensation=%d (current=%d, EEPROM=%d)\n", __func__, tdiff, sc->temp, temp); for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++) { /* Convert dBm to half-dBm. */ maxchpwr = sc->maxpwr[chan] * 2; if ((ridx / 8) & 1) maxchpwr -= 6; /* MIMO 2T: -3dB */ pwr = maxpwr; /* Adjust TX power based on rate. */ if ((ridx % 8) == 5) pwr -= 15; /* OFDM48: -7.5dB */ else if ((ridx % 8) == 6) pwr -= 17; /* OFDM54: -8.5dB */ else if ((ridx % 8) == 7) pwr -= 20; /* OFDM60: -10dB */ else pwr -= 10; /* Others: -5dB */ /* Do not exceed channel max TX power. */ if (pwr > maxchpwr) pwr = maxchpwr; idx = gain - (pwr - power) - tdiff - vdiff; if ((ridx / 8) & 1) /* MIMO */ idx += (int32_t)le32toh(uc->atten[grp][c]); if (cmd.band == 0) idx += 9; /* 5GHz */ if (ridx == IWN_RIDX_MAX) idx += 5; /* CCK */ /* Make sure idx stays in a valid range. */ if (idx < 0) idx = 0; else if (idx > IWN4965_MAX_PWR_INDEX) idx = IWN4965_MAX_PWR_INDEX; DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_TXPOW, "%s: Tx chain %d, rate idx %d: power=%d\n", __func__, c, ridx, idx); cmd.power[ridx].rf_gain[c] = rf_gain[idx]; cmd.power[ridx].dsp_gain[c] = dsp_gain[idx]; } } DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_TXPOW, "%s: set tx power for chan %d\n", __func__, chan); return iwn_cmd(sc, IWN_CMD_TXPOWER, &cmd, sizeof cmd, async); #undef interpolate #undef fdivround } static int iwn5000_set_txpower(struct iwn_softc *sc, struct ieee80211_channel *ch, int async) { struct iwn5000_cmd_txpower cmd; int cmdid; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* * TX power calibration is handled automatically by the firmware * for 5000 Series. */ memset(&cmd, 0, sizeof cmd); cmd.global_limit = 2 * IWN5000_TXPOWER_MAX_DBM; /* 16 dBm */ cmd.flags = IWN5000_TXPOWER_NO_CLOSED; cmd.srv_limit = IWN5000_TXPOWER_AUTO; DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_XMIT, "%s: setting TX power; rev=%d\n", __func__, IWN_UCODE_API(sc->ucode_rev)); if (IWN_UCODE_API(sc->ucode_rev) == 1) cmdid = IWN_CMD_TXPOWER_DBM_V1; else cmdid = IWN_CMD_TXPOWER_DBM; return iwn_cmd(sc, cmdid, &cmd, sizeof cmd, async); } /* * Retrieve the maximum RSSI (in dBm) among receivers. */ static int iwn4965_get_rssi(struct iwn_softc *sc, struct iwn_rx_stat *stat) { struct iwn4965_rx_phystat *phy = (void *)stat->phybuf; uint8_t mask, agc; int rssi; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); mask = (le16toh(phy->antenna) >> 4) & IWN_ANT_ABC; agc = (le16toh(phy->agc) >> 7) & 0x7f; rssi = 0; if (mask & IWN_ANT_A) rssi = MAX(rssi, phy->rssi[0]); if (mask & IWN_ANT_B) rssi = MAX(rssi, phy->rssi[2]); if (mask & IWN_ANT_C) rssi = MAX(rssi, phy->rssi[4]); DPRINTF(sc, IWN_DEBUG_RECV, "%s: agc %d mask 0x%x rssi %d %d %d result %d\n", __func__, agc, mask, phy->rssi[0], phy->rssi[2], phy->rssi[4], rssi - agc - IWN_RSSI_TO_DBM); return rssi - agc - IWN_RSSI_TO_DBM; } static int iwn5000_get_rssi(struct iwn_softc *sc, struct iwn_rx_stat *stat) { struct iwn5000_rx_phystat *phy = (void *)stat->phybuf; uint8_t agc; int rssi; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); agc = (le32toh(phy->agc) >> 9) & 0x7f; rssi = MAX(le16toh(phy->rssi[0]) & 0xff, le16toh(phy->rssi[1]) & 0xff); rssi = MAX(le16toh(phy->rssi[2]) & 0xff, rssi); DPRINTF(sc, IWN_DEBUG_RECV, "%s: agc %d rssi %d %d %d result %d\n", __func__, agc, phy->rssi[0], phy->rssi[1], phy->rssi[2], rssi - agc - IWN_RSSI_TO_DBM); return rssi - agc - IWN_RSSI_TO_DBM; } /* * Retrieve the average noise (in dBm) among receivers. */ static int iwn_get_noise(const struct iwn_rx_general_stats *stats) { int i, total, nbant, noise; total = nbant = 0; for (i = 0; i < 3; i++) { if ((noise = le32toh(stats->noise[i]) & 0xff) == 0) continue; total += noise; nbant++; } /* There should be at least one antenna but check anyway. */ return (nbant == 0) ? -127 : (total / nbant) - 107; } /* * Compute temperature (in degC) from last received statistics. */ static int iwn4965_get_temperature(struct iwn_softc *sc) { struct iwn_ucode_info *uc = &sc->ucode_info; int32_t r1, r2, r3, r4, temp; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); r1 = le32toh(uc->temp[0].chan20MHz); r2 = le32toh(uc->temp[1].chan20MHz); r3 = le32toh(uc->temp[2].chan20MHz); r4 = le32toh(sc->rawtemp); if (r1 == r3) /* Prevents division by 0 (should not happen). */ return 0; /* Sign-extend 23-bit R4 value to 32-bit. */ r4 = ((r4 & 0xffffff) ^ 0x800000) - 0x800000; /* Compute temperature in Kelvin. */ temp = (259 * (r4 - r2)) / (r3 - r1); temp = (temp * 97) / 100 + 8; DPRINTF(sc, IWN_DEBUG_ANY, "temperature %dK/%dC\n", temp, IWN_KTOC(temp)); return IWN_KTOC(temp); } static int iwn5000_get_temperature(struct iwn_softc *sc) { int32_t temp; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* * Temperature is not used by the driver for 5000 Series because * TX power calibration is handled by firmware. */ temp = le32toh(sc->rawtemp); if (sc->hw_type == IWN_HW_REV_TYPE_5150) { temp = (temp / -5) + sc->temp_off; temp = IWN_KTOC(temp); } return temp; } /* * Initialize sensitivity calibration state machine. */ static int iwn_init_sensitivity(struct iwn_softc *sc) { struct iwn_ops *ops = &sc->ops; struct iwn_calib_state *calib = &sc->calib; uint32_t flags; int error; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* Reset calibration state machine. */ memset(calib, 0, sizeof (*calib)); calib->state = IWN_CALIB_STATE_INIT; calib->cck_state = IWN_CCK_STATE_HIFA; /* Set initial correlation values. */ calib->ofdm_x1 = sc->limits->min_ofdm_x1; calib->ofdm_mrc_x1 = sc->limits->min_ofdm_mrc_x1; calib->ofdm_x4 = sc->limits->min_ofdm_x4; calib->ofdm_mrc_x4 = sc->limits->min_ofdm_mrc_x4; calib->cck_x4 = 125; calib->cck_mrc_x4 = sc->limits->min_cck_mrc_x4; calib->energy_cck = sc->limits->energy_cck; /* Write initial sensitivity. */ if ((error = iwn_send_sensitivity(sc)) != 0) return error; /* Write initial gains. */ if ((error = ops->init_gains(sc)) != 0) return error; /* Request statistics at each beacon interval. */ flags = 0; DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: sending request for statistics\n", __func__); return iwn_cmd(sc, IWN_CMD_GET_STATISTICS, &flags, sizeof flags, 1); } /* * Collect noise and RSSI statistics for the first 20 beacons received * after association and use them to determine connected antennas and * to set differential gains. */ static void iwn_collect_noise(struct iwn_softc *sc, const struct iwn_rx_general_stats *stats) { struct iwn_ops *ops = &sc->ops; struct iwn_calib_state *calib = &sc->calib; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; uint32_t val; int i; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); /* Accumulate RSSI and noise for all 3 antennas. */ for (i = 0; i < 3; i++) { calib->rssi[i] += le32toh(stats->rssi[i]) & 0xff; calib->noise[i] += le32toh(stats->noise[i]) & 0xff; } /* NB: We update differential gains only once after 20 beacons. */ if (++calib->nbeacons < 20) return; /* Determine highest average RSSI. */ val = MAX(calib->rssi[0], calib->rssi[1]); val = MAX(calib->rssi[2], val); /* Determine which antennas are connected. */ sc->chainmask = sc->rxchainmask; for (i = 0; i < 3; i++) if (val - calib->rssi[i] > 15 * 20) sc->chainmask &= ~(1 << i); DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_XMIT, "%s: RX chains mask: theoretical=0x%x, actual=0x%x\n", __func__, sc->rxchainmask, sc->chainmask); /* If none of the TX antennas are connected, keep at least one. */ if ((sc->chainmask & sc->txchainmask) == 0) sc->chainmask |= IWN_LSB(sc->txchainmask); (void)ops->set_gains(sc); calib->state = IWN_CALIB_STATE_RUN; #ifdef notyet /* XXX Disable RX chains with no antennas connected. */ sc->rxon->rxchain = htole16(IWN_RXCHAIN_SEL(sc->chainmask)); if (sc->sc_is_scanning) device_printf(sc->sc_dev, "%s: is_scanning set, before RXON\n", __func__); (void)iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, 1); #endif /* Enable power-saving mode if requested by user. */ if (ic->ic_flags & IEEE80211_F_PMGTON) (void)iwn_set_pslevel(sc, 0, 3, 1); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); } static int iwn4965_init_gains(struct iwn_softc *sc) { struct iwn_phy_calib_gain cmd; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); memset(&cmd, 0, sizeof cmd); cmd.code = IWN4965_PHY_CALIB_DIFF_GAIN; /* Differential gains initially set to 0 for all 3 antennas. */ DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: setting initial differential gains\n", __func__); return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1); } static int iwn5000_init_gains(struct iwn_softc *sc) { struct iwn_phy_calib cmd; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); memset(&cmd, 0, sizeof cmd); cmd.code = sc->reset_noise_gain; cmd.ngroups = 1; cmd.isvalid = 1; DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: setting initial differential gains\n", __func__); return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1); } static int iwn4965_set_gains(struct iwn_softc *sc) { struct iwn_calib_state *calib = &sc->calib; struct iwn_phy_calib_gain cmd; int i, delta, noise; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* Get minimal noise among connected antennas. */ noise = INT_MAX; /* NB: There's at least one antenna. */ for (i = 0; i < 3; i++) if (sc->chainmask & (1 << i)) noise = MIN(calib->noise[i], noise); memset(&cmd, 0, sizeof cmd); cmd.code = IWN4965_PHY_CALIB_DIFF_GAIN; /* Set differential gains for connected antennas. */ for (i = 0; i < 3; i++) { if (sc->chainmask & (1 << i)) { /* Compute attenuation (in unit of 1.5dB). */ delta = (noise - (int32_t)calib->noise[i]) / 30; /* NB: delta <= 0 */ /* Limit to [-4.5dB,0]. */ cmd.gain[i] = MIN(abs(delta), 3); if (delta < 0) cmd.gain[i] |= 1 << 2; /* sign bit */ } } DPRINTF(sc, IWN_DEBUG_CALIBRATE, "setting differential gains Ant A/B/C: %x/%x/%x (%x)\n", cmd.gain[0], cmd.gain[1], cmd.gain[2], sc->chainmask); return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1); } static int iwn5000_set_gains(struct iwn_softc *sc) { struct iwn_calib_state *calib = &sc->calib; struct iwn_phy_calib_gain cmd; int i, ant, div, delta; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* We collected 20 beacons and !=6050 need a 1.5 factor. */ div = (sc->hw_type == IWN_HW_REV_TYPE_6050) ? 20 : 30; memset(&cmd, 0, sizeof cmd); cmd.code = sc->noise_gain; cmd.ngroups = 1; cmd.isvalid = 1; /* Get first available RX antenna as referential. */ ant = IWN_LSB(sc->rxchainmask); /* Set differential gains for other antennas. */ for (i = ant + 1; i < 3; i++) { if (sc->chainmask & (1 << i)) { /* The delta is relative to antenna "ant". */ delta = ((int32_t)calib->noise[ant] - (int32_t)calib->noise[i]) / div; /* Limit to [-4.5dB,+4.5dB]. */ cmd.gain[i - 1] = MIN(abs(delta), 3); if (delta < 0) cmd.gain[i - 1] |= 1 << 2; /* sign bit */ } } DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_XMIT, "setting differential gains Ant B/C: %x/%x (%x)\n", cmd.gain[0], cmd.gain[1], sc->chainmask); return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1); } /* * Tune RF RX sensitivity based on the number of false alarms detected * during the last beacon period. */ static void iwn_tune_sensitivity(struct iwn_softc *sc, const struct iwn_rx_stats *stats) { #define inc(val, inc, max) \ if ((val) < (max)) { \ if ((val) < (max) - (inc)) \ (val) += (inc); \ else \ (val) = (max); \ needs_update = 1; \ } #define dec(val, dec, min) \ if ((val) > (min)) { \ if ((val) > (min) + (dec)) \ (val) -= (dec); \ else \ (val) = (min); \ needs_update = 1; \ } const struct iwn_sensitivity_limits *limits = sc->limits; struct iwn_calib_state *calib = &sc->calib; uint32_t val, rxena, fa; uint32_t energy[3], energy_min; uint8_t noise[3], noise_ref; int i, needs_update = 0; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); /* Check that we've been enabled long enough. */ if ((rxena = le32toh(stats->general.load)) == 0){ DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end not so long\n", __func__); return; } /* Compute number of false alarms since last call for OFDM. */ fa = le32toh(stats->ofdm.bad_plcp) - calib->bad_plcp_ofdm; fa += le32toh(stats->ofdm.fa) - calib->fa_ofdm; fa *= 200 * IEEE80211_DUR_TU; /* 200TU */ if (fa > 50 * rxena) { /* High false alarm count, decrease sensitivity. */ DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: OFDM high false alarm count: %u\n", __func__, fa); inc(calib->ofdm_x1, 1, limits->max_ofdm_x1); inc(calib->ofdm_mrc_x1, 1, limits->max_ofdm_mrc_x1); inc(calib->ofdm_x4, 1, limits->max_ofdm_x4); inc(calib->ofdm_mrc_x4, 1, limits->max_ofdm_mrc_x4); } else if (fa < 5 * rxena) { /* Low false alarm count, increase sensitivity. */ DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: OFDM low false alarm count: %u\n", __func__, fa); dec(calib->ofdm_x1, 1, limits->min_ofdm_x1); dec(calib->ofdm_mrc_x1, 1, limits->min_ofdm_mrc_x1); dec(calib->ofdm_x4, 1, limits->min_ofdm_x4); dec(calib->ofdm_mrc_x4, 1, limits->min_ofdm_mrc_x4); } /* Compute maximum noise among 3 receivers. */ for (i = 0; i < 3; i++) noise[i] = (le32toh(stats->general.noise[i]) >> 8) & 0xff; val = MAX(noise[0], noise[1]); val = MAX(noise[2], val); /* Insert it into our samples table. */ calib->noise_samples[calib->cur_noise_sample] = val; calib->cur_noise_sample = (calib->cur_noise_sample + 1) % 20; /* Compute maximum noise among last 20 samples. */ noise_ref = calib->noise_samples[0]; for (i = 1; i < 20; i++) noise_ref = MAX(noise_ref, calib->noise_samples[i]); /* Compute maximum energy among 3 receivers. */ for (i = 0; i < 3; i++) energy[i] = le32toh(stats->general.energy[i]); val = MIN(energy[0], energy[1]); val = MIN(energy[2], val); /* Insert it into our samples table. */ calib->energy_samples[calib->cur_energy_sample] = val; calib->cur_energy_sample = (calib->cur_energy_sample + 1) % 10; /* Compute minimum energy among last 10 samples. */ energy_min = calib->energy_samples[0]; for (i = 1; i < 10; i++) energy_min = MAX(energy_min, calib->energy_samples[i]); energy_min += 6; /* Compute number of false alarms since last call for CCK. */ fa = le32toh(stats->cck.bad_plcp) - calib->bad_plcp_cck; fa += le32toh(stats->cck.fa) - calib->fa_cck; fa *= 200 * IEEE80211_DUR_TU; /* 200TU */ if (fa > 50 * rxena) { /* High false alarm count, decrease sensitivity. */ DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: CCK high false alarm count: %u\n", __func__, fa); calib->cck_state = IWN_CCK_STATE_HIFA; calib->low_fa = 0; if (calib->cck_x4 > 160) { calib->noise_ref = noise_ref; if (calib->energy_cck > 2) dec(calib->energy_cck, 2, energy_min); } if (calib->cck_x4 < 160) { calib->cck_x4 = 161; needs_update = 1; } else inc(calib->cck_x4, 3, limits->max_cck_x4); inc(calib->cck_mrc_x4, 3, limits->max_cck_mrc_x4); } else if (fa < 5 * rxena) { /* Low false alarm count, increase sensitivity. */ DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: CCK low false alarm count: %u\n", __func__, fa); calib->cck_state = IWN_CCK_STATE_LOFA; calib->low_fa++; if (calib->cck_state != IWN_CCK_STATE_INIT && (((int32_t)calib->noise_ref - (int32_t)noise_ref) > 2 || calib->low_fa > 100)) { inc(calib->energy_cck, 2, limits->min_energy_cck); dec(calib->cck_x4, 3, limits->min_cck_x4); dec(calib->cck_mrc_x4, 3, limits->min_cck_mrc_x4); } } else { /* Not worth to increase or decrease sensitivity. */ DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: CCK normal false alarm count: %u\n", __func__, fa); calib->low_fa = 0; calib->noise_ref = noise_ref; if (calib->cck_state == IWN_CCK_STATE_HIFA) { /* Previous interval had many false alarms. */ dec(calib->energy_cck, 8, energy_min); } calib->cck_state = IWN_CCK_STATE_INIT; } if (needs_update) (void)iwn_send_sensitivity(sc); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); #undef dec #undef inc } static int iwn_send_sensitivity(struct iwn_softc *sc) { struct iwn_calib_state *calib = &sc->calib; struct iwn_enhanced_sensitivity_cmd cmd; int len; memset(&cmd, 0, sizeof cmd); len = sizeof (struct iwn_sensitivity_cmd); cmd.which = IWN_SENSITIVITY_WORKTBL; /* OFDM modulation. */ cmd.corr_ofdm_x1 = htole16(calib->ofdm_x1); cmd.corr_ofdm_mrc_x1 = htole16(calib->ofdm_mrc_x1); cmd.corr_ofdm_x4 = htole16(calib->ofdm_x4); cmd.corr_ofdm_mrc_x4 = htole16(calib->ofdm_mrc_x4); cmd.energy_ofdm = htole16(sc->limits->energy_ofdm); cmd.energy_ofdm_th = htole16(62); /* CCK modulation. */ cmd.corr_cck_x4 = htole16(calib->cck_x4); cmd.corr_cck_mrc_x4 = htole16(calib->cck_mrc_x4); cmd.energy_cck = htole16(calib->energy_cck); /* Barker modulation: use default values. */ cmd.corr_barker = htole16(190); cmd.corr_barker_mrc = htole16(sc->limits->barker_mrc); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: set sensitivity %d/%d/%d/%d/%d/%d/%d\n", __func__, calib->ofdm_x1, calib->ofdm_mrc_x1, calib->ofdm_x4, calib->ofdm_mrc_x4, calib->cck_x4, calib->cck_mrc_x4, calib->energy_cck); if (!(sc->sc_flags & IWN_FLAG_ENH_SENS)) goto send; /* Enhanced sensitivity settings. */ len = sizeof (struct iwn_enhanced_sensitivity_cmd); cmd.ofdm_det_slope_mrc = htole16(668); cmd.ofdm_det_icept_mrc = htole16(4); cmd.ofdm_det_slope = htole16(486); cmd.ofdm_det_icept = htole16(37); cmd.cck_det_slope_mrc = htole16(853); cmd.cck_det_icept_mrc = htole16(4); cmd.cck_det_slope = htole16(476); cmd.cck_det_icept = htole16(99); send: return iwn_cmd(sc, IWN_CMD_SET_SENSITIVITY, &cmd, len, 1); } /* * Look at the increase of PLCP errors over time; if it exceeds * a programmed threshold then trigger an RF retune. */ static void iwn_check_rx_recovery(struct iwn_softc *sc, struct iwn_stats *rs) { int32_t delta_ofdm, delta_ht, delta_cck; struct iwn_calib_state *calib = &sc->calib; int delta_ticks, cur_ticks; int delta_msec; int thresh; /* * Calculate the difference between the current and * previous statistics. */ delta_cck = le32toh(rs->rx.cck.bad_plcp) - calib->bad_plcp_cck; delta_ofdm = le32toh(rs->rx.ofdm.bad_plcp) - calib->bad_plcp_ofdm; delta_ht = le32toh(rs->rx.ht.bad_plcp) - calib->bad_plcp_ht; /* * Calculate the delta in time between successive statistics * messages. Yes, it can roll over; so we make sure that * this doesn't happen. * * XXX go figure out what to do about rollover * XXX go figure out what to do if ticks rolls over to -ve instead! * XXX go stab signed integer overflow undefined-ness in the face. */ cur_ticks = ticks; delta_ticks = cur_ticks - sc->last_calib_ticks; /* * If any are negative, then the firmware likely reset; so just * bail. We'll pick this up next time. */ if (delta_cck < 0 || delta_ofdm < 0 || delta_ht < 0 || delta_ticks < 0) return; /* * delta_ticks is in ticks; we need to convert it up to milliseconds * so we can do some useful math with it. */ delta_msec = ticks_to_msecs(delta_ticks); /* * Calculate what our threshold is given the current delta_msec. */ thresh = sc->base_params->plcp_err_threshold * delta_msec; DPRINTF(sc, IWN_DEBUG_STATE, "%s: time delta: %d; cck=%d, ofdm=%d, ht=%d, total=%d, thresh=%d\n", __func__, delta_msec, delta_cck, delta_ofdm, delta_ht, (delta_msec + delta_cck + delta_ofdm + delta_ht), thresh); /* * If we need a retune, then schedule a single channel scan * to a channel that isn't the currently active one! * * The math from linux iwlwifi: * * if ((delta * 100 / msecs) > threshold) */ if (thresh > 0 && (delta_cck + delta_ofdm + delta_ht) * 100 > thresh) { DPRINTF(sc, IWN_DEBUG_ANY, "%s: PLCP error threshold raw (%d) comparison (%d) " "over limit (%d); retune!\n", __func__, (delta_cck + delta_ofdm + delta_ht), (delta_cck + delta_ofdm + delta_ht) * 100, thresh); } } /* * Set STA mode power saving level (between 0 and 5). * Level 0 is CAM (Continuously Aware Mode), 5 is for maximum power saving. */ static int iwn_set_pslevel(struct iwn_softc *sc, int dtim, int level, int async) { struct iwn_pmgt_cmd cmd; const struct iwn_pmgt *pmgt; uint32_t max, skip_dtim; uint32_t reg; int i; DPRINTF(sc, IWN_DEBUG_PWRSAVE, "%s: dtim=%d, level=%d, async=%d\n", __func__, dtim, level, async); /* Select which PS parameters to use. */ if (dtim <= 2) pmgt = &iwn_pmgt[0][level]; else if (dtim <= 10) pmgt = &iwn_pmgt[1][level]; else pmgt = &iwn_pmgt[2][level]; memset(&cmd, 0, sizeof cmd); if (level != 0) /* not CAM */ cmd.flags |= htole16(IWN_PS_ALLOW_SLEEP); if (level == 5) cmd.flags |= htole16(IWN_PS_FAST_PD); /* Retrieve PCIe Active State Power Management (ASPM). */ reg = pci_read_config(sc->sc_dev, sc->sc_cap_off + 0x10, 1); if (!(reg & 0x1)) /* L0s Entry disabled. */ cmd.flags |= htole16(IWN_PS_PCI_PMGT); cmd.rxtimeout = htole32(pmgt->rxtimeout * 1024); cmd.txtimeout = htole32(pmgt->txtimeout * 1024); if (dtim == 0) { dtim = 1; skip_dtim = 0; } else skip_dtim = pmgt->skip_dtim; if (skip_dtim != 0) { cmd.flags |= htole16(IWN_PS_SLEEP_OVER_DTIM); max = pmgt->intval[4]; if (max == (uint32_t)-1) max = dtim * (skip_dtim + 1); else if (max > dtim) max = (max / dtim) * dtim; } else max = dtim; for (i = 0; i < 5; i++) cmd.intval[i] = htole32(MIN(max, pmgt->intval[i])); DPRINTF(sc, IWN_DEBUG_RESET, "setting power saving level to %d\n", level); return iwn_cmd(sc, IWN_CMD_SET_POWER_MODE, &cmd, sizeof cmd, async); } static int iwn_send_btcoex(struct iwn_softc *sc) { struct iwn_bluetooth cmd; memset(&cmd, 0, sizeof cmd); cmd.flags = IWN_BT_COEX_CHAN_ANN | IWN_BT_COEX_BT_PRIO; cmd.lead_time = IWN_BT_LEAD_TIME_DEF; cmd.max_kill = IWN_BT_MAX_KILL_DEF; DPRINTF(sc, IWN_DEBUG_RESET, "%s: configuring bluetooth coexistence\n", __func__); return iwn_cmd(sc, IWN_CMD_BT_COEX, &cmd, sizeof(cmd), 0); } static int iwn_send_advanced_btcoex(struct iwn_softc *sc) { static const uint32_t btcoex_3wire[12] = { 0xaaaaaaaa, 0xaaaaaaaa, 0xaeaaaaaa, 0xaaaaaaaa, 0xcc00ff28, 0x0000aaaa, 0xcc00aaaa, 0x0000aaaa, 0xc0004000, 0x00004000, 0xf0005000, 0xf0005000, }; struct iwn6000_btcoex_config btconfig; struct iwn2000_btcoex_config btconfig2k; struct iwn_btcoex_priotable btprio; struct iwn_btcoex_prot btprot; int error, i; uint8_t flags; memset(&btconfig, 0, sizeof btconfig); memset(&btconfig2k, 0, sizeof btconfig2k); flags = IWN_BT_FLAG_COEX6000_MODE_3W << IWN_BT_FLAG_COEX6000_MODE_SHIFT; // Done as is in linux kernel 3.2 if (sc->base_params->bt_sco_disable) flags &= ~IWN_BT_FLAG_SYNC_2_BT_DISABLE; else flags |= IWN_BT_FLAG_SYNC_2_BT_DISABLE; flags |= IWN_BT_FLAG_COEX6000_CHAN_INHIBITION; /* Default flags result is 145 as old value */ /* * Flags value has to be review. Values must change if we * which to disable it */ if (sc->base_params->bt_session_2) { btconfig2k.flags = flags; btconfig2k.max_kill = 5; btconfig2k.bt3_t7_timer = 1; btconfig2k.kill_ack = htole32(0xffff0000); btconfig2k.kill_cts = htole32(0xffff0000); btconfig2k.sample_time = 2; btconfig2k.bt3_t2_timer = 0xc; for (i = 0; i < 12; i++) btconfig2k.lookup_table[i] = htole32(btcoex_3wire[i]); btconfig2k.valid = htole16(0xff); btconfig2k.prio_boost = htole32(0xf0); DPRINTF(sc, IWN_DEBUG_RESET, "%s: configuring advanced bluetooth coexistence" " session 2, flags : 0x%x\n", __func__, flags); error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig2k, sizeof(btconfig2k), 1); } else { btconfig.flags = flags; btconfig.max_kill = 5; btconfig.bt3_t7_timer = 1; btconfig.kill_ack = htole32(0xffff0000); btconfig.kill_cts = htole32(0xffff0000); btconfig.sample_time = 2; btconfig.bt3_t2_timer = 0xc; for (i = 0; i < 12; i++) btconfig.lookup_table[i] = htole32(btcoex_3wire[i]); btconfig.valid = htole16(0xff); btconfig.prio_boost = 0xf0; DPRINTF(sc, IWN_DEBUG_RESET, "%s: configuring advanced bluetooth coexistence," " flags : 0x%x\n", __func__, flags); error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig, sizeof(btconfig), 1); } if (error != 0) return error; memset(&btprio, 0, sizeof btprio); btprio.calib_init1 = 0x6; btprio.calib_init2 = 0x7; btprio.calib_periodic_low1 = 0x2; btprio.calib_periodic_low2 = 0x3; btprio.calib_periodic_high1 = 0x4; btprio.calib_periodic_high2 = 0x5; btprio.dtim = 0x6; btprio.scan52 = 0x8; btprio.scan24 = 0xa; error = iwn_cmd(sc, IWN_CMD_BT_COEX_PRIOTABLE, &btprio, sizeof(btprio), 1); if (error != 0) return error; /* Force BT state machine change. */ memset(&btprot, 0, sizeof btprot); btprot.open = 1; btprot.type = 1; error = iwn_cmd(sc, IWN_CMD_BT_COEX_PROT, &btprot, sizeof(btprot), 1); if (error != 0) return error; btprot.open = 0; return iwn_cmd(sc, IWN_CMD_BT_COEX_PROT, &btprot, sizeof(btprot), 1); } static int iwn5000_runtime_calib(struct iwn_softc *sc) { struct iwn5000_calib_config cmd; memset(&cmd, 0, sizeof cmd); cmd.ucode.once.enable = 0xffffffff; cmd.ucode.once.start = IWN5000_CALIB_DC; DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: configuring runtime calibration\n", __func__); return iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof(cmd), 0); } static int iwn_config(struct iwn_softc *sc) { struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; uint32_t txmask; uint16_t rxchain; int error; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); if ((sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET) && (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2)) { device_printf(sc->sc_dev,"%s: temp_offset and temp_offsetv2 are" " exclusive each together. Review NIC config file. Conf" " : 0x%08x Flags : 0x%08x \n", __func__, sc->base_params->calib_need, (IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET | IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2)); return (EINVAL); } /* Compute temperature calib if needed. Will be send by send calib */ if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET) { error = iwn5000_temp_offset_calib(sc); if (error != 0) { device_printf(sc->sc_dev, "%s: could not set temperature offset\n", __func__); return (error); } } else if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2) { error = iwn5000_temp_offset_calibv2(sc); if (error != 0) { device_printf(sc->sc_dev, "%s: could not compute temperature offset v2\n", __func__); return (error); } } if (sc->hw_type == IWN_HW_REV_TYPE_6050) { /* Configure runtime DC calibration. */ error = iwn5000_runtime_calib(sc); if (error != 0) { device_printf(sc->sc_dev, "%s: could not configure runtime calibration\n", __func__); return error; } } /* Configure valid TX chains for >=5000 Series. */ if (sc->hw_type != IWN_HW_REV_TYPE_4965 && IWN_UCODE_API(sc->ucode_rev) > 1) { txmask = htole32(sc->txchainmask); DPRINTF(sc, IWN_DEBUG_RESET | IWN_DEBUG_XMIT, "%s: configuring valid TX chains 0x%x\n", __func__, txmask); error = iwn_cmd(sc, IWN5000_CMD_TX_ANT_CONFIG, &txmask, sizeof txmask, 0); if (error != 0) { device_printf(sc->sc_dev, "%s: could not configure valid TX chains, " "error %d\n", __func__, error); return error; } } /* Configure bluetooth coexistence. */ error = 0; /* Configure bluetooth coexistence if needed. */ if (sc->base_params->bt_mode == IWN_BT_ADVANCED) error = iwn_send_advanced_btcoex(sc); if (sc->base_params->bt_mode == IWN_BT_SIMPLE) error = iwn_send_btcoex(sc); if (error != 0) { device_printf(sc->sc_dev, "%s: could not configure bluetooth coexistence, error %d\n", __func__, error); return error; } /* Set mode, channel, RX filter and enable RX. */ sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; memset(sc->rxon, 0, sizeof (struct iwn_rxon)); IEEE80211_ADDR_COPY(sc->rxon->myaddr, IF_LLADDR(ifp)); IEEE80211_ADDR_COPY(sc->rxon->wlap, IF_LLADDR(ifp)); sc->rxon->chan = ieee80211_chan2ieee(ic, ic->ic_curchan); sc->rxon->flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF); if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) sc->rxon->flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ); switch (ic->ic_opmode) { case IEEE80211_M_STA: sc->rxon->mode = IWN_MODE_STA; sc->rxon->filter = htole32(IWN_FILTER_MULTICAST); break; case IEEE80211_M_MONITOR: sc->rxon->mode = IWN_MODE_MONITOR; sc->rxon->filter = htole32(IWN_FILTER_MULTICAST | IWN_FILTER_CTL | IWN_FILTER_PROMISC); break; default: /* Should not get there. */ break; } sc->rxon->cck_mask = 0x0f; /* not yet negotiated */ sc->rxon->ofdm_mask = 0xff; /* not yet negotiated */ sc->rxon->ht_single_mask = 0xff; sc->rxon->ht_dual_mask = 0xff; sc->rxon->ht_triple_mask = 0xff; /* * In active association mode, ensure that * all the receive chains are enabled. * * Since we're not yet doing SMPS, don't allow the * number of idle RX chains to be less than the active * number. */ rxchain = IWN_RXCHAIN_VALID(sc->rxchainmask) | IWN_RXCHAIN_MIMO_COUNT(sc->nrxchains) | IWN_RXCHAIN_IDLE_COUNT(sc->nrxchains); sc->rxon->rxchain = htole16(rxchain); DPRINTF(sc, IWN_DEBUG_RESET | IWN_DEBUG_XMIT, "%s: rxchainmask=0x%x, nrxchains=%d\n", __func__, sc->rxchainmask, sc->nrxchains); DPRINTF(sc, IWN_DEBUG_RESET, "%s: setting configuration\n", __func__); if (sc->sc_is_scanning) device_printf(sc->sc_dev, "%s: is_scanning set, before RXON\n", __func__); error = iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, 0); if (error != 0) { device_printf(sc->sc_dev, "%s: RXON command failed\n", __func__); return error; } if ((error = iwn_add_broadcast_node(sc, 0)) != 0) { device_printf(sc->sc_dev, "%s: could not add broadcast node\n", __func__); return error; } /* Configuration has changed, set TX power accordingly. */ if ((error = ops->set_txpower(sc, ic->ic_curchan, 0)) != 0) { device_printf(sc->sc_dev, "%s: could not set TX power\n", __func__); return error; } if ((error = iwn_set_critical_temp(sc)) != 0) { device_printf(sc->sc_dev, "%s: could not set critical temperature\n", __func__); return error; } /* Set power saving level to CAM during initialization. */ if ((error = iwn_set_pslevel(sc, 0, 0, 0)) != 0) { device_printf(sc->sc_dev, "%s: could not set power saving level\n", __func__); return error; } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return 0; } static uint16_t iwn_get_active_dwell_time(struct iwn_softc *sc, struct ieee80211_channel *c, uint8_t n_probes) { /* No channel? Default to 2GHz settings */ if (c == NULL || IEEE80211_IS_CHAN_2GHZ(c)) { return (IWN_ACTIVE_DWELL_TIME_2GHZ + IWN_ACTIVE_DWELL_FACTOR_2GHZ * (n_probes + 1)); } /* 5GHz dwell time */ return (IWN_ACTIVE_DWELL_TIME_5GHZ + IWN_ACTIVE_DWELL_FACTOR_5GHZ * (n_probes + 1)); } /* * Limit the total dwell time to 85% of the beacon interval. * * Returns the dwell time in milliseconds. */ static uint16_t iwn_limit_dwell(struct iwn_softc *sc, uint16_t dwell_time) { struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = NULL; int bintval = 0; /* bintval is in TU (1.024mS) */ if (! TAILQ_EMPTY(&ic->ic_vaps)) { vap = TAILQ_FIRST(&ic->ic_vaps); bintval = vap->iv_bss->ni_intval; } /* * If it's non-zero, we should calculate the minimum of * it and the DWELL_BASE. * * XXX Yes, the math should take into account that bintval * is 1.024mS, not 1mS.. */ if (bintval > 0) { DPRINTF(sc, IWN_DEBUG_SCAN, "%s: bintval=%d\n", __func__, bintval); return (MIN(IWN_PASSIVE_DWELL_BASE, ((bintval * 85) / 100))); } /* No association context? Default */ return (IWN_PASSIVE_DWELL_BASE); } static uint16_t iwn_get_passive_dwell_time(struct iwn_softc *sc, struct ieee80211_channel *c) { uint16_t passive; if (c == NULL || IEEE80211_IS_CHAN_2GHZ(c)) { passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_2GHZ; } else { passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_5GHZ; } /* Clamp to the beacon interval if we're associated */ return (iwn_limit_dwell(sc, passive)); } static int iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap, struct ieee80211_scan_state *ss, struct ieee80211_channel *c) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_node *ni = vap->iv_bss; struct iwn_scan_hdr *hdr; struct iwn_cmd_data *tx; struct iwn_scan_essid *essid; struct iwn_scan_chan *chan; struct ieee80211_frame *wh; struct ieee80211_rateset *rs; uint8_t *buf, *frm; uint16_t rxchain; uint8_t txant; int buflen, error; int is_active; uint16_t dwell_active, dwell_passive; uint32_t extra, scan_service_time; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); /* * We are absolutely not allowed to send a scan command when another * scan command is pending. */ if (sc->sc_is_scanning) { device_printf(sc->sc_dev, "%s: called whilst scanning!\n", __func__); return (EAGAIN); } /* Assign the scan channel */ c = ic->ic_curchan; sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; buf = malloc(IWN_SCAN_MAXSZ, M_DEVBUF, M_NOWAIT | M_ZERO); if (buf == NULL) { device_printf(sc->sc_dev, "%s: could not allocate buffer for scan command\n", __func__); return ENOMEM; } hdr = (struct iwn_scan_hdr *)buf; /* * Move to the next channel if no frames are received within 10ms * after sending the probe request. */ hdr->quiet_time = htole16(10); /* timeout in milliseconds */ hdr->quiet_threshold = htole16(1); /* min # of packets */ /* * Max needs to be greater than active and passive and quiet! * It's also in microseconds! */ hdr->max_svc = htole32(250 * 1024); /* * Reset scan: interval=100 * Normal scan: interval=becaon interval * suspend_time: 100 (TU) * */ extra = (100 /* suspend_time */ / 100 /* beacon interval */) << 22; //scan_service_time = extra | ((100 /* susp */ % 100 /* int */) * 1024); scan_service_time = (4 << 22) | (100 * 1024); /* Hardcode for now! */ hdr->pause_svc = htole32(scan_service_time); /* Select antennas for scanning. */ rxchain = IWN_RXCHAIN_VALID(sc->rxchainmask) | IWN_RXCHAIN_FORCE_MIMO_SEL(sc->rxchainmask) | IWN_RXCHAIN_DRIVER_FORCE; if (IEEE80211_IS_CHAN_A(c) && sc->hw_type == IWN_HW_REV_TYPE_4965) { /* Ant A must be avoided in 5GHz because of an HW bug. */ rxchain |= IWN_RXCHAIN_FORCE_SEL(IWN_ANT_B); } else /* Use all available RX antennas. */ rxchain |= IWN_RXCHAIN_FORCE_SEL(sc->rxchainmask); hdr->rxchain = htole16(rxchain); hdr->filter = htole32(IWN_FILTER_MULTICAST | IWN_FILTER_BEACON); tx = (struct iwn_cmd_data *)(hdr + 1); tx->flags = htole32(IWN_TX_AUTO_SEQ); tx->id = sc->broadcast_id; tx->lifetime = htole32(IWN_LIFETIME_INFINITE); if (IEEE80211_IS_CHAN_5GHZ(c)) { /* Send probe requests at 6Mbps. */ tx->rate = htole32(0xd); rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; } else { hdr->flags = htole32(IWN_RXON_24GHZ | IWN_RXON_AUTO); if (sc->hw_type == IWN_HW_REV_TYPE_4965 && sc->rxon->associd && sc->rxon->chan > 14) tx->rate = htole32(0xd); else { /* Send probe requests at 1Mbps. */ tx->rate = htole32(10 | IWN_RFLAG_CCK); } rs = &ic->ic_sup_rates[IEEE80211_MODE_11G]; } /* Use the first valid TX antenna. */ txant = IWN_LSB(sc->txchainmask); tx->rate |= htole32(IWN_RFLAG_ANT(txant)); /* * Only do active scanning if we're announcing a probe request * for a given SSID (or more, if we ever add it to the driver.) */ is_active = 0; /* * If we're scanning for a specific SSID, add it to the command. * * XXX maybe look at adding support for scanning multiple SSIDs? */ essid = (struct iwn_scan_essid *)(tx + 1); if (ss != NULL) { if (ss->ss_ssid[0].len != 0) { essid[0].id = IEEE80211_ELEMID_SSID; essid[0].len = ss->ss_ssid[0].len; memcpy(essid[0].data, ss->ss_ssid[0].ssid, ss->ss_ssid[0].len); } DPRINTF(sc, IWN_DEBUG_SCAN, "%s: ssid_len=%d, ssid=%*s\n", __func__, ss->ss_ssid[0].len, ss->ss_ssid[0].len, ss->ss_ssid[0].ssid); if (ss->ss_nssid > 0) is_active = 1; } /* * Build a probe request frame. Most of the following code is a * copy & paste of what is done in net80211. */ wh = (struct ieee80211_frame *)(essid + 20); wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ; wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); IEEE80211_ADDR_COPY(wh->i_addr2, IF_LLADDR(ifp)); IEEE80211_ADDR_COPY(wh->i_addr3, ifp->if_broadcastaddr); *(uint16_t *)&wh->i_dur[0] = 0; /* filled by HW */ *(uint16_t *)&wh->i_seq[0] = 0; /* filled by HW */ frm = (uint8_t *)(wh + 1); frm = ieee80211_add_ssid(frm, NULL, 0); frm = ieee80211_add_rates(frm, rs); if (rs->rs_nrates > IEEE80211_RATE_SIZE) frm = ieee80211_add_xrates(frm, rs); if (ic->ic_htcaps & IEEE80211_HTC_HT) frm = ieee80211_add_htcap(frm, ni); /* Set length of probe request. */ tx->len = htole16(frm - (uint8_t *)wh); /* * If active scanning is requested but a certain channel is * marked passive, we can do active scanning if we detect * transmissions. * * There is an issue with some firmware versions that triggers * a sysassert on a "good CRC threshold" of zero (== disabled), * on a radar channel even though this means that we should NOT * send probes. * * The "good CRC threshold" is the number of frames that we * need to receive during our dwell time on a channel before * sending out probes -- setting this to a huge value will * mean we never reach it, but at the same time work around * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER * here instead of IWL_GOOD_CRC_TH_DISABLED. * * This was fixed in later versions along with some other * scan changes, and the threshold behaves as a flag in those * versions. */ /* * If we're doing active scanning, set the crc_threshold * to a suitable value. This is different to active veruss * passive scanning depending upon the channel flags; the * firmware will obey that particular check for us. */ if (sc->tlv_feature_flags & IWN_UCODE_TLV_FLAGS_NEWSCAN) hdr->crc_threshold = is_active ? IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_DISABLED; else hdr->crc_threshold = is_active ? IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_NEVER; chan = (struct iwn_scan_chan *)frm; chan->chan = htole16(ieee80211_chan2ieee(ic, c)); chan->flags = 0; if (ss->ss_nssid > 0) chan->flags |= htole32(IWN_CHAN_NPBREQS(1)); chan->dsp_gain = 0x6e; /* * Set the passive/active flag depending upon the channel mode. * XXX TODO: take the is_active flag into account as well? */ if (c->ic_flags & IEEE80211_CHAN_PASSIVE) chan->flags |= htole32(IWN_CHAN_PASSIVE); else chan->flags |= htole32(IWN_CHAN_ACTIVE); /* * Calculate the active/passive dwell times. */ dwell_active = iwn_get_active_dwell_time(sc, c, ss->ss_nssid); dwell_passive = iwn_get_passive_dwell_time(sc, c); /* Make sure they're valid */ if (dwell_passive <= dwell_active) dwell_passive = dwell_active + 1; chan->active = htole16(dwell_active); chan->passive = htole16(dwell_passive); - if (IEEE80211_IS_CHAN_5GHZ(c) && - !(c->ic_flags & IEEE80211_CHAN_PASSIVE)) { + if (IEEE80211_IS_CHAN_5GHZ(c)) chan->rf_gain = 0x3b; - } else if (IEEE80211_IS_CHAN_5GHZ(c)) { - chan->rf_gain = 0x3b; - } else if (!(c->ic_flags & IEEE80211_CHAN_PASSIVE)) { + else chan->rf_gain = 0x28; - } else { - chan->rf_gain = 0x28; - } DPRINTF(sc, IWN_DEBUG_STATE, "%s: chan %u flags 0x%x rf_gain 0x%x " "dsp_gain 0x%x active %d passive %d scan_svc_time %d crc 0x%x " "isactive=%d numssid=%d\n", __func__, chan->chan, chan->flags, chan->rf_gain, chan->dsp_gain, dwell_active, dwell_passive, scan_service_time, hdr->crc_threshold, is_active, ss->ss_nssid); hdr->nchan++; chan++; buflen = (uint8_t *)chan - buf; hdr->len = htole16(buflen); if (sc->sc_is_scanning) { device_printf(sc->sc_dev, "%s: called with is_scanning set!\n", __func__); } sc->sc_is_scanning = 1; DPRINTF(sc, IWN_DEBUG_STATE, "sending scan command nchan=%d\n", hdr->nchan); error = iwn_cmd(sc, IWN_CMD_SCAN, buf, buflen, 1); free(buf, M_DEVBUF); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return error; } static int iwn_auth(struct iwn_softc *sc, struct ieee80211vap *vap) { struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_node *ni = vap->iv_bss; int error; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; /* Update adapter configuration. */ IEEE80211_ADDR_COPY(sc->rxon->bssid, ni->ni_bssid); sc->rxon->chan = ieee80211_chan2ieee(ic, ni->ni_chan); sc->rxon->flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF); if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) sc->rxon->flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ); if (ic->ic_flags & IEEE80211_F_SHSLOT) sc->rxon->flags |= htole32(IWN_RXON_SHSLOT); if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) sc->rxon->flags |= htole32(IWN_RXON_SHPREAMBLE); if (IEEE80211_IS_CHAN_A(ni->ni_chan)) { sc->rxon->cck_mask = 0; sc->rxon->ofdm_mask = 0x15; } else if (IEEE80211_IS_CHAN_B(ni->ni_chan)) { sc->rxon->cck_mask = 0x03; sc->rxon->ofdm_mask = 0; } else { /* Assume 802.11b/g. */ sc->rxon->cck_mask = 0x03; sc->rxon->ofdm_mask = 0x15; } DPRINTF(sc, IWN_DEBUG_STATE, "rxon chan %d flags %x cck %x ofdm %x\n", sc->rxon->chan, sc->rxon->flags, sc->rxon->cck_mask, sc->rxon->ofdm_mask); if (sc->sc_is_scanning) device_printf(sc->sc_dev, "%s: is_scanning set, before RXON\n", __func__); error = iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, 1); if (error != 0) { device_printf(sc->sc_dev, "%s: RXON command failed, error %d\n", __func__, error); return error; } /* Configuration has changed, set TX power accordingly. */ if ((error = ops->set_txpower(sc, ni->ni_chan, 1)) != 0) { device_printf(sc->sc_dev, "%s: could not set TX power, error %d\n", __func__, error); return error; } /* * Reconfiguring RXON clears the firmware nodes table so we must * add the broadcast node again. */ if ((error = iwn_add_broadcast_node(sc, 1)) != 0) { device_printf(sc->sc_dev, "%s: could not add broadcast node, error %d\n", __func__, error); return error; } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return 0; } static int iwn_run(struct iwn_softc *sc, struct ieee80211vap *vap) { struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_node *ni = vap->iv_bss; struct iwn_node_info node; uint32_t htflags = 0; int error; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX]; if (ic->ic_opmode == IEEE80211_M_MONITOR) { /* Link LED blinks while monitoring. */ iwn_set_led(sc, IWN_LED_LINK, 5, 5); return 0; } if ((error = iwn_set_timing(sc, ni)) != 0) { device_printf(sc->sc_dev, "%s: could not set timing, error %d\n", __func__, error); return error; } /* Update adapter configuration. */ IEEE80211_ADDR_COPY(sc->rxon->bssid, ni->ni_bssid); sc->rxon->associd = htole16(IEEE80211_AID(ni->ni_associd)); sc->rxon->chan = ieee80211_chan2ieee(ic, ni->ni_chan); sc->rxon->flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF); if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) sc->rxon->flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ); if (ic->ic_flags & IEEE80211_F_SHSLOT) sc->rxon->flags |= htole32(IWN_RXON_SHSLOT); if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) sc->rxon->flags |= htole32(IWN_RXON_SHPREAMBLE); if (IEEE80211_IS_CHAN_A(ni->ni_chan)) { sc->rxon->cck_mask = 0; sc->rxon->ofdm_mask = 0x15; } else if (IEEE80211_IS_CHAN_B(ni->ni_chan)) { sc->rxon->cck_mask = 0x03; sc->rxon->ofdm_mask = 0; } else { /* Assume 802.11b/g. */ sc->rxon->cck_mask = 0x0f; sc->rxon->ofdm_mask = 0x15; } if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { htflags |= IWN_RXON_HT_PROTMODE(ic->ic_curhtprotmode); if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { switch (ic->ic_curhtprotmode) { case IEEE80211_HTINFO_OPMODE_HT20PR: htflags |= IWN_RXON_HT_MODEPURE40; break; default: htflags |= IWN_RXON_HT_MODEMIXED; break; } } if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan)) htflags |= IWN_RXON_HT_HT40MINUS; } sc->rxon->flags |= htole32(htflags); sc->rxon->filter |= htole32(IWN_FILTER_BSS); DPRINTF(sc, IWN_DEBUG_STATE, "rxon chan %d flags %x\n", sc->rxon->chan, sc->rxon->flags); if (sc->sc_is_scanning) device_printf(sc->sc_dev, "%s: is_scanning set, before RXON\n", __func__); error = iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, 1); if (error != 0) { device_printf(sc->sc_dev, "%s: could not update configuration, error %d\n", __func__, error); return error; } /* Configuration has changed, set TX power accordingly. */ if ((error = ops->set_txpower(sc, ni->ni_chan, 1)) != 0) { device_printf(sc->sc_dev, "%s: could not set TX power, error %d\n", __func__, error); return error; } /* Fake a join to initialize the TX rate. */ ((struct iwn_node *)ni)->id = IWN_ID_BSS; iwn_newassoc(ni, 1); /* Add BSS node. */ memset(&node, 0, sizeof node); IEEE80211_ADDR_COPY(node.macaddr, ni->ni_macaddr); node.id = IWN_ID_BSS; if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { switch (ni->ni_htcap & IEEE80211_HTCAP_SMPS) { case IEEE80211_HTCAP_SMPS_ENA: node.htflags |= htole32(IWN_SMPS_MIMO_DIS); break; case IEEE80211_HTCAP_SMPS_DYNAMIC: node.htflags |= htole32(IWN_SMPS_MIMO_PROT); break; } node.htflags |= htole32(IWN_AMDPU_SIZE_FACTOR(3) | IWN_AMDPU_DENSITY(5)); /* 4us */ if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) node.htflags |= htole32(IWN_NODE_HT40); } DPRINTF(sc, IWN_DEBUG_STATE, "%s: adding BSS node\n", __func__); error = ops->add_node(sc, &node, 1); if (error != 0) { device_printf(sc->sc_dev, "%s: could not add BSS node, error %d\n", __func__, error); return error; } DPRINTF(sc, IWN_DEBUG_STATE, "%s: setting link quality for node %d\n", __func__, node.id); if ((error = iwn_set_link_quality(sc, ni)) != 0) { device_printf(sc->sc_dev, "%s: could not setup link quality for node %d, error %d\n", __func__, node.id, error); return error; } if ((error = iwn_init_sensitivity(sc)) != 0) { device_printf(sc->sc_dev, "%s: could not set sensitivity, error %d\n", __func__, error); return error; } /* Start periodic calibration timer. */ sc->calib.state = IWN_CALIB_STATE_ASSOC; sc->calib_cnt = 0; callout_reset(&sc->calib_to, msecs_to_ticks(500), iwn_calib_timeout, sc); /* Link LED always on while associated. */ iwn_set_led(sc, IWN_LED_LINK, 0, 1); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return 0; } /* * This function is called by upper layer when an ADDBA request is received * from another STA and before the ADDBA response is sent. */ static int iwn_ampdu_rx_start(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap, int baparamset, int batimeout, int baseqctl) { #define MS(_v, _f) (((_v) & _f) >> _f##_S) struct iwn_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct iwn_ops *ops = &sc->ops; struct iwn_node *wn = (void *)ni; struct iwn_node_info node; uint16_t ssn; uint8_t tid; int error; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); tid = MS(le16toh(baparamset), IEEE80211_BAPS_TID); ssn = MS(le16toh(baseqctl), IEEE80211_BASEQ_START); memset(&node, 0, sizeof node); node.id = wn->id; node.control = IWN_NODE_UPDATE; node.flags = IWN_FLAG_SET_ADDBA; node.addba_tid = tid; node.addba_ssn = htole16(ssn); DPRINTF(sc, IWN_DEBUG_RECV, "ADDBA RA=%d TID=%d SSN=%d\n", wn->id, tid, ssn); error = ops->add_node(sc, &node, 1); if (error != 0) return error; return sc->sc_ampdu_rx_start(ni, rap, baparamset, batimeout, baseqctl); #undef MS } /* * This function is called by upper layer on teardown of an HT-immediate * Block Ack agreement (eg. uppon receipt of a DELBA frame). */ static void iwn_ampdu_rx_stop(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap) { struct ieee80211com *ic = ni->ni_ic; struct iwn_softc *sc = ic->ic_ifp->if_softc; struct iwn_ops *ops = &sc->ops; struct iwn_node *wn = (void *)ni; struct iwn_node_info node; uint8_t tid; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* XXX: tid as an argument */ for (tid = 0; tid < WME_NUM_TID; tid++) { if (&ni->ni_rx_ampdu[tid] == rap) break; } memset(&node, 0, sizeof node); node.id = wn->id; node.control = IWN_NODE_UPDATE; node.flags = IWN_FLAG_SET_DELBA; node.delba_tid = tid; DPRINTF(sc, IWN_DEBUG_RECV, "DELBA RA=%d TID=%d\n", wn->id, tid); (void)ops->add_node(sc, &node, 1); sc->sc_ampdu_rx_stop(ni, rap); } static int iwn_addba_request(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, int dialogtoken, int baparamset, int batimeout) { struct iwn_softc *sc = ni->ni_ic->ic_ifp->if_softc; int qid; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); for (qid = sc->firstaggqueue; qid < sc->ntxqs; qid++) { if (sc->qid2tap[qid] == NULL) break; } if (qid == sc->ntxqs) { DPRINTF(sc, IWN_DEBUG_XMIT, "%s: not free aggregation queue\n", __func__); return 0; } tap->txa_private = malloc(sizeof(int), M_DEVBUF, M_NOWAIT); if (tap->txa_private == NULL) { device_printf(sc->sc_dev, "%s: failed to alloc TX aggregation structure\n", __func__); return 0; } sc->qid2tap[qid] = tap; *(int *)tap->txa_private = qid; return sc->sc_addba_request(ni, tap, dialogtoken, baparamset, batimeout); } static int iwn_addba_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap, int code, int baparamset, int batimeout) { struct iwn_softc *sc = ni->ni_ic->ic_ifp->if_softc; int qid = *(int *)tap->txa_private; uint8_t tid = tap->txa_tid; int ret; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); if (code == IEEE80211_STATUS_SUCCESS) { ni->ni_txseqs[tid] = tap->txa_start & 0xfff; ret = iwn_ampdu_tx_start(ni->ni_ic, ni, tid); if (ret != 1) return ret; } else { sc->qid2tap[qid] = NULL; free(tap->txa_private, M_DEVBUF); tap->txa_private = NULL; } return sc->sc_addba_response(ni, tap, code, baparamset, batimeout); } /* * This function is called by upper layer when an ADDBA response is received * from another STA. */ static int iwn_ampdu_tx_start(struct ieee80211com *ic, struct ieee80211_node *ni, uint8_t tid) { struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[tid]; struct iwn_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct iwn_ops *ops = &sc->ops; struct iwn_node *wn = (void *)ni; struct iwn_node_info node; int error, qid; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* Enable TX for the specified RA/TID. */ wn->disable_tid &= ~(1 << tid); memset(&node, 0, sizeof node); node.id = wn->id; node.control = IWN_NODE_UPDATE; node.flags = IWN_FLAG_SET_DISABLE_TID; node.disable_tid = htole16(wn->disable_tid); error = ops->add_node(sc, &node, 1); if (error != 0) return 0; if ((error = iwn_nic_lock(sc)) != 0) return 0; qid = *(int *)tap->txa_private; DPRINTF(sc, IWN_DEBUG_XMIT, "%s: ra=%d tid=%d ssn=%d qid=%d\n", __func__, wn->id, tid, tap->txa_start, qid); ops->ampdu_tx_start(sc, ni, qid, tid, tap->txa_start & 0xfff); iwn_nic_unlock(sc); iwn_set_link_quality(sc, ni); return 1; } static void iwn_ampdu_tx_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) { struct iwn_softc *sc = ni->ni_ic->ic_ifp->if_softc; struct iwn_ops *ops = &sc->ops; uint8_t tid = tap->txa_tid; int qid; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); sc->sc_addba_stop(ni, tap); if (tap->txa_private == NULL) return; qid = *(int *)tap->txa_private; if (sc->txq[qid].queued != 0) return; if (iwn_nic_lock(sc) != 0) return; ops->ampdu_tx_stop(sc, qid, tid, tap->txa_start & 0xfff); iwn_nic_unlock(sc); sc->qid2tap[qid] = NULL; free(tap->txa_private, M_DEVBUF); tap->txa_private = NULL; } static void iwn4965_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni, int qid, uint8_t tid, uint16_t ssn) { struct iwn_node *wn = (void *)ni; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* Stop TX scheduler while we're changing its configuration. */ iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid), IWN4965_TXQ_STATUS_CHGACT); /* Assign RA/TID translation to the queue. */ iwn_mem_write_2(sc, sc->sched_base + IWN4965_SCHED_TRANS_TBL(qid), wn->id << 4 | tid); /* Enable chain-building mode for the queue. */ iwn_prph_setbits(sc, IWN4965_SCHED_QCHAIN_SEL, 1 << qid); /* Set starting sequence number from the ADDBA request. */ sc->txq[qid].cur = sc->txq[qid].read = (ssn & 0xff); IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | (ssn & 0xff)); iwn_prph_write(sc, IWN4965_SCHED_QUEUE_RDPTR(qid), ssn); /* Set scheduler window size. */ iwn_mem_write(sc, sc->sched_base + IWN4965_SCHED_QUEUE_OFFSET(qid), IWN_SCHED_WINSZ); /* Set scheduler frame limit. */ iwn_mem_write(sc, sc->sched_base + IWN4965_SCHED_QUEUE_OFFSET(qid) + 4, IWN_SCHED_LIMIT << 16); /* Enable interrupts for the queue. */ iwn_prph_setbits(sc, IWN4965_SCHED_INTR_MASK, 1 << qid); /* Mark the queue as active. */ iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid), IWN4965_TXQ_STATUS_ACTIVE | IWN4965_TXQ_STATUS_AGGR_ENA | iwn_tid2fifo[tid] << 1); } static void iwn4965_ampdu_tx_stop(struct iwn_softc *sc, int qid, uint8_t tid, uint16_t ssn) { DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* Stop TX scheduler while we're changing its configuration. */ iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid), IWN4965_TXQ_STATUS_CHGACT); /* Set starting sequence number from the ADDBA request. */ IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | (ssn & 0xff)); iwn_prph_write(sc, IWN4965_SCHED_QUEUE_RDPTR(qid), ssn); /* Disable interrupts for the queue. */ iwn_prph_clrbits(sc, IWN4965_SCHED_INTR_MASK, 1 << qid); /* Mark the queue as inactive. */ iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid), IWN4965_TXQ_STATUS_INACTIVE | iwn_tid2fifo[tid] << 1); } static void iwn5000_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni, int qid, uint8_t tid, uint16_t ssn) { DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); struct iwn_node *wn = (void *)ni; /* Stop TX scheduler while we're changing its configuration. */ iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), IWN5000_TXQ_STATUS_CHGACT); /* Assign RA/TID translation to the queue. */ iwn_mem_write_2(sc, sc->sched_base + IWN5000_SCHED_TRANS_TBL(qid), wn->id << 4 | tid); /* Enable chain-building mode for the queue. */ iwn_prph_setbits(sc, IWN5000_SCHED_QCHAIN_SEL, 1 << qid); /* Enable aggregation for the queue. */ iwn_prph_setbits(sc, IWN5000_SCHED_AGGR_SEL, 1 << qid); /* Set starting sequence number from the ADDBA request. */ sc->txq[qid].cur = sc->txq[qid].read = (ssn & 0xff); IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | (ssn & 0xff)); iwn_prph_write(sc, IWN5000_SCHED_QUEUE_RDPTR(qid), ssn); /* Set scheduler window size and frame limit. */ iwn_mem_write(sc, sc->sched_base + IWN5000_SCHED_QUEUE_OFFSET(qid) + 4, IWN_SCHED_LIMIT << 16 | IWN_SCHED_WINSZ); /* Enable interrupts for the queue. */ iwn_prph_setbits(sc, IWN5000_SCHED_INTR_MASK, 1 << qid); /* Mark the queue as active. */ iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), IWN5000_TXQ_STATUS_ACTIVE | iwn_tid2fifo[tid]); } static void iwn5000_ampdu_tx_stop(struct iwn_softc *sc, int qid, uint8_t tid, uint16_t ssn) { DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* Stop TX scheduler while we're changing its configuration. */ iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), IWN5000_TXQ_STATUS_CHGACT); /* Disable aggregation for the queue. */ iwn_prph_clrbits(sc, IWN5000_SCHED_AGGR_SEL, 1 << qid); /* Set starting sequence number from the ADDBA request. */ IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | (ssn & 0xff)); iwn_prph_write(sc, IWN5000_SCHED_QUEUE_RDPTR(qid), ssn); /* Disable interrupts for the queue. */ iwn_prph_clrbits(sc, IWN5000_SCHED_INTR_MASK, 1 << qid); /* Mark the queue as inactive. */ iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), IWN5000_TXQ_STATUS_INACTIVE | iwn_tid2fifo[tid]); } /* * Query calibration tables from the initialization firmware. We do this * only once at first boot. Called from a process context. */ static int iwn5000_query_calibration(struct iwn_softc *sc) { struct iwn5000_calib_config cmd; int error; memset(&cmd, 0, sizeof cmd); cmd.ucode.once.enable = htole32(0xffffffff); cmd.ucode.once.start = htole32(0xffffffff); cmd.ucode.once.send = htole32(0xffffffff); cmd.ucode.flags = htole32(0xffffffff); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: sending calibration query\n", __func__); error = iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof cmd, 0); if (error != 0) return error; /* Wait at most two seconds for calibration to complete. */ if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE)) error = msleep(sc, &sc->sc_mtx, PCATCH, "iwncal", 2 * hz); return error; } /* * Send calibration results to the runtime firmware. These results were * obtained on first boot from the initialization firmware. */ static int iwn5000_send_calibration(struct iwn_softc *sc) { int idx, error; for (idx = 0; idx < IWN5000_PHY_CALIB_MAX_RESULT; idx++) { if (!(sc->base_params->calib_need & (1<calibcmd[idx].buf == NULL) { DPRINTF(sc, IWN_DEBUG_CALIBRATE, "Need calib idx : %d but no available data\n", idx); continue; } DPRINTF(sc, IWN_DEBUG_CALIBRATE, "send calibration result idx=%d len=%d\n", idx, sc->calibcmd[idx].len); error = iwn_cmd(sc, IWN_CMD_PHY_CALIB, sc->calibcmd[idx].buf, sc->calibcmd[idx].len, 0); if (error != 0) { device_printf(sc->sc_dev, "%s: could not send calibration result, error %d\n", __func__, error); return error; } } return 0; } static int iwn5000_send_wimax_coex(struct iwn_softc *sc) { struct iwn5000_wimax_coex wimax; #if 0 if (sc->hw_type == IWN_HW_REV_TYPE_6050) { /* Enable WiMAX coexistence for combo adapters. */ wimax.flags = IWN_WIMAX_COEX_ASSOC_WA_UNMASK | IWN_WIMAX_COEX_UNASSOC_WA_UNMASK | IWN_WIMAX_COEX_STA_TABLE_VALID | IWN_WIMAX_COEX_ENABLE; memcpy(wimax.events, iwn6050_wimax_events, sizeof iwn6050_wimax_events); } else #endif { /* Disable WiMAX coexistence. */ wimax.flags = 0; memset(wimax.events, 0, sizeof wimax.events); } DPRINTF(sc, IWN_DEBUG_RESET, "%s: Configuring WiMAX coexistence\n", __func__); return iwn_cmd(sc, IWN5000_CMD_WIMAX_COEX, &wimax, sizeof wimax, 0); } static int iwn5000_crystal_calib(struct iwn_softc *sc) { struct iwn5000_phy_calib_crystal cmd; memset(&cmd, 0, sizeof cmd); cmd.code = IWN5000_PHY_CALIB_CRYSTAL; cmd.ngroups = 1; cmd.isvalid = 1; cmd.cap_pin[0] = le32toh(sc->eeprom_crystal) & 0xff; cmd.cap_pin[1] = (le32toh(sc->eeprom_crystal) >> 16) & 0xff; DPRINTF(sc, IWN_DEBUG_CALIBRATE, "sending crystal calibration %d, %d\n", cmd.cap_pin[0], cmd.cap_pin[1]); return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0); } static int iwn5000_temp_offset_calib(struct iwn_softc *sc) { struct iwn5000_phy_calib_temp_offset cmd; memset(&cmd, 0, sizeof cmd); cmd.code = IWN5000_PHY_CALIB_TEMP_OFFSET; cmd.ngroups = 1; cmd.isvalid = 1; if (sc->eeprom_temp != 0) cmd.offset = htole16(sc->eeprom_temp); else cmd.offset = htole16(IWN_DEFAULT_TEMP_OFFSET); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "setting radio sensor offset to %d\n", le16toh(cmd.offset)); return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0); } static int iwn5000_temp_offset_calibv2(struct iwn_softc *sc) { struct iwn5000_phy_calib_temp_offsetv2 cmd; memset(&cmd, 0, sizeof cmd); cmd.code = IWN5000_PHY_CALIB_TEMP_OFFSET; cmd.ngroups = 1; cmd.isvalid = 1; if (sc->eeprom_temp != 0) { cmd.offset_low = htole16(sc->eeprom_temp); cmd.offset_high = htole16(sc->eeprom_temp_high); } else { cmd.offset_low = htole16(IWN_DEFAULT_TEMP_OFFSET); cmd.offset_high = htole16(IWN_DEFAULT_TEMP_OFFSET); } cmd.burnt_voltage_ref = htole16(sc->eeprom_voltage); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "setting radio sensor low offset to %d, high offset to %d, voltage to %d\n", le16toh(cmd.offset_low), le16toh(cmd.offset_high), le16toh(cmd.burnt_voltage_ref)); return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0); } /* * This function is called after the runtime firmware notifies us of its * readiness (called in a process context). */ static int iwn4965_post_alive(struct iwn_softc *sc) { int error, qid; if ((error = iwn_nic_lock(sc)) != 0) return error; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* Clear TX scheduler state in SRAM. */ sc->sched_base = iwn_prph_read(sc, IWN_SCHED_SRAM_ADDR); iwn_mem_set_region_4(sc, sc->sched_base + IWN4965_SCHED_CTX_OFF, 0, IWN4965_SCHED_CTX_LEN / sizeof (uint32_t)); /* Set physical address of TX scheduler rings (1KB aligned). */ iwn_prph_write(sc, IWN4965_SCHED_DRAM_ADDR, sc->sched_dma.paddr >> 10); IWN_SETBITS(sc, IWN_FH_TX_CHICKEN, IWN_FH_TX_CHICKEN_SCHED_RETRY); /* Disable chain mode for all our 16 queues. */ iwn_prph_write(sc, IWN4965_SCHED_QCHAIN_SEL, 0); for (qid = 0; qid < IWN4965_NTXQUEUES; qid++) { iwn_prph_write(sc, IWN4965_SCHED_QUEUE_RDPTR(qid), 0); IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | 0); /* Set scheduler window size. */ iwn_mem_write(sc, sc->sched_base + IWN4965_SCHED_QUEUE_OFFSET(qid), IWN_SCHED_WINSZ); /* Set scheduler frame limit. */ iwn_mem_write(sc, sc->sched_base + IWN4965_SCHED_QUEUE_OFFSET(qid) + 4, IWN_SCHED_LIMIT << 16); } /* Enable interrupts for all our 16 queues. */ iwn_prph_write(sc, IWN4965_SCHED_INTR_MASK, 0xffff); /* Identify TX FIFO rings (0-7). */ iwn_prph_write(sc, IWN4965_SCHED_TXFACT, 0xff); /* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */ for (qid = 0; qid < 7; qid++) { static uint8_t qid2fifo[] = { 3, 2, 1, 0, 4, 5, 6 }; iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid), IWN4965_TXQ_STATUS_ACTIVE | qid2fifo[qid] << 1); } iwn_nic_unlock(sc); return 0; } /* * This function is called after the initialization or runtime firmware * notifies us of its readiness (called in a process context). */ static int iwn5000_post_alive(struct iwn_softc *sc) { int error, qid; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); /* Switch to using ICT interrupt mode. */ iwn5000_ict_reset(sc); if ((error = iwn_nic_lock(sc)) != 0){ DPRINTF(sc, IWN_DEBUG_TRACE, "->%s end in error\n", __func__); return error; } /* Clear TX scheduler state in SRAM. */ sc->sched_base = iwn_prph_read(sc, IWN_SCHED_SRAM_ADDR); iwn_mem_set_region_4(sc, sc->sched_base + IWN5000_SCHED_CTX_OFF, 0, IWN5000_SCHED_CTX_LEN / sizeof (uint32_t)); /* Set physical address of TX scheduler rings (1KB aligned). */ iwn_prph_write(sc, IWN5000_SCHED_DRAM_ADDR, sc->sched_dma.paddr >> 10); IWN_SETBITS(sc, IWN_FH_TX_CHICKEN, IWN_FH_TX_CHICKEN_SCHED_RETRY); /* Enable chain mode for all queues, except command queue. */ if (sc->sc_flags & IWN_FLAG_PAN_SUPPORT) iwn_prph_write(sc, IWN5000_SCHED_QCHAIN_SEL, 0xfffdf); else iwn_prph_write(sc, IWN5000_SCHED_QCHAIN_SEL, 0xfffef); iwn_prph_write(sc, IWN5000_SCHED_AGGR_SEL, 0); for (qid = 0; qid < IWN5000_NTXQUEUES; qid++) { iwn_prph_write(sc, IWN5000_SCHED_QUEUE_RDPTR(qid), 0); IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | 0); iwn_mem_write(sc, sc->sched_base + IWN5000_SCHED_QUEUE_OFFSET(qid), 0); /* Set scheduler window size and frame limit. */ iwn_mem_write(sc, sc->sched_base + IWN5000_SCHED_QUEUE_OFFSET(qid) + 4, IWN_SCHED_LIMIT << 16 | IWN_SCHED_WINSZ); } /* Enable interrupts for all our 20 queues. */ iwn_prph_write(sc, IWN5000_SCHED_INTR_MASK, 0xfffff); /* Identify TX FIFO rings (0-7). */ iwn_prph_write(sc, IWN5000_SCHED_TXFACT, 0xff); /* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */ if (sc->sc_flags & IWN_FLAG_PAN_SUPPORT) { /* Mark TX rings as active. */ for (qid = 0; qid < 11; qid++) { static uint8_t qid2fifo[] = { 3, 2, 1, 0, 0, 4, 2, 5, 4, 7, 5 }; iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), IWN5000_TXQ_STATUS_ACTIVE | qid2fifo[qid]); } } else { /* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */ for (qid = 0; qid < 7; qid++) { static uint8_t qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 }; iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid), IWN5000_TXQ_STATUS_ACTIVE | qid2fifo[qid]); } } iwn_nic_unlock(sc); /* Configure WiMAX coexistence for combo adapters. */ error = iwn5000_send_wimax_coex(sc); if (error != 0) { device_printf(sc->sc_dev, "%s: could not configure WiMAX coexistence, error %d\n", __func__, error); return error; } if (sc->hw_type != IWN_HW_REV_TYPE_5150) { /* Perform crystal calibration. */ error = iwn5000_crystal_calib(sc); if (error != 0) { device_printf(sc->sc_dev, "%s: crystal calibration failed, error %d\n", __func__, error); return error; } } if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE)) { /* Query calibration from the initialization firmware. */ if ((error = iwn5000_query_calibration(sc)) != 0) { device_printf(sc->sc_dev, "%s: could not query calibration, error %d\n", __func__, error); return error; } /* * We have the calibration results now, reboot with the * runtime firmware (call ourselves recursively!) */ iwn_hw_stop(sc); error = iwn_hw_init(sc); } else { /* Send calibration results to runtime firmware. */ error = iwn5000_send_calibration(sc); } DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return error; } /* * The firmware boot code is small and is intended to be copied directly into * the NIC internal memory (no DMA transfer). */ static int iwn4965_load_bootcode(struct iwn_softc *sc, const uint8_t *ucode, int size) { int error, ntries; size /= sizeof (uint32_t); if ((error = iwn_nic_lock(sc)) != 0) return error; /* Copy microcode image into NIC memory. */ iwn_prph_write_region_4(sc, IWN_BSM_SRAM_BASE, (const uint32_t *)ucode, size); iwn_prph_write(sc, IWN_BSM_WR_MEM_SRC, 0); iwn_prph_write(sc, IWN_BSM_WR_MEM_DST, IWN_FW_TEXT_BASE); iwn_prph_write(sc, IWN_BSM_WR_DWCOUNT, size); /* Start boot load now. */ iwn_prph_write(sc, IWN_BSM_WR_CTRL, IWN_BSM_WR_CTRL_START); /* Wait for transfer to complete. */ for (ntries = 0; ntries < 1000; ntries++) { if (!(iwn_prph_read(sc, IWN_BSM_WR_CTRL) & IWN_BSM_WR_CTRL_START)) break; DELAY(10); } if (ntries == 1000) { device_printf(sc->sc_dev, "%s: could not load boot firmware\n", __func__); iwn_nic_unlock(sc); return ETIMEDOUT; } /* Enable boot after power up. */ iwn_prph_write(sc, IWN_BSM_WR_CTRL, IWN_BSM_WR_CTRL_START_EN); iwn_nic_unlock(sc); return 0; } static int iwn4965_load_firmware(struct iwn_softc *sc) { struct iwn_fw_info *fw = &sc->fw; struct iwn_dma_info *dma = &sc->fw_dma; int error; /* Copy initialization sections into pre-allocated DMA-safe memory. */ memcpy(dma->vaddr, fw->init.data, fw->init.datasz); bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); memcpy(dma->vaddr + IWN4965_FW_DATA_MAXSZ, fw->init.text, fw->init.textsz); bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); /* Tell adapter where to find initialization sections. */ if ((error = iwn_nic_lock(sc)) != 0) return error; iwn_prph_write(sc, IWN_BSM_DRAM_DATA_ADDR, dma->paddr >> 4); iwn_prph_write(sc, IWN_BSM_DRAM_DATA_SIZE, fw->init.datasz); iwn_prph_write(sc, IWN_BSM_DRAM_TEXT_ADDR, (dma->paddr + IWN4965_FW_DATA_MAXSZ) >> 4); iwn_prph_write(sc, IWN_BSM_DRAM_TEXT_SIZE, fw->init.textsz); iwn_nic_unlock(sc); /* Load firmware boot code. */ error = iwn4965_load_bootcode(sc, fw->boot.text, fw->boot.textsz); if (error != 0) { device_printf(sc->sc_dev, "%s: could not load boot firmware\n", __func__); return error; } /* Now press "execute". */ IWN_WRITE(sc, IWN_RESET, 0); /* Wait at most one second for first alive notification. */ if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "iwninit", hz)) != 0) { device_printf(sc->sc_dev, "%s: timeout waiting for adapter to initialize, error %d\n", __func__, error); return error; } /* Retrieve current temperature for initial TX power calibration. */ sc->rawtemp = sc->ucode_info.temp[3].chan20MHz; sc->temp = iwn4965_get_temperature(sc); /* Copy runtime sections into pre-allocated DMA-safe memory. */ memcpy(dma->vaddr, fw->main.data, fw->main.datasz); bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); memcpy(dma->vaddr + IWN4965_FW_DATA_MAXSZ, fw->main.text, fw->main.textsz); bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); /* Tell adapter where to find runtime sections. */ if ((error = iwn_nic_lock(sc)) != 0) return error; iwn_prph_write(sc, IWN_BSM_DRAM_DATA_ADDR, dma->paddr >> 4); iwn_prph_write(sc, IWN_BSM_DRAM_DATA_SIZE, fw->main.datasz); iwn_prph_write(sc, IWN_BSM_DRAM_TEXT_ADDR, (dma->paddr + IWN4965_FW_DATA_MAXSZ) >> 4); iwn_prph_write(sc, IWN_BSM_DRAM_TEXT_SIZE, IWN_FW_UPDATED | fw->main.textsz); iwn_nic_unlock(sc); return 0; } static int iwn5000_load_firmware_section(struct iwn_softc *sc, uint32_t dst, const uint8_t *section, int size) { struct iwn_dma_info *dma = &sc->fw_dma; int error; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* Copy firmware section into pre-allocated DMA-safe memory. */ memcpy(dma->vaddr, section, size); bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_PREWRITE); if ((error = iwn_nic_lock(sc)) != 0) return error; IWN_WRITE(sc, IWN_FH_TX_CONFIG(IWN_SRVC_DMACHNL), IWN_FH_TX_CONFIG_DMA_PAUSE); IWN_WRITE(sc, IWN_FH_SRAM_ADDR(IWN_SRVC_DMACHNL), dst); IWN_WRITE(sc, IWN_FH_TFBD_CTRL0(IWN_SRVC_DMACHNL), IWN_LOADDR(dma->paddr)); IWN_WRITE(sc, IWN_FH_TFBD_CTRL1(IWN_SRVC_DMACHNL), IWN_HIADDR(dma->paddr) << 28 | size); IWN_WRITE(sc, IWN_FH_TXBUF_STATUS(IWN_SRVC_DMACHNL), IWN_FH_TXBUF_STATUS_TBNUM(1) | IWN_FH_TXBUF_STATUS_TBIDX(1) | IWN_FH_TXBUF_STATUS_TFBD_VALID); /* Kick Flow Handler to start DMA transfer. */ IWN_WRITE(sc, IWN_FH_TX_CONFIG(IWN_SRVC_DMACHNL), IWN_FH_TX_CONFIG_DMA_ENA | IWN_FH_TX_CONFIG_CIRQ_HOST_ENDTFD); iwn_nic_unlock(sc); /* Wait at most five seconds for FH DMA transfer to complete. */ return msleep(sc, &sc->sc_mtx, PCATCH, "iwninit", 5 * hz); } static int iwn5000_load_firmware(struct iwn_softc *sc) { struct iwn_fw_part *fw; int error; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* Load the initialization firmware on first boot only. */ fw = (sc->sc_flags & IWN_FLAG_CALIB_DONE) ? &sc->fw.main : &sc->fw.init; error = iwn5000_load_firmware_section(sc, IWN_FW_TEXT_BASE, fw->text, fw->textsz); if (error != 0) { device_printf(sc->sc_dev, "%s: could not load firmware %s section, error %d\n", __func__, ".text", error); return error; } error = iwn5000_load_firmware_section(sc, IWN_FW_DATA_BASE, fw->data, fw->datasz); if (error != 0) { device_printf(sc->sc_dev, "%s: could not load firmware %s section, error %d\n", __func__, ".data", error); return error; } /* Now press "execute". */ IWN_WRITE(sc, IWN_RESET, 0); return 0; } /* * Extract text and data sections from a legacy firmware image. */ static int iwn_read_firmware_leg(struct iwn_softc *sc, struct iwn_fw_info *fw) { const uint32_t *ptr; size_t hdrlen = 24; uint32_t rev; ptr = (const uint32_t *)fw->data; rev = le32toh(*ptr++); sc->ucode_rev = rev; /* Check firmware API version. */ if (IWN_FW_API(rev) <= 1) { device_printf(sc->sc_dev, "%s: bad firmware, need API version >=2\n", __func__); return EINVAL; } if (IWN_FW_API(rev) >= 3) { /* Skip build number (version 2 header). */ hdrlen += 4; ptr++; } if (fw->size < hdrlen) { device_printf(sc->sc_dev, "%s: firmware too short: %zu bytes\n", __func__, fw->size); return EINVAL; } fw->main.textsz = le32toh(*ptr++); fw->main.datasz = le32toh(*ptr++); fw->init.textsz = le32toh(*ptr++); fw->init.datasz = le32toh(*ptr++); fw->boot.textsz = le32toh(*ptr++); /* Check that all firmware sections fit. */ if (fw->size < hdrlen + fw->main.textsz + fw->main.datasz + fw->init.textsz + fw->init.datasz + fw->boot.textsz) { device_printf(sc->sc_dev, "%s: firmware too short: %zu bytes\n", __func__, fw->size); return EINVAL; } /* Get pointers to firmware sections. */ fw->main.text = (const uint8_t *)ptr; fw->main.data = fw->main.text + fw->main.textsz; fw->init.text = fw->main.data + fw->main.datasz; fw->init.data = fw->init.text + fw->init.textsz; fw->boot.text = fw->init.data + fw->init.datasz; return 0; } /* * Extract text and data sections from a TLV firmware image. */ static int iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw, uint16_t alt) { const struct iwn_fw_tlv_hdr *hdr; const struct iwn_fw_tlv *tlv; const uint8_t *ptr, *end; uint64_t altmask; uint32_t len, tmp; if (fw->size < sizeof (*hdr)) { device_printf(sc->sc_dev, "%s: firmware too short: %zu bytes\n", __func__, fw->size); return EINVAL; } hdr = (const struct iwn_fw_tlv_hdr *)fw->data; if (hdr->signature != htole32(IWN_FW_SIGNATURE)) { device_printf(sc->sc_dev, "%s: bad firmware signature 0x%08x\n", __func__, le32toh(hdr->signature)); return EINVAL; } DPRINTF(sc, IWN_DEBUG_RESET, "FW: \"%.64s\", build 0x%x\n", hdr->descr, le32toh(hdr->build)); sc->ucode_rev = le32toh(hdr->rev); /* * Select the closest supported alternative that is less than * or equal to the specified one. */ altmask = le64toh(hdr->altmask); while (alt > 0 && !(altmask & (1ULL << alt))) alt--; /* Downgrade. */ DPRINTF(sc, IWN_DEBUG_RESET, "using alternative %d\n", alt); ptr = (const uint8_t *)(hdr + 1); end = (const uint8_t *)(fw->data + fw->size); /* Parse type-length-value fields. */ while (ptr + sizeof (*tlv) <= end) { tlv = (const struct iwn_fw_tlv *)ptr; len = le32toh(tlv->len); ptr += sizeof (*tlv); if (ptr + len > end) { device_printf(sc->sc_dev, "%s: firmware too short: %zu bytes\n", __func__, fw->size); return EINVAL; } /* Skip other alternatives. */ if (tlv->alt != 0 && tlv->alt != htole16(alt)) goto next; switch (le16toh(tlv->type)) { case IWN_FW_TLV_MAIN_TEXT: fw->main.text = ptr; fw->main.textsz = len; break; case IWN_FW_TLV_MAIN_DATA: fw->main.data = ptr; fw->main.datasz = len; break; case IWN_FW_TLV_INIT_TEXT: fw->init.text = ptr; fw->init.textsz = len; break; case IWN_FW_TLV_INIT_DATA: fw->init.data = ptr; fw->init.datasz = len; break; case IWN_FW_TLV_BOOT_TEXT: fw->boot.text = ptr; fw->boot.textsz = len; break; case IWN_FW_TLV_ENH_SENS: if (!len) sc->sc_flags |= IWN_FLAG_ENH_SENS; break; case IWN_FW_TLV_PHY_CALIB: tmp = le32toh(*ptr); if (tmp < 253) { sc->reset_noise_gain = tmp; sc->noise_gain = tmp + 1; } break; case IWN_FW_TLV_PAN: sc->sc_flags |= IWN_FLAG_PAN_SUPPORT; DPRINTF(sc, IWN_DEBUG_RESET, "PAN Support found: %d\n", 1); break; case IWN_FW_TLV_FLAGS: if (len < sizeof(uint32_t)) break; if (len % sizeof(uint32_t)) break; sc->tlv_feature_flags = le32toh(*ptr); DPRINTF(sc, IWN_DEBUG_RESET, "%s: feature: 0x%08x\n", __func__, sc->tlv_feature_flags); break; case IWN_FW_TLV_PBREQ_MAXLEN: case IWN_FW_TLV_RUNT_EVTLOG_PTR: case IWN_FW_TLV_RUNT_EVTLOG_SIZE: case IWN_FW_TLV_RUNT_ERRLOG_PTR: case IWN_FW_TLV_INIT_EVTLOG_PTR: case IWN_FW_TLV_INIT_EVTLOG_SIZE: case IWN_FW_TLV_INIT_ERRLOG_PTR: case IWN_FW_TLV_WOWLAN_INST: case IWN_FW_TLV_WOWLAN_DATA: DPRINTF(sc, IWN_DEBUG_RESET, "TLV type %d recognized but not handled\n", le16toh(tlv->type)); break; default: DPRINTF(sc, IWN_DEBUG_RESET, "TLV type %d not handled\n", le16toh(tlv->type)); break; } next: /* TLV fields are 32-bit aligned. */ ptr += (len + 3) & ~3; } return 0; } static int iwn_read_firmware(struct iwn_softc *sc) { struct iwn_fw_info *fw = &sc->fw; int error; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); IWN_UNLOCK(sc); memset(fw, 0, sizeof (*fw)); /* Read firmware image from filesystem. */ sc->fw_fp = firmware_get(sc->fwname); if (sc->fw_fp == NULL) { device_printf(sc->sc_dev, "%s: could not read firmware %s\n", __func__, sc->fwname); IWN_LOCK(sc); return EINVAL; } IWN_LOCK(sc); fw->size = sc->fw_fp->datasize; fw->data = (const uint8_t *)sc->fw_fp->data; if (fw->size < sizeof (uint32_t)) { device_printf(sc->sc_dev, "%s: firmware too short: %zu bytes\n", __func__, fw->size); firmware_put(sc->fw_fp, FIRMWARE_UNLOAD); sc->fw_fp = NULL; return EINVAL; } /* Retrieve text and data sections. */ if (*(const uint32_t *)fw->data != 0) /* Legacy image. */ error = iwn_read_firmware_leg(sc, fw); else error = iwn_read_firmware_tlv(sc, fw, 1); if (error != 0) { device_printf(sc->sc_dev, "%s: could not read firmware sections, error %d\n", __func__, error); firmware_put(sc->fw_fp, FIRMWARE_UNLOAD); sc->fw_fp = NULL; return error; } device_printf(sc->sc_dev, "%s: ucode rev=0x%08x\n", __func__, sc->ucode_rev); /* Make sure text and data sections fit in hardware memory. */ if (fw->main.textsz > sc->fw_text_maxsz || fw->main.datasz > sc->fw_data_maxsz || fw->init.textsz > sc->fw_text_maxsz || fw->init.datasz > sc->fw_data_maxsz || fw->boot.textsz > IWN_FW_BOOT_TEXT_MAXSZ || (fw->boot.textsz & 3) != 0) { device_printf(sc->sc_dev, "%s: firmware sections too large\n", __func__); firmware_put(sc->fw_fp, FIRMWARE_UNLOAD); sc->fw_fp = NULL; return EINVAL; } /* We can proceed with loading the firmware. */ return 0; } static int iwn_clock_wait(struct iwn_softc *sc) { int ntries; /* Set "initialization complete" bit. */ IWN_SETBITS(sc, IWN_GP_CNTRL, IWN_GP_CNTRL_INIT_DONE); /* Wait for clock stabilization. */ for (ntries = 0; ntries < 2500; ntries++) { if (IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_MAC_CLOCK_READY) return 0; DELAY(10); } device_printf(sc->sc_dev, "%s: timeout waiting for clock stabilization\n", __func__); return ETIMEDOUT; } static int iwn_apm_init(struct iwn_softc *sc) { uint32_t reg; int error; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* Disable L0s exit timer (NMI bug workaround). */ IWN_SETBITS(sc, IWN_GIO_CHICKEN, IWN_GIO_CHICKEN_DIS_L0S_TIMER); /* Don't wait for ICH L0s (ICH bug workaround). */ IWN_SETBITS(sc, IWN_GIO_CHICKEN, IWN_GIO_CHICKEN_L1A_NO_L0S_RX); /* Set FH wait threshold to max (HW bug under stress workaround). */ IWN_SETBITS(sc, IWN_DBG_HPET_MEM, 0xffff0000); /* Enable HAP INTA to move adapter from L1a to L0s. */ IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_HAP_WAKE_L1A); /* Retrieve PCIe Active State Power Management (ASPM). */ reg = pci_read_config(sc->sc_dev, sc->sc_cap_off + 0x10, 1); /* Workaround for HW instability in PCIe L0->L0s->L1 transition. */ if (reg & 0x02) /* L1 Entry enabled. */ IWN_SETBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA); else IWN_CLRBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA); if (sc->base_params->pll_cfg_val) IWN_SETBITS(sc, IWN_ANA_PLL, sc->base_params->pll_cfg_val); /* Wait for clock stabilization before accessing prph. */ if ((error = iwn_clock_wait(sc)) != 0) return error; if ((error = iwn_nic_lock(sc)) != 0) return error; if (sc->hw_type == IWN_HW_REV_TYPE_4965) { /* Enable DMA and BSM (Bootstrap State Machine). */ iwn_prph_write(sc, IWN_APMG_CLK_EN, IWN_APMG_CLK_CTRL_DMA_CLK_RQT | IWN_APMG_CLK_CTRL_BSM_CLK_RQT); } else { /* Enable DMA. */ iwn_prph_write(sc, IWN_APMG_CLK_EN, IWN_APMG_CLK_CTRL_DMA_CLK_RQT); } DELAY(20); /* Disable L1-Active. */ iwn_prph_setbits(sc, IWN_APMG_PCI_STT, IWN_APMG_PCI_STT_L1A_DIS); iwn_nic_unlock(sc); return 0; } static void iwn_apm_stop_master(struct iwn_softc *sc) { int ntries; /* Stop busmaster DMA activity. */ IWN_SETBITS(sc, IWN_RESET, IWN_RESET_STOP_MASTER); for (ntries = 0; ntries < 100; ntries++) { if (IWN_READ(sc, IWN_RESET) & IWN_RESET_MASTER_DISABLED) return; DELAY(10); } device_printf(sc->sc_dev, "%s: timeout waiting for master\n", __func__); } static void iwn_apm_stop(struct iwn_softc *sc) { iwn_apm_stop_master(sc); /* Reset the entire device. */ IWN_SETBITS(sc, IWN_RESET, IWN_RESET_SW); DELAY(10); /* Clear "initialization complete" bit. */ IWN_CLRBITS(sc, IWN_GP_CNTRL, IWN_GP_CNTRL_INIT_DONE); } static int iwn4965_nic_config(struct iwn_softc *sc) { DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); if (IWN_RFCFG_TYPE(sc->rfcfg) == 1) { /* * I don't believe this to be correct but this is what the * vendor driver is doing. Probably the bits should not be * shifted in IWN_RFCFG_*. */ IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_RFCFG_TYPE(sc->rfcfg) | IWN_RFCFG_STEP(sc->rfcfg) | IWN_RFCFG_DASH(sc->rfcfg)); } IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_RADIO_SI | IWN_HW_IF_CONFIG_MAC_SI); return 0; } static int iwn5000_nic_config(struct iwn_softc *sc) { uint32_t tmp; int error; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); if (IWN_RFCFG_TYPE(sc->rfcfg) < 3) { IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_RFCFG_TYPE(sc->rfcfg) | IWN_RFCFG_STEP(sc->rfcfg) | IWN_RFCFG_DASH(sc->rfcfg)); } IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_RADIO_SI | IWN_HW_IF_CONFIG_MAC_SI); if ((error = iwn_nic_lock(sc)) != 0) return error; iwn_prph_setbits(sc, IWN_APMG_PS, IWN_APMG_PS_EARLY_PWROFF_DIS); if (sc->hw_type == IWN_HW_REV_TYPE_1000) { /* * Select first Switching Voltage Regulator (1.32V) to * solve a stability issue related to noisy DC2DC line * in the silicon of 1000 Series. */ tmp = iwn_prph_read(sc, IWN_APMG_DIGITAL_SVR); tmp &= ~IWN_APMG_DIGITAL_SVR_VOLTAGE_MASK; tmp |= IWN_APMG_DIGITAL_SVR_VOLTAGE_1_32; iwn_prph_write(sc, IWN_APMG_DIGITAL_SVR, tmp); } iwn_nic_unlock(sc); if (sc->sc_flags & IWN_FLAG_INTERNAL_PA) { /* Use internal power amplifier only. */ IWN_WRITE(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_2X2_IPA); } if (sc->base_params->additional_nic_config && sc->calib_ver >= 6) { /* Indicate that ROM calibration version is >=6. */ IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_CALIB_VER6); } if (sc->base_params->additional_gp_drv_bit) IWN_SETBITS(sc, IWN_GP_DRIVER, sc->base_params->additional_gp_drv_bit); return 0; } /* * Take NIC ownership over Intel Active Management Technology (AMT). */ static int iwn_hw_prepare(struct iwn_softc *sc) { int ntries; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); /* Check if hardware is ready. */ IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_NIC_READY); for (ntries = 0; ntries < 5; ntries++) { if (IWN_READ(sc, IWN_HW_IF_CONFIG) & IWN_HW_IF_CONFIG_NIC_READY) return 0; DELAY(10); } /* Hardware not ready, force into ready state. */ IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_PREPARE); for (ntries = 0; ntries < 15000; ntries++) { if (!(IWN_READ(sc, IWN_HW_IF_CONFIG) & IWN_HW_IF_CONFIG_PREPARE_DONE)) break; DELAY(10); } if (ntries == 15000) return ETIMEDOUT; /* Hardware should be ready now. */ IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_NIC_READY); for (ntries = 0; ntries < 5; ntries++) { if (IWN_READ(sc, IWN_HW_IF_CONFIG) & IWN_HW_IF_CONFIG_NIC_READY) return 0; DELAY(10); } return ETIMEDOUT; } static int iwn_hw_init(struct iwn_softc *sc) { struct iwn_ops *ops = &sc->ops; int error, chnl, qid; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); /* Clear pending interrupts. */ IWN_WRITE(sc, IWN_INT, 0xffffffff); if ((error = iwn_apm_init(sc)) != 0) { device_printf(sc->sc_dev, "%s: could not power ON adapter, error %d\n", __func__, error); return error; } /* Select VMAIN power source. */ if ((error = iwn_nic_lock(sc)) != 0) return error; iwn_prph_clrbits(sc, IWN_APMG_PS, IWN_APMG_PS_PWR_SRC_MASK); iwn_nic_unlock(sc); /* Perform adapter-specific initialization. */ if ((error = ops->nic_config(sc)) != 0) return error; /* Initialize RX ring. */ if ((error = iwn_nic_lock(sc)) != 0) return error; IWN_WRITE(sc, IWN_FH_RX_CONFIG, 0); IWN_WRITE(sc, IWN_FH_RX_WPTR, 0); /* Set physical address of RX ring (256-byte aligned). */ IWN_WRITE(sc, IWN_FH_RX_BASE, sc->rxq.desc_dma.paddr >> 8); /* Set physical address of RX status (16-byte aligned). */ IWN_WRITE(sc, IWN_FH_STATUS_WPTR, sc->rxq.stat_dma.paddr >> 4); /* Enable RX. */ IWN_WRITE(sc, IWN_FH_RX_CONFIG, IWN_FH_RX_CONFIG_ENA | IWN_FH_RX_CONFIG_IGN_RXF_EMPTY | /* HW bug workaround */ IWN_FH_RX_CONFIG_IRQ_DST_HOST | IWN_FH_RX_CONFIG_SINGLE_FRAME | IWN_FH_RX_CONFIG_RB_TIMEOUT(0) | IWN_FH_RX_CONFIG_NRBD(IWN_RX_RING_COUNT_LOG)); iwn_nic_unlock(sc); IWN_WRITE(sc, IWN_FH_RX_WPTR, (IWN_RX_RING_COUNT - 1) & ~7); if ((error = iwn_nic_lock(sc)) != 0) return error; /* Initialize TX scheduler. */ iwn_prph_write(sc, sc->sched_txfact_addr, 0); /* Set physical address of "keep warm" page (16-byte aligned). */ IWN_WRITE(sc, IWN_FH_KW_ADDR, sc->kw_dma.paddr >> 4); /* Initialize TX rings. */ for (qid = 0; qid < sc->ntxqs; qid++) { struct iwn_tx_ring *txq = &sc->txq[qid]; /* Set physical address of TX ring (256-byte aligned). */ IWN_WRITE(sc, IWN_FH_CBBC_QUEUE(qid), txq->desc_dma.paddr >> 8); } iwn_nic_unlock(sc); /* Enable DMA channels. */ for (chnl = 0; chnl < sc->ndmachnls; chnl++) { IWN_WRITE(sc, IWN_FH_TX_CONFIG(chnl), IWN_FH_TX_CONFIG_DMA_ENA | IWN_FH_TX_CONFIG_DMA_CREDIT_ENA); } /* Clear "radio off" and "commands blocked" bits. */ IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_RFKILL); IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_CMD_BLOCKED); /* Clear pending interrupts. */ IWN_WRITE(sc, IWN_INT, 0xffffffff); /* Enable interrupt coalescing. */ IWN_WRITE(sc, IWN_INT_COALESCING, 512 / 8); /* Enable interrupts. */ IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); /* _Really_ make sure "radio off" bit is cleared! */ IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_RFKILL); IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_RFKILL); /* Enable shadow registers. */ if (sc->base_params->shadow_reg_enable) IWN_SETBITS(sc, IWN_SHADOW_REG_CTRL, 0x800fffff); if ((error = ops->load_firmware(sc)) != 0) { device_printf(sc->sc_dev, "%s: could not load firmware, error %d\n", __func__, error); return error; } /* Wait at most one second for firmware alive notification. */ if ((error = msleep(sc, &sc->sc_mtx, PCATCH, "iwninit", hz)) != 0) { device_printf(sc->sc_dev, "%s: timeout waiting for adapter to initialize, error %d\n", __func__, error); return error; } /* Do post-firmware initialization. */ DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return ops->post_alive(sc); } static void iwn_hw_stop(struct iwn_softc *sc) { int chnl, qid, ntries; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); IWN_WRITE(sc, IWN_RESET, IWN_RESET_NEVO); /* Disable interrupts. */ IWN_WRITE(sc, IWN_INT_MASK, 0); IWN_WRITE(sc, IWN_INT, 0xffffffff); IWN_WRITE(sc, IWN_FH_INT, 0xffffffff); sc->sc_flags &= ~IWN_FLAG_USE_ICT; /* Make sure we no longer hold the NIC lock. */ iwn_nic_unlock(sc); /* Stop TX scheduler. */ iwn_prph_write(sc, sc->sched_txfact_addr, 0); /* Stop all DMA channels. */ if (iwn_nic_lock(sc) == 0) { for (chnl = 0; chnl < sc->ndmachnls; chnl++) { IWN_WRITE(sc, IWN_FH_TX_CONFIG(chnl), 0); for (ntries = 0; ntries < 200; ntries++) { if (IWN_READ(sc, IWN_FH_TX_STATUS) & IWN_FH_TX_STATUS_IDLE(chnl)) break; DELAY(10); } } iwn_nic_unlock(sc); } /* Stop RX ring. */ iwn_reset_rx_ring(sc, &sc->rxq); /* Reset all TX rings. */ for (qid = 0; qid < sc->ntxqs; qid++) iwn_reset_tx_ring(sc, &sc->txq[qid]); if (iwn_nic_lock(sc) == 0) { iwn_prph_write(sc, IWN_APMG_CLK_DIS, IWN_APMG_CLK_CTRL_DMA_CLK_RQT); iwn_nic_unlock(sc); } DELAY(5); /* Power OFF adapter. */ iwn_apm_stop(sc); } static void iwn_radio_on(void *arg0, int pending) { struct iwn_softc *sc = arg0; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); if (vap != NULL) { iwn_init(sc); ieee80211_init(vap); } } static void iwn_radio_off(void *arg0, int pending) { struct iwn_softc *sc = arg0; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); iwn_stop(sc); if (vap != NULL) ieee80211_stop(vap); /* Enable interrupts to get RF toggle notification. */ IWN_LOCK(sc); IWN_WRITE(sc, IWN_INT, 0xffffffff); IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); IWN_UNLOCK(sc); } static void iwn_panicked(void *arg0, int pending) { struct iwn_softc *sc = arg0; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); int error; if (vap == NULL) { printf("%s: null vap\n", __func__); return; } device_printf(sc->sc_dev, "%s: controller panicked, iv_state = %d; " "resetting...\n", __func__, vap->iv_state); IWN_LOCK(sc); iwn_stop_locked(sc); iwn_init_locked(sc); if (vap->iv_state >= IEEE80211_S_AUTH && (error = iwn_auth(sc, vap)) != 0) { device_printf(sc->sc_dev, "%s: could not move to auth state\n", __func__); } if (vap->iv_state >= IEEE80211_S_RUN && (error = iwn_run(sc, vap)) != 0) { device_printf(sc->sc_dev, "%s: could not move to run state\n", __func__); } /* Only run start once the NIC is in a useful state, like associated */ iwn_start_locked(sc->sc_ifp); IWN_UNLOCK(sc); } static void iwn_init_locked(struct iwn_softc *sc) { struct ifnet *ifp = sc->sc_ifp; int error; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); IWN_LOCK_ASSERT(sc); if ((error = iwn_hw_prepare(sc)) != 0) { device_printf(sc->sc_dev, "%s: hardware not ready, error %d\n", __func__, error); goto fail; } /* Initialize interrupt mask to default value. */ sc->int_mask = IWN_INT_MASK_DEF; sc->sc_flags &= ~IWN_FLAG_USE_ICT; /* Check that the radio is not disabled by hardware switch. */ if (!(IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_RFKILL)) { device_printf(sc->sc_dev, "radio is disabled by hardware switch\n"); /* Enable interrupts to get RF toggle notifications. */ IWN_WRITE(sc, IWN_INT, 0xffffffff); IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask); return; } /* Read firmware images from the filesystem. */ if ((error = iwn_read_firmware(sc)) != 0) { device_printf(sc->sc_dev, "%s: could not read firmware, error %d\n", __func__, error); goto fail; } /* Initialize hardware and upload firmware. */ error = iwn_hw_init(sc); firmware_put(sc->fw_fp, FIRMWARE_UNLOAD); sc->fw_fp = NULL; if (error != 0) { device_printf(sc->sc_dev, "%s: could not initialize hardware, error %d\n", __func__, error); goto fail; } /* Configure adapter now that it is ready. */ if ((error = iwn_config(sc)) != 0) { device_printf(sc->sc_dev, "%s: could not configure device, error %d\n", __func__, error); goto fail; } ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp->if_drv_flags |= IFF_DRV_RUNNING; callout_reset(&sc->watchdog_to, hz, iwn_watchdog, sc); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return; fail: iwn_stop_locked(sc); DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end in error\n",__func__); } static void iwn_init(void *arg) { struct iwn_softc *sc = arg; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; IWN_LOCK(sc); iwn_init_locked(sc); IWN_UNLOCK(sc); if (ifp->if_drv_flags & IFF_DRV_RUNNING) ieee80211_start_all(ic); } static void iwn_stop_locked(struct iwn_softc *sc) { struct ifnet *ifp = sc->sc_ifp; IWN_LOCK_ASSERT(sc); sc->sc_is_scanning = 0; sc->sc_tx_timer = 0; callout_stop(&sc->watchdog_to); callout_stop(&sc->calib_to); ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); /* Power OFF hardware. */ iwn_hw_stop(sc); } static void iwn_stop(struct iwn_softc *sc) { IWN_LOCK(sc); iwn_stop_locked(sc); IWN_UNLOCK(sc); } /* * Callback from net80211 to start a scan. */ static void iwn_scan_start(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; struct iwn_softc *sc = ifp->if_softc; IWN_LOCK(sc); /* make the link LED blink while we're scanning */ iwn_set_led(sc, IWN_LED_LINK, 20, 2); IWN_UNLOCK(sc); } /* * Callback from net80211 to terminate a scan. */ static void iwn_scan_end(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; struct iwn_softc *sc = ifp->if_softc; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); IWN_LOCK(sc); if (vap->iv_state == IEEE80211_S_RUN) { /* Set link LED to ON status if we are associated */ iwn_set_led(sc, IWN_LED_LINK, 0, 1); } IWN_UNLOCK(sc); } /* * Callback from net80211 to force a channel change. */ static void iwn_set_channel(struct ieee80211com *ic) { const struct ieee80211_channel *c = ic->ic_curchan; struct ifnet *ifp = ic->ic_ifp; struct iwn_softc *sc = ifp->if_softc; int error; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); IWN_LOCK(sc); sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq); sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags); sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq); sc->sc_txtap.wt_chan_flags = htole16(c->ic_flags); /* * Only need to set the channel in Monitor mode. AP scanning and auth * are already taken care of by their respective firmware commands. */ if (ic->ic_opmode == IEEE80211_M_MONITOR) { error = iwn_config(sc); if (error != 0) device_printf(sc->sc_dev, "%s: error %d settting channel\n", __func__, error); } IWN_UNLOCK(sc); } /* * Callback from net80211 to start scanning of the current channel. */ static void iwn_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) { struct ieee80211vap *vap = ss->ss_vap; struct iwn_softc *sc = vap->iv_ic->ic_ifp->if_softc; struct ieee80211com *ic = vap->iv_ic; int error; IWN_LOCK(sc); error = iwn_scan(sc, vap, ss, ic->ic_curchan); IWN_UNLOCK(sc); if (error != 0) ieee80211_cancel_scan(vap); } /* * Callback from net80211 to handle the minimum dwell time being met. * The intent is to terminate the scan but we just let the firmware * notify us when it's finished as we have no safe way to abort it. */ static void iwn_scan_mindwell(struct ieee80211_scan_state *ss) { /* NB: don't try to abort scan; wait for firmware to finish */ } static void iwn_hw_reset(void *arg0, int pending) { struct iwn_softc *sc = arg0; struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__); iwn_stop(sc); iwn_init(sc); ieee80211_notify_radio(ic, 1); } #ifdef IWN_DEBUG #define IWN_DESC(x) case x: return #x -#define COUNTOF(array) (sizeof(array) / sizeof(array[0])) /* * Translate CSR code to string */ static char *iwn_get_csr_string(int csr) { switch (csr) { IWN_DESC(IWN_HW_IF_CONFIG); IWN_DESC(IWN_INT_COALESCING); IWN_DESC(IWN_INT); IWN_DESC(IWN_INT_MASK); IWN_DESC(IWN_FH_INT); IWN_DESC(IWN_GPIO_IN); IWN_DESC(IWN_RESET); IWN_DESC(IWN_GP_CNTRL); IWN_DESC(IWN_HW_REV); IWN_DESC(IWN_EEPROM); IWN_DESC(IWN_EEPROM_GP); IWN_DESC(IWN_OTP_GP); IWN_DESC(IWN_GIO); IWN_DESC(IWN_GP_UCODE); IWN_DESC(IWN_GP_DRIVER); IWN_DESC(IWN_UCODE_GP1); IWN_DESC(IWN_UCODE_GP2); IWN_DESC(IWN_LED); IWN_DESC(IWN_DRAM_INT_TBL); IWN_DESC(IWN_GIO_CHICKEN); IWN_DESC(IWN_ANA_PLL); IWN_DESC(IWN_HW_REV_WA); IWN_DESC(IWN_DBG_HPET_MEM); default: return "UNKNOWN CSR"; } } /* * This function print firmware register */ static void iwn_debug_register(struct iwn_softc *sc) { int i; static const uint32_t csr_tbl[] = { IWN_HW_IF_CONFIG, IWN_INT_COALESCING, IWN_INT, IWN_INT_MASK, IWN_FH_INT, IWN_GPIO_IN, IWN_RESET, IWN_GP_CNTRL, IWN_HW_REV, IWN_EEPROM, IWN_EEPROM_GP, IWN_OTP_GP, IWN_GIO, IWN_GP_UCODE, IWN_GP_DRIVER, IWN_UCODE_GP1, IWN_UCODE_GP2, IWN_LED, IWN_DRAM_INT_TBL, IWN_GIO_CHICKEN, IWN_ANA_PLL, IWN_HW_REV_WA, IWN_DBG_HPET_MEM, }; DPRINTF(sc, IWN_DEBUG_REGISTER, "CSR values: (2nd byte of IWN_INT_COALESCING is IWN_INT_PERIODIC)%s", "\n"); - for (i = 0; i < COUNTOF(csr_tbl); i++){ + for (i = 0; i < nitems(csr_tbl); i++){ DPRINTF(sc, IWN_DEBUG_REGISTER," %10s: 0x%08x ", iwn_get_csr_string(csr_tbl[i]), IWN_READ(sc, csr_tbl[i])); if ((i+1) % 3 == 0) DPRINTF(sc, IWN_DEBUG_REGISTER,"%s","\n"); } DPRINTF(sc, IWN_DEBUG_REGISTER,"%s","\n"); } #endif Index: projects/ci20_mips/sys/dev/ixl/if_ixlv.c =================================================================== --- projects/ci20_mips/sys/dev/ixl/if_ixlv.c (revision 283030) +++ projects/ci20_mips/sys/dev/ixl/if_ixlv.c (revision 283031) @@ -1,2972 +1,2972 @@ /****************************************************************************** Copyright (c) 2013-2015, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ /*$FreeBSD$*/ #ifndef IXL_STANDALONE_BUILD #include "opt_inet.h" #include "opt_inet6.h" #include "opt_rss.h" #endif #include "ixl.h" #include "ixlv.h" #ifdef RSS #include #endif /********************************************************************* * Driver version *********************************************************************/ char ixlv_driver_version[] = "1.2.4"; /********************************************************************* * PCI Device ID Table * * Used by probe to select devices to load on * Last field stores an index into ixlv_strings * Last entry must be all 0s * * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } *********************************************************************/ static ixl_vendor_info_t ixlv_vendor_info_array[] = { {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_VF, 0, 0, 0}, {I40E_INTEL_VENDOR_ID, I40E_DEV_ID_VF_HV, 0, 0, 0}, /* required last entry */ {0, 0, 0, 0, 0} }; /********************************************************************* * Table of branding strings *********************************************************************/ static char *ixlv_strings[] = { "Intel(R) Ethernet Connection XL710 VF Driver" }; /********************************************************************* * Function prototypes *********************************************************************/ static int ixlv_probe(device_t); static int ixlv_attach(device_t); static int ixlv_detach(device_t); static int ixlv_shutdown(device_t); static void ixlv_init_locked(struct ixlv_sc *); static int ixlv_allocate_pci_resources(struct ixlv_sc *); static void ixlv_free_pci_resources(struct ixlv_sc *); static int ixlv_assign_msix(struct ixlv_sc *); static int ixlv_init_msix(struct ixlv_sc *); static int ixlv_init_taskqueue(struct ixlv_sc *); static int ixlv_setup_queues(struct ixlv_sc *); static void ixlv_config_rss(struct ixlv_sc *); static void ixlv_stop(struct ixlv_sc *); static void ixlv_add_multi(struct ixl_vsi *); static void ixlv_del_multi(struct ixl_vsi *); static void ixlv_free_queues(struct ixl_vsi *); static int ixlv_setup_interface(device_t, struct ixlv_sc *); static int ixlv_media_change(struct ifnet *); static void ixlv_media_status(struct ifnet *, struct ifmediareq *); static void ixlv_local_timer(void *); static int ixlv_add_mac_filter(struct ixlv_sc *, u8 *, u16); static int ixlv_del_mac_filter(struct ixlv_sc *sc, u8 *macaddr); static void ixlv_init_filters(struct ixlv_sc *); static void ixlv_free_filters(struct ixlv_sc *); static void ixlv_msix_que(void *); static void ixlv_msix_adminq(void *); static void ixlv_do_adminq(void *, int); static void ixlv_do_adminq_locked(struct ixlv_sc *sc); static void ixlv_handle_que(void *, int); static int ixlv_reset(struct ixlv_sc *); static int ixlv_reset_complete(struct i40e_hw *); static void ixlv_set_queue_rx_itr(struct ixl_queue *); static void ixlv_set_queue_tx_itr(struct ixl_queue *); static void ixl_init_cmd_complete(struct ixl_vc_cmd *, void *, enum i40e_status_code); static void ixlv_enable_adminq_irq(struct i40e_hw *); static void ixlv_disable_adminq_irq(struct i40e_hw *); static void ixlv_enable_queue_irq(struct i40e_hw *, int); static void ixlv_disable_queue_irq(struct i40e_hw *, int); static void ixlv_setup_vlan_filters(struct ixlv_sc *); static void ixlv_register_vlan(void *, struct ifnet *, u16); static void ixlv_unregister_vlan(void *, struct ifnet *, u16); static void ixlv_init_hw(struct ixlv_sc *); static int ixlv_setup_vc(struct ixlv_sc *); static int ixlv_vf_config(struct ixlv_sc *); static void ixlv_cap_txcsum_tso(struct ixl_vsi *, struct ifnet *, int); static void ixlv_add_sysctls(struct ixlv_sc *); static int ixlv_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS); static int ixlv_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS); /********************************************************************* * FreeBSD Device Interface Entry Points *********************************************************************/ static device_method_t ixlv_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ixlv_probe), DEVMETHOD(device_attach, ixlv_attach), DEVMETHOD(device_detach, ixlv_detach), DEVMETHOD(device_shutdown, ixlv_shutdown), {0, 0} }; static driver_t ixlv_driver = { "ixlv", ixlv_methods, sizeof(struct ixlv_sc), }; devclass_t ixlv_devclass; DRIVER_MODULE(ixlv, pci, ixlv_driver, ixlv_devclass, 0, 0); MODULE_DEPEND(ixlv, pci, 1, 1, 1); MODULE_DEPEND(ixlv, ether, 1, 1, 1); /* ** TUNEABLE PARAMETERS: */ static SYSCTL_NODE(_hw, OID_AUTO, ixlv, CTLFLAG_RD, 0, "IXLV driver parameters"); /* ** Number of descriptors per ring: ** - TX and RX are the same size */ static int ixlv_ringsz = DEFAULT_RING; TUNABLE_INT("hw.ixlv.ringsz", &ixlv_ringsz); SYSCTL_INT(_hw_ixlv, OID_AUTO, ring_size, CTLFLAG_RDTUN, &ixlv_ringsz, 0, "Descriptor Ring Size"); /* Set to zero to auto calculate */ int ixlv_max_queues = 0; TUNABLE_INT("hw.ixlv.max_queues", &ixlv_max_queues); SYSCTL_INT(_hw_ixlv, OID_AUTO, max_queues, CTLFLAG_RDTUN, &ixlv_max_queues, 0, "Number of Queues"); /* ** Number of entries in Tx queue buf_ring. ** Increasing this will reduce the number of ** errors when transmitting fragmented UDP ** packets. */ static int ixlv_txbrsz = DEFAULT_TXBRSZ; TUNABLE_INT("hw.ixlv.txbrsz", &ixlv_txbrsz); SYSCTL_INT(_hw_ixlv, OID_AUTO, txbr_size, CTLFLAG_RDTUN, &ixlv_txbrsz, 0, "TX Buf Ring Size"); /* ** Controls for Interrupt Throttling ** - true/false for dynamic adjustment ** - default values for static ITR */ int ixlv_dynamic_rx_itr = 0; TUNABLE_INT("hw.ixlv.dynamic_rx_itr", &ixlv_dynamic_rx_itr); SYSCTL_INT(_hw_ixlv, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN, &ixlv_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate"); int ixlv_dynamic_tx_itr = 0; TUNABLE_INT("hw.ixlv.dynamic_tx_itr", &ixlv_dynamic_tx_itr); SYSCTL_INT(_hw_ixlv, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN, &ixlv_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate"); int ixlv_rx_itr = IXL_ITR_8K; TUNABLE_INT("hw.ixlv.rx_itr", &ixlv_rx_itr); SYSCTL_INT(_hw_ixlv, OID_AUTO, rx_itr, CTLFLAG_RDTUN, &ixlv_rx_itr, 0, "RX Interrupt Rate"); int ixlv_tx_itr = IXL_ITR_4K; TUNABLE_INT("hw.ixlv.tx_itr", &ixlv_tx_itr); SYSCTL_INT(_hw_ixlv, OID_AUTO, tx_itr, CTLFLAG_RDTUN, &ixlv_tx_itr, 0, "TX Interrupt Rate"); /********************************************************************* * Device identification routine * * ixlv_probe determines if the driver should be loaded on * the hardware based on PCI vendor/device id of the device. * * return BUS_PROBE_DEFAULT on success, positive on failure *********************************************************************/ static int ixlv_probe(device_t dev) { ixl_vendor_info_t *ent; u16 pci_vendor_id, pci_device_id; u16 pci_subvendor_id, pci_subdevice_id; char device_name[256]; INIT_DEBUGOUT("ixlv_probe: begin"); pci_vendor_id = pci_get_vendor(dev); if (pci_vendor_id != I40E_INTEL_VENDOR_ID) return (ENXIO); pci_device_id = pci_get_device(dev); pci_subvendor_id = pci_get_subvendor(dev); pci_subdevice_id = pci_get_subdevice(dev); ent = ixlv_vendor_info_array; while (ent->vendor_id != 0) { if ((pci_vendor_id == ent->vendor_id) && (pci_device_id == ent->device_id) && ((pci_subvendor_id == ent->subvendor_id) || (ent->subvendor_id == 0)) && ((pci_subdevice_id == ent->subdevice_id) || (ent->subdevice_id == 0))) { sprintf(device_name, "%s, Version - %s", ixlv_strings[ent->index], ixlv_driver_version); device_set_desc_copy(dev, device_name); return (BUS_PROBE_DEFAULT); } ent++; } return (ENXIO); } /********************************************************************* * Device initialization routine * * The attach entry point is called when the driver is being loaded. * This routine identifies the type of hardware, allocates all resources * and initializes the hardware. * * return 0 on success, positive on failure *********************************************************************/ static int ixlv_attach(device_t dev) { struct ixlv_sc *sc; struct i40e_hw *hw; struct ixl_vsi *vsi; int error = 0; INIT_DBG_DEV(dev, "begin"); /* Allocate, clear, and link in our primary soft structure */ sc = device_get_softc(dev); sc->dev = sc->osdep.dev = dev; hw = &sc->hw; vsi = &sc->vsi; vsi->dev = dev; /* Initialize hw struct */ ixlv_init_hw(sc); /* Allocate filter lists */ ixlv_init_filters(sc); /* Core Lock Init*/ mtx_init(&sc->mtx, device_get_nameunit(dev), "IXL SC Lock", MTX_DEF); /* Set up the timer callout */ callout_init_mtx(&sc->timer, &sc->mtx, 0); /* Do PCI setup - map BAR0, etc */ if (ixlv_allocate_pci_resources(sc)) { device_printf(dev, "%s: Allocation of PCI resources failed\n", __func__); error = ENXIO; goto err_early; } INIT_DBG_DEV(dev, "Allocated PCI resources and MSIX vectors"); error = i40e_set_mac_type(hw); if (error) { device_printf(dev, "%s: set_mac_type failed: %d\n", __func__, error); goto err_pci_res; } error = ixlv_reset_complete(hw); if (error) { device_printf(dev, "%s: Device is still being reset\n", __func__); goto err_pci_res; } INIT_DBG_DEV(dev, "VF Device is ready for configuration"); error = ixlv_setup_vc(sc); if (error) { device_printf(dev, "%s: Error setting up PF comms, %d\n", __func__, error); goto err_pci_res; } INIT_DBG_DEV(dev, "PF API version verified"); /* TODO: Figure out why MDD events occur when this reset is removed. */ /* Need API version before sending reset message */ error = ixlv_reset(sc); if (error) { device_printf(dev, "VF reset failed; reload the driver\n"); goto err_aq; } INIT_DBG_DEV(dev, "VF reset complete"); /* Ask for VF config from PF */ error = ixlv_vf_config(sc); if (error) { device_printf(dev, "Error getting configuration from PF: %d\n", error); goto err_aq; } INIT_DBG_DEV(dev, "VF config from PF:"); INIT_DBG_DEV(dev, "VSIs %d, Queues %d, Max Vectors %d, Max MTU %d", sc->vf_res->num_vsis, sc->vf_res->num_queue_pairs, sc->vf_res->max_vectors, sc->vf_res->max_mtu); INIT_DBG_DEV(dev, "Offload flags: %#010x", sc->vf_res->vf_offload_flags); // TODO: Move this into ixlv_vf_config? /* got VF config message back from PF, now we can parse it */ for (int i = 0; i < sc->vf_res->num_vsis; i++) { if (sc->vf_res->vsi_res[i].vsi_type == I40E_VSI_SRIOV) sc->vsi_res = &sc->vf_res->vsi_res[i]; } if (!sc->vsi_res) { device_printf(dev, "%s: no LAN VSI found\n", __func__); error = EIO; goto err_res_buf; } INIT_DBG_DEV(dev, "Resource Acquisition complete"); /* If no mac address was assigned just make a random one */ if (!ixlv_check_ether_addr(hw->mac.addr)) { u8 addr[ETHER_ADDR_LEN]; arc4rand(&addr, sizeof(addr), 0); addr[0] &= 0xFE; addr[0] |= 0x02; bcopy(addr, hw->mac.addr, sizeof(addr)); } vsi->id = sc->vsi_res->vsi_id; vsi->back = (void *)sc; sc->link_up = TRUE; /* This allocates the memory and early settings */ if (ixlv_setup_queues(sc) != 0) { device_printf(dev, "%s: setup queues failed!\n", __func__); error = EIO; goto out; } /* Setup the stack interface */ if (ixlv_setup_interface(dev, sc) != 0) { device_printf(dev, "%s: setup interface failed!\n", __func__); error = EIO; goto out; } INIT_DBG_DEV(dev, "Queue memory and interface setup"); /* Do queue interrupt setup */ ixlv_assign_msix(sc); /* Start AdminQ taskqueue */ ixlv_init_taskqueue(sc); /* Initialize stats */ bzero(&sc->vsi.eth_stats, sizeof(struct i40e_eth_stats)); ixlv_add_sysctls(sc); /* Register for VLAN events */ vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, ixlv_register_vlan, vsi, EVENTHANDLER_PRI_FIRST); vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, ixlv_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST); /* We want AQ enabled early */ ixlv_enable_adminq_irq(hw); /* Set things up to run init */ sc->init_state = IXLV_INIT_READY; ixl_vc_init_mgr(sc, &sc->vc_mgr); INIT_DBG_DEV(dev, "end"); return (error); out: ixlv_free_queues(vsi); err_res_buf: free(sc->vf_res, M_DEVBUF); err_aq: i40e_shutdown_adminq(hw); err_pci_res: ixlv_free_pci_resources(sc); err_early: mtx_destroy(&sc->mtx); ixlv_free_filters(sc); INIT_DBG_DEV(dev, "end: error %d", error); return (error); } /********************************************************************* * Device removal routine * * The detach entry point is called when the driver is being removed. * This routine stops the adapter and deallocates all the resources * that were allocated for driver operation. * * return 0 on success, positive on failure *********************************************************************/ static int ixlv_detach(device_t dev) { struct ixlv_sc *sc = device_get_softc(dev); struct ixl_vsi *vsi = &sc->vsi; INIT_DBG_DEV(dev, "begin"); /* Make sure VLANS are not using driver */ if (vsi->ifp->if_vlantrunk != NULL) { if_printf(vsi->ifp, "Vlan in use, detach first\n"); INIT_DBG_DEV(dev, "end"); return (EBUSY); } /* Stop driver */ ether_ifdetach(vsi->ifp); if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) { mtx_lock(&sc->mtx); ixlv_stop(sc); mtx_unlock(&sc->mtx); } /* Unregister VLAN events */ if (vsi->vlan_attach != NULL) EVENTHANDLER_DEREGISTER(vlan_config, vsi->vlan_attach); if (vsi->vlan_detach != NULL) EVENTHANDLER_DEREGISTER(vlan_unconfig, vsi->vlan_detach); /* Drain VC mgr */ callout_drain(&sc->vc_mgr.callout); i40e_shutdown_adminq(&sc->hw); taskqueue_free(sc->tq); if_free(vsi->ifp); free(sc->vf_res, M_DEVBUF); ixlv_free_pci_resources(sc); ixlv_free_queues(vsi); mtx_destroy(&sc->mtx); ixlv_free_filters(sc); bus_generic_detach(dev); INIT_DBG_DEV(dev, "end"); return (0); } /********************************************************************* * * Shutdown entry point * **********************************************************************/ static int ixlv_shutdown(device_t dev) { struct ixlv_sc *sc = device_get_softc(dev); INIT_DBG_DEV(dev, "begin"); mtx_lock(&sc->mtx); ixlv_stop(sc); mtx_unlock(&sc->mtx); INIT_DBG_DEV(dev, "end"); return (0); } /* * Configure TXCSUM(IPV6) and TSO(4/6) * - the hardware handles these together so we * need to tweak them */ static void ixlv_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask) { /* Enable/disable TXCSUM/TSO4 */ if (!(ifp->if_capenable & IFCAP_TXCSUM) && !(ifp->if_capenable & IFCAP_TSO4)) { if (mask & IFCAP_TXCSUM) { ifp->if_capenable |= IFCAP_TXCSUM; /* enable TXCSUM, restore TSO if previously enabled */ if (vsi->flags & IXL_FLAGS_KEEP_TSO4) { vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; ifp->if_capenable |= IFCAP_TSO4; } } else if (mask & IFCAP_TSO4) { ifp->if_capenable |= (IFCAP_TXCSUM | IFCAP_TSO4); vsi->flags &= ~IXL_FLAGS_KEEP_TSO4; if_printf(ifp, "TSO4 requires txcsum, enabling both...\n"); } } else if((ifp->if_capenable & IFCAP_TXCSUM) && !(ifp->if_capenable & IFCAP_TSO4)) { if (mask & IFCAP_TXCSUM) ifp->if_capenable &= ~IFCAP_TXCSUM; else if (mask & IFCAP_TSO4) ifp->if_capenable |= IFCAP_TSO4; } else if((ifp->if_capenable & IFCAP_TXCSUM) && (ifp->if_capenable & IFCAP_TSO4)) { if (mask & IFCAP_TXCSUM) { vsi->flags |= IXL_FLAGS_KEEP_TSO4; ifp->if_capenable &= ~(IFCAP_TXCSUM | IFCAP_TSO4); if_printf(ifp, "TSO4 requires txcsum, disabling both...\n"); } else if (mask & IFCAP_TSO4) ifp->if_capenable &= ~IFCAP_TSO4; } /* Enable/disable TXCSUM_IPV6/TSO6 */ if (!(ifp->if_capenable & IFCAP_TXCSUM_IPV6) && !(ifp->if_capenable & IFCAP_TSO6)) { if (mask & IFCAP_TXCSUM_IPV6) { ifp->if_capenable |= IFCAP_TXCSUM_IPV6; if (vsi->flags & IXL_FLAGS_KEEP_TSO6) { vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; ifp->if_capenable |= IFCAP_TSO6; } } else if (mask & IFCAP_TSO6) { ifp->if_capenable |= (IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); vsi->flags &= ~IXL_FLAGS_KEEP_TSO6; if_printf(ifp, "TSO6 requires txcsum6, enabling both...\n"); } } else if((ifp->if_capenable & IFCAP_TXCSUM_IPV6) && !(ifp->if_capenable & IFCAP_TSO6)) { if (mask & IFCAP_TXCSUM_IPV6) ifp->if_capenable &= ~IFCAP_TXCSUM_IPV6; else if (mask & IFCAP_TSO6) ifp->if_capenable |= IFCAP_TSO6; } else if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6) && (ifp->if_capenable & IFCAP_TSO6)) { if (mask & IFCAP_TXCSUM_IPV6) { vsi->flags |= IXL_FLAGS_KEEP_TSO6; ifp->if_capenable &= ~(IFCAP_TXCSUM_IPV6 | IFCAP_TSO6); if_printf(ifp, "TSO6 requires txcsum6, disabling both...\n"); } else if (mask & IFCAP_TSO6) ifp->if_capenable &= ~IFCAP_TSO6; } } /********************************************************************* * Ioctl entry point * * ixlv_ioctl is called when the user wants to configure the * interface. * * return 0 on success, positive on failure **********************************************************************/ static int ixlv_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { struct ixl_vsi *vsi = ifp->if_softc; struct ixlv_sc *sc = vsi->back; struct ifreq *ifr = (struct ifreq *)data; #if defined(INET) || defined(INET6) struct ifaddr *ifa = (struct ifaddr *)data; bool avoid_reset = FALSE; #endif int error = 0; switch (command) { case SIOCSIFADDR: #ifdef INET if (ifa->ifa_addr->sa_family == AF_INET) avoid_reset = TRUE; #endif #ifdef INET6 if (ifa->ifa_addr->sa_family == AF_INET6) avoid_reset = TRUE; #endif #if defined(INET) || defined(INET6) /* ** Calling init results in link renegotiation, ** so we avoid doing it when possible. */ if (avoid_reset) { ifp->if_flags |= IFF_UP; if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) ixlv_init(vsi); #ifdef INET if (!(ifp->if_flags & IFF_NOARP)) arp_ifinit(ifp, ifa); #endif } else error = ether_ioctl(ifp, command, data); break; #endif case SIOCSIFMTU: IOCTL_DBG_IF2(ifp, "SIOCSIFMTU (Set Interface MTU)"); mtx_lock(&sc->mtx); if (ifr->ifr_mtu > IXL_MAX_FRAME - ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN) { error = EINVAL; IOCTL_DBG_IF(ifp, "mtu too large"); } else { IOCTL_DBG_IF2(ifp, "mtu: %lu -> %d", ifp->if_mtu, ifr->ifr_mtu); // ERJ: Interestingly enough, these types don't match ifp->if_mtu = (u_long)ifr->ifr_mtu; vsi->max_frame_size = ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_VLAN_ENCAP_LEN; ixlv_init_locked(sc); } mtx_unlock(&sc->mtx); break; case SIOCSIFFLAGS: IOCTL_DBG_IF2(ifp, "SIOCSIFFLAGS (Set Interface Flags)"); mtx_lock(&sc->mtx); if (ifp->if_flags & IFF_UP) { if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) ixlv_init_locked(sc); } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) ixlv_stop(sc); sc->if_flags = ifp->if_flags; mtx_unlock(&sc->mtx); break; case SIOCADDMULTI: IOCTL_DBG_IF2(ifp, "SIOCADDMULTI"); if (ifp->if_drv_flags & IFF_DRV_RUNNING) { mtx_lock(&sc->mtx); ixlv_disable_intr(vsi); ixlv_add_multi(vsi); ixlv_enable_intr(vsi); mtx_unlock(&sc->mtx); } break; case SIOCDELMULTI: IOCTL_DBG_IF2(ifp, "SIOCDELMULTI"); if (sc->init_state == IXLV_RUNNING) { mtx_lock(&sc->mtx); ixlv_disable_intr(vsi); ixlv_del_multi(vsi); ixlv_enable_intr(vsi); mtx_unlock(&sc->mtx); } break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: IOCTL_DBG_IF2(ifp, "SIOCxIFMEDIA (Get/Set Interface Media)"); error = ifmedia_ioctl(ifp, ifr, &sc->media, command); break; case SIOCSIFCAP: { int mask = ifr->ifr_reqcap ^ ifp->if_capenable; IOCTL_DBG_IF2(ifp, "SIOCSIFCAP (Set Capabilities)"); ixlv_cap_txcsum_tso(vsi, ifp, mask); if (mask & IFCAP_RXCSUM) ifp->if_capenable ^= IFCAP_RXCSUM; if (mask & IFCAP_RXCSUM_IPV6) ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; if (mask & IFCAP_LRO) ifp->if_capenable ^= IFCAP_LRO; if (mask & IFCAP_VLAN_HWTAGGING) ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; if (mask & IFCAP_VLAN_HWFILTER) ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; if (mask & IFCAP_VLAN_HWTSO) ifp->if_capenable ^= IFCAP_VLAN_HWTSO; if (ifp->if_drv_flags & IFF_DRV_RUNNING) { ixlv_init(vsi); } VLAN_CAPABILITIES(ifp); break; } default: IOCTL_DBG_IF2(ifp, "UNKNOWN (0x%X)", (int)command); error = ether_ioctl(ifp, command, data); break; } return (error); } /* ** To do a reinit on the VF is unfortunately more complicated ** than a physical device, we must have the PF more or less ** completely recreate our memory, so many things that were ** done only once at attach in traditional drivers now must be ** redone at each reinitialization. This function does that ** 'prelude' so we can then call the normal locked init code. */ int ixlv_reinit_locked(struct ixlv_sc *sc) { struct i40e_hw *hw = &sc->hw; struct ixl_vsi *vsi = &sc->vsi; struct ifnet *ifp = vsi->ifp; struct ixlv_mac_filter *mf, *mf_temp; struct ixlv_vlan_filter *vf; int error = 0; INIT_DBG_IF(ifp, "begin"); if (ifp->if_drv_flags & IFF_DRV_RUNNING) ixlv_stop(sc); error = ixlv_reset(sc); INIT_DBG_IF(ifp, "VF was reset"); /* set the state in case we went thru RESET */ sc->init_state = IXLV_RUNNING; /* ** Resetting the VF drops all filters from hardware; ** we need to mark them to be re-added in init. */ SLIST_FOREACH_SAFE(mf, sc->mac_filters, next, mf_temp) { if (mf->flags & IXL_FILTER_DEL) { SLIST_REMOVE(sc->mac_filters, mf, ixlv_mac_filter, next); free(mf, M_DEVBUF); } else mf->flags |= IXL_FILTER_ADD; } if (vsi->num_vlans != 0) SLIST_FOREACH(vf, sc->vlan_filters, next) vf->flags = IXL_FILTER_ADD; else { /* clean any stale filters */ while (!SLIST_EMPTY(sc->vlan_filters)) { vf = SLIST_FIRST(sc->vlan_filters); SLIST_REMOVE_HEAD(sc->vlan_filters, next); free(vf, M_DEVBUF); } } ixlv_enable_adminq_irq(hw); ixl_vc_flush(&sc->vc_mgr); INIT_DBG_IF(ifp, "end"); return (error); } static void ixl_init_cmd_complete(struct ixl_vc_cmd *cmd, void *arg, enum i40e_status_code code) { struct ixlv_sc *sc; sc = arg; /* * Ignore "Adapter Stopped" message as that happens if an ifconfig down * happens while a command is in progress, so we don't print an error * in that case. */ if (code != I40E_SUCCESS && code != I40E_ERR_ADAPTER_STOPPED) { if_printf(sc->vsi.ifp, "Error %d waiting for PF to complete operation %d\n", code, cmd->request); } } static void ixlv_init_locked(struct ixlv_sc *sc) { struct i40e_hw *hw = &sc->hw; struct ixl_vsi *vsi = &sc->vsi; struct ixl_queue *que = vsi->queues; struct ifnet *ifp = vsi->ifp; int error = 0; INIT_DBG_IF(ifp, "begin"); IXLV_CORE_LOCK_ASSERT(sc); /* Do a reinit first if an init has already been done */ if ((sc->init_state == IXLV_RUNNING) || (sc->init_state == IXLV_RESET_REQUIRED) || (sc->init_state == IXLV_RESET_PENDING)) error = ixlv_reinit_locked(sc); /* Don't bother with init if we failed reinit */ if (error) goto init_done; /* Remove existing MAC filter if new MAC addr is set */ if (bcmp(IF_LLADDR(ifp), hw->mac.addr, ETHER_ADDR_LEN) != 0) { error = ixlv_del_mac_filter(sc, hw->mac.addr); if (error == 0) ixl_vc_enqueue(&sc->vc_mgr, &sc->del_mac_cmd, IXLV_FLAG_AQ_DEL_MAC_FILTER, ixl_init_cmd_complete, sc); } /* Check for an LAA mac address... */ bcopy(IF_LLADDR(ifp), hw->mac.addr, ETHER_ADDR_LEN); ifp->if_hwassist = 0; if (ifp->if_capenable & IFCAP_TSO) ifp->if_hwassist |= CSUM_TSO; if (ifp->if_capenable & IFCAP_TXCSUM) ifp->if_hwassist |= (CSUM_OFFLOAD_IPV4 & ~CSUM_IP); if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) ifp->if_hwassist |= CSUM_OFFLOAD_IPV6; /* Add mac filter for this VF to PF */ if (i40e_validate_mac_addr(hw->mac.addr) == I40E_SUCCESS) { error = ixlv_add_mac_filter(sc, hw->mac.addr, 0); if (!error || error == EEXIST) ixl_vc_enqueue(&sc->vc_mgr, &sc->add_mac_cmd, IXLV_FLAG_AQ_ADD_MAC_FILTER, ixl_init_cmd_complete, sc); } /* Setup vlan's if needed */ ixlv_setup_vlan_filters(sc); /* Prepare the queues for operation */ for (int i = 0; i < vsi->num_queues; i++, que++) { struct rx_ring *rxr = &que->rxr; ixl_init_tx_ring(que); if (vsi->max_frame_size <= MCLBYTES) rxr->mbuf_sz = MCLBYTES; else rxr->mbuf_sz = MJUMPAGESIZE; ixl_init_rx_ring(que); } /* Configure queues */ ixl_vc_enqueue(&sc->vc_mgr, &sc->config_queues_cmd, IXLV_FLAG_AQ_CONFIGURE_QUEUES, ixl_init_cmd_complete, sc); /* Set up RSS */ ixlv_config_rss(sc); /* Map vectors */ ixl_vc_enqueue(&sc->vc_mgr, &sc->map_vectors_cmd, IXLV_FLAG_AQ_MAP_VECTORS, ixl_init_cmd_complete, sc); /* Enable queues */ ixl_vc_enqueue(&sc->vc_mgr, &sc->enable_queues_cmd, IXLV_FLAG_AQ_ENABLE_QUEUES, ixl_init_cmd_complete, sc); /* Start the local timer */ callout_reset(&sc->timer, hz, ixlv_local_timer, sc); sc->init_state = IXLV_RUNNING; init_done: INIT_DBG_IF(ifp, "end"); return; } /* ** Init entry point for the stack */ void ixlv_init(void *arg) { struct ixl_vsi *vsi = (struct ixl_vsi *)arg; struct ixlv_sc *sc = vsi->back; int retries = 0; mtx_lock(&sc->mtx); ixlv_init_locked(sc); mtx_unlock(&sc->mtx); /* Wait for init_locked to finish */ while (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING) && ++retries < 100) { i40e_msec_delay(10); } if (retries >= IXLV_AQ_MAX_ERR) if_printf(vsi->ifp, "Init failed to complete in alloted time!\n"); } /* * ixlv_attach() helper function; gathers information about * the (virtual) hardware for use elsewhere in the driver. */ static void ixlv_init_hw(struct ixlv_sc *sc) { struct i40e_hw *hw = &sc->hw; device_t dev = sc->dev; /* Save off the information about this board */ hw->vendor_id = pci_get_vendor(dev); hw->device_id = pci_get_device(dev); hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); hw->subsystem_vendor_id = pci_read_config(dev, PCIR_SUBVEND_0, 2); hw->subsystem_device_id = pci_read_config(dev, PCIR_SUBDEV_0, 2); hw->bus.device = pci_get_slot(dev); hw->bus.func = pci_get_function(dev); } /* * ixlv_attach() helper function; initalizes the admin queue * and attempts to establish contact with the PF by * retrying the initial "API version" message several times * or until the PF responds. */ static int ixlv_setup_vc(struct ixlv_sc *sc) { struct i40e_hw *hw = &sc->hw; device_t dev = sc->dev; int error = 0, ret_error = 0, asq_retries = 0; bool send_api_ver_retried = 0; /* Need to set these AQ paramters before initializing AQ */ hw->aq.num_arq_entries = IXL_AQ_LEN; hw->aq.num_asq_entries = IXL_AQ_LEN; hw->aq.arq_buf_size = IXL_AQ_BUFSZ; hw->aq.asq_buf_size = IXL_AQ_BUFSZ; for (int i = 0; i < IXLV_AQ_MAX_ERR; i++) { /* Initialize admin queue */ error = i40e_init_adminq(hw); if (error) { device_printf(dev, "%s: init_adminq failed: %d\n", __func__, error); ret_error = 1; continue; } INIT_DBG_DEV(dev, "Initialized Admin Queue, attempt %d", i+1); retry_send: /* Send VF's API version */ error = ixlv_send_api_ver(sc); if (error) { i40e_shutdown_adminq(hw); ret_error = 2; device_printf(dev, "%s: unable to send api" " version to PF on attempt %d, error %d\n", __func__, i+1, error); } asq_retries = 0; while (!i40e_asq_done(hw)) { if (++asq_retries > IXLV_AQ_MAX_ERR) { i40e_shutdown_adminq(hw); DDPRINTF(dev, "Admin Queue timeout " "(waiting for send_api_ver), %d more retries...", IXLV_AQ_MAX_ERR - (i + 1)); ret_error = 3; break; } i40e_msec_delay(10); } if (asq_retries > IXLV_AQ_MAX_ERR) continue; INIT_DBG_DEV(dev, "Sent API version message to PF"); /* Verify that the VF accepts the PF's API version */ error = ixlv_verify_api_ver(sc); if (error == ETIMEDOUT) { if (!send_api_ver_retried) { /* Resend message, one more time */ send_api_ver_retried++; device_printf(dev, "%s: Timeout while verifying API version on first" " try!\n", __func__); goto retry_send; } else { device_printf(dev, "%s: Timeout while verifying API version on second" " try!\n", __func__); ret_error = 4; break; } } if (error) { device_printf(dev, "%s: Unable to verify API version," " error %d\n", __func__, error); ret_error = 5; } break; } if (ret_error >= 4) i40e_shutdown_adminq(hw); return (ret_error); } /* * ixlv_attach() helper function; asks the PF for this VF's * configuration, and saves the information if it receives it. */ static int ixlv_vf_config(struct ixlv_sc *sc) { struct i40e_hw *hw = &sc->hw; device_t dev = sc->dev; int bufsz, error = 0, ret_error = 0; int asq_retries, retried = 0; retry_config: error = ixlv_send_vf_config_msg(sc); if (error) { device_printf(dev, "%s: Unable to send VF config request, attempt %d," " error %d\n", __func__, retried + 1, error); ret_error = 2; } asq_retries = 0; while (!i40e_asq_done(hw)) { if (++asq_retries > IXLV_AQ_MAX_ERR) { device_printf(dev, "%s: Admin Queue timeout " "(waiting for send_vf_config_msg), attempt %d\n", __func__, retried + 1); ret_error = 3; goto fail; } i40e_msec_delay(10); } INIT_DBG_DEV(dev, "Sent VF config message to PF, attempt %d", retried + 1); if (!sc->vf_res) { bufsz = sizeof(struct i40e_virtchnl_vf_resource) + (I40E_MAX_VF_VSI * sizeof(struct i40e_virtchnl_vsi_resource)); sc->vf_res = malloc(bufsz, M_DEVBUF, M_NOWAIT); if (!sc->vf_res) { device_printf(dev, "%s: Unable to allocate memory for VF configuration" " message from PF on attempt %d\n", __func__, retried + 1); ret_error = 1; goto fail; } } /* Check for VF config response */ error = ixlv_get_vf_config(sc); if (error == ETIMEDOUT) { /* The 1st time we timeout, send the configuration message again */ if (!retried) { retried++; goto retry_config; } } if (error) { device_printf(dev, "%s: Unable to get VF configuration from PF after %d tries!\n", __func__, retried + 1); ret_error = 4; } goto done; fail: free(sc->vf_res, M_DEVBUF); done: return (ret_error); } /* * Allocate MSI/X vectors, setup the AQ vector early */ static int ixlv_init_msix(struct ixlv_sc *sc) { device_t dev = sc->dev; int rid, want, vectors, queues, available; rid = PCIR_BAR(IXL_BAR); sc->msix_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->msix_mem) { /* May not be enabled */ device_printf(sc->dev, "Unable to map MSIX table \n"); goto fail; } available = pci_msix_count(dev); if (available == 0) { /* system has msix disabled */ bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->msix_mem); sc->msix_mem = NULL; goto fail; } /* Figure out a reasonable auto config value */ queues = (mp_ncpus > (available - 1)) ? (available - 1) : mp_ncpus; /* Override with hardcoded value if sane */ if ((ixlv_max_queues != 0) && (ixlv_max_queues <= queues)) queues = ixlv_max_queues; #ifdef RSS /* If we're doing RSS, clamp at the number of RSS buckets */ if (queues > rss_getnumbuckets()) queues = rss_getnumbuckets(); #endif /* Enforce the VF max value */ if (queues > IXLV_MAX_QUEUES) queues = IXLV_MAX_QUEUES; /* ** Want one vector (RX/TX pair) per queue ** plus an additional for the admin queue. */ want = queues + 1; if (want <= available) /* Have enough */ vectors = want; else { device_printf(sc->dev, "MSIX Configuration Problem, " "%d vectors available but %d wanted!\n", available, want); goto fail; } #ifdef RSS /* * If we're doing RSS, the number of queues needs to * match the number of RSS buckets that are configured. * * + If there's more queues than RSS buckets, we'll end * up with queues that get no traffic. * * + If there's more RSS buckets than queues, we'll end * up having multiple RSS buckets map to the same queue, * so there'll be some contention. */ if (queues != rss_getnumbuckets()) { device_printf(dev, "%s: queues (%d) != RSS buckets (%d)" "; performance will be impacted.\n", __func__, queues, rss_getnumbuckets()); } #endif if (pci_alloc_msix(dev, &vectors) == 0) { device_printf(sc->dev, "Using MSIX interrupts with %d vectors\n", vectors); sc->msix = vectors; sc->vsi.num_queues = queues; } /* ** Explicitly set the guest PCI BUSMASTER capability ** and we must rewrite the ENABLE in the MSIX control ** register again at this point to cause the host to ** successfully initialize us. */ { u16 pci_cmd_word; int msix_ctrl; pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); pci_cmd_word |= PCIM_CMD_BUSMASTEREN; pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2); pci_find_cap(dev, PCIY_MSIX, &rid); rid += PCIR_MSIX_CTRL; msix_ctrl = pci_read_config(dev, rid, 2); msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; pci_write_config(dev, rid, msix_ctrl, 2); } /* Next we need to setup the vector for the Admin Queue */ rid = 1; // zero vector + 1 sc->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (sc->res == NULL) { device_printf(dev,"Unable to allocate" " bus resource: AQ interrupt \n"); goto fail; } if (bus_setup_intr(dev, sc->res, INTR_TYPE_NET | INTR_MPSAFE, NULL, ixlv_msix_adminq, sc, &sc->tag)) { sc->res = NULL; device_printf(dev, "Failed to register AQ handler"); goto fail; } bus_describe_intr(dev, sc->res, sc->tag, "adminq"); return (vectors); fail: /* The VF driver MUST use MSIX */ return (0); } static int ixlv_allocate_pci_resources(struct ixlv_sc *sc) { int rid; device_t dev = sc->dev; rid = PCIR_BAR(0); sc->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!(sc->pci_mem)) { device_printf(dev,"Unable to allocate bus resource: memory\n"); return (ENXIO); } sc->osdep.mem_bus_space_tag = rman_get_bustag(sc->pci_mem); sc->osdep.mem_bus_space_handle = rman_get_bushandle(sc->pci_mem); sc->osdep.mem_bus_space_size = rman_get_size(sc->pci_mem); sc->osdep.flush_reg = I40E_VFGEN_RSTAT; sc->hw.hw_addr = (u8 *) &sc->osdep.mem_bus_space_handle; sc->hw.back = &sc->osdep; /* Disable adminq interrupts */ ixlv_disable_adminq_irq(&sc->hw); /* ** Now setup MSI/X, it will return ** us the number of supported vectors */ sc->msix = ixlv_init_msix(sc); /* We fail without MSIX support */ if (sc->msix == 0) return (ENXIO); return (0); } static void ixlv_free_pci_resources(struct ixlv_sc *sc) { struct ixl_vsi *vsi = &sc->vsi; struct ixl_queue *que = vsi->queues; device_t dev = sc->dev; /* We may get here before stations are setup */ if (que == NULL) goto early; /* ** Release all msix queue resources: */ for (int i = 0; i < vsi->num_queues; i++, que++) { int rid = que->msix + 1; if (que->tag != NULL) { bus_teardown_intr(dev, que->res, que->tag); que->tag = NULL; } if (que->res != NULL) bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); } early: /* Clean the AdminQ interrupt */ if (sc->tag != NULL) { bus_teardown_intr(dev, sc->res, sc->tag); sc->tag = NULL; } if (sc->res != NULL) bus_release_resource(dev, SYS_RES_IRQ, 1, sc->res); pci_release_msi(dev); if (sc->msix_mem != NULL) bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(IXL_BAR), sc->msix_mem); if (sc->pci_mem != NULL) bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), sc->pci_mem); return; } /* * Create taskqueue and tasklet for Admin Queue interrupts. */ static int ixlv_init_taskqueue(struct ixlv_sc *sc) { int error = 0; TASK_INIT(&sc->aq_irq, 0, ixlv_do_adminq, sc); sc->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, taskqueue_thread_enqueue, &sc->tq); taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s sc->tq", device_get_nameunit(sc->dev)); return (error); } /********************************************************************* * * Setup MSIX Interrupt resources and handlers for the VSI queues * **********************************************************************/ static int ixlv_assign_msix(struct ixlv_sc *sc) { device_t dev = sc->dev; struct ixl_vsi *vsi = &sc->vsi; struct ixl_queue *que = vsi->queues; struct tx_ring *txr; int error, rid, vector = 1; #ifdef RSS cpuset_t cpu_mask; #endif for (int i = 0; i < vsi->num_queues; i++, vector++, que++) { int cpu_id = i; rid = vector + 1; txr = &que->txr; que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (que->res == NULL) { device_printf(dev,"Unable to allocate" " bus resource: que interrupt [%d]\n", vector); return (ENXIO); } /* Set the handler function */ error = bus_setup_intr(dev, que->res, INTR_TYPE_NET | INTR_MPSAFE, NULL, ixlv_msix_que, que, &que->tag); if (error) { que->res = NULL; device_printf(dev, "Failed to register que handler"); return (error); } bus_describe_intr(dev, que->res, que->tag, "que %d", i); /* Bind the vector to a CPU */ #ifdef RSS cpu_id = rss_getcpu(i % rss_getnumbuckets()); #endif bus_bind_intr(dev, que->res, cpu_id); que->msix = vector; vsi->que_mask |= (u64)(1 << que->msix); TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); TASK_INIT(&que->task, 0, ixlv_handle_que, que); que->tq = taskqueue_create_fast("ixlv_que", M_NOWAIT, taskqueue_thread_enqueue, &que->tq); #ifdef RSS CPU_SETOF(cpu_id, &cpu_mask); taskqueue_start_threads_cpuset(&que->tq, 1, PI_NET, &cpu_mask, "%s (bucket %d)", device_get_nameunit(dev), cpu_id); #else taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", device_get_nameunit(dev)); #endif } return (0); } /* ** Requests a VF reset from the PF. ** ** Requires the VF's Admin Queue to be initialized. */ static int ixlv_reset(struct ixlv_sc *sc) { struct i40e_hw *hw = &sc->hw; device_t dev = sc->dev; int error = 0; /* Ask the PF to reset us if we are initiating */ if (sc->init_state != IXLV_RESET_PENDING) ixlv_request_reset(sc); i40e_msec_delay(100); error = ixlv_reset_complete(hw); if (error) { device_printf(dev, "%s: VF reset failed\n", __func__); return (error); } error = i40e_shutdown_adminq(hw); if (error) { device_printf(dev, "%s: shutdown_adminq failed: %d\n", __func__, error); return (error); } error = i40e_init_adminq(hw); if (error) { device_printf(dev, "%s: init_adminq failed: %d\n", __func__, error); return(error); } return (0); } static int ixlv_reset_complete(struct i40e_hw *hw) { u32 reg; for (int i = 0; i < 100; i++) { reg = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; if ((reg == I40E_VFR_VFACTIVE) || (reg == I40E_VFR_COMPLETED)) return (0); i40e_msec_delay(100); } return (EBUSY); } /********************************************************************* * * Setup networking device structure and register an interface. * **********************************************************************/ static int ixlv_setup_interface(device_t dev, struct ixlv_sc *sc) { struct ifnet *ifp; struct ixl_vsi *vsi = &sc->vsi; struct ixl_queue *que = vsi->queues; INIT_DBG_DEV(dev, "begin"); ifp = vsi->ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { device_printf(dev, "%s: could not allocate ifnet" " structure!\n", __func__); return (-1); } if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_mtu = ETHERMTU; ifp->if_baudrate = 4000000000; // ?? ifp->if_init = ixlv_init; ifp->if_softc = vsi; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = ixlv_ioctl; #if __FreeBSD_version >= 1100000 if_setgetcounterfn(ifp, ixl_get_counter); #endif ifp->if_transmit = ixl_mq_start; ifp->if_qflush = ixl_qflush; ifp->if_snd.ifq_maxlen = que->num_desc - 2; ether_ifattach(ifp, sc->hw.mac.addr); vsi->max_frame_size = ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_VLAN_ENCAP_LEN; /* * Tell the upper layer(s) we support long frames. */ ifp->if_hdrlen = sizeof(struct ether_vlan_header); ifp->if_capabilities |= IFCAP_HWCSUM; ifp->if_capabilities |= IFCAP_HWCSUM_IPV6; ifp->if_capabilities |= IFCAP_TSO; ifp->if_capabilities |= IFCAP_JUMBO_MTU; ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWTSO | IFCAP_VLAN_MTU | IFCAP_VLAN_HWCSUM | IFCAP_LRO; ifp->if_capenable = ifp->if_capabilities; /* ** Don't turn this on by default, if vlans are ** created on another pseudo device (eg. lagg) ** then vlan events are not passed thru, breaking ** operation, but with HW FILTER off it works. If ** using vlans directly on the ixl driver you can ** enable this and get full hardware tag filtering. */ ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; /* * Specify the media types supported by this adapter and register * callbacks to update media and link information */ ifmedia_init(&sc->media, IFM_IMASK, ixlv_media_change, ixlv_media_status); // JFV Add media types later? ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); INIT_DBG_DEV(dev, "end"); return (0); } /* ** Allocate and setup the interface queues */ static int ixlv_setup_queues(struct ixlv_sc *sc) { device_t dev = sc->dev; struct ixl_vsi *vsi; struct ixl_queue *que; struct tx_ring *txr; struct rx_ring *rxr; int rsize, tsize; int error = I40E_SUCCESS; vsi = &sc->vsi; vsi->back = (void *)sc; vsi->hw = &sc->hw; vsi->num_vlans = 0; /* Get memory for the station queues */ if (!(vsi->queues = (struct ixl_queue *) malloc(sizeof(struct ixl_queue) * vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate queue memory\n"); error = ENOMEM; goto early; } for (int i = 0; i < vsi->num_queues; i++) { que = &vsi->queues[i]; que->num_desc = ixlv_ringsz; que->me = i; que->vsi = vsi; /* mark the queue as active */ vsi->active_queues |= (u64)1 << que->me; txr = &que->txr; txr->que = que; txr->tail = I40E_QTX_TAIL1(que->me); /* Initialize the TX lock */ snprintf(txr->mtx_name, sizeof(txr->mtx_name), "%s:tx(%d)", device_get_nameunit(dev), que->me); mtx_init(&txr->mtx, txr->mtx_name, NULL, MTX_DEF); /* ** Create the TX descriptor ring, the extra int is ** added as the location for HEAD WB. */ tsize = roundup2((que->num_desc * sizeof(struct i40e_tx_desc)) + sizeof(u32), DBA_ALIGN); if (i40e_allocate_dma_mem(&sc->hw, &txr->dma, i40e_mem_reserved, tsize, DBA_ALIGN)) { device_printf(dev, "Unable to allocate TX Descriptor memory\n"); error = ENOMEM; goto fail; } txr->base = (struct i40e_tx_desc *)txr->dma.va; bzero((void *)txr->base, tsize); /* Now allocate transmit soft structs for the ring */ if (ixl_allocate_tx_data(que)) { device_printf(dev, "Critical Failure setting up TX structures\n"); error = ENOMEM; goto fail; } /* Allocate a buf ring */ txr->br = buf_ring_alloc(ixlv_txbrsz, M_DEVBUF, M_WAITOK, &txr->mtx); if (txr->br == NULL) { device_printf(dev, "Critical Failure setting up TX buf ring\n"); error = ENOMEM; goto fail; } /* * Next the RX queues... */ rsize = roundup2(que->num_desc * sizeof(union i40e_rx_desc), DBA_ALIGN); rxr = &que->rxr; rxr->que = que; rxr->tail = I40E_QRX_TAIL1(que->me); /* Initialize the RX side lock */ snprintf(rxr->mtx_name, sizeof(rxr->mtx_name), "%s:rx(%d)", device_get_nameunit(dev), que->me); mtx_init(&rxr->mtx, rxr->mtx_name, NULL, MTX_DEF); if (i40e_allocate_dma_mem(&sc->hw, &rxr->dma, i40e_mem_reserved, rsize, 4096)) { //JFV - should this be DBA? device_printf(dev, "Unable to allocate RX Descriptor memory\n"); error = ENOMEM; goto fail; } rxr->base = (union i40e_rx_desc *)rxr->dma.va; bzero((void *)rxr->base, rsize); /* Allocate receive soft structs for the ring*/ if (ixl_allocate_rx_data(que)) { device_printf(dev, "Critical Failure setting up receive structs\n"); error = ENOMEM; goto fail; } } return (0); fail: - free(vsi->queues, M_DEVBUF); for (int i = 0; i < vsi->num_queues; i++) { que = &vsi->queues[i]; rxr = &que->rxr; txr = &que->txr; if (rxr->base) i40e_free_dma_mem(&sc->hw, &rxr->dma); if (txr->base) i40e_free_dma_mem(&sc->hw, &txr->dma); } + free(vsi->queues, M_DEVBUF); early: return (error); } /* ** This routine is run via an vlan config EVENT, ** it enables us to use the HW Filter table since ** we can get the vlan id. This just creates the ** entry in the soft version of the VFTA, init will ** repopulate the real table. */ static void ixlv_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) { struct ixl_vsi *vsi = arg; struct ixlv_sc *sc = vsi->back; struct ixlv_vlan_filter *v; if (ifp->if_softc != arg) /* Not our event */ return; if ((vtag == 0) || (vtag > 4095)) /* Invalid */ return; /* Sanity check - make sure it doesn't already exist */ SLIST_FOREACH(v, sc->vlan_filters, next) { if (v->vlan == vtag) return; } mtx_lock(&sc->mtx); ++vsi->num_vlans; v = malloc(sizeof(struct ixlv_vlan_filter), M_DEVBUF, M_NOWAIT | M_ZERO); SLIST_INSERT_HEAD(sc->vlan_filters, v, next); v->vlan = vtag; v->flags = IXL_FILTER_ADD; ixl_vc_enqueue(&sc->vc_mgr, &sc->add_vlan_cmd, IXLV_FLAG_AQ_ADD_VLAN_FILTER, ixl_init_cmd_complete, sc); mtx_unlock(&sc->mtx); return; } /* ** This routine is run via an vlan ** unconfig EVENT, remove our entry ** in the soft vfta. */ static void ixlv_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) { struct ixl_vsi *vsi = arg; struct ixlv_sc *sc = vsi->back; struct ixlv_vlan_filter *v; int i = 0; if (ifp->if_softc != arg) return; if ((vtag == 0) || (vtag > 4095)) /* Invalid */ return; mtx_lock(&sc->mtx); SLIST_FOREACH(v, sc->vlan_filters, next) { if (v->vlan == vtag) { v->flags = IXL_FILTER_DEL; ++i; --vsi->num_vlans; } } if (i) ixl_vc_enqueue(&sc->vc_mgr, &sc->del_vlan_cmd, IXLV_FLAG_AQ_DEL_VLAN_FILTER, ixl_init_cmd_complete, sc); mtx_unlock(&sc->mtx); return; } /* ** Get a new filter and add it to the mac filter list. */ static struct ixlv_mac_filter * ixlv_get_mac_filter(struct ixlv_sc *sc) { struct ixlv_mac_filter *f; f = malloc(sizeof(struct ixlv_mac_filter), M_DEVBUF, M_NOWAIT | M_ZERO); if (f) SLIST_INSERT_HEAD(sc->mac_filters, f, next); return (f); } /* ** Find the filter with matching MAC address */ static struct ixlv_mac_filter * ixlv_find_mac_filter(struct ixlv_sc *sc, u8 *macaddr) { struct ixlv_mac_filter *f; bool match = FALSE; SLIST_FOREACH(f, sc->mac_filters, next) { if (cmp_etheraddr(f->macaddr, macaddr)) { match = TRUE; break; } } if (!match) f = NULL; return (f); } /* ** Admin Queue interrupt handler */ static void ixlv_msix_adminq(void *arg) { struct ixlv_sc *sc = arg; struct i40e_hw *hw = &sc->hw; u32 reg, mask; reg = rd32(hw, I40E_VFINT_ICR01); mask = rd32(hw, I40E_VFINT_ICR0_ENA1); reg = rd32(hw, I40E_VFINT_DYN_CTL01); reg |= I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; wr32(hw, I40E_VFINT_DYN_CTL01, reg); /* schedule task */ taskqueue_enqueue(sc->tq, &sc->aq_irq); return; } void ixlv_enable_intr(struct ixl_vsi *vsi) { struct i40e_hw *hw = vsi->hw; struct ixl_queue *que = vsi->queues; ixlv_enable_adminq_irq(hw); for (int i = 0; i < vsi->num_queues; i++, que++) ixlv_enable_queue_irq(hw, que->me); } void ixlv_disable_intr(struct ixl_vsi *vsi) { struct i40e_hw *hw = vsi->hw; struct ixl_queue *que = vsi->queues; ixlv_disable_adminq_irq(hw); for (int i = 0; i < vsi->num_queues; i++, que++) ixlv_disable_queue_irq(hw, que->me); } static void ixlv_disable_adminq_irq(struct i40e_hw *hw) { wr32(hw, I40E_VFINT_DYN_CTL01, 0); wr32(hw, I40E_VFINT_ICR0_ENA1, 0); /* flush */ rd32(hw, I40E_VFGEN_RSTAT); return; } static void ixlv_enable_adminq_irq(struct i40e_hw *hw) { wr32(hw, I40E_VFINT_DYN_CTL01, I40E_VFINT_DYN_CTL01_INTENA_MASK | I40E_VFINT_DYN_CTL01_ITR_INDX_MASK); wr32(hw, I40E_VFINT_ICR0_ENA1, I40E_VFINT_ICR0_ENA_ADMINQ_MASK); /* flush */ rd32(hw, I40E_VFGEN_RSTAT); return; } static void ixlv_enable_queue_irq(struct i40e_hw *hw, int id) { u32 reg; reg = I40E_VFINT_DYN_CTLN1_INTENA_MASK | I40E_VFINT_DYN_CTLN_CLEARPBA_MASK; wr32(hw, I40E_VFINT_DYN_CTLN1(id), reg); } static void ixlv_disable_queue_irq(struct i40e_hw *hw, int id) { wr32(hw, I40E_VFINT_DYN_CTLN1(id), 0); rd32(hw, I40E_VFGEN_RSTAT); return; } /* ** Provide a update to the queue RX ** interrupt moderation value. */ static void ixlv_set_queue_rx_itr(struct ixl_queue *que) { struct ixl_vsi *vsi = que->vsi; struct i40e_hw *hw = vsi->hw; struct rx_ring *rxr = &que->rxr; u16 rx_itr; u16 rx_latency = 0; int rx_bytes; /* Idle, do nothing */ if (rxr->bytes == 0) return; if (ixlv_dynamic_rx_itr) { rx_bytes = rxr->bytes/rxr->itr; rx_itr = rxr->itr; /* Adjust latency range */ switch (rxr->latency) { case IXL_LOW_LATENCY: if (rx_bytes > 10) { rx_latency = IXL_AVE_LATENCY; rx_itr = IXL_ITR_20K; } break; case IXL_AVE_LATENCY: if (rx_bytes > 20) { rx_latency = IXL_BULK_LATENCY; rx_itr = IXL_ITR_8K; } else if (rx_bytes <= 10) { rx_latency = IXL_LOW_LATENCY; rx_itr = IXL_ITR_100K; } break; case IXL_BULK_LATENCY: if (rx_bytes <= 20) { rx_latency = IXL_AVE_LATENCY; rx_itr = IXL_ITR_20K; } break; } rxr->latency = rx_latency; if (rx_itr != rxr->itr) { /* do an exponential smoothing */ rx_itr = (10 * rx_itr * rxr->itr) / ((9 * rx_itr) + rxr->itr); rxr->itr = rx_itr & IXL_MAX_ITR; wr32(hw, I40E_VFINT_ITRN1(IXL_RX_ITR, que->me), rxr->itr); } } else { /* We may have have toggled to non-dynamic */ if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC) vsi->rx_itr_setting = ixlv_rx_itr; /* Update the hardware if needed */ if (rxr->itr != vsi->rx_itr_setting) { rxr->itr = vsi->rx_itr_setting; wr32(hw, I40E_VFINT_ITRN1(IXL_RX_ITR, que->me), rxr->itr); } } rxr->bytes = 0; rxr->packets = 0; return; } /* ** Provide a update to the queue TX ** interrupt moderation value. */ static void ixlv_set_queue_tx_itr(struct ixl_queue *que) { struct ixl_vsi *vsi = que->vsi; struct i40e_hw *hw = vsi->hw; struct tx_ring *txr = &que->txr; u16 tx_itr; u16 tx_latency = 0; int tx_bytes; /* Idle, do nothing */ if (txr->bytes == 0) return; if (ixlv_dynamic_tx_itr) { tx_bytes = txr->bytes/txr->itr; tx_itr = txr->itr; switch (txr->latency) { case IXL_LOW_LATENCY: if (tx_bytes > 10) { tx_latency = IXL_AVE_LATENCY; tx_itr = IXL_ITR_20K; } break; case IXL_AVE_LATENCY: if (tx_bytes > 20) { tx_latency = IXL_BULK_LATENCY; tx_itr = IXL_ITR_8K; } else if (tx_bytes <= 10) { tx_latency = IXL_LOW_LATENCY; tx_itr = IXL_ITR_100K; } break; case IXL_BULK_LATENCY: if (tx_bytes <= 20) { tx_latency = IXL_AVE_LATENCY; tx_itr = IXL_ITR_20K; } break; } txr->latency = tx_latency; if (tx_itr != txr->itr) { /* do an exponential smoothing */ tx_itr = (10 * tx_itr * txr->itr) / ((9 * tx_itr) + txr->itr); txr->itr = tx_itr & IXL_MAX_ITR; wr32(hw, I40E_VFINT_ITRN1(IXL_TX_ITR, que->me), txr->itr); } } else { /* We may have have toggled to non-dynamic */ if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC) vsi->tx_itr_setting = ixlv_tx_itr; /* Update the hardware if needed */ if (txr->itr != vsi->tx_itr_setting) { txr->itr = vsi->tx_itr_setting; wr32(hw, I40E_VFINT_ITRN1(IXL_TX_ITR, que->me), txr->itr); } } txr->bytes = 0; txr->packets = 0; return; } /* ** ** MSIX Interrupt Handlers and Tasklets ** */ static void ixlv_handle_que(void *context, int pending) { struct ixl_queue *que = context; struct ixl_vsi *vsi = que->vsi; struct i40e_hw *hw = vsi->hw; struct tx_ring *txr = &que->txr; struct ifnet *ifp = vsi->ifp; bool more; if (ifp->if_drv_flags & IFF_DRV_RUNNING) { more = ixl_rxeof(que, IXL_RX_LIMIT); mtx_lock(&txr->mtx); ixl_txeof(que); if (!drbr_empty(ifp, txr->br)) ixl_mq_start_locked(ifp, txr); mtx_unlock(&txr->mtx); if (more) { taskqueue_enqueue(que->tq, &que->task); return; } } /* Reenable this interrupt - hmmm */ ixlv_enable_queue_irq(hw, que->me); return; } /********************************************************************* * * MSIX Queue Interrupt Service routine * **********************************************************************/ static void ixlv_msix_que(void *arg) { struct ixl_queue *que = arg; struct ixl_vsi *vsi = que->vsi; struct i40e_hw *hw = vsi->hw; struct tx_ring *txr = &que->txr; bool more_tx, more_rx; /* Spurious interrupts are ignored */ if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)) return; ++que->irqs; more_rx = ixl_rxeof(que, IXL_RX_LIMIT); mtx_lock(&txr->mtx); more_tx = ixl_txeof(que); /* ** Make certain that if the stack ** has anything queued the task gets ** scheduled to handle it. */ if (!drbr_empty(vsi->ifp, txr->br)) more_tx = 1; mtx_unlock(&txr->mtx); ixlv_set_queue_rx_itr(que); ixlv_set_queue_tx_itr(que); if (more_tx || more_rx) taskqueue_enqueue(que->tq, &que->task); else ixlv_enable_queue_irq(hw, que->me); return; } /********************************************************************* * * Media Ioctl callback * * This routine is called whenever the user queries the status of * the interface using ifconfig. * **********************************************************************/ static void ixlv_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) { struct ixl_vsi *vsi = ifp->if_softc; struct ixlv_sc *sc = vsi->back; INIT_DBG_IF(ifp, "begin"); mtx_lock(&sc->mtx); ixlv_update_link_status(sc); ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; if (!sc->link_up) { mtx_unlock(&sc->mtx); INIT_DBG_IF(ifp, "end: link not up"); return; } ifmr->ifm_status |= IFM_ACTIVE; /* Hardware is always full-duplex */ ifmr->ifm_active |= IFM_FDX; mtx_unlock(&sc->mtx); INIT_DBG_IF(ifp, "end"); return; } /********************************************************************* * * Media Ioctl callback * * This routine is called when the user changes speed/duplex using * media/mediopt option with ifconfig. * **********************************************************************/ static int ixlv_media_change(struct ifnet * ifp) { struct ixl_vsi *vsi = ifp->if_softc; struct ifmedia *ifm = &vsi->media; INIT_DBG_IF(ifp, "begin"); if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) return (EINVAL); INIT_DBG_IF(ifp, "end"); return (0); } /********************************************************************* * Multicast Initialization * * This routine is called by init to reset a fresh state. * **********************************************************************/ static void ixlv_init_multi(struct ixl_vsi *vsi) { struct ixlv_mac_filter *f; struct ixlv_sc *sc = vsi->back; int mcnt = 0; IOCTL_DBG_IF(vsi->ifp, "begin"); /* First clear any multicast filters */ SLIST_FOREACH(f, sc->mac_filters, next) { if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) { f->flags |= IXL_FILTER_DEL; mcnt++; } } if (mcnt > 0) ixl_vc_enqueue(&sc->vc_mgr, &sc->del_multi_cmd, IXLV_FLAG_AQ_DEL_MAC_FILTER, ixl_init_cmd_complete, sc); IOCTL_DBG_IF(vsi->ifp, "end"); } static void ixlv_add_multi(struct ixl_vsi *vsi) { struct ifmultiaddr *ifma; struct ifnet *ifp = vsi->ifp; struct ixlv_sc *sc = vsi->back; int mcnt = 0; IOCTL_DBG_IF(ifp, "begin"); if_maddr_rlock(ifp); /* ** Get a count, to decide if we ** simply use multicast promiscuous. */ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; mcnt++; } if_maddr_runlock(ifp); // TODO: Remove -- cannot set promiscuous mode in a VF if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) { /* delete all multicast filters */ ixlv_init_multi(vsi); sc->promiscuous_flags |= I40E_FLAG_VF_MULTICAST_PROMISC; ixl_vc_enqueue(&sc->vc_mgr, &sc->add_multi_cmd, IXLV_FLAG_AQ_CONFIGURE_PROMISC, ixl_init_cmd_complete, sc); IOCTL_DEBUGOUT("%s: end: too many filters", __func__); return; } mcnt = 0; if_maddr_rlock(ifp); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; if (!ixlv_add_mac_filter(sc, (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr), IXL_FILTER_MC)) mcnt++; } if_maddr_runlock(ifp); /* ** Notify AQ task that sw filters need to be ** added to hw list */ if (mcnt > 0) ixl_vc_enqueue(&sc->vc_mgr, &sc->add_multi_cmd, IXLV_FLAG_AQ_ADD_MAC_FILTER, ixl_init_cmd_complete, sc); IOCTL_DBG_IF(ifp, "end"); } static void ixlv_del_multi(struct ixl_vsi *vsi) { struct ixlv_mac_filter *f; struct ifmultiaddr *ifma; struct ifnet *ifp = vsi->ifp; struct ixlv_sc *sc = vsi->back; int mcnt = 0; bool match = FALSE; IOCTL_DBG_IF(ifp, "begin"); /* Search for removed multicast addresses */ if_maddr_rlock(ifp); SLIST_FOREACH(f, sc->mac_filters, next) { if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) { /* check if mac address in filter is in sc's list */ match = FALSE; TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr); if (cmp_etheraddr(f->macaddr, mc_addr)) { match = TRUE; break; } } /* if this filter is not in the sc's list, remove it */ if (match == FALSE && !(f->flags & IXL_FILTER_DEL)) { f->flags |= IXL_FILTER_DEL; mcnt++; IOCTL_DBG_IF(ifp, "marked: " MAC_FORMAT, MAC_FORMAT_ARGS(f->macaddr)); } else if (match == FALSE) IOCTL_DBG_IF(ifp, "exists: " MAC_FORMAT, MAC_FORMAT_ARGS(f->macaddr)); } } if_maddr_runlock(ifp); if (mcnt > 0) ixl_vc_enqueue(&sc->vc_mgr, &sc->del_multi_cmd, IXLV_FLAG_AQ_DEL_MAC_FILTER, ixl_init_cmd_complete, sc); IOCTL_DBG_IF(ifp, "end"); } /********************************************************************* * Timer routine * * This routine checks for link status,updates statistics, * and runs the watchdog check. * **********************************************************************/ static void ixlv_local_timer(void *arg) { struct ixlv_sc *sc = arg; struct i40e_hw *hw = &sc->hw; struct ixl_vsi *vsi = &sc->vsi; struct ixl_queue *que = vsi->queues; device_t dev = sc->dev; int hung = 0; u32 mask, val; IXLV_CORE_LOCK_ASSERT(sc); /* If Reset is in progress just bail */ if (sc->init_state == IXLV_RESET_PENDING) return; /* Check for when PF triggers a VF reset */ val = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; if (val != I40E_VFR_VFACTIVE && val != I40E_VFR_COMPLETED) { DDPRINTF(dev, "reset in progress! (%d)", val); return; } ixlv_request_stats(sc); /* clean and process any events */ taskqueue_enqueue(sc->tq, &sc->aq_irq); /* ** Check status on the queues for a hang */ mask = (I40E_VFINT_DYN_CTLN_INTENA_MASK | I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK); for (int i = 0; i < vsi->num_queues; i++,que++) { /* Any queues with outstanding work get a sw irq */ if (que->busy) wr32(hw, I40E_VFINT_DYN_CTLN1(que->me), mask); /* ** Each time txeof runs without cleaning, but there ** are uncleaned descriptors it increments busy. If ** we get to 5 we declare it hung. */ if (que->busy == IXL_QUEUE_HUNG) { ++hung; /* Mark the queue as inactive */ vsi->active_queues &= ~((u64)1 << que->me); continue; } else { /* Check if we've come back from hung */ if ((vsi->active_queues & ((u64)1 << que->me)) == 0) vsi->active_queues |= ((u64)1 << que->me); } if (que->busy >= IXL_MAX_TX_BUSY) { device_printf(dev,"Warning queue %d " "appears to be hung!\n", i); que->busy = IXL_QUEUE_HUNG; ++hung; } } /* Only reset when all queues show hung */ if (hung == vsi->num_queues) goto hung; callout_reset(&sc->timer, hz, ixlv_local_timer, sc); return; hung: device_printf(dev, "Local Timer: TX HANG DETECTED - Resetting!!\n"); sc->init_state = IXLV_RESET_REQUIRED; ixlv_init_locked(sc); } /* ** Note: this routine updates the OS on the link state ** the real check of the hardware only happens with ** a link interrupt. */ void ixlv_update_link_status(struct ixlv_sc *sc) { struct ixl_vsi *vsi = &sc->vsi; struct ifnet *ifp = vsi->ifp; if (sc->link_up){ if (vsi->link_active == FALSE) { if (bootverbose) if_printf(ifp,"Link is Up, %d Gbps\n", (sc->link_speed == I40E_LINK_SPEED_40GB) ? 40:10); vsi->link_active = TRUE; if_link_state_change(ifp, LINK_STATE_UP); } } else { /* Link down */ if (vsi->link_active == TRUE) { if (bootverbose) if_printf(ifp,"Link is Down\n"); if_link_state_change(ifp, LINK_STATE_DOWN); vsi->link_active = FALSE; } } return; } /********************************************************************* * * This routine disables all traffic on the adapter by issuing a * global reset on the MAC and deallocates TX/RX buffers. * **********************************************************************/ static void ixlv_stop(struct ixlv_sc *sc) { struct ifnet *ifp; int start; ifp = sc->vsi.ifp; INIT_DBG_IF(ifp, "begin"); IXLV_CORE_LOCK_ASSERT(sc); ixl_vc_flush(&sc->vc_mgr); ixlv_disable_queues(sc); start = ticks; while ((ifp->if_drv_flags & IFF_DRV_RUNNING) && ((ticks - start) < hz/10)) ixlv_do_adminq_locked(sc); /* Stop the local timer */ callout_stop(&sc->timer); INIT_DBG_IF(ifp, "end"); } /********************************************************************* * * Free all station queue structs. * **********************************************************************/ static void ixlv_free_queues(struct ixl_vsi *vsi) { struct ixlv_sc *sc = (struct ixlv_sc *)vsi->back; struct ixl_queue *que = vsi->queues; for (int i = 0; i < vsi->num_queues; i++, que++) { struct tx_ring *txr = &que->txr; struct rx_ring *rxr = &que->rxr; if (!mtx_initialized(&txr->mtx)) /* uninitialized */ continue; IXL_TX_LOCK(txr); ixl_free_que_tx(que); if (txr->base) i40e_free_dma_mem(&sc->hw, &txr->dma); IXL_TX_UNLOCK(txr); IXL_TX_LOCK_DESTROY(txr); if (!mtx_initialized(&rxr->mtx)) /* uninitialized */ continue; IXL_RX_LOCK(rxr); ixl_free_que_rx(que); if (rxr->base) i40e_free_dma_mem(&sc->hw, &rxr->dma); IXL_RX_UNLOCK(rxr); IXL_RX_LOCK_DESTROY(rxr); } free(vsi->queues, M_DEVBUF); } /* ** ixlv_config_rss - setup RSS ** ** RSS keys and table are cleared on VF reset. */ static void ixlv_config_rss(struct ixlv_sc *sc) { struct i40e_hw *hw = &sc->hw; struct ixl_vsi *vsi = &sc->vsi; u32 lut = 0; u64 set_hena = 0, hena; int i, j, que_id; #ifdef RSS u32 rss_hash_config; u32 rss_seed[IXL_KEYSZ]; #else u32 rss_seed[IXL_KEYSZ] = {0x41b01687, 0x183cfd8c, 0xce880440, 0x580cbc3c, 0x35897377, 0x328b25e1, 0x4fa98922, 0xb7d90c14, 0xd5bad70d, 0xcd15a2c1}; #endif /* Don't set up RSS if using a single queue */ if (vsi->num_queues == 1) { wr32(hw, I40E_VFQF_HENA(0), 0); wr32(hw, I40E_VFQF_HENA(1), 0); ixl_flush(hw); return; } #ifdef RSS /* Fetch the configured RSS key */ rss_getkey((uint8_t *) &rss_seed); #endif /* Fill out hash function seed */ for (i = 0; i <= IXL_KEYSZ; i++) wr32(hw, I40E_VFQF_HKEY(i), rss_seed[i]); /* Enable PCTYPES for RSS: */ #ifdef RSS rss_hash_config = rss_gethashconfig(); if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP); if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP); #else set_hena = ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | ((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD); #endif hena = (u64)rd32(hw, I40E_VFQF_HENA(0)) | ((u64)rd32(hw, I40E_VFQF_HENA(1)) << 32); hena |= set_hena; wr32(hw, I40E_VFQF_HENA(0), (u32)hena); wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32)); /* Populate the LUT with max no. of queues in round robin fashion */ for (i = 0, j = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++, j++) { if (j == vsi->num_queues) j = 0; #ifdef RSS /* * Fetch the RSS bucket id for the given indirection entry. * Cap it at the number of configured buckets (which is * num_queues.) */ que_id = rss_get_indirection_to_bucket(i); que_id = que_id % vsi->num_queues; #else que_id = j; #endif /* lut = 4-byte sliding window of 4 lut entries */ lut = (lut << 8) | (que_id & 0xF); /* On i = 3, we have 4 entries in lut; write to the register */ if ((i & 3) == 3) { wr32(hw, I40E_VFQF_HLUT(i), lut); DDPRINTF(sc->dev, "HLUT(%2d): %#010x", i, lut); } } ixl_flush(hw); } /* ** This routine refreshes vlan filters, called by init ** it scans the filter table and then updates the AQ */ static void ixlv_setup_vlan_filters(struct ixlv_sc *sc) { struct ixl_vsi *vsi = &sc->vsi; struct ixlv_vlan_filter *f; int cnt = 0; if (vsi->num_vlans == 0) return; /* ** Scan the filter table for vlan entries, ** and if found call for the AQ update. */ SLIST_FOREACH(f, sc->vlan_filters, next) if (f->flags & IXL_FILTER_ADD) cnt++; if (cnt > 0) ixl_vc_enqueue(&sc->vc_mgr, &sc->add_vlan_cmd, IXLV_FLAG_AQ_ADD_VLAN_FILTER, ixl_init_cmd_complete, sc); } /* ** This routine adds new MAC filters to the sc's list; ** these are later added in hardware by sending a virtual ** channel message. */ static int ixlv_add_mac_filter(struct ixlv_sc *sc, u8 *macaddr, u16 flags) { struct ixlv_mac_filter *f; /* Does one already exist? */ f = ixlv_find_mac_filter(sc, macaddr); if (f != NULL) { IDPRINTF(sc->vsi.ifp, "exists: " MAC_FORMAT, MAC_FORMAT_ARGS(macaddr)); return (EEXIST); } /* If not, get a new empty filter */ f = ixlv_get_mac_filter(sc); if (f == NULL) { if_printf(sc->vsi.ifp, "%s: no filters available!!\n", __func__); return (ENOMEM); } IDPRINTF(sc->vsi.ifp, "marked: " MAC_FORMAT, MAC_FORMAT_ARGS(macaddr)); bcopy(macaddr, f->macaddr, ETHER_ADDR_LEN); f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); f->flags |= flags; return (0); } /* ** Marks a MAC filter for deletion. */ static int ixlv_del_mac_filter(struct ixlv_sc *sc, u8 *macaddr) { struct ixlv_mac_filter *f; f = ixlv_find_mac_filter(sc, macaddr); if (f == NULL) return (ENOENT); f->flags |= IXL_FILTER_DEL; return (0); } /* ** Tasklet handler for MSIX Adminq interrupts ** - done outside interrupt context since it might sleep */ static void ixlv_do_adminq(void *context, int pending) { struct ixlv_sc *sc = context; mtx_lock(&sc->mtx); ixlv_do_adminq_locked(sc); mtx_unlock(&sc->mtx); return; } static void ixlv_do_adminq_locked(struct ixlv_sc *sc) { struct i40e_hw *hw = &sc->hw; struct i40e_arq_event_info event; struct i40e_virtchnl_msg *v_msg; device_t dev = sc->dev; u16 result = 0; u32 reg, oldreg; i40e_status ret; IXLV_CORE_LOCK_ASSERT(sc); event.buf_len = IXL_AQ_BUF_SZ; event.msg_buf = sc->aq_buffer; v_msg = (struct i40e_virtchnl_msg *)&event.desc; do { ret = i40e_clean_arq_element(hw, &event, &result); if (ret) break; ixlv_vc_completion(sc, v_msg->v_opcode, v_msg->v_retval, event.msg_buf, event.msg_len); if (result != 0) bzero(event.msg_buf, IXL_AQ_BUF_SZ); } while (result); /* check for Admin queue errors */ oldreg = reg = rd32(hw, hw->aq.arq.len); if (reg & I40E_VF_ARQLEN_ARQVFE_MASK) { device_printf(dev, "ARQ VF Error detected\n"); reg &= ~I40E_VF_ARQLEN_ARQVFE_MASK; } if (reg & I40E_VF_ARQLEN_ARQOVFL_MASK) { device_printf(dev, "ARQ Overflow Error detected\n"); reg &= ~I40E_VF_ARQLEN_ARQOVFL_MASK; } if (reg & I40E_VF_ARQLEN_ARQCRIT_MASK) { device_printf(dev, "ARQ Critical Error detected\n"); reg &= ~I40E_VF_ARQLEN_ARQCRIT_MASK; } if (oldreg != reg) wr32(hw, hw->aq.arq.len, reg); oldreg = reg = rd32(hw, hw->aq.asq.len); if (reg & I40E_VF_ATQLEN_ATQVFE_MASK) { device_printf(dev, "ASQ VF Error detected\n"); reg &= ~I40E_VF_ATQLEN_ATQVFE_MASK; } if (reg & I40E_VF_ATQLEN_ATQOVFL_MASK) { device_printf(dev, "ASQ Overflow Error detected\n"); reg &= ~I40E_VF_ATQLEN_ATQOVFL_MASK; } if (reg & I40E_VF_ATQLEN_ATQCRIT_MASK) { device_printf(dev, "ASQ Critical Error detected\n"); reg &= ~I40E_VF_ATQLEN_ATQCRIT_MASK; } if (oldreg != reg) wr32(hw, hw->aq.asq.len, reg); ixlv_enable_adminq_irq(hw); } static void ixlv_add_sysctls(struct ixlv_sc *sc) { device_t dev = sc->dev; struct ixl_vsi *vsi = &sc->vsi; struct i40e_eth_stats *es = &vsi->eth_stats; struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); struct sysctl_oid *tree = device_get_sysctl_tree(dev); struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); struct sysctl_oid *vsi_node, *queue_node; struct sysctl_oid_list *vsi_list, *queue_list; #define QUEUE_NAME_LEN 32 char queue_namebuf[QUEUE_NAME_LEN]; struct ixl_queue *queues = vsi->queues; struct tx_ring *txr; struct rx_ring *rxr; /* Driver statistics sysctls */ SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", CTLFLAG_RD, &sc->watchdog_events, "Watchdog timeouts"); SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "admin_irq", CTLFLAG_RD, &sc->admin_irq, "Admin Queue IRQ Handled"); /* VSI statistics sysctls */ vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "vsi", CTLFLAG_RD, NULL, "VSI-specific statistics"); vsi_list = SYSCTL_CHILDREN(vsi_node); struct ixl_sysctl_info ctls[] = { {&es->rx_bytes, "good_octets_rcvd", "Good Octets Received"}, {&es->rx_unicast, "ucast_pkts_rcvd", "Unicast Packets Received"}, {&es->rx_multicast, "mcast_pkts_rcvd", "Multicast Packets Received"}, {&es->rx_broadcast, "bcast_pkts_rcvd", "Broadcast Packets Received"}, {&es->rx_discards, "rx_discards", "Discarded RX packets"}, {&es->rx_unknown_protocol, "rx_unknown_proto", "RX unknown protocol packets"}, {&es->tx_bytes, "good_octets_txd", "Good Octets Transmitted"}, {&es->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"}, {&es->tx_multicast, "mcast_pkts_txd", "Multicast Packets Transmitted"}, {&es->tx_broadcast, "bcast_pkts_txd", "Broadcast Packets Transmitted"}, {&es->tx_errors, "tx_errors", "TX packet errors"}, // end {0,0,0} }; struct ixl_sysctl_info *entry = ctls; while (entry->stat != 0) { SYSCTL_ADD_QUAD(ctx, child, OID_AUTO, entry->name, CTLFLAG_RD, entry->stat, entry->description); entry++; } /* Queue sysctls */ for (int q = 0; q < vsi->num_queues; q++) { snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q); queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "Queue Name"); queue_list = SYSCTL_CHILDREN(queue_node); txr = &(queues[q].txr); rxr = &(queues[q].rxr); SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed", CTLFLAG_RD, &(queues[q].mbuf_defrag_failed), "m_defrag() failed"); SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "dropped", CTLFLAG_RD, &(queues[q].dropped_pkts), "Driver dropped packets"); SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "irqs", CTLFLAG_RD, &(queues[q].irqs), "irqs on this queue"); SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "tso_tx", CTLFLAG_RD, &(queues[q].tso), "TSO"); SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "tx_dma_setup", CTLFLAG_RD, &(queues[q].tx_dma_setup), "Driver tx dma failure in xmit"); SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", CTLFLAG_RD, &(txr->no_desc), "Queue No Descriptor Available"); SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "tx_packets", CTLFLAG_RD, &(txr->total_packets), "Queue Packets Transmitted"); SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "tx_bytes", CTLFLAG_RD, &(txr->tx_bytes), "Queue Bytes Transmitted"); SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "rx_packets", CTLFLAG_RD, &(rxr->rx_packets), "Queue Packets Received"); SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "rx_bytes", CTLFLAG_RD, &(rxr->rx_bytes), "Queue Bytes Received"); /* Examine queue state */ SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qtx_head", CTLTYPE_UINT | CTLFLAG_RD, &queues[q], sizeof(struct ixl_queue), ixlv_sysctl_qtx_tail_handler, "IU", "Queue Transmit Descriptor Tail"); SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qrx_head", CTLTYPE_UINT | CTLFLAG_RD, &queues[q], sizeof(struct ixl_queue), ixlv_sysctl_qrx_tail_handler, "IU", "Queue Receive Descriptor Tail"); } } static void ixlv_init_filters(struct ixlv_sc *sc) { sc->mac_filters = malloc(sizeof(struct ixlv_mac_filter), M_DEVBUF, M_NOWAIT | M_ZERO); SLIST_INIT(sc->mac_filters); sc->vlan_filters = malloc(sizeof(struct ixlv_vlan_filter), M_DEVBUF, M_NOWAIT | M_ZERO); SLIST_INIT(sc->vlan_filters); return; } static void ixlv_free_filters(struct ixlv_sc *sc) { struct ixlv_mac_filter *f; struct ixlv_vlan_filter *v; while (!SLIST_EMPTY(sc->mac_filters)) { f = SLIST_FIRST(sc->mac_filters); SLIST_REMOVE_HEAD(sc->mac_filters, next); free(f, M_DEVBUF); } while (!SLIST_EMPTY(sc->vlan_filters)) { v = SLIST_FIRST(sc->vlan_filters); SLIST_REMOVE_HEAD(sc->vlan_filters, next); free(v, M_DEVBUF); } return; } /** * ixlv_sysctl_qtx_tail_handler * Retrieves I40E_QTX_TAIL1 value from hardware * for a sysctl. */ static int ixlv_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS) { struct ixl_queue *que; int error; u32 val; que = ((struct ixl_queue *)oidp->oid_arg1); if (!que) return 0; val = rd32(que->vsi->hw, que->txr.tail); error = sysctl_handle_int(oidp, &val, 0, req); if (error || !req->newptr) return error; return (0); } /** * ixlv_sysctl_qrx_tail_handler * Retrieves I40E_QRX_TAIL1 value from hardware * for a sysctl. */ static int ixlv_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS) { struct ixl_queue *que; int error; u32 val; que = ((struct ixl_queue *)oidp->oid_arg1); if (!que) return 0; val = rd32(que->vsi->hw, que->rxr.tail); error = sysctl_handle_int(oidp, &val, 0, req); if (error || !req->newptr) return error; return (0); } Index: projects/ci20_mips/sys/dev/netmap/netmap_mem2.c =================================================================== --- projects/ci20_mips/sys/dev/netmap/netmap_mem2.c (revision 283030) +++ projects/ci20_mips/sys/dev/netmap/netmap_mem2.c (revision 283031) @@ -1,1554 +1,1605 @@ /* * Copyright (C) 2012-2014 Matteo Landi, Luigi Rizzo, Giuseppe Lettieri. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifdef linux #include "bsd_glue.h" #endif /* linux */ #ifdef __APPLE__ #include "osx_glue.h" #endif /* __APPLE__ */ #ifdef __FreeBSD__ #include /* prerequisite */ __FBSDID("$FreeBSD$"); #include #include #include #include /* vtophys */ #include /* vtophys */ #include /* sockaddrs */ #include #include #include #include #include #include /* bus_dmamap_* */ #endif /* __FreeBSD__ */ #include #include #include "netmap_mem2.h" #define NETMAP_BUF_MAX_NUM 20*4096*2 /* large machine */ #define NETMAP_POOL_MAX_NAMSZ 32 enum { NETMAP_IF_POOL = 0, NETMAP_RING_POOL, NETMAP_BUF_POOL, NETMAP_POOLS_NR }; struct netmap_obj_params { u_int size; u_int num; }; struct netmap_obj_pool { char name[NETMAP_POOL_MAX_NAMSZ]; /* name of the allocator */ /* ---------------------------------------------------*/ /* these are only meaningful if the pool is finalized */ /* (see 'finalized' field in netmap_mem_d) */ u_int objtotal; /* actual total number of objects. */ u_int memtotal; /* actual total memory space */ u_int numclusters; /* actual number of clusters */ u_int objfree; /* number of free objects. */ struct lut_entry *lut; /* virt,phys addresses, objtotal entries */ uint32_t *bitmap; /* one bit per buffer, 1 means free */ uint32_t bitmap_slots; /* number of uint32 entries in bitmap */ /* ---------------------------------------------------*/ /* limits */ u_int objminsize; /* minimum object size */ u_int objmaxsize; /* maximum object size */ u_int nummin; /* minimum number of objects */ u_int nummax; /* maximum number of objects */ /* these are changed only by config */ u_int _objtotal; /* total number of objects */ u_int _objsize; /* object size */ u_int _clustsize; /* cluster size */ u_int _clustentries; /* objects per cluster */ u_int _numclusters; /* number of clusters */ /* requested values */ u_int r_objtotal; u_int r_objsize; }; #ifdef linux // XXX a mtx would suffice here 20130415 lr #define NMA_LOCK_T struct semaphore #else /* !linux */ #define NMA_LOCK_T struct mtx #endif /* linux */ typedef int (*netmap_mem_config_t)(struct netmap_mem_d*); typedef int (*netmap_mem_finalize_t)(struct netmap_mem_d*); typedef void (*netmap_mem_deref_t)(struct netmap_mem_d*); typedef uint16_t nm_memid_t; struct netmap_mem_d { NMA_LOCK_T nm_mtx; /* protect the allocator */ u_int nm_totalsize; /* shorthand */ u_int flags; #define NETMAP_MEM_FINALIZED 0x1 /* preallocation done */ int lasterr; /* last error for curr config */ int refcount; /* existing priv structures */ /* the three allocators */ struct netmap_obj_pool pools[NETMAP_POOLS_NR]; - netmap_mem_config_t config; - netmap_mem_finalize_t finalize; - netmap_mem_deref_t deref; + netmap_mem_config_t config; /* called with NMA_LOCK held */ + netmap_mem_finalize_t finalize; /* called with NMA_LOCK held */ + netmap_mem_deref_t deref; /* called with NMA_LOCK held */ nm_memid_t nm_id; /* allocator identifier */ int nm_grp; /* iommu groupd id */ /* list of all existing allocators, sorted by nm_id */ struct netmap_mem_d *prev, *next; }; /* accessor functions */ struct lut_entry* netmap_mem_get_lut(struct netmap_mem_d *nmd) { return nmd->pools[NETMAP_BUF_POOL].lut; } u_int netmap_mem_get_buftotal(struct netmap_mem_d *nmd) { return nmd->pools[NETMAP_BUF_POOL].objtotal; } size_t netmap_mem_get_bufsize(struct netmap_mem_d *nmd) { return nmd->pools[NETMAP_BUF_POOL]._objsize; } #ifdef linux #define NMA_LOCK_INIT(n) sema_init(&(n)->nm_mtx, 1) #define NMA_LOCK_DESTROY(n) #define NMA_LOCK(n) down(&(n)->nm_mtx) #define NMA_UNLOCK(n) up(&(n)->nm_mtx) #else /* !linux */ #define NMA_LOCK_INIT(n) mtx_init(&(n)->nm_mtx, "netmap memory allocator lock", NULL, MTX_DEF) #define NMA_LOCK_DESTROY(n) mtx_destroy(&(n)->nm_mtx) #define NMA_LOCK(n) mtx_lock(&(n)->nm_mtx) #define NMA_UNLOCK(n) mtx_unlock(&(n)->nm_mtx) #endif /* linux */ struct netmap_obj_params netmap_params[NETMAP_POOLS_NR] = { [NETMAP_IF_POOL] = { .size = 1024, .num = 100, }, [NETMAP_RING_POOL] = { .size = 9*PAGE_SIZE, .num = 200, }, [NETMAP_BUF_POOL] = { .size = 2048, .num = NETMAP_BUF_MAX_NUM, }, }; struct netmap_obj_params netmap_min_priv_params[NETMAP_POOLS_NR] = { [NETMAP_IF_POOL] = { .size = 1024, .num = 1, }, [NETMAP_RING_POOL] = { .size = 5*PAGE_SIZE, .num = 4, }, [NETMAP_BUF_POOL] = { .size = 2048, .num = 4098, }, }; /* * nm_mem is the memory allocator used for all physical interfaces * running in netmap mode. * Virtual (VALE) ports will have each its own allocator. */ static int netmap_mem_global_config(struct netmap_mem_d *nmd); static int netmap_mem_global_finalize(struct netmap_mem_d *nmd); static void netmap_mem_global_deref(struct netmap_mem_d *nmd); struct netmap_mem_d nm_mem = { /* Our memory allocator. */ .pools = { [NETMAP_IF_POOL] = { .name = "netmap_if", .objminsize = sizeof(struct netmap_if), .objmaxsize = 4096, .nummin = 10, /* don't be stingy */ .nummax = 10000, /* XXX very large */ }, [NETMAP_RING_POOL] = { .name = "netmap_ring", .objminsize = sizeof(struct netmap_ring), .objmaxsize = 32*PAGE_SIZE, .nummin = 2, .nummax = 1024, }, [NETMAP_BUF_POOL] = { .name = "netmap_buf", .objminsize = 64, .objmaxsize = 65536, .nummin = 4, .nummax = 1000000, /* one million! */ }, }, .config = netmap_mem_global_config, .finalize = netmap_mem_global_finalize, .deref = netmap_mem_global_deref, .nm_id = 1, .nm_grp = -1, .prev = &nm_mem, .next = &nm_mem, }; struct netmap_mem_d *netmap_last_mem_d = &nm_mem; /* blueprint for the private memory allocators */ static int netmap_mem_private_config(struct netmap_mem_d *nmd); static int netmap_mem_private_finalize(struct netmap_mem_d *nmd); static void netmap_mem_private_deref(struct netmap_mem_d *nmd); const struct netmap_mem_d nm_blueprint = { .pools = { [NETMAP_IF_POOL] = { .name = "%s_if", .objminsize = sizeof(struct netmap_if), .objmaxsize = 4096, .nummin = 1, .nummax = 100, }, [NETMAP_RING_POOL] = { .name = "%s_ring", .objminsize = sizeof(struct netmap_ring), .objmaxsize = 32*PAGE_SIZE, .nummin = 2, .nummax = 1024, }, [NETMAP_BUF_POOL] = { .name = "%s_buf", .objminsize = 64, .objmaxsize = 65536, .nummin = 4, .nummax = 1000000, /* one million! */ }, }, .config = netmap_mem_private_config, .finalize = netmap_mem_private_finalize, .deref = netmap_mem_private_deref, .flags = NETMAP_MEM_PRIVATE, }; /* memory allocator related sysctls */ #define STRINGIFY(x) #x #define DECLARE_SYSCTLS(id, name) \ SYSCTL_INT(_dev_netmap, OID_AUTO, name##_size, \ CTLFLAG_RW, &netmap_params[id].size, 0, "Requested size of netmap " STRINGIFY(name) "s"); \ SYSCTL_INT(_dev_netmap, OID_AUTO, name##_curr_size, \ CTLFLAG_RD, &nm_mem.pools[id]._objsize, 0, "Current size of netmap " STRINGIFY(name) "s"); \ SYSCTL_INT(_dev_netmap, OID_AUTO, name##_num, \ CTLFLAG_RW, &netmap_params[id].num, 0, "Requested number of netmap " STRINGIFY(name) "s"); \ SYSCTL_INT(_dev_netmap, OID_AUTO, name##_curr_num, \ CTLFLAG_RD, &nm_mem.pools[id].objtotal, 0, "Current number of netmap " STRINGIFY(name) "s"); \ SYSCTL_INT(_dev_netmap, OID_AUTO, priv_##name##_size, \ CTLFLAG_RW, &netmap_min_priv_params[id].size, 0, \ "Default size of private netmap " STRINGIFY(name) "s"); \ SYSCTL_INT(_dev_netmap, OID_AUTO, priv_##name##_num, \ CTLFLAG_RW, &netmap_min_priv_params[id].num, 0, \ "Default number of private netmap " STRINGIFY(name) "s") SYSCTL_DECL(_dev_netmap); DECLARE_SYSCTLS(NETMAP_IF_POOL, if); DECLARE_SYSCTLS(NETMAP_RING_POOL, ring); DECLARE_SYSCTLS(NETMAP_BUF_POOL, buf); static int nm_mem_assign_id(struct netmap_mem_d *nmd) { nm_memid_t id; struct netmap_mem_d *scan = netmap_last_mem_d; int error = ENOMEM; NMA_LOCK(&nm_mem); do { /* we rely on unsigned wrap around */ id = scan->nm_id + 1; if (id == 0) /* reserve 0 as error value */ id = 1; scan = scan->next; if (id != scan->nm_id) { nmd->nm_id = id; nmd->prev = scan->prev; nmd->next = scan; scan->prev->next = nmd; scan->prev = nmd; netmap_last_mem_d = nmd; error = 0; break; } } while (scan != netmap_last_mem_d); NMA_UNLOCK(&nm_mem); return error; } static void nm_mem_release_id(struct netmap_mem_d *nmd) { NMA_LOCK(&nm_mem); nmd->prev->next = nmd->next; nmd->next->prev = nmd->prev; if (netmap_last_mem_d == nmd) netmap_last_mem_d = nmd->prev; nmd->prev = nmd->next = NULL; NMA_UNLOCK(&nm_mem); } static int nm_mem_assign_group(struct netmap_mem_d *nmd, struct device *dev) { int err = 0, id; id = nm_iommu_group_id(dev); if (netmap_verbose) D("iommu_group %d", id); NMA_LOCK(nmd); if (nmd->nm_grp < 0) nmd->nm_grp = id; if (nmd->nm_grp != id) nmd->lasterr = err = ENOMEM; NMA_UNLOCK(nmd); return err; } /* * First, find the allocator that contains the requested offset, * then locate the cluster through a lookup table. */ vm_paddr_t netmap_mem_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset) { int i; vm_ooffset_t o = offset; vm_paddr_t pa; struct netmap_obj_pool *p; NMA_LOCK(nmd); p = nmd->pools; for (i = 0; i < NETMAP_POOLS_NR; offset -= p[i].memtotal, i++) { if (offset >= p[i].memtotal) continue; // now lookup the cluster's address pa = vtophys(p[i].lut[offset / p[i]._objsize].vaddr) + offset % p[i]._objsize; NMA_UNLOCK(nmd); return pa; } /* this is only in case of errors */ D("invalid ofs 0x%x out of 0x%x 0x%x 0x%x", (u_int)o, p[NETMAP_IF_POOL].memtotal, p[NETMAP_IF_POOL].memtotal + p[NETMAP_RING_POOL].memtotal, p[NETMAP_IF_POOL].memtotal + p[NETMAP_RING_POOL].memtotal + p[NETMAP_BUF_POOL].memtotal); NMA_UNLOCK(nmd); return 0; // XXX bad address } int netmap_mem_get_info(struct netmap_mem_d* nmd, u_int* size, u_int *memflags, nm_memid_t *id) { int error = 0; NMA_LOCK(nmd); error = nmd->config(nmd); if (error) goto out; if (size) { if (nmd->flags & NETMAP_MEM_FINALIZED) { *size = nmd->nm_totalsize; } else { int i; *size = 0; for (i = 0; i < NETMAP_POOLS_NR; i++) { struct netmap_obj_pool *p = nmd->pools + i; *size += (p->_numclusters * p->_clustsize); } } } if (memflags) *memflags = nmd->flags; if (id) *id = nmd->nm_id; out: NMA_UNLOCK(nmd); return error; } /* * we store objects by kernel address, need to find the offset * within the pool to export the value to userspace. * Algorithm: scan until we find the cluster, then add the * actual offset in the cluster */ static ssize_t netmap_obj_offset(struct netmap_obj_pool *p, const void *vaddr) { int i, k = p->_clustentries, n = p->objtotal; ssize_t ofs = 0; for (i = 0; i < n; i += k, ofs += p->_clustsize) { const char *base = p->lut[i].vaddr; ssize_t relofs = (const char *) vaddr - base; if (relofs < 0 || relofs >= p->_clustsize) continue; ofs = ofs + relofs; ND("%s: return offset %d (cluster %d) for pointer %p", p->name, ofs, i, vaddr); return ofs; } D("address %p is not contained inside any cluster (%s)", vaddr, p->name); return 0; /* An error occurred */ } /* Helper functions which convert virtual addresses to offsets */ #define netmap_if_offset(n, v) \ netmap_obj_offset(&(n)->pools[NETMAP_IF_POOL], (v)) #define netmap_ring_offset(n, v) \ ((n)->pools[NETMAP_IF_POOL].memtotal + \ netmap_obj_offset(&(n)->pools[NETMAP_RING_POOL], (v))) #define netmap_buf_offset(n, v) \ ((n)->pools[NETMAP_IF_POOL].memtotal + \ (n)->pools[NETMAP_RING_POOL].memtotal + \ netmap_obj_offset(&(n)->pools[NETMAP_BUF_POOL], (v))) ssize_t netmap_mem_if_offset(struct netmap_mem_d *nmd, const void *addr) { ssize_t v; NMA_LOCK(nmd); v = netmap_if_offset(nmd, addr); NMA_UNLOCK(nmd); return v; } /* * report the index, and use start position as a hint, * otherwise buffer allocation becomes terribly expensive. */ static void * netmap_obj_malloc(struct netmap_obj_pool *p, u_int len, uint32_t *start, uint32_t *index) { uint32_t i = 0; /* index in the bitmap */ uint32_t mask, j; /* slot counter */ void *vaddr = NULL; if (len > p->_objsize) { D("%s request size %d too large", p->name, len); // XXX cannot reduce the size return NULL; } if (p->objfree == 0) { D("no more %s objects", p->name); return NULL; } if (start) i = *start; /* termination is guaranteed by p->free, but better check bounds on i */ while (vaddr == NULL && i < p->bitmap_slots) { uint32_t cur = p->bitmap[i]; if (cur == 0) { /* bitmask is fully used */ i++; continue; } /* locate a slot */ for (j = 0, mask = 1; (cur & mask) == 0; j++, mask <<= 1) ; p->bitmap[i] &= ~mask; /* mark object as in use */ p->objfree--; vaddr = p->lut[i * 32 + j].vaddr; if (index) *index = i * 32 + j; } ND("%s allocator: allocated object @ [%d][%d]: vaddr %p", i, j, vaddr); if (start) *start = i; return vaddr; } /* * free by index, not by address. * XXX should we also cleanup the content ? */ static int netmap_obj_free(struct netmap_obj_pool *p, uint32_t j) { uint32_t *ptr, mask; if (j >= p->objtotal) { D("invalid index %u, max %u", j, p->objtotal); return 1; } ptr = &p->bitmap[j / 32]; mask = (1 << (j % 32)); if (*ptr & mask) { D("ouch, double free on buffer %d", j); return 1; } else { *ptr |= mask; p->objfree++; return 0; } } /* * free by address. This is slow but is only used for a few * objects (rings, nifp) */ static void netmap_obj_free_va(struct netmap_obj_pool *p, void *vaddr) { u_int i, j, n = p->numclusters; for (i = 0, j = 0; i < n; i++, j += p->_clustentries) { void *base = p->lut[i * p->_clustentries].vaddr; ssize_t relofs = (ssize_t) vaddr - (ssize_t) base; /* Given address, is out of the scope of the current cluster.*/ if (vaddr < base || relofs >= p->_clustsize) continue; j = j + relofs / p->_objsize; /* KASSERT(j != 0, ("Cannot free object 0")); */ netmap_obj_free(p, j); return; } D("address %p is not contained inside any cluster (%s)", vaddr, p->name); } #define netmap_mem_bufsize(n) \ ((n)->pools[NETMAP_BUF_POOL]._objsize) #define netmap_if_malloc(n, len) netmap_obj_malloc(&(n)->pools[NETMAP_IF_POOL], len, NULL, NULL) #define netmap_if_free(n, v) netmap_obj_free_va(&(n)->pools[NETMAP_IF_POOL], (v)) #define netmap_ring_malloc(n, len) netmap_obj_malloc(&(n)->pools[NETMAP_RING_POOL], len, NULL, NULL) #define netmap_ring_free(n, v) netmap_obj_free_va(&(n)->pools[NETMAP_RING_POOL], (v)) #define netmap_buf_malloc(n, _pos, _index) \ netmap_obj_malloc(&(n)->pools[NETMAP_BUF_POOL], netmap_mem_bufsize(n), _pos, _index) #if 0 // XXX unused /* Return the index associated to the given packet buffer */ #define netmap_buf_index(n, v) \ (netmap_obj_offset(&(n)->pools[NETMAP_BUF_POOL], (v)) / NETMAP_BDG_BUF_SIZE(n)) #endif /* * allocate extra buffers in a linked list. * returns the actual number. */ uint32_t netmap_extra_alloc(struct netmap_adapter *na, uint32_t *head, uint32_t n) { struct netmap_mem_d *nmd = na->nm_mem; uint32_t i, pos = 0; /* opaque, scan position in the bitmap */ NMA_LOCK(nmd); *head = 0; /* default, 'null' index ie empty list */ for (i = 0 ; i < n; i++) { uint32_t cur = *head; /* save current head */ uint32_t *p = netmap_buf_malloc(nmd, &pos, head); if (p == NULL) { D("no more buffers after %d of %d", i, n); *head = cur; /* restore */ break; } RD(5, "allocate buffer %d -> %d", *head, cur); *p = cur; /* link to previous head */ } NMA_UNLOCK(nmd); return i; } static void netmap_extra_free(struct netmap_adapter *na, uint32_t head) { struct lut_entry *lut = na->na_lut; struct netmap_mem_d *nmd = na->nm_mem; struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL]; uint32_t i, cur, *buf; D("freeing the extra list"); for (i = 0; head >=2 && head < p->objtotal; i++) { cur = head; buf = lut[head].vaddr; head = *buf; *buf = 0; if (netmap_obj_free(p, cur)) break; } if (head != 0) D("breaking with head %d", head); D("freed %d buffers", i); } /* Return nonzero on error */ static int netmap_new_bufs(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n) { struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL]; u_int i = 0; /* slot counter */ uint32_t pos = 0; /* slot in p->bitmap */ uint32_t index = 0; /* buffer index */ for (i = 0; i < n; i++) { void *vaddr = netmap_buf_malloc(nmd, &pos, &index); if (vaddr == NULL) { D("no more buffers after %d of %d", i, n); goto cleanup; } slot[i].buf_idx = index; slot[i].len = p->_objsize; slot[i].flags = 0; } ND("allocated %d buffers, %d available, first at %d", n, p->objfree, pos); return (0); cleanup: while (i > 0) { i--; netmap_obj_free(p, slot[i].buf_idx); } bzero(slot, n * sizeof(slot[0])); return (ENOMEM); } static void netmap_mem_set_ring(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n, uint32_t index) { struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL]; u_int i; for (i = 0; i < n; i++) { slot[i].buf_idx = index; slot[i].len = p->_objsize; slot[i].flags = 0; } } static void netmap_free_buf(struct netmap_mem_d *nmd, uint32_t i) { struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL]; if (i < 2 || i >= p->objtotal) { D("Cannot free buf#%d: should be in [2, %d[", i, p->objtotal); return; } netmap_obj_free(p, i); } static void netmap_free_bufs(struct netmap_mem_d *nmd, struct netmap_slot *slot, u_int n) { u_int i; for (i = 0; i < n; i++) { if (slot[i].buf_idx > 2) netmap_free_buf(nmd, slot[i].buf_idx); } } static void netmap_reset_obj_allocator(struct netmap_obj_pool *p) { if (p == NULL) return; if (p->bitmap) free(p->bitmap, M_NETMAP); p->bitmap = NULL; if (p->lut) { u_int i; size_t sz = p->_clustsize; + /* + * Free each cluster allocated in + * netmap_finalize_obj_allocator(). The cluster start + * addresses are stored at multiples of p->_clusterentries + * in the lut. + */ for (i = 0; i < p->objtotal; i += p->_clustentries) { if (p->lut[i].vaddr) contigfree(p->lut[i].vaddr, sz, M_NETMAP); } bzero(p->lut, sizeof(struct lut_entry) * p->objtotal); #ifdef linux vfree(p->lut); #else free(p->lut, M_NETMAP); #endif } p->lut = NULL; p->objtotal = 0; p->memtotal = 0; p->numclusters = 0; p->objfree = 0; } /* * Free all resources related to an allocator. */ static void netmap_destroy_obj_allocator(struct netmap_obj_pool *p) { if (p == NULL) return; netmap_reset_obj_allocator(p); } /* * We receive a request for objtotal objects, of size objsize each. * Internally we may round up both numbers, as we allocate objects * in small clusters multiple of the page size. * We need to keep track of objtotal and clustentries, * as they are needed when freeing memory. * * XXX note -- userspace needs the buffers to be contiguous, * so we cannot afford gaps at the end of a cluster. */ /* call with NMA_LOCK held */ static int netmap_config_obj_allocator(struct netmap_obj_pool *p, u_int objtotal, u_int objsize) { int i; u_int clustsize; /* the cluster size, multiple of page size */ u_int clustentries; /* how many objects per entry */ /* we store the current request, so we can * detect configuration changes later */ p->r_objtotal = objtotal; p->r_objsize = objsize; #define MAX_CLUSTSIZE (1<<22) // 4 MB #define LINE_ROUND NM_CACHE_ALIGN // 64 if (objsize >= MAX_CLUSTSIZE) { /* we could do it but there is no point */ D("unsupported allocation for %d bytes", objsize); return EINVAL; } /* make sure objsize is a multiple of LINE_ROUND */ i = (objsize & (LINE_ROUND - 1)); if (i) { D("XXX aligning object by %d bytes", LINE_ROUND - i); objsize += LINE_ROUND - i; } if (objsize < p->objminsize || objsize > p->objmaxsize) { D("requested objsize %d out of range [%d, %d]", objsize, p->objminsize, p->objmaxsize); return EINVAL; } if (objtotal < p->nummin || objtotal > p->nummax) { D("requested objtotal %d out of range [%d, %d]", objtotal, p->nummin, p->nummax); return EINVAL; } /* * Compute number of objects using a brute-force approach: * given a max cluster size, * we try to fill it with objects keeping track of the * wasted space to the next page boundary. */ for (clustentries = 0, i = 1;; i++) { u_int delta, used = i * objsize; if (used > MAX_CLUSTSIZE) break; delta = used % PAGE_SIZE; if (delta == 0) { // exact solution clustentries = i; break; } } /* exact solution not found */ if (clustentries == 0) { D("unsupported allocation for %d bytes", objsize); return EINVAL; } /* compute clustsize */ clustsize = clustentries * objsize; if (netmap_verbose) D("objsize %d clustsize %d objects %d", objsize, clustsize, clustentries); /* * The number of clusters is n = ceil(objtotal/clustentries) * objtotal' = n * clustentries */ p->_clustentries = clustentries; p->_clustsize = clustsize; p->_numclusters = (objtotal + clustentries - 1) / clustentries; /* actual values (may be larger than requested) */ p->_objsize = objsize; p->_objtotal = p->_numclusters * clustentries; return 0; } /* call with NMA_LOCK held */ static int netmap_finalize_obj_allocator(struct netmap_obj_pool *p) { int i; /* must be signed */ size_t n; /* optimistically assume we have enough memory */ p->numclusters = p->_numclusters; p->objtotal = p->_objtotal; n = sizeof(struct lut_entry) * p->objtotal; #ifdef linux p->lut = vmalloc(n); #else p->lut = malloc(n, M_NETMAP, M_NOWAIT | M_ZERO); #endif if (p->lut == NULL) { D("Unable to create lookup table (%d bytes) for '%s'", (int)n, p->name); goto clean; } /* Allocate the bitmap */ n = (p->objtotal + 31) / 32; p->bitmap = malloc(sizeof(uint32_t) * n, M_NETMAP, M_NOWAIT | M_ZERO); if (p->bitmap == NULL) { D("Unable to create bitmap (%d entries) for allocator '%s'", (int)n, p->name); goto clean; } p->bitmap_slots = n; /* * Allocate clusters, init pointers and bitmap */ n = p->_clustsize; for (i = 0; i < (int)p->objtotal;) { int lim = i + p->_clustentries; char *clust; clust = contigmalloc(n, M_NETMAP, M_NOWAIT | M_ZERO, (size_t)0, -1UL, PAGE_SIZE, 0); if (clust == NULL) { /* * If we get here, there is a severe memory shortage, * so halve the allocated memory to reclaim some. */ D("Unable to create cluster at %d for '%s' allocator", i, p->name); if (i < 2) /* nothing to halve */ goto out; lim = i / 2; for (i--; i >= lim; i--) { p->bitmap[ (i>>5) ] &= ~( 1 << (i & 31) ); if (i % p->_clustentries == 0 && p->lut[i].vaddr) contigfree(p->lut[i].vaddr, n, M_NETMAP); + p->lut[i].vaddr = NULL; } out: p->objtotal = i; /* we may have stopped in the middle of a cluster */ p->numclusters = (i + p->_clustentries - 1) / p->_clustentries; break; } + /* + * Set bitmap and lut state for all buffers in the current + * cluster. + * + * [i, lim) is the set of buffer indexes that cover the + * current cluster. + * + * 'clust' is really the address of the current buffer in + * the current cluster as we index through it with a stride + * of p->_objsize. + */ for (; i < lim; i++, clust += p->_objsize) { p->bitmap[ (i>>5) ] |= ( 1 << (i & 31) ); p->lut[i].vaddr = clust; p->lut[i].paddr = vtophys(clust); } } p->objfree = p->objtotal; p->memtotal = p->numclusters * p->_clustsize; if (p->objfree == 0) goto clean; if (netmap_verbose) D("Pre-allocated %d clusters (%d/%dKB) for '%s'", p->numclusters, p->_clustsize >> 10, p->memtotal >> 10, p->name); return 0; clean: netmap_reset_obj_allocator(p); return ENOMEM; } /* call with lock held */ static int netmap_memory_config_changed(struct netmap_mem_d *nmd) { int i; for (i = 0; i < NETMAP_POOLS_NR; i++) { if (nmd->pools[i].r_objsize != netmap_params[i].size || nmd->pools[i].r_objtotal != netmap_params[i].num) return 1; } return 0; } static void netmap_mem_reset_all(struct netmap_mem_d *nmd) { int i; if (netmap_verbose) D("resetting %p", nmd); for (i = 0; i < NETMAP_POOLS_NR; i++) { netmap_reset_obj_allocator(&nmd->pools[i]); } nmd->flags &= ~NETMAP_MEM_FINALIZED; } static int netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na) { int i, lim = p->_objtotal; if (na->pdev == NULL) return 0; #ifdef __FreeBSD__ (void)i; (void)lim; D("unsupported on FreeBSD"); #else /* linux */ for (i = 2; i < lim; i++) { netmap_unload_map(na, (bus_dma_tag_t) na->pdev, &p->lut[i].paddr); } #endif /* linux */ return 0; } static int netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na) { #ifdef __FreeBSD__ D("unsupported on FreeBSD"); #else /* linux */ int i, lim = p->_objtotal; if (na->pdev == NULL) return 0; for (i = 2; i < lim; i++) { netmap_load_map(na, (bus_dma_tag_t) na->pdev, &p->lut[i].paddr, p->lut[i].vaddr); } #endif /* linux */ return 0; } static int netmap_mem_finalize_all(struct netmap_mem_d *nmd) { int i; if (nmd->flags & NETMAP_MEM_FINALIZED) return 0; nmd->lasterr = 0; nmd->nm_totalsize = 0; for (i = 0; i < NETMAP_POOLS_NR; i++) { nmd->lasterr = netmap_finalize_obj_allocator(&nmd->pools[i]); if (nmd->lasterr) goto error; nmd->nm_totalsize += nmd->pools[i].memtotal; } /* buffers 0 and 1 are reserved */ nmd->pools[NETMAP_BUF_POOL].objfree -= 2; nmd->pools[NETMAP_BUF_POOL].bitmap[0] = ~3; nmd->flags |= NETMAP_MEM_FINALIZED; if (netmap_verbose) D("interfaces %d KB, rings %d KB, buffers %d MB", nmd->pools[NETMAP_IF_POOL].memtotal >> 10, nmd->pools[NETMAP_RING_POOL].memtotal >> 10, nmd->pools[NETMAP_BUF_POOL].memtotal >> 20); if (netmap_verbose) D("Free buffers: %d", nmd->pools[NETMAP_BUF_POOL].objfree); return 0; error: netmap_mem_reset_all(nmd); return nmd->lasterr; } void netmap_mem_private_delete(struct netmap_mem_d *nmd) { if (nmd == NULL) return; if (netmap_verbose) D("deleting %p", nmd); if (nmd->refcount > 0) D("bug: deleting mem allocator with refcount=%d!", nmd->refcount); nm_mem_release_id(nmd); if (netmap_verbose) D("done deleting %p", nmd); NMA_LOCK_DESTROY(nmd); free(nmd, M_DEVBUF); } static int netmap_mem_private_config(struct netmap_mem_d *nmd) { /* nothing to do, we are configured on creation * and configuration never changes thereafter */ return 0; } static int netmap_mem_private_finalize(struct netmap_mem_d *nmd) { int err; - NMA_LOCK(nmd); nmd->refcount++; err = netmap_mem_finalize_all(nmd); - NMA_UNLOCK(nmd); return err; } static void netmap_mem_private_deref(struct netmap_mem_d *nmd) { - NMA_LOCK(nmd); if (--nmd->refcount <= 0) netmap_mem_reset_all(nmd); - NMA_UNLOCK(nmd); } /* * allocator for private memory */ struct netmap_mem_d * netmap_mem_private_new(const char *name, u_int txr, u_int txd, u_int rxr, u_int rxd, u_int extra_bufs, u_int npipes, int *perr) { struct netmap_mem_d *d = NULL; struct netmap_obj_params p[NETMAP_POOLS_NR]; int i, err; u_int v, maxd; d = malloc(sizeof(struct netmap_mem_d), M_DEVBUF, M_NOWAIT | M_ZERO); if (d == NULL) { err = ENOMEM; goto error; } *d = nm_blueprint; err = nm_mem_assign_id(d); if (err) goto error; /* account for the fake host rings */ txr++; rxr++; /* copy the min values */ for (i = 0; i < NETMAP_POOLS_NR; i++) { p[i] = netmap_min_priv_params[i]; } /* possibly increase them to fit user request */ v = sizeof(struct netmap_if) + sizeof(ssize_t) * (txr + rxr); if (p[NETMAP_IF_POOL].size < v) p[NETMAP_IF_POOL].size = v; v = 2 + 4 * npipes; if (p[NETMAP_IF_POOL].num < v) p[NETMAP_IF_POOL].num = v; maxd = (txd > rxd) ? txd : rxd; v = sizeof(struct netmap_ring) + sizeof(struct netmap_slot) * maxd; if (p[NETMAP_RING_POOL].size < v) p[NETMAP_RING_POOL].size = v; /* each pipe endpoint needs two tx rings (1 normal + 1 host, fake) * and two rx rings (again, 1 normal and 1 fake host) */ v = txr + rxr + 8 * npipes; if (p[NETMAP_RING_POOL].num < v) p[NETMAP_RING_POOL].num = v; /* for each pipe we only need the buffers for the 4 "real" rings. * On the other end, the pipe ring dimension may be different from * the parent port ring dimension. As a compromise, we allocate twice the * space actually needed if the pipe rings were the same size as the parent rings */ v = (4 * npipes + rxr) * rxd + (4 * npipes + txr) * txd + 2 + extra_bufs; /* the +2 is for the tx and rx fake buffers (indices 0 and 1) */ if (p[NETMAP_BUF_POOL].num < v) p[NETMAP_BUF_POOL].num = v; if (netmap_verbose) D("req if %d*%d ring %d*%d buf %d*%d", p[NETMAP_IF_POOL].num, p[NETMAP_IF_POOL].size, p[NETMAP_RING_POOL].num, p[NETMAP_RING_POOL].size, p[NETMAP_BUF_POOL].num, p[NETMAP_BUF_POOL].size); for (i = 0; i < NETMAP_POOLS_NR; i++) { snprintf(d->pools[i].name, NETMAP_POOL_MAX_NAMSZ, nm_blueprint.pools[i].name, name); err = netmap_config_obj_allocator(&d->pools[i], p[i].num, p[i].size); if (err) goto error; } d->flags &= ~NETMAP_MEM_FINALIZED; NMA_LOCK_INIT(d); return d; error: netmap_mem_private_delete(d); if (perr) *perr = err; return NULL; } /* call with lock held */ static int netmap_mem_global_config(struct netmap_mem_d *nmd) { int i; if (nmd->refcount) /* already in use, we cannot change the configuration */ goto out; if (!netmap_memory_config_changed(nmd)) goto out; D("reconfiguring"); if (nmd->flags & NETMAP_MEM_FINALIZED) { /* reset previous allocation */ for (i = 0; i < NETMAP_POOLS_NR; i++) { netmap_reset_obj_allocator(&nmd->pools[i]); } nmd->flags &= ~NETMAP_MEM_FINALIZED; } for (i = 0; i < NETMAP_POOLS_NR; i++) { nmd->lasterr = netmap_config_obj_allocator(&nmd->pools[i], netmap_params[i].num, netmap_params[i].size); if (nmd->lasterr) goto out; } out: return nmd->lasterr; } static int netmap_mem_global_finalize(struct netmap_mem_d *nmd) { int err; - - NMA_LOCK(nmd); - - + /* update configuration if changed */ if (netmap_mem_global_config(nmd)) goto out; nmd->refcount++; if (nmd->flags & NETMAP_MEM_FINALIZED) { /* may happen if config is not changed */ ND("nothing to do"); goto out; } if (netmap_mem_finalize_all(nmd)) goto out; nmd->lasterr = 0; out: if (nmd->lasterr) nmd->refcount--; err = nmd->lasterr; - NMA_UNLOCK(nmd); - return err; } int netmap_mem_init(void) { NMA_LOCK_INIT(&nm_mem); return (0); } void netmap_mem_fini(void) { int i; for (i = 0; i < NETMAP_POOLS_NR; i++) { netmap_destroy_obj_allocator(&nm_mem.pools[i]); } NMA_LOCK_DESTROY(&nm_mem); } static void netmap_free_rings(struct netmap_adapter *na) { struct netmap_kring *kring; struct netmap_ring *ring; if (!na->tx_rings) return; for (kring = na->tx_rings; kring != na->rx_rings; kring++) { ring = kring->ring; if (ring == NULL) continue; netmap_free_bufs(na->nm_mem, ring->slot, kring->nkr_num_slots); netmap_ring_free(na->nm_mem, ring); kring->ring = NULL; } for (/* cont'd from above */; kring != na->tailroom; kring++) { ring = kring->ring; if (ring == NULL) continue; netmap_free_bufs(na->nm_mem, ring->slot, kring->nkr_num_slots); netmap_ring_free(na->nm_mem, ring); kring->ring = NULL; } } /* call with NMA_LOCK held * * * Allocate netmap rings and buffers for this card * The rings are contiguous, but have variable size. * The kring array must follow the layout described * in netmap_krings_create(). */ int netmap_mem_rings_create(struct netmap_adapter *na) { struct netmap_ring *ring; u_int len, ndesc; struct netmap_kring *kring; u_int i; NMA_LOCK(na->nm_mem); /* transmit rings */ for (i =0, kring = na->tx_rings; kring != na->rx_rings; kring++, i++) { if (kring->ring) { ND("%s %ld already created", kring->name, kring - na->tx_rings); continue; /* already created by somebody else */ } ndesc = kring->nkr_num_slots; len = sizeof(struct netmap_ring) + ndesc * sizeof(struct netmap_slot); ring = netmap_ring_malloc(na->nm_mem, len); if (ring == NULL) { D("Cannot allocate tx_ring"); goto cleanup; } ND("txring at %p", ring); kring->ring = ring; *(uint32_t *)(uintptr_t)&ring->num_slots = ndesc; *(int64_t *)(uintptr_t)&ring->buf_ofs = (na->nm_mem->pools[NETMAP_IF_POOL].memtotal + na->nm_mem->pools[NETMAP_RING_POOL].memtotal) - netmap_ring_offset(na->nm_mem, ring); /* copy values from kring */ ring->head = kring->rhead; ring->cur = kring->rcur; ring->tail = kring->rtail; *(uint16_t *)(uintptr_t)&ring->nr_buf_size = netmap_mem_bufsize(na->nm_mem); ND("%s h %d c %d t %d", kring->name, ring->head, ring->cur, ring->tail); ND("initializing slots for txring"); if (i != na->num_tx_rings || (na->na_flags & NAF_HOST_RINGS)) { /* this is a real ring */ if (netmap_new_bufs(na->nm_mem, ring->slot, ndesc)) { D("Cannot allocate buffers for tx_ring"); goto cleanup; } } else { /* this is a fake tx ring, set all indices to 0 */ netmap_mem_set_ring(na->nm_mem, ring->slot, ndesc, 0); } } /* receive rings */ for ( i = 0 /* kring cont'd from above */ ; kring != na->tailroom; kring++, i++) { if (kring->ring) { ND("%s %ld already created", kring->name, kring - na->rx_rings); continue; /* already created by somebody else */ } ndesc = kring->nkr_num_slots; len = sizeof(struct netmap_ring) + ndesc * sizeof(struct netmap_slot); ring = netmap_ring_malloc(na->nm_mem, len); if (ring == NULL) { D("Cannot allocate rx_ring"); goto cleanup; } ND("rxring at %p", ring); kring->ring = ring; *(uint32_t *)(uintptr_t)&ring->num_slots = ndesc; *(int64_t *)(uintptr_t)&ring->buf_ofs = (na->nm_mem->pools[NETMAP_IF_POOL].memtotal + na->nm_mem->pools[NETMAP_RING_POOL].memtotal) - netmap_ring_offset(na->nm_mem, ring); /* copy values from kring */ ring->head = kring->rhead; ring->cur = kring->rcur; ring->tail = kring->rtail; *(int *)(uintptr_t)&ring->nr_buf_size = netmap_mem_bufsize(na->nm_mem); ND("%s h %d c %d t %d", kring->name, ring->head, ring->cur, ring->tail); ND("initializing slots for rxring %p", ring); if (i != na->num_rx_rings || (na->na_flags & NAF_HOST_RINGS)) { /* this is a real ring */ if (netmap_new_bufs(na->nm_mem, ring->slot, ndesc)) { D("Cannot allocate buffers for rx_ring"); goto cleanup; } } else { /* this is a fake rx ring, set all indices to 1 */ netmap_mem_set_ring(na->nm_mem, ring->slot, ndesc, 1); } } NMA_UNLOCK(na->nm_mem); return 0; cleanup: netmap_free_rings(na); NMA_UNLOCK(na->nm_mem); return ENOMEM; } void netmap_mem_rings_delete(struct netmap_adapter *na) { /* last instance, release bufs and rings */ NMA_LOCK(na->nm_mem); netmap_free_rings(na); NMA_UNLOCK(na->nm_mem); } /* call with NMA_LOCK held */ /* * Allocate the per-fd structure netmap_if. * * We assume that the configuration stored in na * (number of tx/rx rings and descs) does not change while * the interface is in netmap mode. */ struct netmap_if * netmap_mem_if_new(struct netmap_adapter *na) { struct netmap_if *nifp; ssize_t base; /* handy for relative offsets between rings and nifp */ u_int i, len, ntx, nrx; /* account for the (eventually fake) host rings */ ntx = na->num_tx_rings + 1; nrx = na->num_rx_rings + 1; /* * the descriptor is followed inline by an array of offsets * to the tx and rx rings in the shared memory region. */ NMA_LOCK(na->nm_mem); len = sizeof(struct netmap_if) + (nrx + ntx) * sizeof(ssize_t); nifp = netmap_if_malloc(na->nm_mem, len); if (nifp == NULL) { NMA_UNLOCK(na->nm_mem); return NULL; } /* initialize base fields -- override const */ *(u_int *)(uintptr_t)&nifp->ni_tx_rings = na->num_tx_rings; *(u_int *)(uintptr_t)&nifp->ni_rx_rings = na->num_rx_rings; strncpy(nifp->ni_name, na->name, (size_t)IFNAMSIZ); /* * fill the slots for the rx and tx rings. They contain the offset * between the ring and nifp, so the information is usable in * userspace to reach the ring from the nifp. */ base = netmap_if_offset(na->nm_mem, nifp); for (i = 0; i < ntx; i++) { *(ssize_t *)(uintptr_t)&nifp->ring_ofs[i] = netmap_ring_offset(na->nm_mem, na->tx_rings[i].ring) - base; } for (i = 0; i < nrx; i++) { *(ssize_t *)(uintptr_t)&nifp->ring_ofs[i+ntx] = netmap_ring_offset(na->nm_mem, na->rx_rings[i].ring) - base; } NMA_UNLOCK(na->nm_mem); return (nifp); } void netmap_mem_if_delete(struct netmap_adapter *na, struct netmap_if *nifp) { if (nifp == NULL) /* nothing to do */ return; NMA_LOCK(na->nm_mem); if (nifp->ni_bufs_head) netmap_extra_free(na, nifp->ni_bufs_head); netmap_if_free(na->nm_mem, nifp); NMA_UNLOCK(na->nm_mem); } static void netmap_mem_global_deref(struct netmap_mem_d *nmd) { - NMA_LOCK(nmd); nmd->refcount--; if (!nmd->refcount) nmd->nm_grp = -1; if (netmap_verbose) D("refcount = %d", nmd->refcount); - NMA_UNLOCK(nmd); } int netmap_mem_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na) { if (nm_mem_assign_group(nmd, na->pdev) < 0) { return ENOMEM; } else { + NMA_LOCK(nmd); nmd->finalize(nmd); + NMA_UNLOCK(nmd); } if (!nmd->lasterr && na->pdev) netmap_mem_map(&nmd->pools[NETMAP_BUF_POOL], na); return nmd->lasterr; } void netmap_mem_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na) { NMA_LOCK(nmd); netmap_mem_unmap(&nmd->pools[NETMAP_BUF_POOL], na); + if (nmd->refcount == 1) { + u_int i; + + /* + * Reset the allocator when it falls out of use so that any + * pool resources leaked by unclean application exits are + * reclaimed. + */ + for (i = 0; i < NETMAP_POOLS_NR; i++) { + struct netmap_obj_pool *p; + u_int j; + + p = &nmd->pools[i]; + p->objfree = p->objtotal; + /* + * Reproduce the net effect of the M_ZERO malloc() + * and marking of free entries in the bitmap that + * occur in finalize_obj_allocator() + */ + memset(p->bitmap, + '\0', + sizeof(uint32_t) * ((p->objtotal + 31) / 32)); + + /* + * Set all the bits in the bitmap that have + * corresponding buffers to 1 to indicate they are + * free. + */ + for (j = 0; j < p->objtotal; j++) { + if (p->lut[j].vaddr != NULL) { + p->bitmap[ (j>>5) ] |= ( 1 << (j & 31) ); + } + } + } + + /* + * Per netmap_mem_finalize_all(), + * buffers 0 and 1 are reserved + */ + nmd->pools[NETMAP_BUF_POOL].objfree -= 2; + nmd->pools[NETMAP_BUF_POOL].bitmap[0] = ~3; + } + nmd->deref(nmd); NMA_UNLOCK(nmd); - return nmd->deref(nmd); } Index: projects/ci20_mips/sys/dev/ofw/ofw_bus_subr.c =================================================================== --- projects/ci20_mips/sys/dev/ofw/ofw_bus_subr.c (revision 283030) +++ projects/ci20_mips/sys/dev/ofw/ofw_bus_subr.c (revision 283031) @@ -1,528 +1,531 @@ /*- * Copyright (c) 2001 - 2003 by Thomas Moestl . * Copyright (c) 2005 Marius Strobl * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include "ofw_bus_if.h" int ofw_bus_gen_setup_devinfo(struct ofw_bus_devinfo *obd, phandle_t node) { if (obd == NULL) return (ENOMEM); /* The 'name' property is considered mandatory. */ if ((OF_getprop_alloc(node, "name", 1, (void **)&obd->obd_name)) == -1) return (EINVAL); OF_getprop_alloc(node, "compatible", 1, (void **)&obd->obd_compat); OF_getprop_alloc(node, "device_type", 1, (void **)&obd->obd_type); OF_getprop_alloc(node, "model", 1, (void **)&obd->obd_model); OF_getprop_alloc(node, "status", 1, (void **)&obd->obd_status); obd->obd_node = node; return (0); } void ofw_bus_gen_destroy_devinfo(struct ofw_bus_devinfo *obd) { if (obd == NULL) return; if (obd->obd_compat != NULL) free(obd->obd_compat, M_OFWPROP); if (obd->obd_model != NULL) free(obd->obd_model, M_OFWPROP); if (obd->obd_name != NULL) free(obd->obd_name, M_OFWPROP); if (obd->obd_type != NULL) free(obd->obd_type, M_OFWPROP); if (obd->obd_status != NULL) free(obd->obd_status, M_OFWPROP); } int ofw_bus_gen_child_pnpinfo_str(device_t cbdev, device_t child, char *buf, size_t buflen) { if (ofw_bus_get_name(child) != NULL) { strlcat(buf, "name=", buflen); strlcat(buf, ofw_bus_get_name(child), buflen); } if (ofw_bus_get_compat(child) != NULL) { strlcat(buf, " compat=", buflen); strlcat(buf, ofw_bus_get_compat(child), buflen); } return (0); }; const char * ofw_bus_gen_get_compat(device_t bus, device_t dev) { const struct ofw_bus_devinfo *obd; obd = OFW_BUS_GET_DEVINFO(bus, dev); if (obd == NULL) return (NULL); return (obd->obd_compat); } const char * ofw_bus_gen_get_model(device_t bus, device_t dev) { const struct ofw_bus_devinfo *obd; obd = OFW_BUS_GET_DEVINFO(bus, dev); if (obd == NULL) return (NULL); return (obd->obd_model); } const char * ofw_bus_gen_get_name(device_t bus, device_t dev) { const struct ofw_bus_devinfo *obd; obd = OFW_BUS_GET_DEVINFO(bus, dev); if (obd == NULL) return (NULL); return (obd->obd_name); } phandle_t ofw_bus_gen_get_node(device_t bus, device_t dev) { const struct ofw_bus_devinfo *obd; obd = OFW_BUS_GET_DEVINFO(bus, dev); if (obd == NULL) return (0); return (obd->obd_node); } const char * ofw_bus_gen_get_type(device_t bus, device_t dev) { const struct ofw_bus_devinfo *obd; obd = OFW_BUS_GET_DEVINFO(bus, dev); if (obd == NULL) return (NULL); return (obd->obd_type); } const char * ofw_bus_get_status(device_t dev) { const struct ofw_bus_devinfo *obd; obd = OFW_BUS_GET_DEVINFO(device_get_parent(dev), dev); if (obd == NULL) return (NULL); return (obd->obd_status); } int ofw_bus_status_okay(device_t dev) { const char *status; status = ofw_bus_get_status(dev); if (status == NULL || strcmp(status, "okay") == 0) return (1); return (0); } static int ofw_bus_node_is_compatible(const char *compat, int len, const char *onecompat) { int onelen, l, ret; onelen = strlen(onecompat); ret = 0; while (len > 0) { if (strlen(compat) == onelen && strncasecmp(compat, onecompat, onelen) == 0) { /* Found it. */ ret = 1; break; } /* Slide to the next sub-string. */ l = strlen(compat) + 1; compat += l; len -= l; } return (ret); } int ofw_bus_is_compatible(device_t dev, const char *onecompat) { phandle_t node; const char *compat; int len; if ((compat = ofw_bus_get_compat(dev)) == NULL) return (0); if ((node = ofw_bus_get_node(dev)) == -1) return (0); /* Get total 'compatible' prop len */ if ((len = OF_getproplen(node, "compatible")) <= 0) return (0); return (ofw_bus_node_is_compatible(compat, len, onecompat)); } int ofw_bus_is_compatible_strict(device_t dev, const char *compatible) { const char *compat; size_t len; if ((compat = ofw_bus_get_compat(dev)) == NULL) return (0); len = strlen(compatible); if (strlen(compat) == len && strncasecmp(compat, compatible, len) == 0) return (1); return (0); } const struct ofw_compat_data * ofw_bus_search_compatible(device_t dev, const struct ofw_compat_data *compat) { if (compat == NULL) return NULL; for (; compat->ocd_str != NULL; ++compat) { if (ofw_bus_is_compatible(dev, compat->ocd_str)) break; } return (compat); } int ofw_bus_has_prop(device_t dev, const char *propname) { phandle_t node; if ((node = ofw_bus_get_node(dev)) == -1) return (0); return (OF_hasprop(node, propname)); } void ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz) { pcell_t addrc; int msksz; if (OF_getencprop(node, "#address-cells", &addrc, sizeof(addrc)) == -1) addrc = 2; ii->opi_addrc = addrc * sizeof(pcell_t); ii->opi_imapsz = OF_getencprop_alloc(node, "interrupt-map", 1, (void **)&ii->opi_imap); if (ii->opi_imapsz > 0) { msksz = OF_getencprop_alloc(node, "interrupt-map-mask", 1, (void **)&ii->opi_imapmsk); /* * Failure to get the mask is ignored; a full mask is used * then. We barf on bad mask sizes, however. */ if (msksz != -1 && msksz != ii->opi_addrc + intrsz) panic("ofw_bus_setup_iinfo: bad interrupt-map-mask " "property!"); } } int ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg, int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz, phandle_t *iparent) { uint8_t maskbuf[regsz + pintrsz]; int rv; if (ii->opi_imapsz <= 0) return (0); KASSERT(regsz >= ii->opi_addrc, ("ofw_bus_lookup_imap: register size too small: %d < %d", regsz, ii->opi_addrc)); if (node != -1) { rv = OF_getencprop(node, "reg", reg, regsz); if (rv < regsz) panic("ofw_bus_lookup_imap: cannot get reg property"); } return (ofw_bus_search_intrmap(pintr, pintrsz, reg, ii->opi_addrc, ii->opi_imap, ii->opi_imapsz, ii->opi_imapmsk, maskbuf, mintr, mintrsz, iparent)); } /* * Map an interrupt using the firmware reg, interrupt-map and * interrupt-map-mask properties. * The interrupt property to be mapped must be of size intrsz, and pointed to * by intr. The regs property of the node for which the mapping is done must * be passed as regs. This property is an array of register specifications; * the size of the address part of such a specification must be passed as * physsz. Only the first element of the property is used. * imap and imapsz hold the interrupt mask and it's size. * imapmsk is a pointer to the interrupt-map-mask property, which must have * a size of physsz + intrsz; it may be NULL, in which case a full mask is * assumed. * maskbuf must point to a buffer of length physsz + intrsz. * The interrupt is returned in result, which must point to a buffer of length * rintrsz (which gives the expected size of the mapped interrupt). * Returns number of cells in the interrupt if a mapping was found, 0 otherwise. */ int ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz, void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result, int rintrsz, phandle_t *iparent) { phandle_t parent; uint8_t *ref = maskbuf; uint8_t *uiintr = intr; uint8_t *uiregs = regs; uint8_t *uiimapmsk = imapmsk; uint8_t *mptr; pcell_t pintrsz; int i, rsz, tsz; rsz = -1; if (imapmsk != NULL) { for (i = 0; i < physsz; i++) ref[i] = uiregs[i] & uiimapmsk[i]; for (i = 0; i < intrsz; i++) ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i]; } else { bcopy(regs, ref, physsz); bcopy(intr, ref + physsz, intrsz); } mptr = imap; i = imapsz; while (i > 0) { bcopy(mptr + physsz + intrsz, &parent, sizeof(parent)); if (OF_searchencprop(OF_node_from_xref(parent), "#interrupt-cells", &pintrsz, sizeof(pintrsz)) == -1) pintrsz = 1; /* default */ pintrsz *= sizeof(pcell_t); /* Compute the map stride size. */ tsz = physsz + intrsz + sizeof(phandle_t) + pintrsz; KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map")); if (bcmp(ref, mptr, physsz + intrsz) == 0) { bcopy(mptr + physsz + intrsz + sizeof(parent), result, MIN(rintrsz, pintrsz)); if (iparent != NULL) *iparent = parent; return (pintrsz/sizeof(pcell_t)); } mptr += tsz; i -= tsz; } return (0); } int ofw_bus_reg_to_rl(device_t dev, phandle_t node, pcell_t acells, pcell_t scells, struct resource_list *rl) { uint64_t phys, size; ssize_t i, j, rid, nreg, ret; uint32_t *reg; char *name; /* * This may be just redundant when having ofw_bus_devinfo * but makes this routine independent of it. */ ret = OF_getencprop_alloc(node, "name", sizeof(*name), (void **)&name); if (ret == -1) name = NULL; ret = OF_getencprop_alloc(node, "reg", sizeof(*reg), (void **)®); nreg = (ret == -1) ? 0 : ret; if (nreg % (acells + scells) != 0) { if (bootverbose) device_printf(dev, "Malformed reg property on <%s>\n", (name == NULL) ? "unknown" : name); nreg = 0; } for (i = 0, rid = 0; i < nreg; i += acells + scells, rid++) { phys = size = 0; for (j = 0; j < acells; j++) { phys <<= 32; phys |= reg[i + j]; } for (j = 0; j < scells; j++) { size <<= 32; size |= reg[i + acells + j]; } /* Skip the dummy reg property of glue devices like ssm(4). */ if (size != 0) resource_list_add(rl, SYS_RES_MEMORY, rid, phys, phys + size - 1, size); } free(name, M_OFWPROP); free(reg, M_OFWPROP); return (0); } int -ofw_bus_intr_to_rl(device_t dev, phandle_t node, struct resource_list *rl) +ofw_bus_intr_to_rl(device_t dev, phandle_t node, + struct resource_list *rl, int *rlen) { phandle_t iparent; uint32_t icells, *intr; int err, i, irqnum, nintr, rid; boolean_t extended; nintr = OF_getencprop_alloc(node, "interrupts", sizeof(*intr), (void **)&intr); if (nintr > 0) { if (OF_searchencprop(node, "interrupt-parent", &iparent, sizeof(iparent)) == -1) { for (iparent = node; iparent != 0; iparent = OF_parent(node)) { if (OF_hasprop(iparent, "interrupt-controller")) break; } if (iparent == 0) { device_printf(dev, "No interrupt-parent found, " "assuming direct parent\n"); iparent = OF_parent(node); } iparent = OF_xref_from_node(iparent); } if (OF_searchencprop(OF_node_from_xref(iparent), "#interrupt-cells", &icells, sizeof(icells)) == -1) { device_printf(dev, "Missing #interrupt-cells " "property, assuming <1>\n"); icells = 1; } if (icells < 1 || icells > nintr) { device_printf(dev, "Invalid #interrupt-cells property " "value <%d>, assuming <1>\n", icells); icells = 1; } extended = false; } else { nintr = OF_getencprop_alloc(node, "interrupts-extended", sizeof(*intr), (void **)&intr); if (nintr <= 0) return (0); extended = true; } err = 0; rid = 0; for (i = 0; i < nintr; i += icells) { if (extended) { iparent = intr[i++]; if (OF_searchencprop(OF_node_from_xref(iparent), "#interrupt-cells", &icells, sizeof(icells)) == -1) { device_printf(dev, "Missing #interrupt-cells " "property\n"); err = ENOENT; break; } if (icells < 1 || (i + icells) > nintr) { device_printf(dev, "Invalid #interrupt-cells " "property value <%d>\n", icells); err = ERANGE; break; } } irqnum = ofw_bus_map_intr(dev, iparent, icells, &intr[i]); resource_list_add(rl, SYS_RES_IRQ, rid++, irqnum, irqnum, 1); } + if (rlen != NULL) + *rlen = rid; free(intr, M_OFWPROP); return (err); } phandle_t ofw_bus_find_compatible(phandle_t node, const char *onecompat) { phandle_t child, ret; void *compat; int len; /* * Traverse all children of 'start' node, and find first with * matching 'compatible' property. */ for (child = OF_child(node); child != 0; child = OF_peer(child)) { len = OF_getprop_alloc(child, "compatible", 1, &compat); if (len >= 0) { ret = ofw_bus_node_is_compatible(compat, len, onecompat); free(compat, M_OFWPROP); if (ret != 0) return (child); } ret = ofw_bus_find_compatible(child, onecompat); if (ret != 0) return (ret); } return (0); } Index: projects/ci20_mips/sys/dev/ofw/ofw_bus_subr.h =================================================================== --- projects/ci20_mips/sys/dev/ofw/ofw_bus_subr.h (revision 283030) +++ projects/ci20_mips/sys/dev/ofw/ofw_bus_subr.h (revision 283031) @@ -1,107 +1,107 @@ /*- * Copyright (c) 2005 Marius Strobl * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _DEV_OFW_OFW_BUS_SUBR_H_ #define _DEV_OFW_OFW_BUS_SUBR_H_ #include #include #include "ofw_bus_if.h" #define ORIP_NOINT -1 #define ORIR_NOTFOUND 0xffffffff struct ofw_bus_iinfo { uint8_t *opi_imap; uint8_t *opi_imapmsk; int opi_imapsz; pcell_t opi_addrc; }; struct ofw_compat_data { const char *ocd_str; uintptr_t ocd_data; }; /* Generic implementation of ofw_bus_if.m methods and helper routines */ int ofw_bus_gen_setup_devinfo(struct ofw_bus_devinfo *, phandle_t); void ofw_bus_gen_destroy_devinfo(struct ofw_bus_devinfo *); ofw_bus_get_compat_t ofw_bus_gen_get_compat; ofw_bus_get_model_t ofw_bus_gen_get_model; ofw_bus_get_name_t ofw_bus_gen_get_name; ofw_bus_get_node_t ofw_bus_gen_get_node; ofw_bus_get_type_t ofw_bus_gen_get_type; /* Helper method to report interesting OF properties in pnpinfo */ bus_child_pnpinfo_str_t ofw_bus_gen_child_pnpinfo_str; /* Routines for processing firmware interrupt maps */ void ofw_bus_setup_iinfo(phandle_t, struct ofw_bus_iinfo *, int); int ofw_bus_lookup_imap(phandle_t, struct ofw_bus_iinfo *, void *, int, void *, int, void *, int, phandle_t *); int ofw_bus_search_intrmap(void *, int, void *, int, void *, int, void *, void *, void *, int, phandle_t *); /* Routines for parsing device-tree data into resource lists. */ int ofw_bus_reg_to_rl(device_t, phandle_t, pcell_t, pcell_t, struct resource_list *); -int ofw_bus_intr_to_rl(device_t, phandle_t, struct resource_list *); +int ofw_bus_intr_to_rl(device_t, phandle_t, struct resource_list *, int *); /* Helper to get device status property */ const char *ofw_bus_get_status(device_t dev); int ofw_bus_status_okay(device_t dev); /* Helper to get node's interrupt parent */ void ofw_bus_find_iparent(phandle_t); /* Helper routine for checking compat prop */ int ofw_bus_is_compatible(device_t, const char *); int ofw_bus_is_compatible_strict(device_t, const char *); /* * Helper routine to search a list of compat properties. The table is * terminated by an entry with a NULL compat-string pointer; a pointer to that * table entry is returned if none of the compat strings match for the device, * giving you control over the not-found value. Will not return NULL unless the * provided table pointer is NULL. */ const struct ofw_compat_data * ofw_bus_search_compatible(device_t, const struct ofw_compat_data *); /* Helper routine for checking existence of a prop */ int ofw_bus_has_prop(device_t, const char *); /* Helper to search for a child with a given compat prop */ phandle_t ofw_bus_find_compatible(phandle_t, const char *); #endif /* !_DEV_OFW_OFW_BUS_SUBR_H_ */ Index: projects/ci20_mips/sys/dev/ofw/ofw_iicbus.c =================================================================== --- projects/ci20_mips/sys/dev/ofw/ofw_iicbus.c (revision 283030) +++ projects/ci20_mips/sys/dev/ofw/ofw_iicbus.c (revision 283031) @@ -1,204 +1,205 @@ /*- * Copyright (c) 2009, Nathan Whitehorn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include "iicbus_if.h" /* Methods */ static device_probe_t ofw_iicbus_probe; static device_attach_t ofw_iicbus_attach; static device_t ofw_iicbus_add_child(device_t dev, u_int order, const char *name, int unit); static const struct ofw_bus_devinfo *ofw_iicbus_get_devinfo(device_t bus, device_t dev); static device_method_t ofw_iicbus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ofw_iicbus_probe), DEVMETHOD(device_attach, ofw_iicbus_attach), /* Bus interface */ DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), DEVMETHOD(bus_add_child, ofw_iicbus_add_child), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, ofw_iicbus_get_devinfo), DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), DEVMETHOD_END }; struct ofw_iicbus_devinfo { struct iicbus_ivar opd_dinfo; /* Must be the first. */ struct ofw_bus_devinfo opd_obdinfo; }; static devclass_t ofwiicbus_devclass; DEFINE_CLASS_1(iicbus, ofw_iicbus_driver, ofw_iicbus_methods, sizeof(struct iicbus_softc), iicbus_driver); DRIVER_MODULE(ofw_iicbus, iicbb, ofw_iicbus_driver, ofwiicbus_devclass, 0, 0); DRIVER_MODULE(ofw_iicbus, iichb, ofw_iicbus_driver, ofwiicbus_devclass, 0, 0); MODULE_VERSION(ofw_iicbus, 1); MODULE_DEPEND(ofw_iicbus, iicbus, 1, 1, 1); static int ofw_iicbus_probe(device_t dev) { if (ofw_bus_get_node(dev) == -1) return (ENXIO); device_set_desc(dev, "OFW I2C bus"); return (0); } static int ofw_iicbus_attach(device_t dev) { struct iicbus_softc *sc = IICBUS_SOFTC(dev); struct ofw_iicbus_devinfo *dinfo; phandle_t child, node; pcell_t freq, paddr; device_t childdev; sc->dev = dev; mtx_init(&sc->lock, "iicbus", NULL, MTX_DEF); /* * If there is a clock-frequency property for the device node, use it as * the starting value for the bus frequency. Then call the common * routine that handles the tunable/sysctl which allows the FDT value to * be overridden by the user. */ node = ofw_bus_get_node(dev); freq = 0; OF_getencprop(node, "clock-frequency", &freq, sizeof(freq)); iicbus_init_frequency(dev, freq); iicbus_reset(dev, IIC_FASTEST, 0, NULL); bus_generic_probe(dev); bus_enumerate_hinted_children(dev); /* * Attach those children represented in the device tree. */ for (child = OF_child(node); child != 0; child = OF_peer(child)) { /* * Try to get the I2C address first from the i2c-address * property, then try the reg property. It moves around * on different systems. */ if (OF_getencprop(child, "i2c-address", &paddr, sizeof(paddr)) == -1) if (OF_getencprop(child, "reg", &paddr, sizeof(paddr)) == -1) continue; /* * Now set up the I2C and OFW bus layer devinfo and add it * to the bus. */ dinfo = malloc(sizeof(struct ofw_iicbus_devinfo), M_DEVBUF, M_NOWAIT | M_ZERO); if (dinfo == NULL) continue; dinfo->opd_dinfo.addr = paddr; if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) != 0) { free(dinfo, M_DEVBUF); continue; } childdev = device_add_child(dev, NULL, -1); resource_list_init(&dinfo->opd_dinfo.rl); - ofw_bus_intr_to_rl(childdev, child, &dinfo->opd_dinfo.rl); + ofw_bus_intr_to_rl(childdev, child, + &dinfo->opd_dinfo.rl, NULL); device_set_ivars(childdev, dinfo); } return (bus_generic_attach(dev)); } static device_t ofw_iicbus_add_child(device_t dev, u_int order, const char *name, int unit) { device_t child; struct ofw_iicbus_devinfo *devi; child = device_add_child_ordered(dev, order, name, unit); if (child == NULL) return (child); devi = malloc(sizeof(struct ofw_iicbus_devinfo), M_DEVBUF, M_NOWAIT | M_ZERO); if (devi == NULL) { device_delete_child(dev, child); return (0); } /* * NULL all the OFW-related parts of the ivars for non-OFW * children. */ devi->opd_obdinfo.obd_node = -1; devi->opd_obdinfo.obd_name = NULL; devi->opd_obdinfo.obd_compat = NULL; devi->opd_obdinfo.obd_type = NULL; devi->opd_obdinfo.obd_model = NULL; device_set_ivars(child, devi); return (child); } static const struct ofw_bus_devinfo * ofw_iicbus_get_devinfo(device_t bus, device_t dev) { struct ofw_iicbus_devinfo *dinfo; dinfo = device_get_ivars(dev); return (&dinfo->opd_obdinfo); } Index: projects/ci20_mips/sys/dev/sfxge/sfxge.c =================================================================== --- projects/ci20_mips/sys/dev/sfxge/sfxge.c (revision 283030) +++ projects/ci20_mips/sys/dev/sfxge/sfxge.c (revision 283031) @@ -1,830 +1,846 @@ /*- * Copyright (c) 2010-2011 Solarflare Communications, Inc. * All rights reserved. * * This software was developed in part by Philip Paeps under contract for * Solarflare Communications, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common/efx.h" #include "sfxge.h" #include "sfxge_rx.h" #include "sfxge_version.h" #define SFXGE_CAP (IFCAP_VLAN_MTU | IFCAP_VLAN_HWCSUM | \ IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO | \ IFCAP_RXCSUM_IPV6 | IFCAP_TXCSUM_IPV6 | \ IFCAP_JUMBO_MTU | IFCAP_LRO | \ IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWSTATS) #define SFXGE_CAP_ENABLE SFXGE_CAP -#define SFXGE_CAP_FIXED (IFCAP_VLAN_MTU | IFCAP_RXCSUM | IFCAP_VLAN_HWCSUM | \ - IFCAP_RXCSUM_IPV6 | \ +#define SFXGE_CAP_FIXED (IFCAP_VLAN_MTU | IFCAP_VLAN_HWCSUM | \ IFCAP_JUMBO_MTU | IFCAP_LINKSTATE | IFCAP_HWSTATS) MALLOC_DEFINE(M_SFXGE, "sfxge", "Solarflare 10GigE driver"); SYSCTL_NODE(_hw, OID_AUTO, sfxge, CTLFLAG_RD, 0, "SFXGE driver parameters"); #define SFXGE_PARAM_RX_RING SFXGE_PARAM(rx_ring) static int sfxge_rx_ring_entries = SFXGE_NDESCS; TUNABLE_INT(SFXGE_PARAM_RX_RING, &sfxge_rx_ring_entries); SYSCTL_INT(_hw_sfxge, OID_AUTO, rx_ring, CTLFLAG_RDTUN, &sfxge_rx_ring_entries, 0, "Maximum number of descriptors in a receive ring"); #define SFXGE_PARAM_TX_RING SFXGE_PARAM(tx_ring) static int sfxge_tx_ring_entries = SFXGE_NDESCS; TUNABLE_INT(SFXGE_PARAM_TX_RING, &sfxge_tx_ring_entries); SYSCTL_INT(_hw_sfxge, OID_AUTO, tx_ring, CTLFLAG_RDTUN, &sfxge_tx_ring_entries, 0, "Maximum number of descriptors in a transmit ring"); static void sfxge_reset(void *arg, int npending); static int sfxge_start(struct sfxge_softc *sc) { int rc; SFXGE_ADAPTER_LOCK_ASSERT_OWNED(sc); if (sc->init_state == SFXGE_STARTED) return (0); if (sc->init_state != SFXGE_REGISTERED) { rc = EINVAL; goto fail; } if ((rc = efx_nic_init(sc->enp)) != 0) goto fail; /* Start processing interrupts. */ if ((rc = sfxge_intr_start(sc)) != 0) goto fail2; /* Start processing events. */ if ((rc = sfxge_ev_start(sc)) != 0) goto fail3; /* Start the receiver side. */ if ((rc = sfxge_rx_start(sc)) != 0) goto fail4; /* Start the transmitter side. */ if ((rc = sfxge_tx_start(sc)) != 0) goto fail5; /* Fire up the port. */ if ((rc = sfxge_port_start(sc)) != 0) goto fail6; sc->init_state = SFXGE_STARTED; /* Tell the stack we're running. */ sc->ifnet->if_drv_flags |= IFF_DRV_RUNNING; sc->ifnet->if_drv_flags &= ~IFF_DRV_OACTIVE; return (0); fail6: sfxge_tx_stop(sc); fail5: sfxge_rx_stop(sc); fail4: sfxge_ev_stop(sc); fail3: sfxge_intr_stop(sc); fail2: efx_nic_fini(sc->enp); fail: device_printf(sc->dev, "sfxge_start: %d\n", rc); return (rc); } static void sfxge_if_init(void *arg) { struct sfxge_softc *sc; sc = (struct sfxge_softc *)arg; SFXGE_ADAPTER_LOCK(sc); (void)sfxge_start(sc); SFXGE_ADAPTER_UNLOCK(sc); } static void sfxge_stop(struct sfxge_softc *sc) { SFXGE_ADAPTER_LOCK_ASSERT_OWNED(sc); if (sc->init_state != SFXGE_STARTED) return; sc->init_state = SFXGE_REGISTERED; /* Stop the port. */ sfxge_port_stop(sc); /* Stop the transmitter. */ sfxge_tx_stop(sc); /* Stop the receiver. */ sfxge_rx_stop(sc); /* Stop processing events. */ sfxge_ev_stop(sc); /* Stop processing interrupts. */ sfxge_intr_stop(sc); efx_nic_fini(sc->enp); sc->ifnet->if_drv_flags &= ~IFF_DRV_RUNNING; } static int sfxge_if_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data) { struct sfxge_softc *sc; struct ifreq *ifr; int error; ifr = (struct ifreq *)data; sc = ifp->if_softc; error = 0; switch (command) { case SIOCSIFFLAGS: SFXGE_ADAPTER_LOCK(sc); if (ifp->if_flags & IFF_UP) { if (ifp->if_drv_flags & IFF_DRV_RUNNING) { if ((ifp->if_flags ^ sc->if_flags) & (IFF_PROMISC | IFF_ALLMULTI)) { sfxge_mac_filter_set(sc); } } else sfxge_start(sc); } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) sfxge_stop(sc); sc->if_flags = ifp->if_flags; SFXGE_ADAPTER_UNLOCK(sc); break; case SIOCSIFMTU: if (ifr->ifr_mtu == ifp->if_mtu) { /* Nothing to do */ error = 0; } else if (ifr->ifr_mtu > SFXGE_MAX_MTU) { error = EINVAL; } else if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { ifp->if_mtu = ifr->ifr_mtu; error = 0; } else { /* Restart required */ SFXGE_ADAPTER_LOCK(sc); sfxge_stop(sc); ifp->if_mtu = ifr->ifr_mtu; error = sfxge_start(sc); SFXGE_ADAPTER_UNLOCK(sc); if (error != 0) { ifp->if_flags &= ~IFF_UP; ifp->if_drv_flags &= ~IFF_DRV_RUNNING; if_down(ifp); } } break; case SIOCADDMULTI: case SIOCDELMULTI: if (ifp->if_drv_flags & IFF_DRV_RUNNING) sfxge_mac_filter_set(sc); break; case SIOCSIFCAP: + { + int reqcap = ifr->ifr_reqcap; + int capchg_mask; + SFXGE_ADAPTER_LOCK(sc); + /* Capabilities to be changed in accordance with request */ + capchg_mask = ifp->if_capenable ^ reqcap; + /* * The networking core already rejects attempts to * enable capabilities we don't have. We still have * to reject attempts to disable capabilities that we * can't (yet) disable. */ - if (~ifr->ifr_reqcap & SFXGE_CAP_FIXED) { + KASSERT((reqcap & ~ifp->if_capabilities) == 0, + ("Unsupported capabilities %x requested %x vs %x", + reqcap & ~ifp->if_capabilities, + reqcap , ifp->if_capabilities)); + if (capchg_mask & SFXGE_CAP_FIXED) { error = EINVAL; SFXGE_ADAPTER_UNLOCK(sc); break; } - ifp->if_capenable = ifr->ifr_reqcap; - if (ifp->if_capenable & IFCAP_TXCSUM) + if (reqcap & IFCAP_TXCSUM) ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP); else ifp->if_hwassist &= ~(CSUM_IP | CSUM_TCP | CSUM_UDP); - if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) + if (reqcap & IFCAP_TXCSUM_IPV6) ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); else ifp->if_hwassist &= ~(CSUM_TCP_IPV6 | CSUM_UDP_IPV6); - if (ifp->if_capenable & IFCAP_TSO) - ifp->if_hwassist |= CSUM_TSO; - else - ifp->if_hwassist &= ~CSUM_TSO; + /* + * The kernel takes both IFCAP_TSOx and CSUM_TSO into + * account before using TSO. So, we do not touch + * checksum flags when IFCAP_TSOx is modified. + * Note that CSUM_TSO is (CSUM_IP_TSO|CSUM_IP6_TSO), + * but both bits are set in IPv4 and IPv6 mbufs. + */ + + ifp->if_capenable = reqcap; + SFXGE_ADAPTER_UNLOCK(sc); break; + } case SIOCSIFMEDIA: case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->media, command); break; default: error = ether_ioctl(ifp, command, data); } return (error); } static void sfxge_ifnet_fini(struct ifnet *ifp) { struct sfxge_softc *sc = ifp->if_softc; SFXGE_ADAPTER_LOCK(sc); sfxge_stop(sc); SFXGE_ADAPTER_UNLOCK(sc); ifmedia_removeall(&sc->media); ether_ifdetach(ifp); if_free(ifp); } static int sfxge_ifnet_init(struct ifnet *ifp, struct sfxge_softc *sc) { const efx_nic_cfg_t *encp = efx_nic_cfg_get(sc->enp); device_t dev; int rc; dev = sc->dev; sc->ifnet = ifp; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_init = sfxge_if_init; ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = sfxge_if_ioctl; ifp->if_capabilities = SFXGE_CAP; ifp->if_capenable = SFXGE_CAP_ENABLE; ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO | CSUM_TCP_IPV6 | CSUM_UDP_IPV6; ether_ifattach(ifp, encp->enc_mac_addr); ifp->if_transmit = sfxge_if_transmit; ifp->if_qflush = sfxge_if_qflush; ifp->if_get_counter = sfxge_get_counter; if ((rc = sfxge_port_ifmedia_init(sc)) != 0) goto fail; return (0); fail: ether_ifdetach(sc->ifnet); return (rc); } void sfxge_sram_buf_tbl_alloc(struct sfxge_softc *sc, size_t n, uint32_t *idp) { KASSERT(sc->buffer_table_next + n <= efx_nic_cfg_get(sc->enp)->enc_buftbl_limit, ("buffer table full")); *idp = sc->buffer_table_next; sc->buffer_table_next += n; } static int sfxge_bar_init(struct sfxge_softc *sc) { efsys_bar_t *esbp = &sc->bar; esbp->esb_rid = PCIR_BAR(EFX_MEM_BAR); if ((esbp->esb_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, &esbp->esb_rid, RF_ACTIVE)) == NULL) { device_printf(sc->dev, "Cannot allocate BAR region %d\n", EFX_MEM_BAR); return (ENXIO); } esbp->esb_tag = rman_get_bustag(esbp->esb_res); esbp->esb_handle = rman_get_bushandle(esbp->esb_res); SFXGE_BAR_LOCK_INIT(esbp, device_get_nameunit(sc->dev)); return (0); } static void sfxge_bar_fini(struct sfxge_softc *sc) { efsys_bar_t *esbp = &sc->bar; bus_release_resource(sc->dev, SYS_RES_MEMORY, esbp->esb_rid, esbp->esb_res); SFXGE_BAR_LOCK_DESTROY(esbp); } static int sfxge_create(struct sfxge_softc *sc) { device_t dev; efx_nic_t *enp; int error; char rss_param_name[sizeof(SFXGE_PARAM(%d.max_rss_channels))]; dev = sc->dev; SFXGE_ADAPTER_LOCK_INIT(sc, device_get_nameunit(sc->dev)); sc->max_rss_channels = 0; snprintf(rss_param_name, sizeof(rss_param_name), SFXGE_PARAM(%d.max_rss_channels), (int)device_get_unit(dev)); TUNABLE_INT_FETCH(rss_param_name, &sc->max_rss_channels); sc->stats_node = SYSCTL_ADD_NODE( device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "stats", CTLFLAG_RD, NULL, "Statistics"); if (sc->stats_node == NULL) { error = ENOMEM; goto fail; } TASK_INIT(&sc->task_reset, 0, sfxge_reset, sc); (void) pci_enable_busmaster(dev); /* Initialize DMA mappings. */ if ((error = sfxge_dma_init(sc)) != 0) goto fail; /* Map the device registers. */ if ((error = sfxge_bar_init(sc)) != 0) goto fail; error = efx_family(pci_get_vendor(dev), pci_get_device(dev), &sc->family); KASSERT(error == 0, ("Family should be filtered by sfxge_probe()")); /* Create the common code nic object. */ SFXGE_EFSYS_LOCK_INIT(&sc->enp_lock, device_get_nameunit(sc->dev), "nic"); if ((error = efx_nic_create(sc->family, (efsys_identifier_t *)sc, &sc->bar, &sc->enp_lock, &enp)) != 0) goto fail3; sc->enp = enp; if (!ISP2(sfxge_rx_ring_entries) || !(sfxge_rx_ring_entries & EFX_RXQ_NDESCS_MASK)) { log(LOG_ERR, "%s=%d must be power of 2 from %u to %u", SFXGE_PARAM_RX_RING, sfxge_rx_ring_entries, EFX_RXQ_MINNDESCS, EFX_RXQ_MAXNDESCS); error = EINVAL; goto fail_rx_ring_entries; } sc->rxq_entries = sfxge_rx_ring_entries; if (!ISP2(sfxge_tx_ring_entries) || !(sfxge_tx_ring_entries & EFX_TXQ_NDESCS_MASK)) { log(LOG_ERR, "%s=%d must be power of 2 from %u to %u", SFXGE_PARAM_TX_RING, sfxge_tx_ring_entries, EFX_TXQ_MINNDESCS, EFX_TXQ_MAXNDESCS); error = EINVAL; goto fail_tx_ring_entries; } sc->txq_entries = sfxge_tx_ring_entries; /* Initialize MCDI to talk to the microcontroller. */ if ((error = sfxge_mcdi_init(sc)) != 0) goto fail4; /* Probe the NIC and build the configuration data area. */ if ((error = efx_nic_probe(enp)) != 0) goto fail5; SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "version", CTLFLAG_RD, SFXGE_VERSION_STRING, 0, "Driver version"); /* Initialize the NVRAM. */ if ((error = efx_nvram_init(enp)) != 0) goto fail6; /* Initialize the VPD. */ if ((error = efx_vpd_init(enp)) != 0) goto fail7; /* Reset the NIC. */ if ((error = efx_nic_reset(enp)) != 0) goto fail8; /* Initialize buffer table allocation. */ sc->buffer_table_next = 0; /* Set up interrupts. */ if ((error = sfxge_intr_init(sc)) != 0) goto fail8; /* Initialize event processing state. */ if ((error = sfxge_ev_init(sc)) != 0) goto fail11; /* Initialize receive state. */ if ((error = sfxge_rx_init(sc)) != 0) goto fail12; /* Initialize transmit state. */ if ((error = sfxge_tx_init(sc)) != 0) goto fail13; /* Initialize port state. */ if ((error = sfxge_port_init(sc)) != 0) goto fail14; sc->init_state = SFXGE_INITIALIZED; return (0); fail14: sfxge_tx_fini(sc); fail13: sfxge_rx_fini(sc); fail12: sfxge_ev_fini(sc); fail11: sfxge_intr_fini(sc); fail8: efx_vpd_fini(enp); fail7: efx_nvram_fini(enp); fail6: efx_nic_unprobe(enp); fail5: sfxge_mcdi_fini(sc); fail4: fail_tx_ring_entries: fail_rx_ring_entries: sc->enp = NULL; efx_nic_destroy(enp); SFXGE_EFSYS_LOCK_DESTROY(&sc->enp_lock); fail3: sfxge_bar_fini(sc); (void) pci_disable_busmaster(sc->dev); fail: sc->dev = NULL; SFXGE_ADAPTER_LOCK_DESTROY(sc); return (error); } static void sfxge_destroy(struct sfxge_softc *sc) { efx_nic_t *enp; /* Clean up port state. */ sfxge_port_fini(sc); /* Clean up transmit state. */ sfxge_tx_fini(sc); /* Clean up receive state. */ sfxge_rx_fini(sc); /* Clean up event processing state. */ sfxge_ev_fini(sc); /* Clean up interrupts. */ sfxge_intr_fini(sc); /* Tear down common code subsystems. */ efx_nic_reset(sc->enp); efx_vpd_fini(sc->enp); efx_nvram_fini(sc->enp); efx_nic_unprobe(sc->enp); /* Tear down MCDI. */ sfxge_mcdi_fini(sc); /* Destroy common code context. */ enp = sc->enp; sc->enp = NULL; efx_nic_destroy(enp); /* Free DMA memory. */ sfxge_dma_fini(sc); /* Free mapped BARs. */ sfxge_bar_fini(sc); (void) pci_disable_busmaster(sc->dev); taskqueue_drain(taskqueue_thread, &sc->task_reset); /* Destroy the softc lock. */ SFXGE_ADAPTER_LOCK_DESTROY(sc); } static int sfxge_vpd_handler(SYSCTL_HANDLER_ARGS) { struct sfxge_softc *sc = arg1; efx_vpd_value_t value; int rc; value.evv_tag = arg2 >> 16; value.evv_keyword = arg2 & 0xffff; if ((rc = efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value)) != 0) return (rc); return (SYSCTL_OUT(req, value.evv_value, value.evv_length)); } static void sfxge_vpd_try_add(struct sfxge_softc *sc, struct sysctl_oid_list *list, efx_vpd_tag_t tag, const char *keyword) { struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev); efx_vpd_value_t value; /* Check whether VPD tag/keyword is present */ value.evv_tag = tag; value.evv_keyword = EFX_VPD_KEYWORD(keyword[0], keyword[1]); if (efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value) != 0) return; SYSCTL_ADD_PROC( ctx, list, OID_AUTO, keyword, CTLTYPE_STRING|CTLFLAG_RD, sc, tag << 16 | EFX_VPD_KEYWORD(keyword[0], keyword[1]), sfxge_vpd_handler, "A", ""); } static int sfxge_vpd_init(struct sfxge_softc *sc) { struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev); struct sysctl_oid *vpd_node; struct sysctl_oid_list *vpd_list; char keyword[3]; efx_vpd_value_t value; int rc; if ((rc = efx_vpd_size(sc->enp, &sc->vpd_size)) != 0) goto fail; sc->vpd_data = malloc(sc->vpd_size, M_SFXGE, M_WAITOK); if ((rc = efx_vpd_read(sc->enp, sc->vpd_data, sc->vpd_size)) != 0) goto fail2; /* Copy ID (product name) into device description, and log it. */ value.evv_tag = EFX_VPD_ID; if (efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value) == 0) { value.evv_value[value.evv_length] = 0; device_set_desc_copy(sc->dev, value.evv_value); device_printf(sc->dev, "%s\n", value.evv_value); } vpd_node = SYSCTL_ADD_NODE( ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, "vpd", CTLFLAG_RD, NULL, "Vital Product Data"); vpd_list = SYSCTL_CHILDREN(vpd_node); /* Add sysctls for all expected and any vendor-defined keywords. */ sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, "PN"); sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, "EC"); sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, "SN"); keyword[0] = 'V'; keyword[2] = 0; for (keyword[1] = '0'; keyword[1] <= '9'; keyword[1]++) sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, keyword); for (keyword[1] = 'A'; keyword[1] <= 'Z'; keyword[1]++) sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, keyword); return (0); fail2: free(sc->vpd_data, M_SFXGE); fail: return (rc); } static void sfxge_vpd_fini(struct sfxge_softc *sc) { free(sc->vpd_data, M_SFXGE); } static void sfxge_reset(void *arg, int npending) { struct sfxge_softc *sc; int rc; (void)npending; sc = (struct sfxge_softc *)arg; SFXGE_ADAPTER_LOCK(sc); if (sc->init_state != SFXGE_STARTED) goto done; sfxge_stop(sc); efx_nic_reset(sc->enp); if ((rc = sfxge_start(sc)) != 0) device_printf(sc->dev, "reset failed (%d); interface is now stopped\n", rc); done: SFXGE_ADAPTER_UNLOCK(sc); } void sfxge_schedule_reset(struct sfxge_softc *sc) { taskqueue_enqueue(taskqueue_thread, &sc->task_reset); } static int sfxge_attach(device_t dev) { struct sfxge_softc *sc; struct ifnet *ifp; int error; sc = device_get_softc(dev); sc->dev = dev; /* Allocate ifnet. */ ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { device_printf(dev, "Couldn't allocate ifnet\n"); error = ENOMEM; goto fail; } sc->ifnet = ifp; /* Initialize hardware. */ if ((error = sfxge_create(sc)) != 0) goto fail2; /* Create the ifnet for the port. */ if ((error = sfxge_ifnet_init(ifp, sc)) != 0) goto fail3; if ((error = sfxge_vpd_init(sc)) != 0) goto fail4; sc->init_state = SFXGE_REGISTERED; return (0); fail4: sfxge_ifnet_fini(ifp); fail3: sfxge_destroy(sc); fail2: if_free(sc->ifnet); fail: return (error); } static int sfxge_detach(device_t dev) { struct sfxge_softc *sc; sc = device_get_softc(dev); sfxge_vpd_fini(sc); /* Destroy the ifnet. */ sfxge_ifnet_fini(sc->ifnet); /* Tear down hardware. */ sfxge_destroy(sc); return (0); } static int sfxge_probe(device_t dev) { uint16_t pci_vendor_id; uint16_t pci_device_id; efx_family_t family; int rc; pci_vendor_id = pci_get_vendor(dev); pci_device_id = pci_get_device(dev); rc = efx_family(pci_vendor_id, pci_device_id, &family); if (rc != 0) return (ENXIO); KASSERT(family == EFX_FAMILY_SIENA, ("impossible controller family")); device_set_desc(dev, "Solarflare SFC9000 family"); return (0); } static device_method_t sfxge_methods[] = { DEVMETHOD(device_probe, sfxge_probe), DEVMETHOD(device_attach, sfxge_attach), DEVMETHOD(device_detach, sfxge_detach), DEVMETHOD_END }; static devclass_t sfxge_devclass; static driver_t sfxge_driver = { "sfxge", sfxge_methods, sizeof(struct sfxge_softc) }; DRIVER_MODULE(sfxge, pci, sfxge_driver, sfxge_devclass, 0, 0); Index: projects/ci20_mips/sys/dev/sfxge/sfxge_port.c =================================================================== --- projects/ci20_mips/sys/dev/sfxge/sfxge_port.c (revision 283030) +++ projects/ci20_mips/sys/dev/sfxge/sfxge_port.c (revision 283031) @@ -1,864 +1,946 @@ /*- * Copyright (c) 2010-2011 Solarflare Communications, Inc. * All rights reserved. * * This software was developed in part by Philip Paeps under contract for * Solarflare Communications, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include "common/efx.h" #include "sfxge.h" +static int sfxge_phy_cap_mask(struct sfxge_softc *, int, uint32_t *); + static int sfxge_mac_stat_update(struct sfxge_softc *sc) { struct sfxge_port *port = &sc->port; efsys_mem_t *esmp = &(port->mac_stats.dma_buf); clock_t now; unsigned int count; int rc; SFXGE_PORT_LOCK_ASSERT_OWNED(port); if (__predict_false(port->init_state != SFXGE_PORT_STARTED)) { rc = 0; goto out; } now = ticks; if (now - port->mac_stats.update_time < hz) { rc = 0; goto out; } port->mac_stats.update_time = now; /* If we're unlucky enough to read statistics wduring the DMA, wait * up to 10ms for it to finish (typically takes <500us) */ for (count = 0; count < 100; ++count) { EFSYS_PROBE1(wait, unsigned int, count); /* Synchronize the DMA memory for reading */ bus_dmamap_sync(esmp->esm_tag, esmp->esm_map, BUS_DMASYNC_POSTREAD); /* Try to update the cached counters */ if ((rc = efx_mac_stats_update(sc->enp, esmp, port->mac_stats.decode_buf, NULL)) != EAGAIN) goto out; DELAY(100); } rc = ETIMEDOUT; out: return (rc); } uint64_t sfxge_get_counter(struct ifnet *ifp, ift_counter c) { struct sfxge_softc *sc = ifp->if_softc; uint64_t *mac_stats; uint64_t val; SFXGE_PORT_LOCK(&sc->port); /* Ignore error and use old values */ (void)sfxge_mac_stat_update(sc); mac_stats = (uint64_t *)sc->port.mac_stats.decode_buf; switch (c) { case IFCOUNTER_IPACKETS: val = mac_stats[EFX_MAC_RX_PKTS]; break; case IFCOUNTER_IERRORS: val = mac_stats[EFX_MAC_RX_ERRORS]; break; case IFCOUNTER_OPACKETS: val = mac_stats[EFX_MAC_TX_PKTS]; break; case IFCOUNTER_OERRORS: val = mac_stats[EFX_MAC_TX_ERRORS]; break; case IFCOUNTER_COLLISIONS: val = mac_stats[EFX_MAC_TX_SGL_COL_PKTS] + mac_stats[EFX_MAC_TX_MULT_COL_PKTS] + mac_stats[EFX_MAC_TX_EX_COL_PKTS] + mac_stats[EFX_MAC_TX_LATE_COL_PKTS]; break; case IFCOUNTER_IBYTES: val = mac_stats[EFX_MAC_RX_OCTETS]; break; case IFCOUNTER_OBYTES: val = mac_stats[EFX_MAC_TX_OCTETS]; break; case IFCOUNTER_OMCASTS: val = mac_stats[EFX_MAC_TX_MULTICST_PKTS] + mac_stats[EFX_MAC_TX_BRDCST_PKTS]; break; case IFCOUNTER_OQDROPS: SFXGE_PORT_UNLOCK(&sc->port); return (sfxge_tx_get_drops(sc)); case IFCOUNTER_IMCASTS: /* if_imcasts is maintained in net/if_ethersubr.c */ case IFCOUNTER_IQDROPS: /* if_iqdrops is maintained in net/if_ethersubr.c */ case IFCOUNTER_NOPROTO: /* if_noproto is maintained in net/if_ethersubr.c */ default: SFXGE_PORT_UNLOCK(&sc->port); return (if_get_counter_default(ifp, c)); } SFXGE_PORT_UNLOCK(&sc->port); return (val); } static int sfxge_mac_stat_handler(SYSCTL_HANDLER_ARGS) { struct sfxge_softc *sc = arg1; unsigned int id = arg2; int rc; uint64_t val; SFXGE_PORT_LOCK(&sc->port); if ((rc = sfxge_mac_stat_update(sc)) == 0) val = ((uint64_t *)sc->port.mac_stats.decode_buf)[id]; SFXGE_PORT_UNLOCK(&sc->port); if (rc == 0) rc = SYSCTL_OUT(req, &val, sizeof(val)); return (rc); } static void sfxge_mac_stat_init(struct sfxge_softc *sc) { struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev); struct sysctl_oid_list *stat_list; unsigned int id; const char *name; stat_list = SYSCTL_CHILDREN(sc->stats_node); /* Initialise the named stats */ for (id = 0; id < EFX_MAC_NSTATS; id++) { name = efx_mac_stat_name(sc->enp, id); SYSCTL_ADD_PROC( ctx, stat_list, OID_AUTO, name, CTLTYPE_U64|CTLFLAG_RD, sc, id, sfxge_mac_stat_handler, "Q", ""); } } #ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS static unsigned int sfxge_port_wanted_fc(struct sfxge_softc *sc) { struct ifmedia_entry *ifm = sc->media.ifm_cur; if (ifm->ifm_media == (IFM_ETHER | IFM_AUTO)) return (EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE); return (((ifm->ifm_media & IFM_ETH_RXPAUSE) ? EFX_FCNTL_RESPOND : 0) | ((ifm->ifm_media & IFM_ETH_TXPAUSE) ? EFX_FCNTL_GENERATE : 0)); } static unsigned int sfxge_port_link_fc_ifm(struct sfxge_softc *sc) { unsigned int wanted_fc, link_fc; efx_mac_fcntl_get(sc->enp, &wanted_fc, &link_fc); return ((link_fc & EFX_FCNTL_RESPOND) ? IFM_ETH_RXPAUSE : 0) | ((link_fc & EFX_FCNTL_GENERATE) ? IFM_ETH_TXPAUSE : 0); } #else /* !SFXGE_HAVE_PAUSE_MEDIAOPTS */ static unsigned int sfxge_port_wanted_fc(struct sfxge_softc *sc) { return (sc->port.wanted_fc); } static unsigned int sfxge_port_link_fc_ifm(struct sfxge_softc *sc) { return (0); } static int sfxge_port_wanted_fc_handler(SYSCTL_HANDLER_ARGS) { struct sfxge_softc *sc; struct sfxge_port *port; unsigned int fcntl; int error; sc = arg1; port = &sc->port; if (req->newptr != NULL) { if ((error = SYSCTL_IN(req, &fcntl, sizeof(fcntl))) != 0) return (error); SFXGE_PORT_LOCK(port); if (port->wanted_fc != fcntl) { if (port->init_state == SFXGE_PORT_STARTED) error = efx_mac_fcntl_set(sc->enp, port->wanted_fc, B_TRUE); if (error == 0) port->wanted_fc = fcntl; } SFXGE_PORT_UNLOCK(port); } else { SFXGE_PORT_LOCK(port); fcntl = port->wanted_fc; SFXGE_PORT_UNLOCK(port); error = SYSCTL_OUT(req, &fcntl, sizeof(fcntl)); } return (error); } static int sfxge_port_link_fc_handler(SYSCTL_HANDLER_ARGS) { struct sfxge_softc *sc; struct sfxge_port *port; unsigned int wanted_fc, link_fc; sc = arg1; port = &sc->port; SFXGE_PORT_LOCK(port); if (__predict_true(port->init_state == SFXGE_PORT_STARTED) && SFXGE_LINK_UP(sc)) efx_mac_fcntl_get(sc->enp, &wanted_fc, &link_fc); else link_fc = 0; SFXGE_PORT_UNLOCK(port); return (SYSCTL_OUT(req, &link_fc, sizeof(link_fc))); } #endif /* SFXGE_HAVE_PAUSE_MEDIAOPTS */ static const uint64_t sfxge_link_baudrate[EFX_LINK_NMODES] = { [EFX_LINK_10HDX] = IF_Mbps(10), [EFX_LINK_10FDX] = IF_Mbps(10), [EFX_LINK_100HDX] = IF_Mbps(100), [EFX_LINK_100FDX] = IF_Mbps(100), [EFX_LINK_1000HDX] = IF_Gbps(1), [EFX_LINK_1000FDX] = IF_Gbps(1), [EFX_LINK_10000FDX] = IF_Gbps(10), }; void sfxge_mac_link_update(struct sfxge_softc *sc, efx_link_mode_t mode) { struct sfxge_port *port; int link_state; port = &sc->port; if (port->link_mode == mode) return; port->link_mode = mode; /* Push link state update to the OS */ link_state = (port->link_mode != EFX_LINK_DOWN ? LINK_STATE_UP : LINK_STATE_DOWN); sc->ifnet->if_baudrate = sfxge_link_baudrate[port->link_mode]; if_link_state_change(sc->ifnet, link_state); } static void sfxge_mac_poll_work(void *arg, int npending) { struct sfxge_softc *sc; efx_nic_t *enp; struct sfxge_port *port; efx_link_mode_t mode; sc = (struct sfxge_softc *)arg; enp = sc->enp; port = &sc->port; SFXGE_PORT_LOCK(port); if (__predict_false(port->init_state != SFXGE_PORT_STARTED)) goto done; /* This may sleep waiting for MCDI completion */ (void)efx_port_poll(enp, &mode); sfxge_mac_link_update(sc, mode); done: SFXGE_PORT_UNLOCK(port); } static int sfxge_mac_filter_set_locked(struct sfxge_softc *sc) { unsigned int bucket[EFX_MAC_HASH_BITS]; struct ifnet *ifp = sc->ifnet; struct ifmultiaddr *ifma; struct sockaddr_dl *sa; efx_nic_t *enp = sc->enp; unsigned int index; int rc; /* Set promisc-unicast and broadcast filter bits */ if ((rc = efx_mac_filter_set(enp, !!(ifp->if_flags & IFF_PROMISC), B_TRUE)) != 0) return (rc); /* Set multicast hash filter */ if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) { for (index = 0; index < EFX_MAC_HASH_BITS; index++) bucket[index] = 1; } else { /* Broadcast frames also go through the multicast * filter, and the broadcast address hashes to * 0xff. */ bucket[0xff] = 1; if_maddr_rlock(ifp); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family == AF_LINK) { sa = (struct sockaddr_dl *)ifma->ifma_addr; index = ether_crc32_le(LLADDR(sa), 6) & 0xff; bucket[index] = 1; } } if_maddr_runlock(ifp); } return (efx_mac_hash_set(enp, bucket)); } int sfxge_mac_filter_set(struct sfxge_softc *sc) { struct sfxge_port *port = &sc->port; int rc; SFXGE_PORT_LOCK(port); /* * The function may be called without softc_lock held in the * case of SIOCADDMULTI and SIOCDELMULTI ioctls. ioctl handler * checks IFF_DRV_RUNNING flag which implies port started, but * it is not guaranteed to remain. softc_lock shared lock can't * be held in the case of these ioctls processing, since it * results in failure where kernel complains that non-sleepable * lock is held in sleeping thread. Both problems are repeatable * on LAG with LACP proto bring up. */ if (__predict_true(port->init_state == SFXGE_PORT_STARTED)) rc = sfxge_mac_filter_set_locked(sc); else rc = 0; SFXGE_PORT_UNLOCK(port); return (rc); } void sfxge_port_stop(struct sfxge_softc *sc) { struct sfxge_port *port; efx_nic_t *enp; port = &sc->port; enp = sc->enp; SFXGE_PORT_LOCK(port); KASSERT(port->init_state == SFXGE_PORT_STARTED, ("port not started")); port->init_state = SFXGE_PORT_INITIALIZED; port->mac_stats.update_time = 0; /* This may call MCDI */ (void)efx_mac_drain(enp, B_TRUE); (void)efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf, 0, B_FALSE); port->link_mode = EFX_LINK_UNKNOWN; /* Destroy the common code port object. */ efx_port_fini(sc->enp); SFXGE_PORT_UNLOCK(port); } int sfxge_port_start(struct sfxge_softc *sc) { uint8_t mac_addr[ETHER_ADDR_LEN]; struct ifnet *ifp = sc->ifnet; struct sfxge_port *port; efx_nic_t *enp; size_t pdu; int rc; + uint32_t phy_cap_mask; port = &sc->port; enp = sc->enp; SFXGE_PORT_LOCK(port); KASSERT(port->init_state == SFXGE_PORT_INITIALIZED, ("port not initialized")); /* Initialize the port object in the common code. */ if ((rc = efx_port_init(sc->enp)) != 0) goto fail; /* Set the SDU */ pdu = EFX_MAC_PDU(ifp->if_mtu); if ((rc = efx_mac_pdu_set(enp, pdu)) != 0) goto fail2; if ((rc = efx_mac_fcntl_set(enp, sfxge_port_wanted_fc(sc), B_TRUE)) != 0) goto fail2; /* Set the unicast address */ if_addr_rlock(ifp); bcopy(LLADDR((struct sockaddr_dl *)ifp->if_addr->ifa_addr), mac_addr, sizeof(mac_addr)); if_addr_runlock(ifp); if ((rc = efx_mac_addr_set(enp, mac_addr)) != 0) goto fail; sfxge_mac_filter_set_locked(sc); /* Update MAC stats by DMA every second */ if ((rc = efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf, 1000, B_FALSE)) != 0) goto fail2; if ((rc = efx_mac_drain(enp, B_FALSE)) != 0) goto fail3; - if ((rc = efx_phy_adv_cap_set(sc->enp, sc->media.ifm_cur->ifm_data)) - != 0) + if ((rc = sfxge_phy_cap_mask(sc, sc->media.ifm_cur->ifm_media, + &phy_cap_mask)) != 0) goto fail4; + if ((rc = efx_phy_adv_cap_set(sc->enp, phy_cap_mask)) != 0) + goto fail5; + port->init_state = SFXGE_PORT_STARTED; /* Single poll in case there were missing initial events */ SFXGE_PORT_UNLOCK(port); sfxge_mac_poll_work(sc, 0); return (0); +fail5: fail4: (void)efx_mac_drain(enp, B_TRUE); fail3: (void)efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf, 0, B_FALSE); fail2: efx_port_fini(sc->enp); fail: SFXGE_PORT_UNLOCK(port); return (rc); } static int sfxge_phy_stat_update(struct sfxge_softc *sc) { struct sfxge_port *port = &sc->port; efsys_mem_t *esmp = &port->phy_stats.dma_buf; clock_t now; unsigned int count; int rc; SFXGE_PORT_LOCK_ASSERT_OWNED(port); if (__predict_false(port->init_state != SFXGE_PORT_STARTED)) { rc = 0; goto out; } now = ticks; if (now - port->phy_stats.update_time < hz) { rc = 0; goto out; } port->phy_stats.update_time = now; /* If we're unlucky enough to read statistics wduring the DMA, wait * up to 10ms for it to finish (typically takes <500us) */ for (count = 0; count < 100; ++count) { EFSYS_PROBE1(wait, unsigned int, count); /* Synchronize the DMA memory for reading */ bus_dmamap_sync(esmp->esm_tag, esmp->esm_map, BUS_DMASYNC_POSTREAD); /* Try to update the cached counters */ if ((rc = efx_phy_stats_update(sc->enp, esmp, port->phy_stats.decode_buf)) != EAGAIN) goto out; DELAY(100); } rc = ETIMEDOUT; out: return (rc); } static int sfxge_phy_stat_handler(SYSCTL_HANDLER_ARGS) { struct sfxge_softc *sc = arg1; unsigned int id = arg2; int rc; uint32_t val; SFXGE_PORT_LOCK(&sc->port); if ((rc = sfxge_phy_stat_update(sc)) == 0) val = ((uint32_t *)sc->port.phy_stats.decode_buf)[id]; SFXGE_PORT_UNLOCK(&sc->port); if (rc == 0) rc = SYSCTL_OUT(req, &val, sizeof(val)); return (rc); } static void sfxge_phy_stat_init(struct sfxge_softc *sc) { struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev); struct sysctl_oid_list *stat_list; unsigned int id; const char *name; uint64_t stat_mask = efx_nic_cfg_get(sc->enp)->enc_phy_stat_mask; stat_list = SYSCTL_CHILDREN(sc->stats_node); /* Initialise the named stats */ for (id = 0; id < EFX_PHY_NSTATS; id++) { if (!(stat_mask & ((uint64_t)1 << id))) continue; name = efx_phy_stat_name(sc->enp, id); SYSCTL_ADD_PROC( ctx, stat_list, OID_AUTO, name, CTLTYPE_UINT|CTLFLAG_RD, sc, id, sfxge_phy_stat_handler, id == EFX_PHY_STAT_OUI ? "IX" : "IU", ""); } } void sfxge_port_fini(struct sfxge_softc *sc) { struct sfxge_port *port; efsys_mem_t *esmp; port = &sc->port; esmp = &port->mac_stats.dma_buf; KASSERT(port->init_state == SFXGE_PORT_INITIALIZED, ("Port not initialized")); port->init_state = SFXGE_PORT_UNINITIALIZED; port->link_mode = EFX_LINK_UNKNOWN; /* Finish with PHY DMA memory */ sfxge_dma_free(&port->phy_stats.dma_buf); free(port->phy_stats.decode_buf, M_SFXGE); sfxge_dma_free(esmp); free(port->mac_stats.decode_buf, M_SFXGE); SFXGE_PORT_LOCK_DESTROY(port); port->sc = NULL; } int sfxge_port_init(struct sfxge_softc *sc) { struct sfxge_port *port; struct sysctl_ctx_list *sysctl_ctx; struct sysctl_oid *sysctl_tree; efsys_mem_t *mac_stats_buf, *phy_stats_buf; int rc; port = &sc->port; mac_stats_buf = &port->mac_stats.dma_buf; phy_stats_buf = &port->phy_stats.dma_buf; KASSERT(port->init_state == SFXGE_PORT_UNINITIALIZED, ("Port already initialized")); port->sc = sc; SFXGE_PORT_LOCK_INIT(port, device_get_nameunit(sc->dev)); port->phy_stats.decode_buf = malloc(EFX_PHY_NSTATS * sizeof(uint32_t), M_SFXGE, M_WAITOK | M_ZERO); if ((rc = sfxge_dma_alloc(sc, EFX_PHY_STATS_SIZE, phy_stats_buf)) != 0) goto fail; sfxge_phy_stat_init(sc); sysctl_ctx = device_get_sysctl_ctx(sc->dev); sysctl_tree = device_get_sysctl_tree(sc->dev); #ifndef SFXGE_HAVE_PAUSE_MEDIAOPTS /* If flow control cannot be configured or reported through * ifmedia, provide sysctls for it. */ port->wanted_fc = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE; SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "wanted_fc", CTLTYPE_UINT|CTLFLAG_RW, sc, 0, sfxge_port_wanted_fc_handler, "IU", "wanted flow control mode"); SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "link_fc", CTLTYPE_UINT|CTLFLAG_RD, sc, 0, sfxge_port_link_fc_handler, "IU", "link flow control mode"); #endif port->mac_stats.decode_buf = malloc(EFX_MAC_NSTATS * sizeof(uint64_t), M_SFXGE, M_WAITOK | M_ZERO); if ((rc = sfxge_dma_alloc(sc, EFX_MAC_STATS_SIZE, mac_stats_buf)) != 0) goto fail2; sfxge_mac_stat_init(sc); port->init_state = SFXGE_PORT_INITIALIZED; return (0); fail2: free(port->mac_stats.decode_buf, M_SFXGE); sfxge_dma_free(phy_stats_buf); fail: free(port->phy_stats.decode_buf, M_SFXGE); SFXGE_PORT_LOCK_DESTROY(port); port->sc = NULL; return (rc); } static const int sfxge_link_mode[EFX_PHY_MEDIA_NTYPES][EFX_LINK_NMODES] = { [EFX_PHY_MEDIA_CX4] = { [EFX_LINK_10000FDX] = IFM_ETHER | IFM_FDX | IFM_10G_CX4, }, [EFX_PHY_MEDIA_KX4] = { [EFX_LINK_10000FDX] = IFM_ETHER | IFM_FDX | IFM_10G_KX4, }, [EFX_PHY_MEDIA_XFP] = { /* Don't know the module type, but assume SR for now. */ [EFX_LINK_10000FDX] = IFM_ETHER | IFM_FDX | IFM_10G_SR, }, [EFX_PHY_MEDIA_SFP_PLUS] = { /* Don't know the module type, but assume SX/SR for now. */ [EFX_LINK_1000FDX] = IFM_ETHER | IFM_FDX | IFM_1000_SX, [EFX_LINK_10000FDX] = IFM_ETHER | IFM_FDX | IFM_10G_SR, }, [EFX_PHY_MEDIA_BASE_T] = { [EFX_LINK_10HDX] = IFM_ETHER | IFM_HDX | IFM_10_T, [EFX_LINK_10FDX] = IFM_ETHER | IFM_FDX | IFM_10_T, [EFX_LINK_100HDX] = IFM_ETHER | IFM_HDX | IFM_100_TX, [EFX_LINK_100FDX] = IFM_ETHER | IFM_FDX | IFM_100_TX, [EFX_LINK_1000HDX] = IFM_ETHER | IFM_HDX | IFM_1000_T, [EFX_LINK_1000FDX] = IFM_ETHER | IFM_FDX | IFM_1000_T, [EFX_LINK_10000FDX] = IFM_ETHER | IFM_FDX | IFM_10G_T, }, }; static void sfxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) { struct sfxge_softc *sc; efx_phy_media_type_t medium_type; efx_link_mode_t mode; sc = ifp->if_softc; SFXGE_ADAPTER_LOCK(sc); ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; if (SFXGE_RUNNING(sc) && SFXGE_LINK_UP(sc)) { ifmr->ifm_status |= IFM_ACTIVE; efx_phy_media_type_get(sc->enp, &medium_type); mode = sc->port.link_mode; ifmr->ifm_active |= sfxge_link_mode[medium_type][mode]; ifmr->ifm_active |= sfxge_port_link_fc_ifm(sc); } SFXGE_ADAPTER_UNLOCK(sc); } +static efx_phy_cap_type_t +sfxge_link_mode_to_phy_cap(efx_link_mode_t mode) +{ + switch (mode) { + case EFX_LINK_10HDX: + return (EFX_PHY_CAP_10HDX); + case EFX_LINK_10FDX: + return (EFX_PHY_CAP_10FDX); + case EFX_LINK_100HDX: + return (EFX_PHY_CAP_100HDX); + case EFX_LINK_100FDX: + return (EFX_PHY_CAP_100FDX); + case EFX_LINK_1000HDX: + return (EFX_PHY_CAP_1000HDX); + case EFX_LINK_1000FDX: + return (EFX_PHY_CAP_1000FDX); + case EFX_LINK_10000FDX: + return (EFX_PHY_CAP_10000FDX); + default: + EFSYS_ASSERT(B_FALSE); + return (EFX_PHY_CAP_INVALID); + } +} + static int +sfxge_phy_cap_mask(struct sfxge_softc *sc, int ifmedia, uint32_t *phy_cap_mask) +{ + efx_phy_media_type_t medium_type; + boolean_t mode_found = B_FALSE; + uint32_t cap_mask, mode_cap_mask; + efx_link_mode_t mode; + efx_phy_cap_type_t phy_cap; + + efx_phy_media_type_get(sc->enp, &medium_type); + if (medium_type >= nitems(sfxge_link_mode)) { + if_printf(sc->ifnet, "unexpected media type %d\n", medium_type); + return (EINVAL); + } + + efx_phy_adv_cap_get(sc->enp, EFX_PHY_CAP_PERM, &cap_mask); + + for (mode = EFX_LINK_10HDX; mode < EFX_LINK_NMODES; mode++) { + if (ifmedia == sfxge_link_mode[medium_type][mode]) { + mode_found = B_TRUE; + break; + } + } + + if (!mode_found) { + /* + * If media is not in the table, it must be IFM_AUTO. + */ + KASSERT((cap_mask & (1 << EFX_PHY_CAP_AN)) && + ifmedia == (IFM_ETHER | IFM_AUTO), + ("%s: no mode for media %d", __func__, ifmedia)); + *phy_cap_mask = (cap_mask & ~(1 << EFX_PHY_CAP_ASYM)); + return (0); + } + + phy_cap = sfxge_link_mode_to_phy_cap(mode); + if (phy_cap == EFX_PHY_CAP_INVALID) { + if_printf(sc->ifnet, + "cannot map link mode %d to phy capability\n", + mode); + return (EINVAL); + } + + mode_cap_mask = (1 << phy_cap); + mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_AN); +#ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS + if (ifmedia & IFM_ETH_RXPAUSE) + mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_PAUSE); + if (!(ifmedia & IFM_ETH_TXPAUSE)) + mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_ASYM); +#else + mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_PAUSE); +#endif + + *phy_cap_mask = mode_cap_mask; + return (0); +} + +static int sfxge_media_change(struct ifnet *ifp) { struct sfxge_softc *sc; struct ifmedia_entry *ifm; int rc; + uint32_t phy_cap_mask; sc = ifp->if_softc; ifm = sc->media.ifm_cur; SFXGE_ADAPTER_LOCK(sc); if (!SFXGE_RUNNING(sc)) { rc = 0; goto out; } rc = efx_mac_fcntl_set(sc->enp, sfxge_port_wanted_fc(sc), B_TRUE); if (rc != 0) goto out; - rc = efx_phy_adv_cap_set(sc->enp, ifm->ifm_data); + if ((rc = sfxge_phy_cap_mask(sc, ifm->ifm_media, &phy_cap_mask)) != 0) + goto out; + + rc = efx_phy_adv_cap_set(sc->enp, phy_cap_mask); out: SFXGE_ADAPTER_UNLOCK(sc); return (rc); } int sfxge_port_ifmedia_init(struct sfxge_softc *sc) { efx_phy_media_type_t medium_type; uint32_t cap_mask, mode_cap_mask; efx_link_mode_t mode; + efx_phy_cap_type_t phy_cap; int mode_ifm, best_mode_ifm = 0; int rc; /* We need port state to initialise the ifmedia list. */ if ((rc = efx_nic_init(sc->enp)) != 0) goto out; if ((rc = efx_port_init(sc->enp)) != 0) goto out2; /* * Register ifconfig callbacks for querying and setting the * link mode and link status. */ ifmedia_init(&sc->media, IFM_IMASK, sfxge_media_change, sfxge_media_status); /* * Map firmware medium type and capabilities to ifmedia types. * ifmedia does not distinguish between forcing the link mode * and disabling auto-negotiation. 1000BASE-T and 10GBASE-T * require AN even if only one link mode is enabled, and for * 100BASE-TX it is useful even if the link mode is forced. * Therefore we never disable auto-negotiation. * * Also enable and advertise flow control by default. */ efx_phy_media_type_get(sc->enp, &medium_type); efx_phy_adv_cap_get(sc->enp, EFX_PHY_CAP_PERM, &cap_mask); - EFX_STATIC_ASSERT(EFX_LINK_10HDX == EFX_PHY_CAP_10HDX + 1); - EFX_STATIC_ASSERT(EFX_LINK_10FDX == EFX_PHY_CAP_10FDX + 1); - EFX_STATIC_ASSERT(EFX_LINK_100HDX == EFX_PHY_CAP_100HDX + 1); - EFX_STATIC_ASSERT(EFX_LINK_100FDX == EFX_PHY_CAP_100FDX + 1); - EFX_STATIC_ASSERT(EFX_LINK_1000HDX == EFX_PHY_CAP_1000HDX + 1); - EFX_STATIC_ASSERT(EFX_LINK_1000FDX == EFX_PHY_CAP_1000FDX + 1); - EFX_STATIC_ASSERT(EFX_LINK_10000FDX == EFX_PHY_CAP_10000FDX + 1); + for (mode = EFX_LINK_10HDX; mode < EFX_LINK_NMODES; mode++) { + phy_cap = sfxge_link_mode_to_phy_cap(mode); + if (phy_cap == EFX_PHY_CAP_INVALID) + continue; - for (mode = EFX_LINK_10HDX; mode <= EFX_LINK_10000FDX; mode++) { - mode_cap_mask = 1 << (mode - 1); + mode_cap_mask = (1 << phy_cap); mode_ifm = sfxge_link_mode[medium_type][mode]; if ((cap_mask & mode_cap_mask) && mode_ifm) { - mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_AN); - -#ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS /* No flow-control */ - ifmedia_add(&sc->media, mode_ifm, mode_cap_mask, NULL); + ifmedia_add(&sc->media, mode_ifm, 0, NULL); +#ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS /* Respond-only. If using AN, we implicitly * offer symmetric as well, but that doesn't * mean we *have* to generate pause frames. */ - mode_cap_mask |= cap_mask & ((1 << EFX_PHY_CAP_PAUSE) | - (1 << EFX_PHY_CAP_ASYM)); mode_ifm |= IFM_ETH_RXPAUSE; - ifmedia_add(&sc->media, mode_ifm, mode_cap_mask, NULL); + ifmedia_add(&sc->media, mode_ifm, 0, NULL); /* Symmetric */ - mode_cap_mask &= ~(1 << EFX_PHY_CAP_ASYM); mode_ifm |= IFM_ETH_TXPAUSE; -#else /* !SFXGE_HAVE_PAUSE_MEDIAOPTS */ - mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_PAUSE); + ifmedia_add(&sc->media, mode_ifm, 0, NULL); #endif - ifmedia_add(&sc->media, mode_ifm, mode_cap_mask, NULL); /* Link modes are numbered in order of speed, * so assume the last one available is the best. */ best_mode_ifm = mode_ifm; } } if (cap_mask & (1 << EFX_PHY_CAP_AN)) { /* Add autoselect mode. */ mode_ifm = IFM_ETHER | IFM_AUTO; - ifmedia_add(&sc->media, mode_ifm, - cap_mask & ~(1 << EFX_PHY_CAP_ASYM), NULL); + ifmedia_add(&sc->media, mode_ifm, 0, NULL); best_mode_ifm = mode_ifm; } if (best_mode_ifm != 0) ifmedia_set(&sc->media, best_mode_ifm); /* Now discard port state until interface is started. */ efx_port_fini(sc->enp); out2: efx_nic_fini(sc->enp); out: return (rc); } Index: projects/ci20_mips/sys/dev/sfxge/sfxge_rx.c =================================================================== --- projects/ci20_mips/sys/dev/sfxge/sfxge_rx.c (revision 283030) +++ projects/ci20_mips/sys/dev/sfxge/sfxge_rx.c (revision 283031) @@ -1,1315 +1,1339 @@ /*- * Copyright (c) 2010-2011 Solarflare Communications, Inc. * All rights reserved. * * This software was developed in part by Philip Paeps under contract for * Solarflare Communications, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common/efx.h" #include "sfxge.h" #include "sfxge_rx.h" #define RX_REFILL_THRESHOLD(_entries) (EFX_RXQ_LIMIT(_entries) * 9 / 10) #ifdef SFXGE_LRO SYSCTL_NODE(_hw_sfxge, OID_AUTO, lro, CTLFLAG_RD, NULL, "Large receive offload (LRO) parameters"); #define SFXGE_LRO_PARAM(_param) SFXGE_PARAM(lro._param) /* Size of the LRO hash table. Must be a power of 2. A larger table * means we can accelerate a larger number of streams. */ static unsigned lro_table_size = 128; TUNABLE_INT(SFXGE_LRO_PARAM(table_size), &lro_table_size); SYSCTL_UINT(_hw_sfxge_lro, OID_AUTO, table_size, CTLFLAG_RDTUN, &lro_table_size, 0, "Size of the LRO hash table (must be a power of 2)"); /* Maximum length of a hash chain. If chains get too long then the lookup * time increases and may exceed the benefit of LRO. */ static unsigned lro_chain_max = 20; TUNABLE_INT(SFXGE_LRO_PARAM(chain_max), &lro_chain_max); SYSCTL_UINT(_hw_sfxge_lro, OID_AUTO, chain_max, CTLFLAG_RDTUN, &lro_chain_max, 0, "The maximum length of a hash chain"); /* Maximum time (in ticks) that a connection can be idle before it's LRO * state is discarded. */ static unsigned lro_idle_ticks; /* initialised in sfxge_rx_init() */ TUNABLE_INT(SFXGE_LRO_PARAM(idle_ticks), &lro_idle_ticks); SYSCTL_UINT(_hw_sfxge_lro, OID_AUTO, idle_ticks, CTLFLAG_RDTUN, &lro_idle_ticks, 0, "The maximum time (in ticks) that a connection can be idle " "before it's LRO state is discarded"); /* Number of packets with payload that must arrive in-order before a * connection is eligible for LRO. The idea is we should avoid coalescing * segments when the sender is in slow-start because reducing the ACK rate * can damage performance. */ static int lro_slow_start_packets = 2000; TUNABLE_INT(SFXGE_LRO_PARAM(slow_start_packets), &lro_slow_start_packets); SYSCTL_UINT(_hw_sfxge_lro, OID_AUTO, slow_start_packets, CTLFLAG_RDTUN, &lro_slow_start_packets, 0, "Number of packets with payload that must arrive in-order before " "a connection is eligible for LRO"); /* Number of packets with payload that must arrive in-order following loss * before a connection is eligible for LRO. The idea is we should avoid * coalescing segments when the sender is recovering from loss, because * reducing the ACK rate can damage performance. */ static int lro_loss_packets = 20; TUNABLE_INT(SFXGE_LRO_PARAM(loss_packets), &lro_loss_packets); SYSCTL_UINT(_hw_sfxge_lro, OID_AUTO, loss_packets, CTLFLAG_RDTUN, &lro_loss_packets, 0, "Number of packets with payload that must arrive in-order " "following loss before a connection is eligible for LRO"); /* Flags for sfxge_lro_conn::l2_id; must not collide with EVL_VLID_MASK */ #define SFXGE_LRO_L2_ID_VLAN 0x4000 #define SFXGE_LRO_L2_ID_IPV6 0x8000 #define SFXGE_LRO_CONN_IS_VLAN_ENCAP(c) ((c)->l2_id & SFXGE_LRO_L2_ID_VLAN) #define SFXGE_LRO_CONN_IS_TCPIPV4(c) (!((c)->l2_id & SFXGE_LRO_L2_ID_IPV6)) /* Compare IPv6 addresses, avoiding conditional branches */ static unsigned long ipv6_addr_cmp(const struct in6_addr *left, const struct in6_addr *right) { #if LONG_BIT == 64 const uint64_t *left64 = (const uint64_t *)left; const uint64_t *right64 = (const uint64_t *)right; return (left64[0] - right64[0]) | (left64[1] - right64[1]); #else return (left->s6_addr32[0] - right->s6_addr32[0]) | (left->s6_addr32[1] - right->s6_addr32[1]) | (left->s6_addr32[2] - right->s6_addr32[2]) | (left->s6_addr32[3] - right->s6_addr32[3]); #endif } #endif /* SFXGE_LRO */ void sfxge_rx_qflush_done(struct sfxge_rxq *rxq) { rxq->flush_state = SFXGE_FLUSH_DONE; } void sfxge_rx_qflush_failed(struct sfxge_rxq *rxq) { rxq->flush_state = SFXGE_FLUSH_FAILED; } static uint8_t toep_key[] = { 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa }; static void sfxge_rx_post_refill(void *arg) { struct sfxge_rxq *rxq = arg; struct sfxge_softc *sc; unsigned int index; struct sfxge_evq *evq; uint16_t magic; sc = rxq->sc; index = rxq->index; evq = sc->evq[index]; magic = SFXGE_MAGIC_RX_QREFILL | index; /* This is guaranteed due to the start/stop order of rx and ev */ KASSERT(evq->init_state == SFXGE_EVQ_STARTED, ("evq not started")); KASSERT(rxq->init_state == SFXGE_RXQ_STARTED, ("rxq not started")); efx_ev_qpost(evq->common, magic); } static void sfxge_rx_schedule_refill(struct sfxge_rxq *rxq, boolean_t retrying) { /* Initially retry after 100 ms, but back off in case of * repeated failures as we probably have to wait for the * administrator to raise the pool limit. */ if (retrying) rxq->refill_delay = min(rxq->refill_delay * 2, 10 * hz); else rxq->refill_delay = hz / 10; callout_reset_curcpu(&rxq->refill_callout, rxq->refill_delay, sfxge_rx_post_refill, rxq); } static struct mbuf *sfxge_rx_alloc_mbuf(struct sfxge_softc *sc) { struct mb_args args; struct mbuf *m; /* Allocate mbuf structure */ args.flags = M_PKTHDR; args.type = MT_DATA; m = (struct mbuf *)uma_zalloc_arg(zone_mbuf, &args, M_NOWAIT); /* Allocate (and attach) packet buffer */ if (m != NULL && !uma_zalloc_arg(sc->rx_buffer_zone, m, M_NOWAIT)) { uma_zfree(zone_mbuf, m); m = NULL; } return (m); } #define SFXGE_REFILL_BATCH 64 static void sfxge_rx_qfill(struct sfxge_rxq *rxq, unsigned int target, boolean_t retrying) { struct sfxge_softc *sc; unsigned int index; struct sfxge_evq *evq; unsigned int batch; unsigned int rxfill; unsigned int mblksize; int ntodo; efsys_dma_addr_t addr[SFXGE_REFILL_BATCH]; sc = rxq->sc; index = rxq->index; evq = sc->evq[index]; prefetch_read_many(sc->enp); prefetch_read_many(rxq->common); SFXGE_EVQ_LOCK_ASSERT_OWNED(evq); if (__predict_false(rxq->init_state != SFXGE_RXQ_STARTED)) return; rxfill = rxq->added - rxq->completed; KASSERT(rxfill <= EFX_RXQ_LIMIT(rxq->entries), ("rxfill > EFX_RXQ_LIMIT(rxq->entries)")); ntodo = min(EFX_RXQ_LIMIT(rxq->entries) - rxfill, target); KASSERT(ntodo <= EFX_RXQ_LIMIT(rxq->entries), ("ntodo > EFX_RQX_LIMIT(rxq->entries)")); if (ntodo == 0) return; batch = 0; mblksize = sc->rx_buffer_size; while (ntodo-- > 0) { unsigned int id; struct sfxge_rx_sw_desc *rx_desc; bus_dma_segment_t seg; struct mbuf *m; id = (rxq->added + batch) & rxq->ptr_mask; rx_desc = &rxq->queue[id]; KASSERT(rx_desc->mbuf == NULL, ("rx_desc->mbuf != NULL")); rx_desc->flags = EFX_DISCARD; m = rx_desc->mbuf = sfxge_rx_alloc_mbuf(sc); if (m == NULL) break; sfxge_map_mbuf_fast(rxq->mem.esm_tag, rxq->mem.esm_map, m, &seg); addr[batch++] = seg.ds_addr; if (batch == SFXGE_REFILL_BATCH) { efx_rx_qpost(rxq->common, addr, mblksize, batch, rxq->completed, rxq->added); rxq->added += batch; batch = 0; } } if (ntodo != 0) sfxge_rx_schedule_refill(rxq, retrying); if (batch != 0) { efx_rx_qpost(rxq->common, addr, mblksize, batch, rxq->completed, rxq->added); rxq->added += batch; } /* Make the descriptors visible to the hardware */ bus_dmamap_sync(rxq->mem.esm_tag, rxq->mem.esm_map, BUS_DMASYNC_PREWRITE); efx_rx_qpush(rxq->common, rxq->added); } void sfxge_rx_qrefill(struct sfxge_rxq *rxq) { if (__predict_false(rxq->init_state != SFXGE_RXQ_STARTED)) return; /* Make sure the queue is full */ sfxge_rx_qfill(rxq, EFX_RXQ_LIMIT(rxq->entries), B_TRUE); } static void __sfxge_rx_deliver(struct sfxge_softc *sc, struct mbuf *m) { struct ifnet *ifp = sc->ifnet; m->m_pkthdr.rcvif = ifp; m->m_pkthdr.csum_data = 0xffff; ifp->if_input(ifp, m); } static void sfxge_rx_deliver(struct sfxge_softc *sc, struct sfxge_rx_sw_desc *rx_desc) { struct mbuf *m = rx_desc->mbuf; int flags = rx_desc->flags; int csum_flags; /* Convert checksum flags */ csum_flags = (flags & EFX_CKSUM_IPV4) ? (CSUM_IP_CHECKED | CSUM_IP_VALID) : 0; if (flags & EFX_CKSUM_TCPUDP) csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; if (flags & (EFX_PKT_IPV4 | EFX_PKT_IPV6)) { m->m_pkthdr.flowid = EFX_RX_HASH_VALUE(EFX_RX_HASHALG_TOEPLITZ, mtod(m, uint8_t *)); /* The hash covers a 4-tuple for TCP only */ M_HASHTYPE_SET(m, (flags & EFX_PKT_IPV4) ? ((flags & EFX_PKT_TCP) ? M_HASHTYPE_RSS_TCP_IPV4 : M_HASHTYPE_RSS_IPV4) : ((flags & EFX_PKT_TCP) ? M_HASHTYPE_RSS_TCP_IPV6 : M_HASHTYPE_RSS_IPV6)); } m->m_data += sc->rx_prefix_size; m->m_len = rx_desc->size - sc->rx_prefix_size; m->m_pkthdr.len = m->m_len; m->m_pkthdr.csum_flags = csum_flags; __sfxge_rx_deliver(sc, rx_desc->mbuf); rx_desc->flags = EFX_DISCARD; rx_desc->mbuf = NULL; } #ifdef SFXGE_LRO static void sfxge_lro_deliver(struct sfxge_lro_state *st, struct sfxge_lro_conn *c) { struct sfxge_softc *sc = st->sc; struct mbuf *m = c->mbuf; struct tcphdr *c_th; int csum_flags; KASSERT(m, ("no mbuf to deliver")); ++st->n_bursts; /* Finish off packet munging and recalculate IP header checksum. */ if (SFXGE_LRO_CONN_IS_TCPIPV4(c)) { struct ip *iph = c->nh; iph->ip_len = htons(iph->ip_len); iph->ip_sum = 0; iph->ip_sum = in_cksum_hdr(iph); c_th = (struct tcphdr *)(iph + 1); csum_flags = (CSUM_DATA_VALID | CSUM_PSEUDO_HDR | CSUM_IP_CHECKED | CSUM_IP_VALID); } else { struct ip6_hdr *iph = c->nh; iph->ip6_plen = htons(iph->ip6_plen); c_th = (struct tcphdr *)(iph + 1); csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR; } c_th->th_win = c->th_last->th_win; c_th->th_ack = c->th_last->th_ack; if (c_th->th_off == c->th_last->th_off) { /* Copy TCP options (take care to avoid going negative). */ int optlen = ((c_th->th_off - 5) & 0xf) << 2u; memcpy(c_th + 1, c->th_last + 1, optlen); } m->m_pkthdr.flowid = c->conn_hash; M_HASHTYPE_SET(m, SFXGE_LRO_CONN_IS_TCPIPV4(c) ? M_HASHTYPE_RSS_TCP_IPV4 : M_HASHTYPE_RSS_TCP_IPV6); m->m_pkthdr.csum_flags = csum_flags; __sfxge_rx_deliver(sc, m); c->mbuf = NULL; c->delivered = 1; } /* Drop the given connection, and add it to the free list. */ static void sfxge_lro_drop(struct sfxge_rxq *rxq, struct sfxge_lro_conn *c) { unsigned bucket; KASSERT(!c->mbuf, ("found orphaned mbuf")); if (c->next_buf.mbuf != NULL) { sfxge_rx_deliver(rxq->sc, &c->next_buf); LIST_REMOVE(c, active_link); } bucket = c->conn_hash & rxq->lro.conns_mask; KASSERT(rxq->lro.conns_n[bucket] > 0, ("LRO: bucket fill level wrong")); --rxq->lro.conns_n[bucket]; TAILQ_REMOVE(&rxq->lro.conns[bucket], c, link); TAILQ_INSERT_HEAD(&rxq->lro.free_conns, c, link); } /* Stop tracking connections that have gone idle in order to keep hash * chains short. */ static void sfxge_lro_purge_idle(struct sfxge_rxq *rxq, unsigned now) { struct sfxge_lro_conn *c; unsigned i; KASSERT(LIST_EMPTY(&rxq->lro.active_conns), ("found active connections")); rxq->lro.last_purge_ticks = now; for (i = 0; i <= rxq->lro.conns_mask; ++i) { if (TAILQ_EMPTY(&rxq->lro.conns[i])) continue; c = TAILQ_LAST(&rxq->lro.conns[i], sfxge_lro_tailq); if (now - c->last_pkt_ticks > lro_idle_ticks) { ++rxq->lro.n_drop_idle; sfxge_lro_drop(rxq, c); } } } static void sfxge_lro_merge(struct sfxge_lro_state *st, struct sfxge_lro_conn *c, struct mbuf *mbuf, struct tcphdr *th) { struct tcphdr *c_th; /* Tack the new mbuf onto the chain. */ KASSERT(!mbuf->m_next, ("mbuf already chained")); c->mbuf_tail->m_next = mbuf; c->mbuf_tail = mbuf; /* Increase length appropriately */ c->mbuf->m_pkthdr.len += mbuf->m_len; /* Update the connection state flags */ if (SFXGE_LRO_CONN_IS_TCPIPV4(c)) { struct ip *iph = c->nh; iph->ip_len += mbuf->m_len; c_th = (struct tcphdr *)(iph + 1); } else { struct ip6_hdr *iph = c->nh; iph->ip6_plen += mbuf->m_len; c_th = (struct tcphdr *)(iph + 1); } c_th->th_flags |= (th->th_flags & TH_PUSH); c->th_last = th; ++st->n_merges; /* Pass packet up now if another segment could overflow the IP * length. */ if (c->mbuf->m_pkthdr.len > 65536 - 9200) sfxge_lro_deliver(st, c); } static void sfxge_lro_start(struct sfxge_lro_state *st, struct sfxge_lro_conn *c, struct mbuf *mbuf, void *nh, struct tcphdr *th) { /* Start the chain */ c->mbuf = mbuf; c->mbuf_tail = c->mbuf; c->nh = nh; c->th_last = th; mbuf->m_pkthdr.len = mbuf->m_len; /* Mangle header fields for later processing */ if (SFXGE_LRO_CONN_IS_TCPIPV4(c)) { struct ip *iph = nh; iph->ip_len = ntohs(iph->ip_len); } else { struct ip6_hdr *iph = nh; iph->ip6_plen = ntohs(iph->ip6_plen); } } /* Try to merge or otherwise hold or deliver (as appropriate) the * packet buffered for this connection (c->next_buf). Return a flag * indicating whether the connection is still active for LRO purposes. */ static int sfxge_lro_try_merge(struct sfxge_rxq *rxq, struct sfxge_lro_conn *c) { struct sfxge_rx_sw_desc *rx_buf = &c->next_buf; char *eh = c->next_eh; int data_length, hdr_length, dont_merge; unsigned th_seq, pkt_length; struct tcphdr *th; unsigned now; if (SFXGE_LRO_CONN_IS_TCPIPV4(c)) { struct ip *iph = c->next_nh; th = (struct tcphdr *)(iph + 1); pkt_length = ntohs(iph->ip_len) + (char *) iph - eh; } else { struct ip6_hdr *iph = c->next_nh; th = (struct tcphdr *)(iph + 1); pkt_length = ntohs(iph->ip6_plen) + (char *) th - eh; } hdr_length = (char *) th + th->th_off * 4 - eh; data_length = (min(pkt_length, rx_buf->size - rxq->sc->rx_prefix_size) - hdr_length); th_seq = ntohl(th->th_seq); dont_merge = ((data_length <= 0) | (th->th_flags & (TH_URG | TH_SYN | TH_RST | TH_FIN))); /* Check for options other than aligned timestamp. */ if (th->th_off != 5) { const uint32_t *opt_ptr = (const uint32_t *) (th + 1); if (th->th_off == 8 && opt_ptr[0] == ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) { /* timestamp option -- okay */ } else { dont_merge = 1; } } if (__predict_false(th_seq != c->next_seq)) { /* Out-of-order, so start counting again. */ if (c->mbuf != NULL) sfxge_lro_deliver(&rxq->lro, c); c->n_in_order_pkts -= lro_loss_packets; c->next_seq = th_seq + data_length; ++rxq->lro.n_misorder; goto deliver_buf_out; } c->next_seq = th_seq + data_length; now = ticks; if (now - c->last_pkt_ticks > lro_idle_ticks) { ++rxq->lro.n_drop_idle; if (c->mbuf != NULL) sfxge_lro_deliver(&rxq->lro, c); sfxge_lro_drop(rxq, c); return (0); } c->last_pkt_ticks = ticks; if (c->n_in_order_pkts < lro_slow_start_packets) { /* May be in slow-start, so don't merge. */ ++rxq->lro.n_slow_start; ++c->n_in_order_pkts; goto deliver_buf_out; } if (__predict_false(dont_merge)) { if (c->mbuf != NULL) sfxge_lro_deliver(&rxq->lro, c); if (th->th_flags & (TH_FIN | TH_RST)) { ++rxq->lro.n_drop_closed; sfxge_lro_drop(rxq, c); return (0); } goto deliver_buf_out; } rx_buf->mbuf->m_data += rxq->sc->rx_prefix_size; if (__predict_true(c->mbuf != NULL)) { /* Remove headers and any padding */ rx_buf->mbuf->m_data += hdr_length; rx_buf->mbuf->m_len = data_length; sfxge_lro_merge(&rxq->lro, c, rx_buf->mbuf, th); } else { /* Remove any padding */ rx_buf->mbuf->m_len = pkt_length; sfxge_lro_start(&rxq->lro, c, rx_buf->mbuf, c->next_nh, th); } rx_buf->mbuf = NULL; return (1); deliver_buf_out: sfxge_rx_deliver(rxq->sc, rx_buf); return (1); } static void sfxge_lro_new_conn(struct sfxge_lro_state *st, uint32_t conn_hash, uint16_t l2_id, void *nh, struct tcphdr *th) { unsigned bucket = conn_hash & st->conns_mask; struct sfxge_lro_conn *c; if (st->conns_n[bucket] >= lro_chain_max) { ++st->n_too_many; return; } if (!TAILQ_EMPTY(&st->free_conns)) { c = TAILQ_FIRST(&st->free_conns); TAILQ_REMOVE(&st->free_conns, c, link); } else { c = malloc(sizeof(*c), M_SFXGE, M_NOWAIT); if (c == NULL) return; c->mbuf = NULL; c->next_buf.mbuf = NULL; } /* Create the connection tracking data */ ++st->conns_n[bucket]; TAILQ_INSERT_HEAD(&st->conns[bucket], c, link); c->l2_id = l2_id; c->conn_hash = conn_hash; c->source = th->th_sport; c->dest = th->th_dport; c->n_in_order_pkts = 0; c->last_pkt_ticks = *(volatile int *)&ticks; c->delivered = 0; ++st->n_new_stream; /* NB. We don't initialise c->next_seq, and it doesn't matter what * value it has. Most likely the next packet received for this * connection will not match -- no harm done. */ } /* Process mbuf and decide whether to dispatch it to the stack now or * later. */ static void sfxge_lro(struct sfxge_rxq *rxq, struct sfxge_rx_sw_desc *rx_buf) { struct sfxge_softc *sc = rxq->sc; struct mbuf *m = rx_buf->mbuf; struct ether_header *eh; struct sfxge_lro_conn *c; uint16_t l2_id; uint16_t l3_proto; void *nh; struct tcphdr *th; uint32_t conn_hash; unsigned bucket; /* Get the hardware hash */ conn_hash = EFX_RX_HASH_VALUE(EFX_RX_HASHALG_TOEPLITZ, mtod(m, uint8_t *)); eh = (struct ether_header *)(m->m_data + sc->rx_prefix_size); if (eh->ether_type == htons(ETHERTYPE_VLAN)) { struct ether_vlan_header *veh = (struct ether_vlan_header *)eh; l2_id = EVL_VLANOFTAG(ntohs(veh->evl_tag)) | SFXGE_LRO_L2_ID_VLAN; l3_proto = veh->evl_proto; nh = veh + 1; } else { l2_id = 0; l3_proto = eh->ether_type; nh = eh + 1; } /* Check whether this is a suitable packet (unfragmented * TCP/IPv4 or TCP/IPv6). If so, find the TCP header and * length, and compute a hash if necessary. If not, return. */ if (l3_proto == htons(ETHERTYPE_IP)) { struct ip *iph = nh; - if ((iph->ip_p - IPPROTO_TCP) | - (iph->ip_hl - (sizeof(*iph) >> 2u)) | + + KASSERT(iph->ip_p == IPPROTO_TCP, + ("IPv4 protocol is not TCP, but packet marker is set")); + if ((iph->ip_hl - (sizeof(*iph) >> 2u)) | (iph->ip_off & htons(IP_MF | IP_OFFMASK))) goto deliver_now; th = (struct tcphdr *)(iph + 1); } else if (l3_proto == htons(ETHERTYPE_IPV6)) { struct ip6_hdr *iph = nh; - if (iph->ip6_nxt != IPPROTO_TCP) - goto deliver_now; + + KASSERT(iph->ip6_nxt == IPPROTO_TCP, + ("IPv6 next header is not TCP, but packet marker is set")); l2_id |= SFXGE_LRO_L2_ID_IPV6; th = (struct tcphdr *)(iph + 1); } else { goto deliver_now; } bucket = conn_hash & rxq->lro.conns_mask; TAILQ_FOREACH(c, &rxq->lro.conns[bucket], link) { if ((c->l2_id - l2_id) | (c->conn_hash - conn_hash)) continue; if ((c->source - th->th_sport) | (c->dest - th->th_dport)) continue; if (c->mbuf != NULL) { if (SFXGE_LRO_CONN_IS_TCPIPV4(c)) { struct ip *c_iph, *iph = nh; c_iph = c->nh; if ((c_iph->ip_src.s_addr - iph->ip_src.s_addr) | (c_iph->ip_dst.s_addr - iph->ip_dst.s_addr)) continue; } else { struct ip6_hdr *c_iph, *iph = nh; c_iph = c->nh; if (ipv6_addr_cmp(&c_iph->ip6_src, &iph->ip6_src) | ipv6_addr_cmp(&c_iph->ip6_dst, &iph->ip6_dst)) continue; } } /* Re-insert at head of list to reduce lookup time. */ TAILQ_REMOVE(&rxq->lro.conns[bucket], c, link); TAILQ_INSERT_HEAD(&rxq->lro.conns[bucket], c, link); if (c->next_buf.mbuf != NULL) { if (!sfxge_lro_try_merge(rxq, c)) goto deliver_now; } else { LIST_INSERT_HEAD(&rxq->lro.active_conns, c, active_link); } c->next_buf = *rx_buf; c->next_eh = eh; c->next_nh = nh; rx_buf->mbuf = NULL; rx_buf->flags = EFX_DISCARD; return; } sfxge_lro_new_conn(&rxq->lro, conn_hash, l2_id, nh, th); deliver_now: sfxge_rx_deliver(sc, rx_buf); } static void sfxge_lro_end_of_burst(struct sfxge_rxq *rxq) { struct sfxge_lro_state *st = &rxq->lro; struct sfxge_lro_conn *c; unsigned t; while (!LIST_EMPTY(&st->active_conns)) { c = LIST_FIRST(&st->active_conns); if (!c->delivered && c->mbuf != NULL) sfxge_lro_deliver(st, c); if (sfxge_lro_try_merge(rxq, c)) { if (c->mbuf != NULL) sfxge_lro_deliver(st, c); LIST_REMOVE(c, active_link); } c->delivered = 0; } t = *(volatile int *)&ticks; if (__predict_false(t != st->last_purge_ticks)) sfxge_lro_purge_idle(rxq, t); } #else /* !SFXGE_LRO */ static void sfxge_lro(struct sfxge_rxq *rxq, struct sfxge_rx_sw_desc *rx_buf) { } static void sfxge_lro_end_of_burst(struct sfxge_rxq *rxq) { } #endif /* SFXGE_LRO */ void sfxge_rx_qcomplete(struct sfxge_rxq *rxq, boolean_t eop) { struct sfxge_softc *sc = rxq->sc; - int lro_enabled = sc->ifnet->if_capenable & IFCAP_LRO; + int if_capenable = sc->ifnet->if_capenable; + int lro_enabled = if_capenable & IFCAP_LRO; unsigned int index; struct sfxge_evq *evq; unsigned int completed; unsigned int level; struct mbuf *m; struct sfxge_rx_sw_desc *prev = NULL; index = rxq->index; evq = sc->evq[index]; SFXGE_EVQ_LOCK_ASSERT_OWNED(evq); completed = rxq->completed; while (completed != rxq->pending) { unsigned int id; struct sfxge_rx_sw_desc *rx_desc; id = completed++ & rxq->ptr_mask; rx_desc = &rxq->queue[id]; m = rx_desc->mbuf; if (__predict_false(rxq->init_state != SFXGE_RXQ_STARTED)) goto discard; if (rx_desc->flags & (EFX_ADDR_MISMATCH | EFX_DISCARD)) goto discard; prefetch_read_many(mtod(m, caddr_t)); - /* Check for loopback packets */ - if (!(rx_desc->flags & EFX_PKT_IPV4) && - !(rx_desc->flags & EFX_PKT_IPV6)) { - struct ether_header *etherhp; + switch (rx_desc->flags & (EFX_PKT_IPV4 | EFX_PKT_IPV6)) { + case EFX_PKT_IPV4: + if (~if_capenable & IFCAP_RXCSUM) + rx_desc->flags &= + ~(EFX_CKSUM_IPV4 | EFX_CKSUM_TCPUDP); + break; + case EFX_PKT_IPV6: + if (~if_capenable & IFCAP_RXCSUM_IPV6) + rx_desc->flags &= ~EFX_CKSUM_TCPUDP; + break; + case 0: + /* Check for loopback packets */ + { + struct ether_header *etherhp; - /*LINTED*/ - etherhp = mtod(m, struct ether_header *); + /*LINTED*/ + etherhp = mtod(m, struct ether_header *); - if (etherhp->ether_type == - htons(SFXGE_ETHERTYPE_LOOPBACK)) { - EFSYS_PROBE(loopback); + if (etherhp->ether_type == + htons(SFXGE_ETHERTYPE_LOOPBACK)) { + EFSYS_PROBE(loopback); - rxq->loopback++; - goto discard; + rxq->loopback++; + goto discard; + } } + break; + default: + KASSERT(B_FALSE, + ("Rx descriptor with both IPv4 and IPv6 flags")); + goto discard; } /* Pass packet up the stack or into LRO (pipelined) */ if (prev != NULL) { - if (lro_enabled) + if (lro_enabled && + ((prev->flags & (EFX_PKT_TCP | EFX_CKSUM_TCPUDP)) == + (EFX_PKT_TCP | EFX_CKSUM_TCPUDP))) sfxge_lro(rxq, prev); else sfxge_rx_deliver(sc, prev); } prev = rx_desc; continue; discard: /* Return the packet to the pool */ m_free(m); rx_desc->mbuf = NULL; } rxq->completed = completed; level = rxq->added - rxq->completed; /* Pass last packet up the stack or into LRO */ if (prev != NULL) { - if (lro_enabled) + if (lro_enabled && + ((prev->flags & (EFX_PKT_TCP | EFX_CKSUM_TCPUDP)) == + (EFX_PKT_TCP | EFX_CKSUM_TCPUDP))) sfxge_lro(rxq, prev); else sfxge_rx_deliver(sc, prev); } /* * If there are any pending flows and this is the end of the * poll then they must be completed. */ if (eop) sfxge_lro_end_of_burst(rxq); /* Top up the queue if necessary */ if (level < rxq->refill_threshold) sfxge_rx_qfill(rxq, EFX_RXQ_LIMIT(rxq->entries), B_FALSE); } static void sfxge_rx_qstop(struct sfxge_softc *sc, unsigned int index) { struct sfxge_rxq *rxq; struct sfxge_evq *evq; unsigned int count; rxq = sc->rxq[index]; evq = sc->evq[index]; SFXGE_EVQ_LOCK(evq); KASSERT(rxq->init_state == SFXGE_RXQ_STARTED, ("rxq not started")); rxq->init_state = SFXGE_RXQ_INITIALIZED; callout_stop(&rxq->refill_callout); again: rxq->flush_state = SFXGE_FLUSH_PENDING; /* Flush the receive queue */ efx_rx_qflush(rxq->common); SFXGE_EVQ_UNLOCK(evq); count = 0; do { /* Spin for 100 ms */ DELAY(100000); if (rxq->flush_state != SFXGE_FLUSH_PENDING) break; } while (++count < 20); SFXGE_EVQ_LOCK(evq); if (rxq->flush_state == SFXGE_FLUSH_FAILED) goto again; rxq->flush_state = SFXGE_FLUSH_DONE; rxq->pending = rxq->added; sfxge_rx_qcomplete(rxq, B_TRUE); KASSERT(rxq->completed == rxq->pending, ("rxq->completed != rxq->pending")); rxq->added = 0; rxq->pending = 0; rxq->completed = 0; rxq->loopback = 0; /* Destroy the common code receive queue. */ efx_rx_qdestroy(rxq->common); efx_sram_buf_tbl_clear(sc->enp, rxq->buf_base_id, EFX_RXQ_NBUFS(sc->rxq_entries)); SFXGE_EVQ_UNLOCK(evq); } static int sfxge_rx_qstart(struct sfxge_softc *sc, unsigned int index) { struct sfxge_rxq *rxq; efsys_mem_t *esmp; struct sfxge_evq *evq; int rc; rxq = sc->rxq[index]; esmp = &rxq->mem; evq = sc->evq[index]; KASSERT(rxq->init_state == SFXGE_RXQ_INITIALIZED, ("rxq->init_state != SFXGE_RXQ_INITIALIZED")); KASSERT(evq->init_state == SFXGE_EVQ_STARTED, ("evq->init_state != SFXGE_EVQ_STARTED")); /* Program the buffer table. */ if ((rc = efx_sram_buf_tbl_set(sc->enp, rxq->buf_base_id, esmp, EFX_RXQ_NBUFS(sc->rxq_entries))) != 0) return (rc); /* Create the common code receive queue. */ if ((rc = efx_rx_qcreate(sc->enp, index, index, EFX_RXQ_TYPE_DEFAULT, esmp, sc->rxq_entries, rxq->buf_base_id, evq->common, &rxq->common)) != 0) goto fail; SFXGE_EVQ_LOCK(evq); /* Enable the receive queue. */ efx_rx_qenable(rxq->common); rxq->init_state = SFXGE_RXQ_STARTED; /* Try to fill the queue from the pool. */ sfxge_rx_qfill(rxq, EFX_RXQ_LIMIT(sc->rxq_entries), B_FALSE); SFXGE_EVQ_UNLOCK(evq); return (0); fail: efx_sram_buf_tbl_clear(sc->enp, rxq->buf_base_id, EFX_RXQ_NBUFS(sc->rxq_entries)); return (rc); } void sfxge_rx_stop(struct sfxge_softc *sc) { int index; /* Stop the receive queue(s) */ index = sc->rxq_count; while (--index >= 0) sfxge_rx_qstop(sc, index); sc->rx_prefix_size = 0; sc->rx_buffer_size = 0; efx_rx_fini(sc->enp); } int sfxge_rx_start(struct sfxge_softc *sc) { struct sfxge_intr *intr; int index; int rc; intr = &sc->intr; /* Initialize the common code receive module. */ if ((rc = efx_rx_init(sc->enp)) != 0) return (rc); /* Calculate the receive packet buffer size. */ sc->rx_prefix_size = EFX_RX_PREFIX_SIZE; sc->rx_buffer_size = (EFX_MAC_PDU(sc->ifnet->if_mtu) + sc->rx_prefix_size); /* Select zone for packet buffers */ if (sc->rx_buffer_size <= MCLBYTES) sc->rx_buffer_zone = zone_clust; else if (sc->rx_buffer_size <= MJUMPAGESIZE) sc->rx_buffer_zone = zone_jumbop; else if (sc->rx_buffer_size <= MJUM9BYTES) sc->rx_buffer_zone = zone_jumbo9; else sc->rx_buffer_zone = zone_jumbo16; /* * Set up the scale table. Enable all hash types and hash insertion. */ for (index = 0; index < SFXGE_RX_SCALE_MAX; index++) sc->rx_indir_table[index] = index % sc->rxq_count; if ((rc = efx_rx_scale_tbl_set(sc->enp, sc->rx_indir_table, SFXGE_RX_SCALE_MAX)) != 0) goto fail; (void)efx_rx_scale_mode_set(sc->enp, EFX_RX_HASHALG_TOEPLITZ, (1 << EFX_RX_HASH_IPV4) | (1 << EFX_RX_HASH_TCPIPV4) | (1 << EFX_RX_HASH_IPV6) | (1 << EFX_RX_HASH_TCPIPV6), B_TRUE); if ((rc = efx_rx_scale_toeplitz_ipv4_key_set(sc->enp, toep_key, sizeof(toep_key))) != 0) goto fail; /* Start the receive queue(s). */ for (index = 0; index < sc->rxq_count; index++) { if ((rc = sfxge_rx_qstart(sc, index)) != 0) goto fail2; } return (0); fail2: while (--index >= 0) sfxge_rx_qstop(sc, index); fail: efx_rx_fini(sc->enp); return (rc); } #ifdef SFXGE_LRO static void sfxge_lro_init(struct sfxge_rxq *rxq) { struct sfxge_lro_state *st = &rxq->lro; unsigned i; st->conns_mask = lro_table_size - 1; KASSERT(!((st->conns_mask + 1) & st->conns_mask), ("lro_table_size must be a power of 2")); st->sc = rxq->sc; st->conns = malloc((st->conns_mask + 1) * sizeof(st->conns[0]), M_SFXGE, M_WAITOK); st->conns_n = malloc((st->conns_mask + 1) * sizeof(st->conns_n[0]), M_SFXGE, M_WAITOK); for (i = 0; i <= st->conns_mask; ++i) { TAILQ_INIT(&st->conns[i]); st->conns_n[i] = 0; } LIST_INIT(&st->active_conns); TAILQ_INIT(&st->free_conns); } static void sfxge_lro_fini(struct sfxge_rxq *rxq) { struct sfxge_lro_state *st = &rxq->lro; struct sfxge_lro_conn *c; unsigned i; /* Return cleanly if sfxge_lro_init() has not been called. */ if (st->conns == NULL) return; KASSERT(LIST_EMPTY(&st->active_conns), ("found active connections")); for (i = 0; i <= st->conns_mask; ++i) { while (!TAILQ_EMPTY(&st->conns[i])) { c = TAILQ_LAST(&st->conns[i], sfxge_lro_tailq); sfxge_lro_drop(rxq, c); } } while (!TAILQ_EMPTY(&st->free_conns)) { c = TAILQ_FIRST(&st->free_conns); TAILQ_REMOVE(&st->free_conns, c, link); KASSERT(!c->mbuf, ("found orphaned mbuf")); free(c, M_SFXGE); } free(st->conns_n, M_SFXGE); free(st->conns, M_SFXGE); st->conns = NULL; } #else static void sfxge_lro_init(struct sfxge_rxq *rxq) { } static void sfxge_lro_fini(struct sfxge_rxq *rxq) { } #endif /* SFXGE_LRO */ static void sfxge_rx_qfini(struct sfxge_softc *sc, unsigned int index) { struct sfxge_rxq *rxq; rxq = sc->rxq[index]; KASSERT(rxq->init_state == SFXGE_RXQ_INITIALIZED, ("rxq->init_state != SFXGE_RXQ_INITIALIZED")); /* Free the context array and the flow table. */ free(rxq->queue, M_SFXGE); sfxge_lro_fini(rxq); /* Release DMA memory. */ sfxge_dma_free(&rxq->mem); sc->rxq[index] = NULL; free(rxq, M_SFXGE); } static int sfxge_rx_qinit(struct sfxge_softc *sc, unsigned int index) { struct sfxge_rxq *rxq; struct sfxge_evq *evq; efsys_mem_t *esmp; int rc; KASSERT(index < sc->rxq_count, ("index >= %d", sc->rxq_count)); rxq = malloc(sizeof(struct sfxge_rxq), M_SFXGE, M_ZERO | M_WAITOK); rxq->sc = sc; rxq->index = index; rxq->entries = sc->rxq_entries; rxq->ptr_mask = rxq->entries - 1; rxq->refill_threshold = RX_REFILL_THRESHOLD(rxq->entries); sc->rxq[index] = rxq; esmp = &rxq->mem; evq = sc->evq[index]; /* Allocate and zero DMA space. */ if ((rc = sfxge_dma_alloc(sc, EFX_RXQ_SIZE(sc->rxq_entries), esmp)) != 0) return (rc); /* Allocate buffer table entries. */ sfxge_sram_buf_tbl_alloc(sc, EFX_RXQ_NBUFS(sc->rxq_entries), &rxq->buf_base_id); /* Allocate the context array and the flow table. */ rxq->queue = malloc(sizeof(struct sfxge_rx_sw_desc) * sc->rxq_entries, M_SFXGE, M_WAITOK | M_ZERO); sfxge_lro_init(rxq); callout_init(&rxq->refill_callout, B_TRUE); rxq->init_state = SFXGE_RXQ_INITIALIZED; return (0); } static const struct { const char *name; size_t offset; } sfxge_rx_stats[] = { #define SFXGE_RX_STAT(name, member) \ { #name, offsetof(struct sfxge_rxq, member) } #ifdef SFXGE_LRO SFXGE_RX_STAT(lro_merges, lro.n_merges), SFXGE_RX_STAT(lro_bursts, lro.n_bursts), SFXGE_RX_STAT(lro_slow_start, lro.n_slow_start), SFXGE_RX_STAT(lro_misorder, lro.n_misorder), SFXGE_RX_STAT(lro_too_many, lro.n_too_many), SFXGE_RX_STAT(lro_new_stream, lro.n_new_stream), SFXGE_RX_STAT(lro_drop_idle, lro.n_drop_idle), SFXGE_RX_STAT(lro_drop_closed, lro.n_drop_closed) #endif }; static int sfxge_rx_stat_handler(SYSCTL_HANDLER_ARGS) { struct sfxge_softc *sc = arg1; unsigned int id = arg2; unsigned int sum, index; /* Sum across all RX queues */ sum = 0; for (index = 0; index < sc->rxq_count; index++) sum += *(unsigned int *)((caddr_t)sc->rxq[index] + sfxge_rx_stats[id].offset); return (SYSCTL_OUT(req, &sum, sizeof(sum))); } static void sfxge_rx_stat_init(struct sfxge_softc *sc) { struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev); struct sysctl_oid_list *stat_list; unsigned int id; stat_list = SYSCTL_CHILDREN(sc->stats_node); for (id = 0; id < nitems(sfxge_rx_stats); id++) { SYSCTL_ADD_PROC( ctx, stat_list, OID_AUTO, sfxge_rx_stats[id].name, CTLTYPE_UINT|CTLFLAG_RD, sc, id, sfxge_rx_stat_handler, "IU", ""); } } void sfxge_rx_fini(struct sfxge_softc *sc) { int index; index = sc->rxq_count; while (--index >= 0) sfxge_rx_qfini(sc, index); sc->rxq_count = 0; } int sfxge_rx_init(struct sfxge_softc *sc) { struct sfxge_intr *intr; int index; int rc; #ifdef SFXGE_LRO if (!ISP2(lro_table_size)) { log(LOG_ERR, "%s=%u must be power of 2", SFXGE_LRO_PARAM(table_size), lro_table_size); rc = EINVAL; goto fail_lro_table_size; } if (lro_idle_ticks == 0) lro_idle_ticks = hz / 10 + 1; /* 100 ms */ #endif intr = &sc->intr; sc->rxq_count = intr->n_alloc; KASSERT(intr->state == SFXGE_INTR_INITIALIZED, ("intr->state != SFXGE_INTR_INITIALIZED")); /* Initialize the receive queue(s) - one per interrupt. */ for (index = 0; index < sc->rxq_count; index++) { if ((rc = sfxge_rx_qinit(sc, index)) != 0) goto fail; } sfxge_rx_stat_init(sc); return (0); fail: /* Tear down the receive queue(s). */ while (--index >= 0) sfxge_rx_qfini(sc, index); sc->rxq_count = 0; #ifdef SFXGE_LRO fail_lro_table_size: #endif return (rc); } Index: projects/ci20_mips/sys/dev/sfxge/sfxge_tx.c =================================================================== --- projects/ci20_mips/sys/dev/sfxge/sfxge_tx.c (revision 283030) +++ projects/ci20_mips/sys/dev/sfxge/sfxge_tx.c (revision 283031) @@ -1,1619 +1,1629 @@ /*- * Copyright (c) 2010-2011 Solarflare Communications, Inc. * All rights reserved. * * This software was developed in part by Philip Paeps under contract for * Solarflare Communications, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* Theory of operation: * * Tx queues allocation and mapping * * One Tx queue with enabled checksum offload is allocated per Rx channel * (event queue). Also 2 Tx queues (one without checksum offload and one * with IP checksum offload only) are allocated and bound to event queue 0. * sfxge_txq_type is used as Tx queue label. * * So, event queue plus label mapping to Tx queue index is: * if event queue index is 0, TxQ-index = TxQ-label * [0..SFXGE_TXQ_NTYPES) * else TxQ-index = SFXGE_TXQ_NTYPES + EvQ-index - 1 * See sfxge_get_txq_by_label() sfxge_ev.c */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common/efx.h" #include "sfxge.h" #include "sfxge_tx.h" /* * Estimate maximum number of Tx descriptors required for TSO packet. * With minimum MSS and maximum mbuf length we might need more (even * than a ring-ful of descriptors), but this should not happen in * practice except due to deliberate attack. In that case we will * truncate the output at a packet boundary. */ #define SFXGE_TSO_MAX_DESC \ (SFXGE_TSO_MAX_SEGS * 2 + SFXGE_TX_MAPPING_MAX_SEG - 1) /* * Set the block level to ensure there is space to generate a * large number of descriptors for TSO. */ #define SFXGE_TXQ_BLOCK_LEVEL(_entries) \ (EFX_TXQ_LIMIT(_entries) - SFXGE_TSO_MAX_DESC) #define SFXGE_PARAM_TX_DPL_GET_MAX SFXGE_PARAM(tx_dpl_get_max) static int sfxge_tx_dpl_get_max = SFXGE_TX_DPL_GET_PKT_LIMIT_DEFAULT; TUNABLE_INT(SFXGE_PARAM_TX_DPL_GET_MAX, &sfxge_tx_dpl_get_max); SYSCTL_INT(_hw_sfxge, OID_AUTO, tx_dpl_get_max, CTLFLAG_RDTUN, &sfxge_tx_dpl_get_max, 0, "Maximum number of any packets in deferred packet get-list"); #define SFXGE_PARAM_TX_DPL_GET_NON_TCP_MAX \ SFXGE_PARAM(tx_dpl_get_non_tcp_max) static int sfxge_tx_dpl_get_non_tcp_max = SFXGE_TX_DPL_GET_NON_TCP_PKT_LIMIT_DEFAULT; TUNABLE_INT(SFXGE_PARAM_TX_DPL_GET_NON_TCP_MAX, &sfxge_tx_dpl_get_non_tcp_max); SYSCTL_INT(_hw_sfxge, OID_AUTO, tx_dpl_get_non_tcp_max, CTLFLAG_RDTUN, &sfxge_tx_dpl_get_non_tcp_max, 0, "Maximum number of non-TCP packets in deferred packet get-list"); #define SFXGE_PARAM_TX_DPL_PUT_MAX SFXGE_PARAM(tx_dpl_put_max) static int sfxge_tx_dpl_put_max = SFXGE_TX_DPL_PUT_PKT_LIMIT_DEFAULT; TUNABLE_INT(SFXGE_PARAM_TX_DPL_PUT_MAX, &sfxge_tx_dpl_put_max); SYSCTL_INT(_hw_sfxge, OID_AUTO, tx_dpl_put_max, CTLFLAG_RDTUN, &sfxge_tx_dpl_put_max, 0, "Maximum number of any packets in deferred packet put-list"); static const struct { const char *name; size_t offset; } sfxge_tx_stats[] = { #define SFXGE_TX_STAT(name, member) \ { #name, offsetof(struct sfxge_txq, member) } SFXGE_TX_STAT(tso_bursts, tso_bursts), SFXGE_TX_STAT(tso_packets, tso_packets), SFXGE_TX_STAT(tso_long_headers, tso_long_headers), SFXGE_TX_STAT(tso_pdrop_too_many, tso_pdrop_too_many), SFXGE_TX_STAT(tso_pdrop_no_rsrc, tso_pdrop_no_rsrc), SFXGE_TX_STAT(tx_collapses, collapses), SFXGE_TX_STAT(tx_drops, drops), SFXGE_TX_STAT(tx_get_overflow, get_overflow), SFXGE_TX_STAT(tx_get_non_tcp_overflow, get_non_tcp_overflow), SFXGE_TX_STAT(tx_put_overflow, put_overflow), SFXGE_TX_STAT(tx_netdown_drops, netdown_drops), }; /* Forward declarations. */ static void sfxge_tx_qdpl_service(struct sfxge_txq *txq); static void sfxge_tx_qlist_post(struct sfxge_txq *txq); static void sfxge_tx_qunblock(struct sfxge_txq *txq); static int sfxge_tx_queue_tso(struct sfxge_txq *txq, struct mbuf *mbuf, const bus_dma_segment_t *dma_seg, int n_dma_seg); void sfxge_tx_qcomplete(struct sfxge_txq *txq, struct sfxge_evq *evq) { unsigned int completed; SFXGE_EVQ_LOCK_ASSERT_OWNED(evq); completed = txq->completed; while (completed != txq->pending) { struct sfxge_tx_mapping *stmp; unsigned int id; id = completed++ & txq->ptr_mask; stmp = &txq->stmp[id]; if (stmp->flags & TX_BUF_UNMAP) { bus_dmamap_unload(txq->packet_dma_tag, stmp->map); if (stmp->flags & TX_BUF_MBUF) { struct mbuf *m = stmp->u.mbuf; do m = m_free(m); while (m != NULL); } else { free(stmp->u.heap_buf, M_SFXGE); } stmp->flags = 0; } } txq->completed = completed; /* Check whether we need to unblock the queue. */ mb(); if (txq->blocked) { unsigned int level; level = txq->added - txq->completed; if (level <= SFXGE_TXQ_UNBLOCK_LEVEL(txq->entries)) sfxge_tx_qunblock(txq); } } static unsigned int sfxge_is_mbuf_non_tcp(struct mbuf *mbuf) { /* Absense of TCP checksum flags does not mean that it is non-TCP * but it should be true if user wants to achieve high throughput. */ return (!(mbuf->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))); } /* * Reorder the put list and append it to the get list. */ static void sfxge_tx_qdpl_swizzle(struct sfxge_txq *txq) { struct sfxge_tx_dpl *stdp; struct mbuf *mbuf, *get_next, **get_tailp; volatile uintptr_t *putp; uintptr_t put; unsigned int count; unsigned int non_tcp_count; SFXGE_TXQ_LOCK_ASSERT_OWNED(txq); stdp = &txq->dpl; /* Acquire the put list. */ putp = &stdp->std_put; put = atomic_readandclear_ptr(putp); mbuf = (void *)put; if (mbuf == NULL) return; /* Reverse the put list. */ get_tailp = &mbuf->m_nextpkt; get_next = NULL; count = 0; non_tcp_count = 0; do { struct mbuf *put_next; non_tcp_count += sfxge_is_mbuf_non_tcp(mbuf); put_next = mbuf->m_nextpkt; mbuf->m_nextpkt = get_next; get_next = mbuf; mbuf = put_next; count++; } while (mbuf != NULL); if (count > stdp->std_put_hiwat) stdp->std_put_hiwat = count; /* Append the reversed put list to the get list. */ KASSERT(*get_tailp == NULL, ("*get_tailp != NULL")); *stdp->std_getp = get_next; stdp->std_getp = get_tailp; stdp->std_get_count += count; stdp->std_get_non_tcp_count += non_tcp_count; } static void sfxge_tx_qreap(struct sfxge_txq *txq) { SFXGE_TXQ_LOCK_ASSERT_OWNED(txq); txq->reaped = txq->completed; } static void sfxge_tx_qlist_post(struct sfxge_txq *txq) { unsigned int old_added; unsigned int level; int rc; SFXGE_TXQ_LOCK_ASSERT_OWNED(txq); KASSERT(txq->n_pend_desc != 0, ("txq->n_pend_desc == 0")); KASSERT(txq->n_pend_desc <= SFXGE_TSO_MAX_DESC, ("txq->n_pend_desc too large")); KASSERT(!txq->blocked, ("txq->blocked")); old_added = txq->added; /* Post the fragment list. */ rc = efx_tx_qpost(txq->common, txq->pend_desc, txq->n_pend_desc, txq->reaped, &txq->added); KASSERT(rc == 0, ("efx_tx_qpost() failed")); /* If efx_tx_qpost() had to refragment, our information about * buffers to free may be associated with the wrong * descriptors. */ KASSERT(txq->added - old_added == txq->n_pend_desc, ("efx_tx_qpost() refragmented descriptors")); level = txq->added - txq->reaped; KASSERT(level <= txq->entries, ("overfilled TX queue")); /* Clear the fragment list. */ txq->n_pend_desc = 0; /* Have we reached the block level? */ if (level < SFXGE_TXQ_BLOCK_LEVEL(txq->entries)) return; /* Reap, and check again */ sfxge_tx_qreap(txq); level = txq->added - txq->reaped; if (level < SFXGE_TXQ_BLOCK_LEVEL(txq->entries)) return; txq->blocked = 1; /* * Avoid a race with completion interrupt handling that could leave * the queue blocked. */ mb(); sfxge_tx_qreap(txq); level = txq->added - txq->reaped; if (level < SFXGE_TXQ_BLOCK_LEVEL(txq->entries)) { mb(); txq->blocked = 0; } } static int sfxge_tx_queue_mbuf(struct sfxge_txq *txq, struct mbuf *mbuf) { bus_dmamap_t *used_map; bus_dmamap_t map; bus_dma_segment_t dma_seg[SFXGE_TX_MAPPING_MAX_SEG]; unsigned int id; struct sfxge_tx_mapping *stmp; efx_buffer_t *desc; int n_dma_seg; int rc; int i; KASSERT(!txq->blocked, ("txq->blocked")); if (mbuf->m_pkthdr.csum_flags & CSUM_TSO) prefetch_read_many(mbuf->m_data); if (__predict_false(txq->init_state != SFXGE_TXQ_STARTED)) { rc = EINTR; goto reject; } /* Load the packet for DMA. */ id = txq->added & txq->ptr_mask; stmp = &txq->stmp[id]; rc = bus_dmamap_load_mbuf_sg(txq->packet_dma_tag, stmp->map, mbuf, dma_seg, &n_dma_seg, 0); if (rc == EFBIG) { /* Try again. */ struct mbuf *new_mbuf = m_collapse(mbuf, M_NOWAIT, SFXGE_TX_MAPPING_MAX_SEG); if (new_mbuf == NULL) goto reject; ++txq->collapses; mbuf = new_mbuf; rc = bus_dmamap_load_mbuf_sg(txq->packet_dma_tag, stmp->map, mbuf, dma_seg, &n_dma_seg, 0); } if (rc != 0) goto reject; /* Make the packet visible to the hardware. */ bus_dmamap_sync(txq->packet_dma_tag, stmp->map, BUS_DMASYNC_PREWRITE); used_map = &stmp->map; if (mbuf->m_pkthdr.csum_flags & CSUM_TSO) { rc = sfxge_tx_queue_tso(txq, mbuf, dma_seg, n_dma_seg); if (rc < 0) goto reject_mapped; stmp = &txq->stmp[rc]; } else { /* Add the mapping to the fragment list, and set flags * for the buffer. */ i = 0; for (;;) { desc = &txq->pend_desc[i]; desc->eb_addr = dma_seg[i].ds_addr; desc->eb_size = dma_seg[i].ds_len; if (i == n_dma_seg - 1) { desc->eb_eop = 1; break; } desc->eb_eop = 0; i++; stmp->flags = 0; if (__predict_false(stmp == &txq->stmp[txq->ptr_mask])) stmp = &txq->stmp[0]; else stmp++; } txq->n_pend_desc = n_dma_seg; } /* * If the mapping required more than one descriptor * then we need to associate the DMA map with the last * descriptor, not the first. */ if (used_map != &stmp->map) { map = stmp->map; stmp->map = *used_map; *used_map = map; } stmp->u.mbuf = mbuf; stmp->flags = TX_BUF_UNMAP | TX_BUF_MBUF; /* Post the fragment list. */ sfxge_tx_qlist_post(txq); return (0); reject_mapped: bus_dmamap_unload(txq->packet_dma_tag, *used_map); reject: /* Drop the packet on the floor. */ m_freem(mbuf); ++txq->drops; return (rc); } /* * Drain the deferred packet list into the transmit queue. */ static void sfxge_tx_qdpl_drain(struct sfxge_txq *txq) { struct sfxge_softc *sc; struct sfxge_tx_dpl *stdp; struct mbuf *mbuf, *next; unsigned int count; unsigned int non_tcp_count; unsigned int pushed; int rc; SFXGE_TXQ_LOCK_ASSERT_OWNED(txq); sc = txq->sc; stdp = &txq->dpl; pushed = txq->added; if (__predict_true(txq->init_state == SFXGE_TXQ_STARTED)) { prefetch_read_many(sc->enp); prefetch_read_many(txq->common); } mbuf = stdp->std_get; count = stdp->std_get_count; non_tcp_count = stdp->std_get_non_tcp_count; if (count > stdp->std_get_hiwat) stdp->std_get_hiwat = count; while (count != 0) { KASSERT(mbuf != NULL, ("mbuf == NULL")); next = mbuf->m_nextpkt; mbuf->m_nextpkt = NULL; ETHER_BPF_MTAP(sc->ifnet, mbuf); /* packet capture */ if (next != NULL) prefetch_read_many(next); rc = sfxge_tx_queue_mbuf(txq, mbuf); --count; non_tcp_count -= sfxge_is_mbuf_non_tcp(mbuf); mbuf = next; if (rc != 0) continue; if (txq->blocked) break; /* Push the fragments to the hardware in batches. */ if (txq->added - pushed >= SFXGE_TX_BATCH) { efx_tx_qpush(txq->common, txq->added); pushed = txq->added; } } if (count == 0) { KASSERT(mbuf == NULL, ("mbuf != NULL")); KASSERT(non_tcp_count == 0, ("inconsistent TCP/non-TCP detection")); stdp->std_get = NULL; stdp->std_get_count = 0; stdp->std_get_non_tcp_count = 0; stdp->std_getp = &stdp->std_get; } else { stdp->std_get = mbuf; stdp->std_get_count = count; stdp->std_get_non_tcp_count = non_tcp_count; } if (txq->added != pushed) efx_tx_qpush(txq->common, txq->added); KASSERT(txq->blocked || stdp->std_get_count == 0, ("queue unblocked but count is non-zero")); } #define SFXGE_TX_QDPL_PENDING(_txq) \ ((_txq)->dpl.std_put != 0) /* * Service the deferred packet list. * * NOTE: drops the txq mutex! */ static void sfxge_tx_qdpl_service(struct sfxge_txq *txq) { SFXGE_TXQ_LOCK_ASSERT_OWNED(txq); do { if (SFXGE_TX_QDPL_PENDING(txq)) sfxge_tx_qdpl_swizzle(txq); if (!txq->blocked) sfxge_tx_qdpl_drain(txq); SFXGE_TXQ_UNLOCK(txq); } while (SFXGE_TX_QDPL_PENDING(txq) && SFXGE_TXQ_TRYLOCK(txq)); } /* - * Put a packet on the deferred packet list. - * - * If we are called with the txq lock held, we put the packet on the "get - * list", otherwise we atomically push it on the "put list". The swizzle - * function takes care of ordering. - * - * The length of the put list is bounded by SFXGE_TX_MAX_DEFERRED. We - * overload the csum_data field in the mbuf to keep track of this length - * because there is no cheap alternative to avoid races. + * Put a packet on the deferred packet get-list. */ static int -sfxge_tx_qdpl_put(struct sfxge_txq *txq, struct mbuf *mbuf, int locked) +sfxge_tx_qdpl_put_locked(struct sfxge_txq *txq, struct mbuf *mbuf) { struct sfxge_tx_dpl *stdp; stdp = &txq->dpl; KASSERT(mbuf->m_nextpkt == NULL, ("mbuf->m_nextpkt != NULL")); - if (locked) { - SFXGE_TXQ_LOCK_ASSERT_OWNED(txq); + SFXGE_TXQ_LOCK_ASSERT_OWNED(txq); - sfxge_tx_qdpl_swizzle(txq); - - if (stdp->std_get_count >= stdp->std_get_max) { - txq->get_overflow++; + if (stdp->std_get_count >= stdp->std_get_max) { + txq->get_overflow++; + return (ENOBUFS); + } + if (sfxge_is_mbuf_non_tcp(mbuf)) { + if (stdp->std_get_non_tcp_count >= + stdp->std_get_non_tcp_max) { + txq->get_non_tcp_overflow++; return (ENOBUFS); } - if (sfxge_is_mbuf_non_tcp(mbuf)) { - if (stdp->std_get_non_tcp_count >= - stdp->std_get_non_tcp_max) { - txq->get_non_tcp_overflow++; - return (ENOBUFS); - } - stdp->std_get_non_tcp_count++; - } + stdp->std_get_non_tcp_count++; + } - *(stdp->std_getp) = mbuf; - stdp->std_getp = &mbuf->m_nextpkt; - stdp->std_get_count++; - } else { - volatile uintptr_t *putp; - uintptr_t old; - uintptr_t new; - unsigned old_len; + *(stdp->std_getp) = mbuf; + stdp->std_getp = &mbuf->m_nextpkt; + stdp->std_get_count++; - putp = &stdp->std_put; - new = (uintptr_t)mbuf; + return (0); +} - do { - old = *putp; - if (old != 0) { - struct mbuf *mp = (struct mbuf *)old; - old_len = mp->m_pkthdr.csum_data; - } else - old_len = 0; - if (old_len >= stdp->std_put_max) { - atomic_add_long(&txq->put_overflow, 1); - return (ENOBUFS); - } - mbuf->m_pkthdr.csum_data = old_len + 1; - mbuf->m_nextpkt = (void *)old; - } while (atomic_cmpset_ptr(putp, old, new) == 0); - } +/* + * Put a packet on the deferred packet put-list. + * + * We overload the csum_data field in the mbuf to keep track of this length + * because there is no cheap alternative to avoid races. + */ +static int +sfxge_tx_qdpl_put_unlocked(struct sfxge_txq *txq, struct mbuf *mbuf) +{ + struct sfxge_tx_dpl *stdp; + volatile uintptr_t *putp; + uintptr_t old; + uintptr_t new; + unsigned old_len; + KASSERT(mbuf->m_nextpkt == NULL, ("mbuf->m_nextpkt != NULL")); + + SFXGE_TXQ_LOCK_ASSERT_NOTOWNED(txq); + + stdp = &txq->dpl; + putp = &stdp->std_put; + new = (uintptr_t)mbuf; + + do { + old = *putp; + if (old != 0) { + struct mbuf *mp = (struct mbuf *)old; + old_len = mp->m_pkthdr.csum_data; + } else + old_len = 0; + if (old_len >= stdp->std_put_max) { + atomic_add_long(&txq->put_overflow, 1); + return (ENOBUFS); + } + mbuf->m_pkthdr.csum_data = old_len + 1; + mbuf->m_nextpkt = (void *)old; + } while (atomic_cmpset_ptr(putp, old, new) == 0); + return (0); } /* * Called from if_transmit - will try to grab the txq lock and enqueue to the * put list if it succeeds, otherwise try to push onto the defer list if space. */ int sfxge_tx_packet_add(struct sfxge_txq *txq, struct mbuf *m) { - int locked; int rc; if (!SFXGE_LINK_UP(txq->sc)) { - rc = ENETDOWN; atomic_add_long(&txq->netdown_drops, 1); - goto fail; + return (ENETDOWN); } /* * Try to grab the txq lock. If we are able to get the lock, * the packet will be appended to the "get list" of the deferred * packet list. Otherwise, it will be pushed on the "put list". */ - locked = SFXGE_TXQ_TRYLOCK(txq); + if (SFXGE_TXQ_TRYLOCK(txq)) { + /* First swizzle put-list to get-list to keep order */ + sfxge_tx_qdpl_swizzle(txq); - if (sfxge_tx_qdpl_put(txq, m, locked) != 0) { - if (locked) + rc = sfxge_tx_qdpl_put_locked(txq, m); + if (rc != 0) { SFXGE_TXQ_UNLOCK(txq); - rc = ENOBUFS; - goto fail; - } + return (rc); + } - /* - * Try to grab the lock again. - * - * If we are able to get the lock, we need to process the deferred - * packet list. If we are not able to get the lock, another thread - * is processing the list. - */ - if (!locked) - locked = SFXGE_TXQ_TRYLOCK(txq); - - if (locked) { /* Try to service the list. */ sfxge_tx_qdpl_service(txq); /* Lock has been dropped. */ + } else { + rc = sfxge_tx_qdpl_put_unlocked(txq, m); + if (rc != 0) + return (rc); + + /* + * Try to grab the lock again. + * + * If we are able to get the lock, we need to process + * the deferred packet list. If we are not able to get + * the lock, another thread is processing the list. + */ + if (SFXGE_TXQ_TRYLOCK(txq)) { + sfxge_tx_qdpl_service(txq); + /* Lock has been dropped. */ + } } - return (0); + SFXGE_TXQ_LOCK_ASSERT_NOTOWNED(txq); -fail: - m_freem(m); - return (rc); + return (0); } static void sfxge_tx_qdpl_flush(struct sfxge_txq *txq) { struct sfxge_tx_dpl *stdp = &txq->dpl; struct mbuf *mbuf, *next; SFXGE_TXQ_LOCK(txq); sfxge_tx_qdpl_swizzle(txq); for (mbuf = stdp->std_get; mbuf != NULL; mbuf = next) { next = mbuf->m_nextpkt; m_freem(mbuf); } stdp->std_get = NULL; stdp->std_get_count = 0; stdp->std_get_non_tcp_count = 0; stdp->std_getp = &stdp->std_get; SFXGE_TXQ_UNLOCK(txq); } void sfxge_if_qflush(struct ifnet *ifp) { struct sfxge_softc *sc; unsigned int i; sc = ifp->if_softc; for (i = 0; i < sc->txq_count; i++) sfxge_tx_qdpl_flush(sc->txq[i]); } /* * TX start -- called by the stack. */ int sfxge_if_transmit(struct ifnet *ifp, struct mbuf *m) { struct sfxge_softc *sc; struct sfxge_txq *txq; int rc; sc = (struct sfxge_softc *)ifp->if_softc; /* * Transmit may be called when interface is up from the kernel * point of view, but not yet up (in progress) from the driver * point of view. I.e. link aggregation bring up. * Transmit may be called when interface is up from the driver * point of view, but already down from the kernel point of * view. I.e. Rx when interface shutdown is in progress. */ KASSERT((ifp->if_flags & IFF_UP) || (sc->if_flags & IFF_UP), ("interface not up")); /* Pick the desired transmit queue. */ if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA | CSUM_TCP_IPV6 | CSUM_UDP_IPV6 | CSUM_TSO)) { int index = 0; /* check if flowid is set */ if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) { uint32_t hash = m->m_pkthdr.flowid; index = sc->rx_indir_table[hash % SFXGE_RX_SCALE_MAX]; } txq = sc->txq[SFXGE_TXQ_IP_TCP_UDP_CKSUM + index]; } else if (m->m_pkthdr.csum_flags & CSUM_DELAY_IP) { txq = sc->txq[SFXGE_TXQ_IP_CKSUM]; } else { txq = sc->txq[SFXGE_TXQ_NON_CKSUM]; } rc = sfxge_tx_packet_add(txq, m); + if (rc != 0) + m_freem(m); return (rc); } /* * Software "TSO". Not quite as good as doing it in hardware, but * still faster than segmenting in the stack. */ struct sfxge_tso_state { /* Output position */ unsigned out_len; /* Remaining length in current segment */ unsigned seqnum; /* Current sequence number */ unsigned packet_space; /* Remaining space in current packet */ /* Input position */ uint64_t dma_addr; /* DMA address of current position */ unsigned in_len; /* Remaining length in current mbuf */ const struct mbuf *mbuf; /* Input mbuf (head of chain) */ u_short protocol; /* Network protocol (after VLAN decap) */ ssize_t nh_off; /* Offset of network header */ ssize_t tcph_off; /* Offset of TCP header */ unsigned header_len; /* Number of bytes of header */ unsigned seg_size; /* TCP segment size */ }; static const struct ip *tso_iph(const struct sfxge_tso_state *tso) { KASSERT(tso->protocol == htons(ETHERTYPE_IP), ("tso_iph() in non-IPv4 state")); return (const struct ip *)(tso->mbuf->m_data + tso->nh_off); } static __unused const struct ip6_hdr *tso_ip6h(const struct sfxge_tso_state *tso) { KASSERT(tso->protocol == htons(ETHERTYPE_IPV6), ("tso_ip6h() in non-IPv6 state")); return (const struct ip6_hdr *)(tso->mbuf->m_data + tso->nh_off); } static const struct tcphdr *tso_tcph(const struct sfxge_tso_state *tso) { return (const struct tcphdr *)(tso->mbuf->m_data + tso->tcph_off); } /* Size of preallocated TSO header buffers. Larger blocks must be * allocated from the heap. */ #define TSOH_STD_SIZE 128 /* At most half the descriptors in the queue at any time will refer to * a TSO header buffer, since they must always be followed by a * payload descriptor referring to an mbuf. */ #define TSOH_COUNT(_txq_entries) ((_txq_entries) / 2u) #define TSOH_PER_PAGE (PAGE_SIZE / TSOH_STD_SIZE) #define TSOH_PAGE_COUNT(_txq_entries) \ ((TSOH_COUNT(_txq_entries) + TSOH_PER_PAGE - 1) / TSOH_PER_PAGE) static int tso_init(struct sfxge_txq *txq) { struct sfxge_softc *sc = txq->sc; unsigned int tsoh_page_count = TSOH_PAGE_COUNT(sc->txq_entries); int i, rc; /* Allocate TSO header buffers */ txq->tsoh_buffer = malloc(tsoh_page_count * sizeof(txq->tsoh_buffer[0]), M_SFXGE, M_WAITOK); for (i = 0; i < tsoh_page_count; i++) { rc = sfxge_dma_alloc(sc, PAGE_SIZE, &txq->tsoh_buffer[i]); if (rc != 0) goto fail; } return (0); fail: while (i-- > 0) sfxge_dma_free(&txq->tsoh_buffer[i]); free(txq->tsoh_buffer, M_SFXGE); txq->tsoh_buffer = NULL; return (rc); } static void tso_fini(struct sfxge_txq *txq) { int i; if (txq->tsoh_buffer != NULL) { for (i = 0; i < TSOH_PAGE_COUNT(txq->sc->txq_entries); i++) sfxge_dma_free(&txq->tsoh_buffer[i]); free(txq->tsoh_buffer, M_SFXGE); } } static void tso_start(struct sfxge_tso_state *tso, struct mbuf *mbuf) { struct ether_header *eh = mtod(mbuf, struct ether_header *); const struct tcphdr *th; struct tcphdr th_copy; tso->mbuf = mbuf; /* Find network protocol and header */ tso->protocol = eh->ether_type; if (tso->protocol == htons(ETHERTYPE_VLAN)) { struct ether_vlan_header *veh = mtod(mbuf, struct ether_vlan_header *); tso->protocol = veh->evl_proto; tso->nh_off = sizeof(*veh); } else { tso->nh_off = sizeof(*eh); } /* Find TCP header */ if (tso->protocol == htons(ETHERTYPE_IP)) { KASSERT(tso_iph(tso)->ip_p == IPPROTO_TCP, ("TSO required on non-TCP packet")); tso->tcph_off = tso->nh_off + 4 * tso_iph(tso)->ip_hl; } else { KASSERT(tso->protocol == htons(ETHERTYPE_IPV6), ("TSO required on non-IP packet")); KASSERT(tso_ip6h(tso)->ip6_nxt == IPPROTO_TCP, ("TSO required on non-TCP packet")); tso->tcph_off = tso->nh_off + sizeof(struct ip6_hdr); } KASSERT(mbuf->m_len >= tso->tcph_off, ("network header is fragmented in mbuf")); /* We need TCP header including flags (window is the next) */ if (mbuf->m_len < tso->tcph_off + offsetof(struct tcphdr, th_win)) { m_copydata(tso->mbuf, tso->tcph_off, sizeof(th_copy), (caddr_t)&th_copy); th = &th_copy; } else { th = tso_tcph(tso); } tso->header_len = tso->tcph_off + 4 * th->th_off; tso->seg_size = mbuf->m_pkthdr.tso_segsz; tso->seqnum = ntohl(th->th_seq); /* These flags must not be duplicated */ KASSERT(!(th->th_flags & (TH_URG | TH_SYN | TH_RST)), ("incompatible TCP flag on TSO packet")); tso->out_len = mbuf->m_pkthdr.len - tso->header_len; } /* * tso_fill_packet_with_fragment - form descriptors for the current fragment * * Form descriptors for the current fragment, until we reach the end * of fragment or end-of-packet. Return 0 on success, 1 if not enough * space. */ static void tso_fill_packet_with_fragment(struct sfxge_txq *txq, struct sfxge_tso_state *tso) { efx_buffer_t *desc; int n; if (tso->in_len == 0 || tso->packet_space == 0) return; KASSERT(tso->in_len > 0, ("TSO input length went negative")); KASSERT(tso->packet_space > 0, ("TSO packet space went negative")); n = min(tso->in_len, tso->packet_space); tso->packet_space -= n; tso->out_len -= n; tso->in_len -= n; desc = &txq->pend_desc[txq->n_pend_desc++]; desc->eb_addr = tso->dma_addr; desc->eb_size = n; desc->eb_eop = tso->out_len == 0 || tso->packet_space == 0; tso->dma_addr += n; } /* Callback from bus_dmamap_load() for long TSO headers. */ static void tso_map_long_header(void *dma_addr_ret, bus_dma_segment_t *segs, int nseg, int error) { *(uint64_t *)dma_addr_ret = ((__predict_true(error == 0) && __predict_true(nseg == 1)) ? segs->ds_addr : 0); } /* * tso_start_new_packet - generate a new header and prepare for the new packet * * Generate a new header and prepare for the new packet. Return 0 on * success, or an error code if failed to alloc header. */ static int tso_start_new_packet(struct sfxge_txq *txq, struct sfxge_tso_state *tso, unsigned int id) { struct sfxge_tx_mapping *stmp = &txq->stmp[id]; struct tcphdr *tsoh_th; unsigned ip_length; caddr_t header; uint64_t dma_addr; bus_dmamap_t map; efx_buffer_t *desc; int rc; /* Allocate a DMA-mapped header buffer. */ if (__predict_true(tso->header_len <= TSOH_STD_SIZE)) { unsigned int page_index = (id / 2) / TSOH_PER_PAGE; unsigned int buf_index = (id / 2) % TSOH_PER_PAGE; header = (txq->tsoh_buffer[page_index].esm_base + buf_index * TSOH_STD_SIZE); dma_addr = (txq->tsoh_buffer[page_index].esm_addr + buf_index * TSOH_STD_SIZE); map = txq->tsoh_buffer[page_index].esm_map; stmp->flags = 0; } else { /* We cannot use bus_dmamem_alloc() as that may sleep */ header = malloc(tso->header_len, M_SFXGE, M_NOWAIT); if (__predict_false(!header)) return (ENOMEM); rc = bus_dmamap_load(txq->packet_dma_tag, stmp->map, header, tso->header_len, tso_map_long_header, &dma_addr, BUS_DMA_NOWAIT); if (__predict_false(dma_addr == 0)) { if (rc == 0) { /* Succeeded but got >1 segment */ bus_dmamap_unload(txq->packet_dma_tag, stmp->map); rc = EINVAL; } free(header, M_SFXGE); return (rc); } map = stmp->map; txq->tso_long_headers++; stmp->u.heap_buf = header; stmp->flags = TX_BUF_UNMAP; } tsoh_th = (struct tcphdr *)(header + tso->tcph_off); /* Copy and update the headers. */ m_copydata(tso->mbuf, 0, tso->header_len, header); tsoh_th->th_seq = htonl(tso->seqnum); tso->seqnum += tso->seg_size; if (tso->out_len > tso->seg_size) { /* This packet will not finish the TSO burst. */ ip_length = tso->header_len - tso->nh_off + tso->seg_size; tsoh_th->th_flags &= ~(TH_FIN | TH_PUSH); } else { /* This packet will be the last in the TSO burst. */ ip_length = tso->header_len - tso->nh_off + tso->out_len; } if (tso->protocol == htons(ETHERTYPE_IP)) { struct ip *tsoh_iph = (struct ip *)(header + tso->nh_off); tsoh_iph->ip_len = htons(ip_length); /* XXX We should increment ip_id, but FreeBSD doesn't * currently allocate extra IDs for multiple segments. */ } else { struct ip6_hdr *tsoh_iph = (struct ip6_hdr *)(header + tso->nh_off); tsoh_iph->ip6_plen = htons(ip_length - sizeof(*tsoh_iph)); } /* Make the header visible to the hardware. */ bus_dmamap_sync(txq->packet_dma_tag, map, BUS_DMASYNC_PREWRITE); tso->packet_space = tso->seg_size; txq->tso_packets++; /* Form a descriptor for this header. */ desc = &txq->pend_desc[txq->n_pend_desc++]; desc->eb_addr = dma_addr; desc->eb_size = tso->header_len; desc->eb_eop = 0; return (0); } static int sfxge_tx_queue_tso(struct sfxge_txq *txq, struct mbuf *mbuf, const bus_dma_segment_t *dma_seg, int n_dma_seg) { struct sfxge_tso_state tso; unsigned int id, next_id; unsigned skipped = 0; tso_start(&tso, mbuf); while (dma_seg->ds_len + skipped <= tso.header_len) { skipped += dma_seg->ds_len; --n_dma_seg; KASSERT(n_dma_seg, ("no payload found in TSO packet")); ++dma_seg; } tso.in_len = dma_seg->ds_len - (tso.header_len - skipped); tso.dma_addr = dma_seg->ds_addr + (tso.header_len - skipped); id = txq->added & txq->ptr_mask; if (__predict_false(tso_start_new_packet(txq, &tso, id))) return (-1); while (1) { id = (id + 1) & txq->ptr_mask; tso_fill_packet_with_fragment(txq, &tso); /* Move onto the next fragment? */ if (tso.in_len == 0) { --n_dma_seg; if (n_dma_seg == 0) break; ++dma_seg; tso.in_len = dma_seg->ds_len; tso.dma_addr = dma_seg->ds_addr; } /* End of packet? */ if (tso.packet_space == 0) { /* If the queue is now full due to tiny MSS, * or we can't create another header, discard * the remainder of the input mbuf but do not * roll back the work we have done. */ if (txq->n_pend_desc + 1 /* header */ + n_dma_seg > SFXGE_TSO_MAX_DESC) { txq->tso_pdrop_too_many++; break; } next_id = (id + 1) & txq->ptr_mask; if (__predict_false(tso_start_new_packet(txq, &tso, next_id))) { txq->tso_pdrop_no_rsrc++; break; } id = next_id; } } txq->tso_bursts++; return (id); } static void sfxge_tx_qunblock(struct sfxge_txq *txq) { struct sfxge_softc *sc; struct sfxge_evq *evq; sc = txq->sc; evq = sc->evq[txq->evq_index]; SFXGE_EVQ_LOCK_ASSERT_OWNED(evq); if (__predict_false(txq->init_state != SFXGE_TXQ_STARTED)) return; SFXGE_TXQ_LOCK(txq); if (txq->blocked) { unsigned int level; level = txq->added - txq->completed; if (level <= SFXGE_TXQ_UNBLOCK_LEVEL(txq->entries)) { /* reaped must be in sync with blocked */ sfxge_tx_qreap(txq); txq->blocked = 0; } } sfxge_tx_qdpl_service(txq); /* note: lock has been dropped */ } void sfxge_tx_qflush_done(struct sfxge_txq *txq) { txq->flush_state = SFXGE_FLUSH_DONE; } static void sfxge_tx_qstop(struct sfxge_softc *sc, unsigned int index) { struct sfxge_txq *txq; struct sfxge_evq *evq; unsigned int count; txq = sc->txq[index]; evq = sc->evq[txq->evq_index]; SFXGE_TXQ_LOCK(txq); KASSERT(txq->init_state == SFXGE_TXQ_STARTED, ("txq->init_state != SFXGE_TXQ_STARTED")); txq->init_state = SFXGE_TXQ_INITIALIZED; txq->flush_state = SFXGE_FLUSH_PENDING; /* Flush the transmit queue. */ efx_tx_qflush(txq->common); SFXGE_TXQ_UNLOCK(txq); count = 0; do { /* Spin for 100ms. */ DELAY(100000); if (txq->flush_state != SFXGE_FLUSH_PENDING) break; } while (++count < 20); SFXGE_EVQ_LOCK(evq); SFXGE_TXQ_LOCK(txq); KASSERT(txq->flush_state != SFXGE_FLUSH_FAILED, ("txq->flush_state == SFXGE_FLUSH_FAILED")); txq->flush_state = SFXGE_FLUSH_DONE; txq->blocked = 0; txq->pending = txq->added; sfxge_tx_qcomplete(txq, evq); KASSERT(txq->completed == txq->added, ("txq->completed != txq->added")); sfxge_tx_qreap(txq); KASSERT(txq->reaped == txq->completed, ("txq->reaped != txq->completed")); txq->added = 0; txq->pending = 0; txq->completed = 0; txq->reaped = 0; /* Destroy the common code transmit queue. */ efx_tx_qdestroy(txq->common); txq->common = NULL; efx_sram_buf_tbl_clear(sc->enp, txq->buf_base_id, EFX_TXQ_NBUFS(sc->txq_entries)); SFXGE_EVQ_UNLOCK(evq); SFXGE_TXQ_UNLOCK(txq); } static int sfxge_tx_qstart(struct sfxge_softc *sc, unsigned int index) { struct sfxge_txq *txq; efsys_mem_t *esmp; uint16_t flags; struct sfxge_evq *evq; int rc; txq = sc->txq[index]; esmp = &txq->mem; evq = sc->evq[txq->evq_index]; KASSERT(txq->init_state == SFXGE_TXQ_INITIALIZED, ("txq->init_state != SFXGE_TXQ_INITIALIZED")); KASSERT(evq->init_state == SFXGE_EVQ_STARTED, ("evq->init_state != SFXGE_EVQ_STARTED")); /* Program the buffer table. */ if ((rc = efx_sram_buf_tbl_set(sc->enp, txq->buf_base_id, esmp, EFX_TXQ_NBUFS(sc->txq_entries))) != 0) return (rc); /* Determine the kind of queue we are creating. */ switch (txq->type) { case SFXGE_TXQ_NON_CKSUM: flags = 0; break; case SFXGE_TXQ_IP_CKSUM: flags = EFX_CKSUM_IPV4; break; case SFXGE_TXQ_IP_TCP_UDP_CKSUM: flags = EFX_CKSUM_IPV4 | EFX_CKSUM_TCPUDP; break; default: KASSERT(0, ("Impossible TX queue")); flags = 0; break; } /* Create the common code transmit queue. */ if ((rc = efx_tx_qcreate(sc->enp, index, txq->type, esmp, sc->txq_entries, txq->buf_base_id, flags, evq->common, &txq->common)) != 0) goto fail; SFXGE_TXQ_LOCK(txq); /* Enable the transmit queue. */ efx_tx_qenable(txq->common); txq->init_state = SFXGE_TXQ_STARTED; SFXGE_TXQ_UNLOCK(txq); return (0); fail: efx_sram_buf_tbl_clear(sc->enp, txq->buf_base_id, EFX_TXQ_NBUFS(sc->txq_entries)); return (rc); } void sfxge_tx_stop(struct sfxge_softc *sc) { int index; index = sc->txq_count; while (--index >= 0) sfxge_tx_qstop(sc, index); /* Tear down the transmit module */ efx_tx_fini(sc->enp); } int sfxge_tx_start(struct sfxge_softc *sc) { int index; int rc; /* Initialize the common code transmit module. */ if ((rc = efx_tx_init(sc->enp)) != 0) return (rc); for (index = 0; index < sc->txq_count; index++) { if ((rc = sfxge_tx_qstart(sc, index)) != 0) goto fail; } return (0); fail: while (--index >= 0) sfxge_tx_qstop(sc, index); efx_tx_fini(sc->enp); return (rc); } static int sfxge_txq_stat_init(struct sfxge_txq *txq, struct sysctl_oid *txq_node) { struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(txq->sc->dev); struct sysctl_oid *stat_node; unsigned int id; stat_node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(txq_node), OID_AUTO, "stats", CTLFLAG_RD, NULL, "Tx queue statistics"); if (stat_node == NULL) return (ENOMEM); for (id = 0; id < nitems(sfxge_tx_stats); id++) { SYSCTL_ADD_ULONG( ctx, SYSCTL_CHILDREN(stat_node), OID_AUTO, sfxge_tx_stats[id].name, CTLFLAG_RD | CTLFLAG_STATS, (unsigned long *)((caddr_t)txq + sfxge_tx_stats[id].offset), ""); } return (0); } /** * Destroy a transmit queue. */ static void sfxge_tx_qfini(struct sfxge_softc *sc, unsigned int index) { struct sfxge_txq *txq; unsigned int nmaps; txq = sc->txq[index]; KASSERT(txq->init_state == SFXGE_TXQ_INITIALIZED, ("txq->init_state != SFXGE_TXQ_INITIALIZED")); if (txq->type == SFXGE_TXQ_IP_TCP_UDP_CKSUM) tso_fini(txq); /* Free the context arrays. */ free(txq->pend_desc, M_SFXGE); nmaps = sc->txq_entries; while (nmaps-- != 0) bus_dmamap_destroy(txq->packet_dma_tag, txq->stmp[nmaps].map); free(txq->stmp, M_SFXGE); /* Release DMA memory mapping. */ sfxge_dma_free(&txq->mem); sc->txq[index] = NULL; SFXGE_TXQ_LOCK_DESTROY(txq); free(txq, M_SFXGE); } static int sfxge_tx_qinit(struct sfxge_softc *sc, unsigned int txq_index, enum sfxge_txq_type type, unsigned int evq_index) { char name[16]; struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev); struct sysctl_oid *txq_node; struct sfxge_txq *txq; struct sfxge_evq *evq; struct sfxge_tx_dpl *stdp; struct sysctl_oid *dpl_node; efsys_mem_t *esmp; unsigned int nmaps; int rc; txq = malloc(sizeof(struct sfxge_txq), M_SFXGE, M_ZERO | M_WAITOK); txq->sc = sc; txq->entries = sc->txq_entries; txq->ptr_mask = txq->entries - 1; sc->txq[txq_index] = txq; esmp = &txq->mem; evq = sc->evq[evq_index]; /* Allocate and zero DMA space for the descriptor ring. */ if ((rc = sfxge_dma_alloc(sc, EFX_TXQ_SIZE(sc->txq_entries), esmp)) != 0) return (rc); /* Allocate buffer table entries. */ sfxge_sram_buf_tbl_alloc(sc, EFX_TXQ_NBUFS(sc->txq_entries), &txq->buf_base_id); /* Create a DMA tag for packet mappings. */ if (bus_dma_tag_create(sc->parent_dma_tag, 1, 0x1000, MIN(0x3FFFFFFFFFFFUL, BUS_SPACE_MAXADDR), BUS_SPACE_MAXADDR, NULL, NULL, 0x11000, SFXGE_TX_MAPPING_MAX_SEG, 0x1000, 0, NULL, NULL, &txq->packet_dma_tag) != 0) { device_printf(sc->dev, "Couldn't allocate txq DMA tag\n"); rc = ENOMEM; goto fail; } /* Allocate pending descriptor array for batching writes. */ txq->pend_desc = malloc(sizeof(efx_buffer_t) * sc->txq_entries, M_SFXGE, M_ZERO | M_WAITOK); /* Allocate and initialise mbuf DMA mapping array. */ txq->stmp = malloc(sizeof(struct sfxge_tx_mapping) * sc->txq_entries, M_SFXGE, M_ZERO | M_WAITOK); for (nmaps = 0; nmaps < sc->txq_entries; nmaps++) { rc = bus_dmamap_create(txq->packet_dma_tag, 0, &txq->stmp[nmaps].map); if (rc != 0) goto fail2; } snprintf(name, sizeof(name), "%u", txq_index); txq_node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(sc->txqs_node), OID_AUTO, name, CTLFLAG_RD, NULL, ""); if (txq_node == NULL) { rc = ENOMEM; goto fail_txq_node; } if (type == SFXGE_TXQ_IP_TCP_UDP_CKSUM && (rc = tso_init(txq)) != 0) goto fail3; if (sfxge_tx_dpl_get_max <= 0) { log(LOG_ERR, "%s=%d must be greater than 0", SFXGE_PARAM_TX_DPL_GET_MAX, sfxge_tx_dpl_get_max); rc = EINVAL; goto fail_tx_dpl_get_max; } if (sfxge_tx_dpl_get_non_tcp_max <= 0) { log(LOG_ERR, "%s=%d must be greater than 0", SFXGE_PARAM_TX_DPL_GET_NON_TCP_MAX, sfxge_tx_dpl_get_non_tcp_max); rc = EINVAL; goto fail_tx_dpl_get_max; } if (sfxge_tx_dpl_put_max < 0) { log(LOG_ERR, "%s=%d must be greater or equal to 0", SFXGE_PARAM_TX_DPL_PUT_MAX, sfxge_tx_dpl_put_max); rc = EINVAL; goto fail_tx_dpl_put_max; } /* Initialize the deferred packet list. */ stdp = &txq->dpl; stdp->std_put_max = sfxge_tx_dpl_put_max; stdp->std_get_max = sfxge_tx_dpl_get_max; stdp->std_get_non_tcp_max = sfxge_tx_dpl_get_non_tcp_max; stdp->std_getp = &stdp->std_get; SFXGE_TXQ_LOCK_INIT(txq, device_get_nameunit(sc->dev), txq_index); dpl_node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(txq_node), OID_AUTO, "dpl", CTLFLAG_RD, NULL, "Deferred packet list statistics"); if (dpl_node == NULL) { rc = ENOMEM; goto fail_dpl_node; } SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(dpl_node), OID_AUTO, "get_count", CTLFLAG_RD | CTLFLAG_STATS, &stdp->std_get_count, 0, ""); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(dpl_node), OID_AUTO, "get_non_tcp_count", CTLFLAG_RD | CTLFLAG_STATS, &stdp->std_get_non_tcp_count, 0, ""); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(dpl_node), OID_AUTO, "get_hiwat", CTLFLAG_RD | CTLFLAG_STATS, &stdp->std_get_hiwat, 0, ""); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(dpl_node), OID_AUTO, "put_hiwat", CTLFLAG_RD | CTLFLAG_STATS, &stdp->std_put_hiwat, 0, ""); rc = sfxge_txq_stat_init(txq, txq_node); if (rc != 0) goto fail_txq_stat_init; txq->type = type; txq->evq_index = evq_index; txq->txq_index = txq_index; txq->init_state = SFXGE_TXQ_INITIALIZED; return (0); fail_txq_stat_init: fail_dpl_node: fail_tx_dpl_put_max: fail_tx_dpl_get_max: fail3: fail_txq_node: free(txq->pend_desc, M_SFXGE); fail2: while (nmaps-- != 0) bus_dmamap_destroy(txq->packet_dma_tag, txq->stmp[nmaps].map); free(txq->stmp, M_SFXGE); bus_dma_tag_destroy(txq->packet_dma_tag); fail: sfxge_dma_free(esmp); return (rc); } static int sfxge_tx_stat_handler(SYSCTL_HANDLER_ARGS) { struct sfxge_softc *sc = arg1; unsigned int id = arg2; unsigned long sum; unsigned int index; /* Sum across all TX queues */ sum = 0; for (index = 0; index < sc->txq_count; index++) sum += *(unsigned long *)((caddr_t)sc->txq[index] + sfxge_tx_stats[id].offset); return (SYSCTL_OUT(req, &sum, sizeof(sum))); } static void sfxge_tx_stat_init(struct sfxge_softc *sc) { struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev); struct sysctl_oid_list *stat_list; unsigned int id; stat_list = SYSCTL_CHILDREN(sc->stats_node); for (id = 0; id < nitems(sfxge_tx_stats); id++) { SYSCTL_ADD_PROC( ctx, stat_list, OID_AUTO, sfxge_tx_stats[id].name, CTLTYPE_ULONG|CTLFLAG_RD, sc, id, sfxge_tx_stat_handler, "LU", ""); } } uint64_t sfxge_tx_get_drops(struct sfxge_softc *sc) { unsigned int index; uint64_t drops = 0; struct sfxge_txq *txq; /* Sum across all TX queues */ for (index = 0; index < sc->txq_count; index++) { txq = sc->txq[index]; /* * In theory, txq->put_overflow and txq->netdown_drops * should use atomic operation and other should be * obtained under txq lock, but it is just statistics. */ drops += txq->drops + txq->get_overflow + txq->get_non_tcp_overflow + txq->put_overflow + txq->netdown_drops + txq->tso_pdrop_too_many + txq->tso_pdrop_no_rsrc; } return (drops); } void sfxge_tx_fini(struct sfxge_softc *sc) { int index; index = sc->txq_count; while (--index >= 0) sfxge_tx_qfini(sc, index); sc->txq_count = 0; } int sfxge_tx_init(struct sfxge_softc *sc) { struct sfxge_intr *intr; int index; int rc; intr = &sc->intr; KASSERT(intr->state == SFXGE_INTR_INITIALIZED, ("intr->state != SFXGE_INTR_INITIALIZED")); sc->txq_count = SFXGE_TXQ_NTYPES - 1 + sc->intr.n_alloc; sc->txqs_node = SYSCTL_ADD_NODE( device_get_sysctl_ctx(sc->dev), SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, "txq", CTLFLAG_RD, NULL, "Tx queues"); if (sc->txqs_node == NULL) { rc = ENOMEM; goto fail_txq_node; } /* Initialize the transmit queues */ if ((rc = sfxge_tx_qinit(sc, SFXGE_TXQ_NON_CKSUM, SFXGE_TXQ_NON_CKSUM, 0)) != 0) goto fail; if ((rc = sfxge_tx_qinit(sc, SFXGE_TXQ_IP_CKSUM, SFXGE_TXQ_IP_CKSUM, 0)) != 0) goto fail2; for (index = 0; index < sc->txq_count - SFXGE_TXQ_NTYPES + 1; index++) { if ((rc = sfxge_tx_qinit(sc, SFXGE_TXQ_NTYPES - 1 + index, SFXGE_TXQ_IP_TCP_UDP_CKSUM, index)) != 0) goto fail3; } sfxge_tx_stat_init(sc); return (0); fail3: while (--index >= 0) sfxge_tx_qfini(sc, SFXGE_TXQ_IP_TCP_UDP_CKSUM + index); sfxge_tx_qfini(sc, SFXGE_TXQ_IP_CKSUM); fail2: sfxge_tx_qfini(sc, SFXGE_TXQ_NON_CKSUM); fail: fail_txq_node: sc->txq_count = 0; return (rc); } Index: projects/ci20_mips/sys/dev/sfxge/sfxge_tx.h =================================================================== --- projects/ci20_mips/sys/dev/sfxge/sfxge_tx.h (revision 283030) +++ projects/ci20_mips/sys/dev/sfxge/sfxge_tx.h (revision 283031) @@ -1,223 +1,225 @@ /*- * Copyright (c) 2010-2011 Solarflare Communications, Inc. * All rights reserved. * * This software was developed in part by Philip Paeps under contract for * Solarflare Communications, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _SFXGE_TX_H #define _SFXGE_TX_H #include #include #include /* Maximum size of TSO packet */ #define SFXGE_TSO_MAX_SIZE (65535) /* * Maximum number of segments to be created for a TSO packet. * Allow for a reasonable minimum MSS of 512. */ #define SFXGE_TSO_MAX_SEGS howmany(SFXGE_TSO_MAX_SIZE, 512) /* Maximum number of DMA segments needed to map an mbuf chain. With * TSO, the mbuf length may be just over 64K, divided into 2K mbuf * clusters. (The chain could be longer than this initially, but can * be shortened with m_collapse().) */ #define SFXGE_TX_MAPPING_MAX_SEG \ (1 + howmany(SFXGE_TSO_MAX_SIZE, MCLBYTES)) /* * Buffer mapping flags. * * Buffers and DMA mappings must be freed when the last descriptor * referring to them is completed. Set the TX_BUF_UNMAP and * TX_BUF_MBUF flags on the last descriptor generated for an mbuf * chain. Set only the TX_BUF_UNMAP flag on a descriptor referring to * a heap buffer. */ enum sfxge_tx_buf_flags { TX_BUF_UNMAP = 1, TX_BUF_MBUF = 2, }; /* * Buffer mapping information for descriptors in flight. */ struct sfxge_tx_mapping { union { struct mbuf *mbuf; caddr_t heap_buf; } u; bus_dmamap_t map; enum sfxge_tx_buf_flags flags; }; #define SFXGE_TX_DPL_GET_PKT_LIMIT_DEFAULT (64 * 1024) #define SFXGE_TX_DPL_GET_NON_TCP_PKT_LIMIT_DEFAULT 1024 #define SFXGE_TX_DPL_PUT_PKT_LIMIT_DEFAULT 1024 /* * Deferred packet list. */ struct sfxge_tx_dpl { unsigned int std_get_max; /* Maximum number of packets * in get list */ unsigned int std_get_non_tcp_max; /* Maximum number * of non-TCP packets * in get list */ unsigned int std_put_max; /* Maximum number of packets * in put list */ uintptr_t std_put; /* Head of put list. */ struct mbuf *std_get; /* Head of get list. */ struct mbuf **std_getp; /* Tail of get list. */ unsigned int std_get_count; /* Packets in get list. */ unsigned int std_get_non_tcp_count; /* Non-TCP packets * in get list */ unsigned int std_get_hiwat; /* Packets in get list * high watermark */ unsigned int std_put_hiwat; /* Packets in put list * high watermark */ }; #define SFXGE_TX_BUFFER_SIZE 0x400 #define SFXGE_TX_HEADER_SIZE 0x100 #define SFXGE_TX_COPY_THRESHOLD 0x200 enum sfxge_txq_state { SFXGE_TXQ_UNINITIALIZED = 0, SFXGE_TXQ_INITIALIZED, SFXGE_TXQ_STARTED }; enum sfxge_txq_type { SFXGE_TXQ_NON_CKSUM = 0, SFXGE_TXQ_IP_CKSUM, SFXGE_TXQ_IP_TCP_UDP_CKSUM, SFXGE_TXQ_NTYPES }; #define SFXGE_TXQ_UNBLOCK_LEVEL(_entries) (EFX_TXQ_LIMIT(_entries) / 4) #define SFXGE_TX_BATCH 64 #define SFXGE_TXQ_LOCK_INIT(_txq, _ifname, _txq_index) \ do { \ struct sfxge_txq *__txq = (_txq); \ \ snprintf((__txq)->lock_name, \ sizeof((__txq)->lock_name), \ "%s:txq%u", (_ifname), (_txq_index)); \ mtx_init(&(__txq)->lock, (__txq)->lock_name, \ NULL, MTX_DEF); \ } while (B_FALSE) #define SFXGE_TXQ_LOCK_DESTROY(_txq) \ mtx_destroy(&(_txq)->lock) #define SFXGE_TXQ_LOCK(_txq) \ mtx_lock(&(_txq)->lock) #define SFXGE_TXQ_TRYLOCK(_txq) \ mtx_trylock(&(_txq)->lock) #define SFXGE_TXQ_UNLOCK(_txq) \ mtx_unlock(&(_txq)->lock) #define SFXGE_TXQ_LOCK_ASSERT_OWNED(_txq) \ mtx_assert(&(_txq)->lock, MA_OWNED) +#define SFXGE_TXQ_LOCK_ASSERT_NOTOWNED(_txq) \ + mtx_assert(&(_txq)->lock, MA_NOTOWNED) struct sfxge_txq { /* The following fields should be written very rarely */ struct sfxge_softc *sc; enum sfxge_txq_state init_state; enum sfxge_flush_state flush_state; enum sfxge_txq_type type; unsigned int txq_index; unsigned int evq_index; efsys_mem_t mem; unsigned int buf_base_id; unsigned int entries; unsigned int ptr_mask; struct sfxge_tx_mapping *stmp; /* Packets in flight. */ bus_dma_tag_t packet_dma_tag; efx_buffer_t *pend_desc; efx_txq_t *common; efsys_mem_t *tsoh_buffer; char lock_name[SFXGE_LOCK_NAME_MAX]; /* This field changes more often and is read regularly on both * the initiation and completion paths */ int blocked __aligned(CACHE_LINE_SIZE); /* The following fields change more often, and are used mostly * on the initiation path */ struct mtx lock __aligned(CACHE_LINE_SIZE); struct sfxge_tx_dpl dpl; /* Deferred packet list. */ unsigned int n_pend_desc; unsigned int added; unsigned int reaped; /* Statistics */ unsigned long tso_bursts; unsigned long tso_packets; unsigned long tso_long_headers; unsigned long collapses; unsigned long drops; unsigned long get_overflow; unsigned long get_non_tcp_overflow; unsigned long put_overflow; unsigned long netdown_drops; unsigned long tso_pdrop_too_many; unsigned long tso_pdrop_no_rsrc; /* The following fields change more often, and are used mostly * on the completion path */ unsigned int pending __aligned(CACHE_LINE_SIZE); unsigned int completed; struct sfxge_txq *next; }; struct sfxge_evq; extern int sfxge_tx_packet_add(struct sfxge_txq *, struct mbuf *); extern uint64_t sfxge_tx_get_drops(struct sfxge_softc *sc); extern int sfxge_tx_init(struct sfxge_softc *sc); extern void sfxge_tx_fini(struct sfxge_softc *sc); extern int sfxge_tx_start(struct sfxge_softc *sc); extern void sfxge_tx_stop(struct sfxge_softc *sc); extern void sfxge_tx_qcomplete(struct sfxge_txq *txq, struct sfxge_evq *evq); extern void sfxge_tx_qflush_done(struct sfxge_txq *txq); extern void sfxge_if_qflush(struct ifnet *ifp); extern int sfxge_if_transmit(struct ifnet *ifp, struct mbuf *m); #endif Index: projects/ci20_mips/sys/kern/init_main.c =================================================================== --- projects/ci20_mips/sys/kern/init_main.c (revision 283030) +++ projects/ci20_mips/sys/kern/init_main.c (revision 283031) @@ -1,867 +1,867 @@ /*- * Copyright (c) 1995 Terrence R. Lambert * All rights reserved. * * Copyright (c) 1982, 1986, 1989, 1991, 1992, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)init_main.c 8.9 (Berkeley) 1/21/94 */ #include __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include "opt_init_path.h" #include "opt_verbose_sysinit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void mi_startup(void); /* Should be elsewhere */ /* Components of the first process -- never freed. */ static struct session session0; static struct pgrp pgrp0; struct proc proc0; struct thread thread0 __aligned(16); struct vmspace vmspace0; struct proc *initproc; #ifndef BOOTHOWTO #define BOOTHOWTO 0 #endif int boothowto = BOOTHOWTO; /* initialized so that it can be patched */ SYSCTL_INT(_debug, OID_AUTO, boothowto, CTLFLAG_RD, &boothowto, 0, "Boot control flags, passed from loader"); #ifndef BOOTVERBOSE #define BOOTVERBOSE 0 #endif int bootverbose = BOOTVERBOSE; SYSCTL_INT(_debug, OID_AUTO, bootverbose, CTLFLAG_RW, &bootverbose, 0, "Control the output of verbose kernel messages"); /* * This ensures that there is at least one entry so that the sysinit_set * symbol is not undefined. A sybsystem ID of SI_SUB_DUMMY is never * executed. */ SYSINIT(placeholder, SI_SUB_DUMMY, SI_ORDER_ANY, NULL, NULL); /* * The sysinit table itself. Items are checked off as the are run. * If we want to register new sysinit types, add them to newsysinit. */ SET_DECLARE(sysinit_set, struct sysinit); struct sysinit **sysinit, **sysinit_end; struct sysinit **newsysinit, **newsysinit_end; /* * Merge a new sysinit set into the current set, reallocating it if * necessary. This can only be called after malloc is running. */ void sysinit_add(struct sysinit **set, struct sysinit **set_end) { struct sysinit **newset; struct sysinit **sipp; struct sysinit **xipp; int count; count = set_end - set; if (newsysinit) count += newsysinit_end - newsysinit; else count += sysinit_end - sysinit; newset = malloc(count * sizeof(*sipp), M_TEMP, M_NOWAIT); if (newset == NULL) panic("cannot malloc for sysinit"); xipp = newset; if (newsysinit) for (sipp = newsysinit; sipp < newsysinit_end; sipp++) *xipp++ = *sipp; else for (sipp = sysinit; sipp < sysinit_end; sipp++) *xipp++ = *sipp; for (sipp = set; sipp < set_end; sipp++) *xipp++ = *sipp; if (newsysinit) free(newsysinit, M_TEMP); newsysinit = newset; newsysinit_end = newset + count; } #if defined (DDB) && defined(VERBOSE_SYSINIT) static const char * symbol_name(vm_offset_t va, db_strategy_t strategy) { const char *name; c_db_sym_t sym; db_expr_t offset; if (va == 0) return (NULL); sym = db_search_symbol(va, strategy, &offset); if (offset != 0) return (NULL); db_symbol_values(sym, &name, NULL); return (name); } #endif /* * System startup; initialize the world, create process 0, mount root * filesystem, and fork to create init and pagedaemon. Most of the * hard work is done in the lower-level initialization routines including * startup(), which does memory initialization and autoconfiguration. * * This allows simple addition of new kernel subsystems that require * boot time initialization. It also allows substitution of subsystem * (for instance, a scheduler, kernel profiler, or VM system) by object * module. Finally, it allows for optional "kernel threads". */ void mi_startup(void) { register struct sysinit **sipp; /* system initialization*/ register struct sysinit **xipp; /* interior loop of sort*/ register struct sysinit *save; /* bubble*/ #if defined(VERBOSE_SYSINIT) int last; int verbose; #endif if (boothowto & RB_VERBOSE) bootverbose++; if (sysinit == NULL) { sysinit = SET_BEGIN(sysinit_set); sysinit_end = SET_LIMIT(sysinit_set); } restart: /* * Perform a bubble sort of the system initialization objects by * their subsystem (primary key) and order (secondary key). */ for (sipp = sysinit; sipp < sysinit_end; sipp++) { for (xipp = sipp + 1; xipp < sysinit_end; xipp++) { if ((*sipp)->subsystem < (*xipp)->subsystem || ((*sipp)->subsystem == (*xipp)->subsystem && (*sipp)->order <= (*xipp)->order)) continue; /* skip*/ save = *sipp; *sipp = *xipp; *xipp = save; } } #if defined(VERBOSE_SYSINIT) last = SI_SUB_COPYRIGHT; verbose = 0; #if !defined(DDB) printf("VERBOSE_SYSINIT: DDB not enabled, symbol lookups disabled.\n"); #endif #endif /* * Traverse the (now) ordered list of system initialization tasks. * Perform each task, and continue on to the next task. */ for (sipp = sysinit; sipp < sysinit_end; sipp++) { if ((*sipp)->subsystem == SI_SUB_DUMMY) continue; /* skip dummy task(s)*/ if ((*sipp)->subsystem == SI_SUB_DONE) continue; #if defined(VERBOSE_SYSINIT) if ((*sipp)->subsystem > last) { verbose = 1; last = (*sipp)->subsystem; printf("subsystem %x\n", last); } if (verbose) { #if defined(DDB) const char *func, *data; func = symbol_name((vm_offset_t)(*sipp)->func, DB_STGY_PROC); data = symbol_name((vm_offset_t)(*sipp)->udata, DB_STGY_ANY); if (func != NULL && data != NULL) printf(" %s(&%s)... ", func, data); else if (func != NULL) printf(" %s(%p)... ", func, (*sipp)->udata); else #endif printf(" %p(%p)... ", (*sipp)->func, (*sipp)->udata); } #endif /* Call function */ (*((*sipp)->func))((*sipp)->udata); #if defined(VERBOSE_SYSINIT) if (verbose) printf("done.\n"); #endif /* Check off the one we're just done */ (*sipp)->subsystem = SI_SUB_DONE; /* Check if we've installed more sysinit items via KLD */ if (newsysinit != NULL) { if (sysinit != SET_BEGIN(sysinit_set)) free(sysinit, M_TEMP); sysinit = newsysinit; sysinit_end = newsysinit_end; newsysinit = NULL; newsysinit_end = NULL; goto restart; } } mtx_assert(&Giant, MA_OWNED | MA_NOTRECURSED); mtx_unlock(&Giant); /* * Now hand over this thread to swapper. */ swapper(); /* NOTREACHED*/ } /* *************************************************************************** **** **** The following SYSINIT's belong elsewhere, but have not yet **** been moved. **** *************************************************************************** */ static void print_caddr_t(void *data) { printf("%s", (char *)data); } static void print_version(void *data __unused) { int len; /* Strip a trailing newline from version. */ len = strlen(version); while (len > 0 && version[len - 1] == '\n') len--; printf("%.*s %s\n", len, version, machine); printf("%s\n", compiler_version); } SYSINIT(announce, SI_SUB_COPYRIGHT, SI_ORDER_FIRST, print_caddr_t, copyright); SYSINIT(trademark, SI_SUB_COPYRIGHT, SI_ORDER_SECOND, print_caddr_t, trademark); SYSINIT(version, SI_SUB_COPYRIGHT, SI_ORDER_THIRD, print_version, NULL); #ifdef WITNESS static char wit_warn[] = "WARNING: WITNESS option enabled, expect reduced performance.\n"; SYSINIT(witwarn, SI_SUB_COPYRIGHT, SI_ORDER_THIRD + 1, print_caddr_t, wit_warn); SYSINIT(witwarn2, SI_SUB_LAST, SI_ORDER_THIRD + 1, print_caddr_t, wit_warn); #endif #ifdef DIAGNOSTIC static char diag_warn[] = "WARNING: DIAGNOSTIC option enabled, expect reduced performance.\n"; SYSINIT(diagwarn, SI_SUB_COPYRIGHT, SI_ORDER_THIRD + 2, print_caddr_t, diag_warn); SYSINIT(diagwarn2, SI_SUB_LAST, SI_ORDER_THIRD + 2, print_caddr_t, diag_warn); #endif static int null_fetch_syscall_args(struct thread *td __unused, struct syscall_args *sa __unused) { panic("null_fetch_syscall_args"); } static void null_set_syscall_retval(struct thread *td __unused, int error __unused) { panic("null_set_syscall_retval"); } struct sysentvec null_sysvec = { .sv_size = 0, .sv_table = NULL, .sv_mask = 0, .sv_sigsize = 0, .sv_sigtbl = NULL, .sv_errsize = 0, .sv_errtbl = NULL, .sv_transtrap = NULL, .sv_fixup = NULL, .sv_sendsig = NULL, .sv_sigcode = NULL, .sv_szsigcode = NULL, .sv_prepsyscall = NULL, .sv_name = "null", .sv_coredump = NULL, .sv_imgact_try = NULL, .sv_minsigstksz = 0, .sv_pagesize = PAGE_SIZE, .sv_minuser = VM_MIN_ADDRESS, .sv_maxuser = VM_MAXUSER_ADDRESS, .sv_usrstack = USRSTACK, .sv_psstrings = PS_STRINGS, .sv_stackprot = VM_PROT_ALL, .sv_copyout_strings = NULL, .sv_setregs = NULL, .sv_fixlimit = NULL, .sv_maxssiz = NULL, .sv_flags = 0, .sv_set_syscall_retval = null_set_syscall_retval, .sv_fetch_syscall_args = null_fetch_syscall_args, .sv_syscallnames = NULL, .sv_schedtail = NULL, }; /* *************************************************************************** **** **** The two following SYSINIT's are proc0 specific glue code. I am not **** convinced that they can not be safely combined, but their order of **** operation has been maintained as the same as the original init_main.c **** for right now. **** **** These probably belong in init_proc.c or kern_proc.c, since they **** deal with proc0 (the fork template process). **** *************************************************************************** */ /* ARGSUSED*/ static void proc0_init(void *dummy __unused) { struct proc *p; struct thread *td; struct ucred *newcred; vm_paddr_t pageablemem; int i; GIANT_REQUIRED; p = &proc0; td = &thread0; /* * Initialize magic number and osrel. */ p->p_magic = P_MAGIC; p->p_osrel = osreldate; /* * Initialize thread and process structures. */ procinit(); /* set up proc zone */ threadinit(); /* set up UMA zones */ /* * Initialise scheduler resources. * Add scheduler specific parts to proc, thread as needed. */ schedinit(); /* scheduler gets its house in order */ /* * Create process 0 (the swapper). */ LIST_INSERT_HEAD(&allproc, p, p_list); LIST_INSERT_HEAD(PIDHASH(0), p, p_hash); mtx_init(&pgrp0.pg_mtx, "process group", NULL, MTX_DEF | MTX_DUPOK); p->p_pgrp = &pgrp0; LIST_INSERT_HEAD(PGRPHASH(0), &pgrp0, pg_hash); LIST_INIT(&pgrp0.pg_members); LIST_INSERT_HEAD(&pgrp0.pg_members, p, p_pglist); pgrp0.pg_session = &session0; mtx_init(&session0.s_mtx, "session", NULL, MTX_DEF); refcount_init(&session0.s_count, 1); session0.s_leader = p; p->p_sysent = &null_sysvec; p->p_flag = P_SYSTEM | P_INMEM; p->p_flag2 = 0; p->p_state = PRS_NORMAL; knlist_init_mtx(&p->p_klist, &p->p_mtx); STAILQ_INIT(&p->p_ktr); p->p_nice = NZERO; /* pid_max cannot be greater than PID_MAX */ td->td_tid = PID_MAX + 1; LIST_INSERT_HEAD(TIDHASH(td->td_tid), td, td_hash); td->td_state = TDS_RUNNING; td->td_pri_class = PRI_TIMESHARE; td->td_user_pri = PUSER; td->td_base_user_pri = PUSER; td->td_lend_user_pri = PRI_MAX; td->td_priority = PVM; td->td_base_pri = PVM; td->td_oncpu = 0; td->td_flags = TDF_INMEM; td->td_pflags = TDP_KTHREAD; td->td_cpuset = cpuset_thread0(); prison0_init(); p->p_peers = 0; p->p_leader = p; p->p_reaper = p; LIST_INIT(&p->p_reaplist); strncpy(p->p_comm, "kernel", sizeof (p->p_comm)); strncpy(td->td_name, "swapper", sizeof (td->td_name)); callout_init_mtx(&p->p_itcallout, &p->p_mtx, 0); callout_init_mtx(&p->p_limco, &p->p_mtx, 0); callout_init(&td->td_slpcallout, CALLOUT_MPSAFE); /* Create credentials. */ newcred = crget(); newcred->cr_ngroups = 1; /* group 0 */ newcred->cr_uidinfo = uifind(0); newcred->cr_ruidinfo = uifind(0); newcred->cr_prison = &prison0; newcred->cr_loginclass = loginclass_find("default"); proc_set_cred_init(p, newcred); #ifdef AUDIT audit_cred_kproc0(newcred); #endif #ifdef MAC mac_cred_create_swapper(newcred); #endif td->td_ucred = crhold(newcred); /* Create sigacts. */ p->p_sigacts = sigacts_alloc(); /* Initialize signal state for process 0. */ siginit(&proc0); /* Create the file descriptor table. */ p->p_fd = fdinit(NULL, false); p->p_fdtol = NULL; /* Create the limits structures. */ p->p_limit = lim_alloc(); for (i = 0; i < RLIM_NLIMITS; i++) p->p_limit->pl_rlimit[i].rlim_cur = p->p_limit->pl_rlimit[i].rlim_max = RLIM_INFINITY; p->p_limit->pl_rlimit[RLIMIT_NOFILE].rlim_cur = p->p_limit->pl_rlimit[RLIMIT_NOFILE].rlim_max = maxfiles; p->p_limit->pl_rlimit[RLIMIT_NPROC].rlim_cur = p->p_limit->pl_rlimit[RLIMIT_NPROC].rlim_max = maxproc; p->p_limit->pl_rlimit[RLIMIT_DATA].rlim_cur = dfldsiz; p->p_limit->pl_rlimit[RLIMIT_DATA].rlim_max = maxdsiz; p->p_limit->pl_rlimit[RLIMIT_STACK].rlim_cur = dflssiz; p->p_limit->pl_rlimit[RLIMIT_STACK].rlim_max = maxssiz; /* Cast to avoid overflow on i386/PAE. */ pageablemem = ptoa((vm_paddr_t)vm_cnt.v_free_count); p->p_limit->pl_rlimit[RLIMIT_RSS].rlim_cur = p->p_limit->pl_rlimit[RLIMIT_RSS].rlim_max = pageablemem; p->p_limit->pl_rlimit[RLIMIT_MEMLOCK].rlim_cur = pageablemem / 3; p->p_limit->pl_rlimit[RLIMIT_MEMLOCK].rlim_max = pageablemem; p->p_cpulimit = RLIM_INFINITY; /* Initialize resource accounting structures. */ racct_create(&p->p_racct); p->p_stats = pstats_alloc(); /* Allocate a prototype map so we have something to fork. */ - pmap_pinit0(vmspace_pmap(&vmspace0)); p->p_vmspace = &vmspace0; vmspace0.vm_refcnt = 1; + pmap_pinit0(vmspace_pmap(&vmspace0)); /* * proc0 is not expected to enter usermode, so there is no special * handling for sv_minuser here, like is done for exec_new_vmspace(). */ vm_map_init(&vmspace0.vm_map, vmspace_pmap(&vmspace0), p->p_sysent->sv_minuser, p->p_sysent->sv_maxuser); /* * Call the init and ctor for the new thread and proc. We wait * to do this until all other structures are fairly sane. */ EVENTHANDLER_INVOKE(process_init, p); EVENTHANDLER_INVOKE(thread_init, td); EVENTHANDLER_INVOKE(process_ctor, p); EVENTHANDLER_INVOKE(thread_ctor, td); /* * Charge root for one process. */ (void)chgproccnt(p->p_ucred->cr_ruidinfo, 1, 0); PROC_LOCK(p); racct_add_force(p, RACCT_NPROC, 1); PROC_UNLOCK(p); } SYSINIT(p0init, SI_SUB_INTRINSIC, SI_ORDER_FIRST, proc0_init, NULL); /* ARGSUSED*/ static void proc0_post(void *dummy __unused) { struct timespec ts; struct proc *p; struct rusage ru; struct thread *td; /* * Now we can look at the time, having had a chance to verify the * time from the filesystem. Pretend that proc0 started now. */ sx_slock(&allproc_lock); FOREACH_PROC_IN_SYSTEM(p) { microuptime(&p->p_stats->p_start); PROC_STATLOCK(p); rufetch(p, &ru); /* Clears thread stats */ PROC_STATUNLOCK(p); p->p_rux.rux_runtime = 0; p->p_rux.rux_uticks = 0; p->p_rux.rux_sticks = 0; p->p_rux.rux_iticks = 0; FOREACH_THREAD_IN_PROC(p, td) { td->td_runtime = 0; } } sx_sunlock(&allproc_lock); PCPU_SET(switchtime, cpu_ticks()); PCPU_SET(switchticks, ticks); /* * Give the ``random'' number generator a thump. */ nanotime(&ts); srandom(ts.tv_sec ^ ts.tv_nsec); } SYSINIT(p0post, SI_SUB_INTRINSIC_POST, SI_ORDER_FIRST, proc0_post, NULL); static void random_init(void *dummy __unused) { /* * After CPU has been started we have some randomness on most * platforms via get_cyclecount(). For platforms that don't * we will reseed random(9) in proc0_post() as well. */ srandom(get_cyclecount()); } SYSINIT(random, SI_SUB_RANDOM, SI_ORDER_FIRST, random_init, NULL); /* *************************************************************************** **** **** The following SYSINIT's and glue code should be moved to the **** respective files on a per subsystem basis. **** *************************************************************************** */ /* *************************************************************************** **** **** The following code probably belongs in another file, like **** kern/init_init.c. **** *************************************************************************** */ /* * List of paths to try when searching for "init". */ static char init_path[MAXPATHLEN] = #ifdef INIT_PATH __XSTRING(INIT_PATH); #else "/sbin/init:/sbin/oinit:/sbin/init.bak:/rescue/init"; #endif SYSCTL_STRING(_kern, OID_AUTO, init_path, CTLFLAG_RD, init_path, 0, "Path used to search the init process"); /* * Shutdown timeout of init(8). * Unused within kernel, but used to control init(8), hence do not remove. */ #ifndef INIT_SHUTDOWN_TIMEOUT #define INIT_SHUTDOWN_TIMEOUT 120 #endif static int init_shutdown_timeout = INIT_SHUTDOWN_TIMEOUT; SYSCTL_INT(_kern, OID_AUTO, init_shutdown_timeout, CTLFLAG_RW, &init_shutdown_timeout, 0, "Shutdown timeout of init(8). " "Unused within kernel, but used to control init(8)"); /* * Start the initial user process; try exec'ing each pathname in init_path. * The program is invoked with one argument containing the boot flags. */ static void start_init(void *dummy) { vm_offset_t addr; struct execve_args args; int options, error; char *var, *path, *next, *s; char *ucp, **uap, *arg0, *arg1; struct thread *td; struct proc *p; mtx_lock(&Giant); GIANT_REQUIRED; td = curthread; p = td->td_proc; vfs_mountroot(); /* Wipe GELI passphrase from the environment. */ kern_unsetenv("kern.geom.eli.passphrase"); /* * Need just enough stack to hold the faked-up "execve()" arguments. */ addr = p->p_sysent->sv_usrstack - PAGE_SIZE; if (vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &addr, PAGE_SIZE, 0, VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0) != 0) panic("init: couldn't allocate argument space"); p->p_vmspace->vm_maxsaddr = (caddr_t)addr; p->p_vmspace->vm_ssize = 1; if ((var = kern_getenv("init_path")) != NULL) { strlcpy(init_path, var, sizeof(init_path)); freeenv(var); } for (path = init_path; *path != '\0'; path = next) { while (*path == ':') path++; if (*path == '\0') break; for (next = path; *next != '\0' && *next != ':'; next++) /* nothing */ ; if (bootverbose) printf("start_init: trying %.*s\n", (int)(next - path), path); /* * Move out the boot flag argument. */ options = 0; ucp = (char *)p->p_sysent->sv_usrstack; (void)subyte(--ucp, 0); /* trailing zero */ if (boothowto & RB_SINGLE) { (void)subyte(--ucp, 's'); options = 1; } #ifdef notyet if (boothowto & RB_FASTBOOT) { (void)subyte(--ucp, 'f'); options = 1; } #endif #ifdef BOOTCDROM (void)subyte(--ucp, 'C'); options = 1; #endif if (options == 0) (void)subyte(--ucp, '-'); (void)subyte(--ucp, '-'); /* leading hyphen */ arg1 = ucp; /* * Move out the file name (also arg 0). */ (void)subyte(--ucp, 0); for (s = next - 1; s >= path; s--) (void)subyte(--ucp, *s); arg0 = ucp; /* * Move out the arg pointers. */ uap = (char **)((intptr_t)ucp & ~(sizeof(intptr_t)-1)); (void)suword((caddr_t)--uap, (long)0); /* terminator */ (void)suword((caddr_t)--uap, (long)(intptr_t)arg1); (void)suword((caddr_t)--uap, (long)(intptr_t)arg0); /* * Point at the arguments. */ args.fname = arg0; args.argv = uap; args.envv = NULL; /* * Now try to exec the program. If can't for any reason * other than it doesn't exist, complain. * * Otherwise, return via fork_trampoline() all the way * to user mode as init! */ if ((error = sys_execve(td, &args)) == 0) { mtx_unlock(&Giant); return; } if (error != ENOENT) printf("exec %.*s: error %d\n", (int)(next - path), path, error); } printf("init: not found in path %s\n", init_path); panic("no init"); } /* * Like kproc_create(), but runs in it's own address space. * We do this early to reserve pid 1. * * Note special case - do not make it runnable yet. Other work * in progress will change this more. */ static void create_init(const void *udata __unused) { struct ucred *newcred, *oldcred; int error; error = fork1(&thread0, RFFDG | RFPROC | RFSTOPPED, 0, &initproc, NULL, 0); if (error) panic("cannot fork init: %d\n", error); KASSERT(initproc->p_pid == 1, ("create_init: initproc->p_pid != 1")); /* divorce init's credentials from the kernel's */ newcred = crget(); sx_xlock(&proctree_lock); PROC_LOCK(initproc); initproc->p_flag |= P_SYSTEM | P_INMEM; initproc->p_treeflag |= P_TREE_REAPER; LIST_INSERT_HEAD(&initproc->p_reaplist, &proc0, p_reapsibling); oldcred = initproc->p_ucred; crcopy(newcred, oldcred); #ifdef MAC mac_cred_create_init(newcred); #endif #ifdef AUDIT audit_cred_proc1(newcred); #endif proc_set_cred(initproc, newcred); PROC_UNLOCK(initproc); sx_xunlock(&proctree_lock); crfree(oldcred); cred_update_thread(FIRST_THREAD_IN_PROC(initproc)); cpu_set_fork_handler(FIRST_THREAD_IN_PROC(initproc), start_init, NULL); } SYSINIT(init, SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL); /* * Make it runnable now. */ static void kick_init(const void *udata __unused) { struct thread *td; td = FIRST_THREAD_IN_PROC(initproc); thread_lock(td); TD_SET_CAN_RUN(td); sched_add(td, SRQ_BORING); thread_unlock(td); } SYSINIT(kickinit, SI_SUB_KTHREAD_INIT, SI_ORDER_MIDDLE, kick_init, NULL); Index: projects/ci20_mips/sys/kern/kern_condvar.c =================================================================== --- projects/ci20_mips/sys/kern/kern_condvar.c (revision 283030) +++ projects/ci20_mips/sys/kern/kern_condvar.c (revision 283031) @@ -1,457 +1,458 @@ /*- * Copyright (c) 2000 Jake Burkholder . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_ktrace.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KTRACE #include #include #endif /* * Common sanity checks for cv_wait* functions. */ #define CV_ASSERT(cvp, lock, td) do { \ KASSERT((td) != NULL, ("%s: td NULL", __func__)); \ KASSERT(TD_IS_RUNNING(td), ("%s: not TDS_RUNNING", __func__)); \ KASSERT((cvp) != NULL, ("%s: cvp NULL", __func__)); \ KASSERT((lock) != NULL, ("%s: lock NULL", __func__)); \ } while (0) /* * Initialize a condition variable. Must be called before use. */ void cv_init(struct cv *cvp, const char *desc) { cvp->cv_description = desc; cvp->cv_waiters = 0; } /* * Destroy a condition variable. The condition variable must be re-initialized * in order to be re-used. */ void cv_destroy(struct cv *cvp) { #ifdef INVARIANTS struct sleepqueue *sq; sleepq_lock(cvp); sq = sleepq_lookup(cvp); sleepq_release(cvp); KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__)); #endif } /* * Wait on a condition variable. The current thread is placed on the condition * variable's wait queue and suspended. A cv_signal or cv_broadcast on the same * condition variable will resume the thread. The mutex is released before * sleeping and will be held on return. It is recommended that the mutex be * held when cv_signal or cv_broadcast are called. */ void _cv_wait(struct cv *cvp, struct lock_object *lock) { WITNESS_SAVE_DECL(lock_witness); struct lock_class *class; struct thread *td; uintptr_t lock_state; td = curthread; lock_state = 0; #ifdef KTRACE if (KTRPOINT(td, KTR_CSW)) ktrcsw(1, 0, cv_wmesg(cvp)); #endif CV_ASSERT(cvp, lock, td); WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, "Waiting on \"%s\"", cvp->cv_description); class = LOCK_CLASS(lock); if (cold || panicstr) { /* * During autoconfiguration, just give interrupts * a chance, then just return. Don't run any other * thread or panic below, in case this is the idle * process and already asleep. */ return; } sleepq_lock(cvp); - cvp->cv_waiters++; + atomic_add_int(&cvp->cv_waiters, 1); if (lock == &Giant.lock_object) mtx_assert(&Giant, MA_OWNED); DROP_GIANT(); sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); if (lock != &Giant.lock_object) { if (class->lc_flags & LC_SLEEPABLE) sleepq_release(cvp); WITNESS_SAVE(lock, lock_witness); lock_state = class->lc_unlock(lock); if (class->lc_flags & LC_SLEEPABLE) sleepq_lock(cvp); } sleepq_wait(cvp, 0); + atomic_subtract_int(&cvp->cv_waiters, 1); #ifdef KTRACE if (KTRPOINT(td, KTR_CSW)) ktrcsw(0, 0, cv_wmesg(cvp)); #endif PICKUP_GIANT(); if (lock != &Giant.lock_object) { class->lc_lock(lock, lock_state); WITNESS_RESTORE(lock, lock_witness); } } /* * Wait on a condition variable. This function differs from cv_wait by * not aquiring the mutex after condition variable was signaled. */ void _cv_wait_unlock(struct cv *cvp, struct lock_object *lock) { struct lock_class *class; struct thread *td; td = curthread; #ifdef KTRACE if (KTRPOINT(td, KTR_CSW)) ktrcsw(1, 0, cv_wmesg(cvp)); #endif CV_ASSERT(cvp, lock, td); WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, "Waiting on \"%s\"", cvp->cv_description); KASSERT(lock != &Giant.lock_object, ("cv_wait_unlock cannot be used with Giant")); class = LOCK_CLASS(lock); if (cold || panicstr) { /* * During autoconfiguration, just give interrupts * a chance, then just return. Don't run any other * thread or panic below, in case this is the idle * process and already asleep. */ class->lc_unlock(lock); return; } sleepq_lock(cvp); - cvp->cv_waiters++; + atomic_add_int(&cvp->cv_waiters, 1); DROP_GIANT(); sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); if (class->lc_flags & LC_SLEEPABLE) sleepq_release(cvp); class->lc_unlock(lock); if (class->lc_flags & LC_SLEEPABLE) sleepq_lock(cvp); sleepq_wait(cvp, 0); + atomic_subtract_int(&cvp->cv_waiters, 1); #ifdef KTRACE if (KTRPOINT(td, KTR_CSW)) ktrcsw(0, 0, cv_wmesg(cvp)); #endif PICKUP_GIANT(); } /* * Wait on a condition variable, allowing interruption by signals. Return 0 if * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if * a signal was caught. If ERESTART is returned the system call should be * restarted if possible. */ int _cv_wait_sig(struct cv *cvp, struct lock_object *lock) { WITNESS_SAVE_DECL(lock_witness); struct lock_class *class; struct thread *td; uintptr_t lock_state; int rval; td = curthread; lock_state = 0; #ifdef KTRACE if (KTRPOINT(td, KTR_CSW)) ktrcsw(1, 0, cv_wmesg(cvp)); #endif CV_ASSERT(cvp, lock, td); WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, "Waiting on \"%s\"", cvp->cv_description); class = LOCK_CLASS(lock); if (cold || panicstr) { /* * After a panic, or during autoconfiguration, just give * interrupts a chance, then just return; don't run any other * procs or panic below, in case this is the idle process and * already asleep. */ return (0); } sleepq_lock(cvp); - cvp->cv_waiters++; + atomic_add_int(&cvp->cv_waiters, 1); if (lock == &Giant.lock_object) mtx_assert(&Giant, MA_OWNED); DROP_GIANT(); sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR | SLEEPQ_INTERRUPTIBLE, 0); if (lock != &Giant.lock_object) { if (class->lc_flags & LC_SLEEPABLE) sleepq_release(cvp); WITNESS_SAVE(lock, lock_witness); lock_state = class->lc_unlock(lock); if (class->lc_flags & LC_SLEEPABLE) sleepq_lock(cvp); } rval = sleepq_wait_sig(cvp, 0); + atomic_subtract_int(&cvp->cv_waiters, 1); #ifdef KTRACE if (KTRPOINT(td, KTR_CSW)) ktrcsw(0, 0, cv_wmesg(cvp)); #endif PICKUP_GIANT(); if (lock != &Giant.lock_object) { class->lc_lock(lock, lock_state); WITNESS_RESTORE(lock, lock_witness); } return (rval); } /* * Wait on a condition variable for (at most) the value specified in sbt * argument. Returns 0 if the process was resumed by cv_signal or cv_broadcast, * EWOULDBLOCK if the timeout expires. */ int _cv_timedwait_sbt(struct cv *cvp, struct lock_object *lock, sbintime_t sbt, sbintime_t pr, int flags) { WITNESS_SAVE_DECL(lock_witness); struct lock_class *class; struct thread *td; int lock_state, rval; td = curthread; lock_state = 0; #ifdef KTRACE if (KTRPOINT(td, KTR_CSW)) ktrcsw(1, 0, cv_wmesg(cvp)); #endif CV_ASSERT(cvp, lock, td); WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, "Waiting on \"%s\"", cvp->cv_description); class = LOCK_CLASS(lock); if (cold || panicstr) { /* * After a panic, or during autoconfiguration, just give * interrupts a chance, then just return; don't run any other * thread or panic below, in case this is the idle process and * already asleep. */ return 0; } sleepq_lock(cvp); - cvp->cv_waiters++; + atomic_add_int(&cvp->cv_waiters, 1); if (lock == &Giant.lock_object) mtx_assert(&Giant, MA_OWNED); DROP_GIANT(); sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); sleepq_set_timeout_sbt(cvp, sbt, pr, flags); if (lock != &Giant.lock_object) { if (class->lc_flags & LC_SLEEPABLE) sleepq_release(cvp); WITNESS_SAVE(lock, lock_witness); lock_state = class->lc_unlock(lock); if (class->lc_flags & LC_SLEEPABLE) sleepq_lock(cvp); } rval = sleepq_timedwait(cvp, 0); + atomic_subtract_int(&cvp->cv_waiters, 1); #ifdef KTRACE if (KTRPOINT(td, KTR_CSW)) ktrcsw(0, 0, cv_wmesg(cvp)); #endif PICKUP_GIANT(); if (lock != &Giant.lock_object) { class->lc_lock(lock, lock_state); WITNESS_RESTORE(lock, lock_witness); } return (rval); } /* * Wait on a condition variable for (at most) the value specified in sbt * argument, allowing interruption by signals. * Returns 0 if the thread was resumed by cv_signal or cv_broadcast, * EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if a signal * was caught. */ int _cv_timedwait_sig_sbt(struct cv *cvp, struct lock_object *lock, sbintime_t sbt, sbintime_t pr, int flags) { WITNESS_SAVE_DECL(lock_witness); struct lock_class *class; struct thread *td; int lock_state, rval; td = curthread; lock_state = 0; #ifdef KTRACE if (KTRPOINT(td, KTR_CSW)) ktrcsw(1, 0, cv_wmesg(cvp)); #endif CV_ASSERT(cvp, lock, td); WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, "Waiting on \"%s\"", cvp->cv_description); class = LOCK_CLASS(lock); if (cold || panicstr) { /* * After a panic, or during autoconfiguration, just give * interrupts a chance, then just return; don't run any other * thread or panic below, in case this is the idle process and * already asleep. */ return 0; } sleepq_lock(cvp); - cvp->cv_waiters++; + atomic_add_int(&cvp->cv_waiters, 1); if (lock == &Giant.lock_object) mtx_assert(&Giant, MA_OWNED); DROP_GIANT(); sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR | SLEEPQ_INTERRUPTIBLE, 0); sleepq_set_timeout_sbt(cvp, sbt, pr, flags); if (lock != &Giant.lock_object) { if (class->lc_flags & LC_SLEEPABLE) sleepq_release(cvp); WITNESS_SAVE(lock, lock_witness); lock_state = class->lc_unlock(lock); if (class->lc_flags & LC_SLEEPABLE) sleepq_lock(cvp); } rval = sleepq_timedwait_sig(cvp, 0); + atomic_subtract_int(&cvp->cv_waiters, 1); #ifdef KTRACE if (KTRPOINT(td, KTR_CSW)) ktrcsw(0, 0, cv_wmesg(cvp)); #endif PICKUP_GIANT(); if (lock != &Giant.lock_object) { class->lc_lock(lock, lock_state); WITNESS_RESTORE(lock, lock_witness); } return (rval); } /* * Signal a condition variable, wakes up one waiting thread. Will also wakeup * the swapper if the process is not in memory, so that it can bring the * sleeping process in. Note that this may also result in additional threads * being made runnable. Should be called with the same mutex as was passed to * cv_wait held. */ void cv_signal(struct cv *cvp) { int wakeup_swapper; wakeup_swapper = 0; sleepq_lock(cvp); - if (cvp->cv_waiters > 0) { - cvp->cv_waiters--; + if (cvp->cv_waiters > 0) wakeup_swapper = sleepq_signal(cvp, SLEEPQ_CONDVAR, 0, 0); - } sleepq_release(cvp); if (wakeup_swapper) kick_proc0(); } /* * Broadcast a signal to a condition variable. Wakes up all waiting threads. * Should be called with the same mutex as was passed to cv_wait held. */ void cv_broadcastpri(struct cv *cvp, int pri) { int wakeup_swapper; /* * XXX sleepq_broadcast pri argument changed from -1 meaning * no pri to 0 meaning no pri. */ wakeup_swapper = 0; if (pri == -1) pri = 0; sleepq_lock(cvp); - if (cvp->cv_waiters > 0) { - cvp->cv_waiters = 0; + if (cvp->cv_waiters > 0) wakeup_swapper = sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri, 0); - } sleepq_release(cvp); if (wakeup_swapper) kick_proc0(); } Index: projects/ci20_mips/sys/kern/kern_thread.c =================================================================== --- projects/ci20_mips/sys/kern/kern_thread.c (revision 283030) +++ projects/ci20_mips/sys/kern/kern_thread.c (revision 283031) @@ -1,1137 +1,1146 @@ /*- * Copyright (C) 2001 Julian Elischer . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice(s), this list of conditions and the following disclaimer as * the first lines of this file unmodified other than the possible * addition of one or more copyright notices. * 2. Redistributions in binary form must reproduce the above copyright * notice(s), this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include "opt_witness.h" #include "opt_hwpmc_hooks.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HWPMC_HOOKS #include #endif #include #include #include #include #include SDT_PROVIDER_DECLARE(proc); SDT_PROBE_DEFINE(proc, , , lwp__exit); /* * thread related storage. */ static uma_zone_t thread_zone; TAILQ_HEAD(, thread) zombie_threads = TAILQ_HEAD_INITIALIZER(zombie_threads); static struct mtx zombie_lock; MTX_SYSINIT(zombie_lock, &zombie_lock, "zombie lock", MTX_SPIN); static void thread_zombie(struct thread *); +static int thread_unsuspend_one(struct thread *td, struct proc *p, + bool boundary); #define TID_BUFFER_SIZE 1024 struct mtx tid_lock; static struct unrhdr *tid_unrhdr; static lwpid_t tid_buffer[TID_BUFFER_SIZE]; static int tid_head, tid_tail; static MALLOC_DEFINE(M_TIDHASH, "tidhash", "thread hash"); struct tidhashhead *tidhashtbl; u_long tidhash; struct rwlock tidhash_lock; static lwpid_t tid_alloc(void) { lwpid_t tid; tid = alloc_unr(tid_unrhdr); if (tid != -1) return (tid); mtx_lock(&tid_lock); if (tid_head == tid_tail) { mtx_unlock(&tid_lock); return (-1); } tid = tid_buffer[tid_head]; tid_head = (tid_head + 1) % TID_BUFFER_SIZE; mtx_unlock(&tid_lock); return (tid); } static void tid_free(lwpid_t tid) { lwpid_t tmp_tid = -1; mtx_lock(&tid_lock); if ((tid_tail + 1) % TID_BUFFER_SIZE == tid_head) { tmp_tid = tid_buffer[tid_head]; tid_head = (tid_head + 1) % TID_BUFFER_SIZE; } tid_buffer[tid_tail] = tid; tid_tail = (tid_tail + 1) % TID_BUFFER_SIZE; mtx_unlock(&tid_lock); if (tmp_tid != -1) free_unr(tid_unrhdr, tmp_tid); } /* * Prepare a thread for use. */ static int thread_ctor(void *mem, int size, void *arg, int flags) { struct thread *td; td = (struct thread *)mem; td->td_state = TDS_INACTIVE; td->td_oncpu = NOCPU; td->td_tid = tid_alloc(); /* * Note that td_critnest begins life as 1 because the thread is not * running and is thereby implicitly waiting to be on the receiving * end of a context switch. */ td->td_critnest = 1; td->td_lend_user_pri = PRI_MAX; EVENTHANDLER_INVOKE(thread_ctor, td); #ifdef AUDIT audit_thread_alloc(td); #endif umtx_thread_alloc(td); return (0); } /* * Reclaim a thread after use. */ static void thread_dtor(void *mem, int size, void *arg) { struct thread *td; td = (struct thread *)mem; #ifdef INVARIANTS /* Verify that this thread is in a safe state to free. */ switch (td->td_state) { case TDS_INHIBITED: case TDS_RUNNING: case TDS_CAN_RUN: case TDS_RUNQ: /* * We must never unlink a thread that is in one of * these states, because it is currently active. */ panic("bad state for thread unlinking"); /* NOTREACHED */ case TDS_INACTIVE: break; default: panic("bad thread state"); /* NOTREACHED */ } #endif #ifdef AUDIT audit_thread_free(td); #endif /* Free all OSD associated to this thread. */ osd_thread_exit(td); EVENTHANDLER_INVOKE(thread_dtor, td); tid_free(td->td_tid); } /* * Initialize type-stable parts of a thread (when newly created). */ static int thread_init(void *mem, int size, int flags) { struct thread *td; td = (struct thread *)mem; td->td_sleepqueue = sleepq_alloc(); td->td_turnstile = turnstile_alloc(); td->td_rlqe = NULL; EVENTHANDLER_INVOKE(thread_init, td); td->td_sched = (struct td_sched *)&td[1]; umtx_thread_init(td); td->td_kstack = 0; td->td_sel = NULL; return (0); } /* * Tear down type-stable parts of a thread (just before being discarded). */ static void thread_fini(void *mem, int size) { struct thread *td; td = (struct thread *)mem; EVENTHANDLER_INVOKE(thread_fini, td); rlqentry_free(td->td_rlqe); turnstile_free(td->td_turnstile); sleepq_free(td->td_sleepqueue); umtx_thread_fini(td); seltdfini(td); } /* * For a newly created process, * link up all the structures and its initial threads etc. * called from: * {arch}/{arch}/machdep.c {arch}_init(), init386() etc. * proc_dtor() (should go away) * proc_init() */ void proc_linkup0(struct proc *p, struct thread *td) { TAILQ_INIT(&p->p_threads); /* all threads in proc */ proc_linkup(p, td); } void proc_linkup(struct proc *p, struct thread *td) { sigqueue_init(&p->p_sigqueue, p); p->p_ksi = ksiginfo_alloc(1); if (p->p_ksi != NULL) { /* XXX p_ksi may be null if ksiginfo zone is not ready */ p->p_ksi->ksi_flags = KSI_EXT | KSI_INS; } LIST_INIT(&p->p_mqnotifier); p->p_numthreads = 0; thread_link(td, p); } /* * Initialize global thread allocation resources. */ void threadinit(void) { mtx_init(&tid_lock, "TID lock", NULL, MTX_DEF); /* * pid_max cannot be greater than PID_MAX. * leave one number for thread0. */ tid_unrhdr = new_unrhdr(PID_MAX + 2, INT_MAX, &tid_lock); thread_zone = uma_zcreate("THREAD", sched_sizeof_thread(), thread_ctor, thread_dtor, thread_init, thread_fini, 16 - 1, 0); tidhashtbl = hashinit(maxproc / 2, M_TIDHASH, &tidhash); rw_init(&tidhash_lock, "tidhash"); } /* * Place an unused thread on the zombie list. * Use the slpq as that must be unused by now. */ void thread_zombie(struct thread *td) { mtx_lock_spin(&zombie_lock); TAILQ_INSERT_HEAD(&zombie_threads, td, td_slpq); mtx_unlock_spin(&zombie_lock); } /* * Release a thread that has exited after cpu_throw(). */ void thread_stash(struct thread *td) { atomic_subtract_rel_int(&td->td_proc->p_exitthreads, 1); thread_zombie(td); } /* * Reap zombie resources. */ void thread_reap(void) { struct thread *td_first, *td_next; /* * Don't even bother to lock if none at this instant, * we really don't care about the next instant.. */ if (!TAILQ_EMPTY(&zombie_threads)) { mtx_lock_spin(&zombie_lock); td_first = TAILQ_FIRST(&zombie_threads); if (td_first) TAILQ_INIT(&zombie_threads); mtx_unlock_spin(&zombie_lock); while (td_first) { td_next = TAILQ_NEXT(td_first, td_slpq); if (td_first->td_ucred) crfree(td_first->td_ucred); thread_free(td_first); td_first = td_next; } } } /* * Allocate a thread. */ struct thread * thread_alloc(int pages) { struct thread *td; thread_reap(); /* check if any zombies to get */ td = (struct thread *)uma_zalloc(thread_zone, M_WAITOK); KASSERT(td->td_kstack == 0, ("thread_alloc got thread with kstack")); if (!vm_thread_new(td, pages)) { uma_zfree(thread_zone, td); return (NULL); } cpu_thread_alloc(td); return (td); } int thread_alloc_stack(struct thread *td, int pages) { KASSERT(td->td_kstack == 0, ("thread_alloc_stack called on a thread with kstack")); if (!vm_thread_new(td, pages)) return (0); cpu_thread_alloc(td); return (1); } /* * Deallocate a thread. */ void thread_free(struct thread *td) { lock_profile_thread_exit(td); if (td->td_cpuset) cpuset_rel(td->td_cpuset); td->td_cpuset = NULL; cpu_thread_free(td); if (td->td_kstack != 0) vm_thread_dispose(td); uma_zfree(thread_zone, td); } /* * Discard the current thread and exit from its context. * Always called with scheduler locked. * * Because we can't free a thread while we're operating under its context, * push the current thread into our CPU's deadthread holder. This means * we needn't worry about someone else grabbing our context before we * do a cpu_throw(). */ void thread_exit(void) { uint64_t runtime, new_switchtime; struct thread *td; struct thread *td2; struct proc *p; int wakeup_swapper; td = curthread; p = td->td_proc; PROC_SLOCK_ASSERT(p, MA_OWNED); mtx_assert(&Giant, MA_NOTOWNED); PROC_LOCK_ASSERT(p, MA_OWNED); KASSERT(p != NULL, ("thread exiting without a process")); CTR3(KTR_PROC, "thread_exit: thread %p (pid %ld, %s)", td, (long)p->p_pid, td->td_name); KASSERT(TAILQ_EMPTY(&td->td_sigqueue.sq_list), ("signal pending")); #ifdef AUDIT AUDIT_SYSCALL_EXIT(0, td); #endif /* * drop FPU & debug register state storage, or any other * architecture specific resources that * would not be on a new untouched process. */ cpu_thread_exit(td); /* XXXSMP */ /* * The last thread is left attached to the process * So that the whole bundle gets recycled. Skip * all this stuff if we never had threads. * EXIT clears all sign of other threads when * it goes to single threading, so the last thread always * takes the short path. */ if (p->p_flag & P_HADTHREADS) { if (p->p_numthreads > 1) { atomic_add_int(&td->td_proc->p_exitthreads, 1); thread_unlink(td); td2 = FIRST_THREAD_IN_PROC(p); sched_exit_thread(td2, td); /* * The test below is NOT true if we are the * sole exiting thread. P_STOPPED_SINGLE is unset * in exit1() after it is the only survivor. */ if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) { if (p->p_numthreads == p->p_suspcount) { thread_lock(p->p_singlethread); wakeup_swapper = thread_unsuspend_one( - p->p_singlethread, p); + p->p_singlethread, p, false); thread_unlock(p->p_singlethread); if (wakeup_swapper) kick_proc0(); } } PCPU_SET(deadthread, td); } else { /* * The last thread is exiting.. but not through exit() */ panic ("thread_exit: Last thread exiting on its own"); } } #ifdef HWPMC_HOOKS /* * If this thread is part of a process that is being tracked by hwpmc(4), * inform the module of the thread's impending exit. */ if (PMC_PROC_IS_USING_PMCS(td->td_proc)) PMC_SWITCH_CONTEXT(td, PMC_FN_CSW_OUT); #endif PROC_UNLOCK(p); PROC_STATLOCK(p); thread_lock(td); PROC_SUNLOCK(p); /* Do the same timestamp bookkeeping that mi_switch() would do. */ new_switchtime = cpu_ticks(); runtime = new_switchtime - PCPU_GET(switchtime); td->td_runtime += runtime; td->td_incruntime += runtime; PCPU_SET(switchtime, new_switchtime); PCPU_SET(switchticks, ticks); PCPU_INC(cnt.v_swtch); /* Save our resource usage in our process. */ td->td_ru.ru_nvcsw++; ruxagg(p, td); rucollect(&p->p_ru, &td->td_ru); PROC_STATUNLOCK(p); td->td_state = TDS_INACTIVE; #ifdef WITNESS witness_thread_exit(td); #endif CTR1(KTR_PROC, "thread_exit: cpu_throw() thread %p", td); sched_throw(td); panic("I'm a teapot!"); /* NOTREACHED */ } /* * Do any thread specific cleanups that may be needed in wait() * called with Giant, proc and schedlock not held. */ void thread_wait(struct proc *p) { struct thread *td; mtx_assert(&Giant, MA_NOTOWNED); KASSERT(p->p_numthreads == 1, ("multiple threads in thread_wait()")); KASSERT(p->p_exitthreads == 0, ("p_exitthreads leaking")); td = FIRST_THREAD_IN_PROC(p); /* Lock the last thread so we spin until it exits cpu_throw(). */ thread_lock(td); thread_unlock(td); lock_profile_thread_exit(td); cpuset_rel(td->td_cpuset); td->td_cpuset = NULL; cpu_thread_clean(td); crfree(td->td_ucred); thread_reap(); /* check for zombie threads etc. */ } /* * Link a thread to a process. * set up anything that needs to be initialized for it to * be used by the process. */ void thread_link(struct thread *td, struct proc *p) { /* * XXX This can't be enabled because it's called for proc0 before * its lock has been created. * PROC_LOCK_ASSERT(p, MA_OWNED); */ td->td_state = TDS_INACTIVE; td->td_proc = p; td->td_flags = TDF_INMEM; LIST_INIT(&td->td_contested); LIST_INIT(&td->td_lprof[0]); LIST_INIT(&td->td_lprof[1]); sigqueue_init(&td->td_sigqueue, p); callout_init(&td->td_slpcallout, CALLOUT_MPSAFE); TAILQ_INSERT_TAIL(&p->p_threads, td, td_plist); p->p_numthreads++; } /* * Called from: * thread_exit() */ void thread_unlink(struct thread *td) { struct proc *p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); TAILQ_REMOVE(&p->p_threads, td, td_plist); p->p_numthreads--; /* could clear a few other things here */ /* Must NOT clear links to proc! */ } static int calc_remaining(struct proc *p, int mode) { int remaining; PROC_LOCK_ASSERT(p, MA_OWNED); PROC_SLOCK_ASSERT(p, MA_OWNED); if (mode == SINGLE_EXIT) remaining = p->p_numthreads; else if (mode == SINGLE_BOUNDARY) remaining = p->p_numthreads - p->p_boundary_count; else if (mode == SINGLE_NO_EXIT || mode == SINGLE_ALLPROC) remaining = p->p_numthreads - p->p_suspcount; else panic("calc_remaining: wrong mode %d", mode); return (remaining); } static int remain_for_mode(int mode) { return (mode == SINGLE_ALLPROC ? 0 : 1); } static int weed_inhib(int mode, struct thread *td2, struct proc *p) { int wakeup_swapper; PROC_LOCK_ASSERT(p, MA_OWNED); PROC_SLOCK_ASSERT(p, MA_OWNED); THREAD_LOCK_ASSERT(td2, MA_OWNED); wakeup_swapper = 0; switch (mode) { case SINGLE_EXIT: if (TD_IS_SUSPENDED(td2)) - wakeup_swapper |= thread_unsuspend_one(td2, p); + wakeup_swapper |= thread_unsuspend_one(td2, p, true); if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR) != 0) wakeup_swapper |= sleepq_abort(td2, EINTR); break; case SINGLE_BOUNDARY: if (TD_IS_SUSPENDED(td2) && (td2->td_flags & TDF_BOUNDARY) == 0) - wakeup_swapper |= thread_unsuspend_one(td2, p); + wakeup_swapper |= thread_unsuspend_one(td2, p, false); if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR) != 0) wakeup_swapper |= sleepq_abort(td2, ERESTART); break; case SINGLE_NO_EXIT: if (TD_IS_SUSPENDED(td2) && (td2->td_flags & TDF_BOUNDARY) == 0) - wakeup_swapper |= thread_unsuspend_one(td2, p); + wakeup_swapper |= thread_unsuspend_one(td2, p, false); if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR) != 0) wakeup_swapper |= sleepq_abort(td2, ERESTART); break; case SINGLE_ALLPROC: /* * ALLPROC suspend tries to avoid spurious EINTR for * threads sleeping interruptable, by suspending the * thread directly, similarly to sig_suspend_threads(). * Since such sleep is not performed at the user * boundary, TDF_BOUNDARY flag is not set, and TDF_ALLPROCSUSP * is used to avoid immediate un-suspend. */ if (TD_IS_SUSPENDED(td2) && (td2->td_flags & (TDF_BOUNDARY | TDF_ALLPROCSUSP)) == 0) - wakeup_swapper |= thread_unsuspend_one(td2, p); + wakeup_swapper |= thread_unsuspend_one(td2, p, false); if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR) != 0) { if ((td2->td_flags & TDF_SBDRY) == 0) { thread_suspend_one(td2); td2->td_flags |= TDF_ALLPROCSUSP; } else { wakeup_swapper |= sleepq_abort(td2, ERESTART); } } break; } return (wakeup_swapper); } /* * Enforce single-threading. * * Returns 1 if the caller must abort (another thread is waiting to * exit the process or similar). Process is locked! * Returns 0 when you are successfully the only thread running. * A process has successfully single threaded in the suspend mode when * There are no threads in user mode. Threads in the kernel must be * allowed to continue until they get to the user boundary. They may even * copy out their return values and data before suspending. They may however be * accelerated in reaching the user boundary as we will wake up * any sleeping threads that are interruptable. (PCATCH). */ int thread_single(struct proc *p, int mode) { struct thread *td; struct thread *td2; int remaining, wakeup_swapper; td = curthread; KASSERT(mode == SINGLE_EXIT || mode == SINGLE_BOUNDARY || mode == SINGLE_ALLPROC || mode == SINGLE_NO_EXIT, ("invalid mode %d", mode)); /* * If allowing non-ALLPROC singlethreading for non-curproc * callers, calc_remaining() and remain_for_mode() should be * adjusted to also account for td->td_proc != p. For now * this is not implemented because it is not used. */ KASSERT((mode == SINGLE_ALLPROC && td->td_proc != p) || (mode != SINGLE_ALLPROC && td->td_proc == p), ("mode %d proc %p curproc %p", mode, p, td->td_proc)); mtx_assert(&Giant, MA_NOTOWNED); PROC_LOCK_ASSERT(p, MA_OWNED); if ((p->p_flag & P_HADTHREADS) == 0 && mode != SINGLE_ALLPROC) return (0); /* Is someone already single threading? */ if (p->p_singlethread != NULL && p->p_singlethread != td) return (1); if (mode == SINGLE_EXIT) { p->p_flag |= P_SINGLE_EXIT; p->p_flag &= ~P_SINGLE_BOUNDARY; } else { p->p_flag &= ~P_SINGLE_EXIT; if (mode == SINGLE_BOUNDARY) p->p_flag |= P_SINGLE_BOUNDARY; else p->p_flag &= ~P_SINGLE_BOUNDARY; } if (mode == SINGLE_ALLPROC) p->p_flag |= P_TOTAL_STOP; p->p_flag |= P_STOPPED_SINGLE; PROC_SLOCK(p); p->p_singlethread = td; remaining = calc_remaining(p, mode); while (remaining != remain_for_mode(mode)) { if (P_SHOULDSTOP(p) != P_STOPPED_SINGLE) goto stopme; wakeup_swapper = 0; FOREACH_THREAD_IN_PROC(p, td2) { if (td2 == td) continue; thread_lock(td2); td2->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK; if (TD_IS_INHIBITED(td2)) { wakeup_swapper |= weed_inhib(mode, td2, p); #ifdef SMP } else if (TD_IS_RUNNING(td2) && td != td2) { forward_signal(td2); #endif } thread_unlock(td2); } if (wakeup_swapper) kick_proc0(); remaining = calc_remaining(p, mode); /* * Maybe we suspended some threads.. was it enough? */ if (remaining == remain_for_mode(mode)) break; stopme: /* * Wake us up when everyone else has suspended. * In the mean time we suspend as well. */ thread_suspend_switch(td, p); remaining = calc_remaining(p, mode); } if (mode == SINGLE_EXIT) { /* * Convert the process to an unthreaded process. The * SINGLE_EXIT is called by exit1() or execve(), in * both cases other threads must be retired. */ KASSERT(p->p_numthreads == 1, ("Unthreading with >1 threads")); p->p_singlethread = NULL; p->p_flag &= ~(P_STOPPED_SINGLE | P_SINGLE_EXIT | P_HADTHREADS); /* * Wait for any remaining threads to exit cpu_throw(). */ while (p->p_exitthreads != 0) { PROC_SUNLOCK(p); PROC_UNLOCK(p); sched_relinquish(td); PROC_LOCK(p); PROC_SLOCK(p); } } else if (mode == SINGLE_BOUNDARY) { /* * Wait until all suspended threads are removed from * the processors. The thread_suspend_check() * increments p_boundary_count while it is still * running, which makes it possible for the execve() * to destroy vmspace while our other threads are * still using the address space. * * We lock the thread, which is only allowed to * succeed after context switch code finished using * the address space. */ FOREACH_THREAD_IN_PROC(p, td2) { if (td2 == td) continue; thread_lock(td2); KASSERT((td2->td_flags & TDF_BOUNDARY) != 0, ("td %p not on boundary", td2)); KASSERT(TD_IS_SUSPENDED(td2), ("td %p is not suspended", td2)); thread_unlock(td2); } } PROC_SUNLOCK(p); return (0); } bool thread_suspend_check_needed(void) { struct proc *p; struct thread *td; td = curthread; p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); return (P_SHOULDSTOP(p) || ((p->p_flag & P_TRACED) != 0 && (td->td_dbgflags & TDB_SUSPEND) != 0)); } /* * Called in from locations that can safely check to see * whether we have to suspend or at least throttle for a * single-thread event (e.g. fork). * * Such locations include userret(). * If the "return_instead" argument is non zero, the thread must be able to * accept 0 (caller may continue), or 1 (caller must abort) as a result. * * The 'return_instead' argument tells the function if it may do a * thread_exit() or suspend, or whether the caller must abort and back * out instead. * * If the thread that set the single_threading request has set the * P_SINGLE_EXIT bit in the process flags then this call will never return * if 'return_instead' is false, but will exit. * * P_SINGLE_EXIT | return_instead == 0| return_instead != 0 *---------------+--------------------+--------------------- * 0 | returns 0 | returns 0 or 1 * | when ST ends | immediately *---------------+--------------------+--------------------- * 1 | thread exits | returns 1 * | | immediately * 0 = thread_exit() or suspension ok, * other = return error instead of stopping the thread. * * While a full suspension is under effect, even a single threading * thread would be suspended if it made this call (but it shouldn't). * This call should only be made from places where * thread_exit() would be safe as that may be the outcome unless * return_instead is set. */ int thread_suspend_check(int return_instead) { struct thread *td; struct proc *p; int wakeup_swapper; td = curthread; p = td->td_proc; mtx_assert(&Giant, MA_NOTOWNED); PROC_LOCK_ASSERT(p, MA_OWNED); while (thread_suspend_check_needed()) { if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) { KASSERT(p->p_singlethread != NULL, ("singlethread not set")); /* * The only suspension in action is a * single-threading. Single threader need not stop. * XXX Should be safe to access unlocked * as it can only be set to be true by us. */ if (p->p_singlethread == td) return (0); /* Exempt from stopping. */ } if ((p->p_flag & P_SINGLE_EXIT) && return_instead) return (EINTR); /* Should we goto user boundary if we didn't come from there? */ if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE && (p->p_flag & P_SINGLE_BOUNDARY) && return_instead) return (ERESTART); /* * Ignore suspend requests for stop signals if they * are deferred. */ if ((P_SHOULDSTOP(p) == P_STOPPED_SIG || (p->p_flag & P_TOTAL_STOP) != 0) && (td->td_flags & TDF_SBDRY) != 0) { KASSERT(return_instead, ("TDF_SBDRY set for unsafe thread_suspend_check")); return (0); } /* * If the process is waiting for us to exit, * this thread should just suicide. * Assumes that P_SINGLE_EXIT implies P_STOPPED_SINGLE. */ if ((p->p_flag & P_SINGLE_EXIT) && (p->p_singlethread != td)) { PROC_UNLOCK(p); tidhash_remove(td); PROC_LOCK(p); tdsigcleanup(td); umtx_thread_exit(td); PROC_SLOCK(p); thread_stopped(p); thread_exit(); } PROC_SLOCK(p); thread_stopped(p); if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) { if (p->p_numthreads == p->p_suspcount + 1) { thread_lock(p->p_singlethread); - wakeup_swapper = - thread_unsuspend_one(p->p_singlethread, p); + wakeup_swapper = thread_unsuspend_one( + p->p_singlethread, p, false); thread_unlock(p->p_singlethread); if (wakeup_swapper) kick_proc0(); } } PROC_UNLOCK(p); thread_lock(td); /* * When a thread suspends, it just * gets taken off all queues. */ thread_suspend_one(td); if (return_instead == 0) { p->p_boundary_count++; td->td_flags |= TDF_BOUNDARY; } PROC_SUNLOCK(p); mi_switch(SW_INVOL | SWT_SUSPEND, NULL); - if (return_instead == 0) - td->td_flags &= ~TDF_BOUNDARY; thread_unlock(td); PROC_LOCK(p); - if (return_instead == 0) { - PROC_SLOCK(p); - p->p_boundary_count--; - PROC_SUNLOCK(p); - } } return (0); } void thread_suspend_switch(struct thread *td, struct proc *p) { KASSERT(!TD_IS_SUSPENDED(td), ("already suspended")); PROC_LOCK_ASSERT(p, MA_OWNED); PROC_SLOCK_ASSERT(p, MA_OWNED); /* * We implement thread_suspend_one in stages here to avoid * dropping the proc lock while the thread lock is owned. */ if (p == td->td_proc) { thread_stopped(p); p->p_suspcount++; } PROC_UNLOCK(p); thread_lock(td); td->td_flags &= ~TDF_NEEDSUSPCHK; TD_SET_SUSPENDED(td); sched_sleep(td, 0); PROC_SUNLOCK(p); DROP_GIANT(); mi_switch(SW_VOL | SWT_SUSPEND, NULL); thread_unlock(td); PICKUP_GIANT(); PROC_LOCK(p); PROC_SLOCK(p); } void thread_suspend_one(struct thread *td) { struct proc *p; p = td->td_proc; PROC_SLOCK_ASSERT(p, MA_OWNED); THREAD_LOCK_ASSERT(td, MA_OWNED); KASSERT(!TD_IS_SUSPENDED(td), ("already suspended")); p->p_suspcount++; td->td_flags &= ~TDF_NEEDSUSPCHK; TD_SET_SUSPENDED(td); sched_sleep(td, 0); } -int -thread_unsuspend_one(struct thread *td, struct proc *p) +static int +thread_unsuspend_one(struct thread *td, struct proc *p, bool boundary) { THREAD_LOCK_ASSERT(td, MA_OWNED); KASSERT(TD_IS_SUSPENDED(td), ("Thread not suspended")); TD_CLR_SUSPENDED(td); td->td_flags &= ~TDF_ALLPROCSUSP; if (td->td_proc == p) { PROC_SLOCK_ASSERT(p, MA_OWNED); p->p_suspcount--; + if (boundary && (td->td_flags & TDF_BOUNDARY) != 0) { + td->td_flags &= ~TDF_BOUNDARY; + p->p_boundary_count--; + } } return (setrunnable(td)); } /* * Allow all threads blocked by single threading to continue running. */ void thread_unsuspend(struct proc *p) { struct thread *td; int wakeup_swapper; PROC_LOCK_ASSERT(p, MA_OWNED); PROC_SLOCK_ASSERT(p, MA_OWNED); wakeup_swapper = 0; if (!P_SHOULDSTOP(p)) { FOREACH_THREAD_IN_PROC(p, td) { thread_lock(td); if (TD_IS_SUSPENDED(td)) { - wakeup_swapper |= thread_unsuspend_one(td, p); + wakeup_swapper |= thread_unsuspend_one(td, p, + true); } thread_unlock(td); } - } else if ((P_SHOULDSTOP(p) == P_STOPPED_SINGLE) && - (p->p_numthreads == p->p_suspcount)) { + } else if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE && + p->p_numthreads == p->p_suspcount) { /* * Stopping everything also did the job for the single * threading request. Now we've downgraded to single-threaded, * let it continue. */ if (p->p_singlethread->td_proc == p) { thread_lock(p->p_singlethread); wakeup_swapper = thread_unsuspend_one( - p->p_singlethread, p); + p->p_singlethread, p, false); thread_unlock(p->p_singlethread); } } if (wakeup_swapper) kick_proc0(); } /* * End the single threading mode.. */ void thread_single_end(struct proc *p, int mode) { struct thread *td; int wakeup_swapper; KASSERT(mode == SINGLE_EXIT || mode == SINGLE_BOUNDARY || mode == SINGLE_ALLPROC || mode == SINGLE_NO_EXIT, ("invalid mode %d", mode)); PROC_LOCK_ASSERT(p, MA_OWNED); KASSERT((mode == SINGLE_ALLPROC && (p->p_flag & P_TOTAL_STOP) != 0) || (mode != SINGLE_ALLPROC && (p->p_flag & P_TOTAL_STOP) == 0), ("mode %d does not match P_TOTAL_STOP", mode)); + KASSERT(mode == SINGLE_ALLPROC || p->p_singlethread == curthread, + ("thread_single_end from other thread %p %p", + curthread, p->p_singlethread)); + KASSERT(mode != SINGLE_BOUNDARY || + (p->p_flag & P_SINGLE_BOUNDARY) != 0, + ("mis-matched SINGLE_BOUNDARY flags %x", p->p_flag)); p->p_flag &= ~(P_STOPPED_SINGLE | P_SINGLE_EXIT | P_SINGLE_BOUNDARY | P_TOTAL_STOP); PROC_SLOCK(p); p->p_singlethread = NULL; wakeup_swapper = 0; /* * If there are other threads they may now run, * unless of course there is a blanket 'stop order' * on the process. The single threader must be allowed * to continue however as this is a bad place to stop. */ if (p->p_numthreads != remain_for_mode(mode) && !P_SHOULDSTOP(p)) { FOREACH_THREAD_IN_PROC(p, td) { thread_lock(td); if (TD_IS_SUSPENDED(td)) { - wakeup_swapper |= thread_unsuspend_one(td, p); + wakeup_swapper |= thread_unsuspend_one(td, p, + mode == SINGLE_BOUNDARY); } thread_unlock(td); } } + KASSERT(mode != SINGLE_BOUNDARY || p->p_boundary_count == 0, + ("inconsistent boundary count %d", p->p_boundary_count)); PROC_SUNLOCK(p); if (wakeup_swapper) kick_proc0(); } struct thread * thread_find(struct proc *p, lwpid_t tid) { struct thread *td; PROC_LOCK_ASSERT(p, MA_OWNED); FOREACH_THREAD_IN_PROC(p, td) { if (td->td_tid == tid) break; } return (td); } /* Locate a thread by number; return with proc lock held. */ struct thread * tdfind(lwpid_t tid, pid_t pid) { #define RUN_THRESH 16 struct thread *td; int run = 0; rw_rlock(&tidhash_lock); LIST_FOREACH(td, TIDHASH(tid), td_hash) { if (td->td_tid == tid) { if (pid != -1 && td->td_proc->p_pid != pid) { td = NULL; break; } PROC_LOCK(td->td_proc); if (td->td_proc->p_state == PRS_NEW) { PROC_UNLOCK(td->td_proc); td = NULL; break; } if (run > RUN_THRESH) { if (rw_try_upgrade(&tidhash_lock)) { LIST_REMOVE(td, td_hash); LIST_INSERT_HEAD(TIDHASH(td->td_tid), td, td_hash); rw_wunlock(&tidhash_lock); return (td); } } break; } run++; } rw_runlock(&tidhash_lock); return (td); } void tidhash_add(struct thread *td) { rw_wlock(&tidhash_lock); LIST_INSERT_HEAD(TIDHASH(td->td_tid), td, td_hash); rw_wunlock(&tidhash_lock); } void tidhash_remove(struct thread *td) { rw_wlock(&tidhash_lock); LIST_REMOVE(td, td_hash); rw_wunlock(&tidhash_lock); } Index: projects/ci20_mips/sys/mips/beri/beri_simplebus.c =================================================================== --- projects/ci20_mips/sys/mips/beri/beri_simplebus.c (revision 283030) +++ projects/ci20_mips/sys/mips/beri/beri_simplebus.c (revision 283031) @@ -1,429 +1,429 @@ /*- * Copyright (c) 2009-2010 The FreeBSD Foundation * All rights reserved. * * This software was developed by Semihalf under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "fdt_ic_if.h" #include "ofw_bus_if.h" #ifdef DEBUG #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ printf(fmt,##args); } while (0) #else #define debugf(fmt, args...) #endif static MALLOC_DEFINE(M_SIMPLEBUS, "simplebus", "simplebus devices information"); struct simplebus_softc { int sc_addr_cells; int sc_size_cells; }; struct simplebus_devinfo { struct ofw_bus_devinfo di_ofw; struct resource_list di_res; /* Interrupts sense-level info for this device */ struct fdt_sense_level di_intr_sl[DI_MAX_INTR_NUM]; }; /* * Prototypes. */ static int simplebus_probe(device_t); static int simplebus_attach(device_t); static int simplebus_print_child(device_t, device_t); static int simplebus_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); static int simplebus_teardown_intr(device_t, device_t, struct resource *, void *); static int simplebus_activate_resource(device_t, device_t, int, int, struct resource *); static struct resource *simplebus_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); static int simplebus_deactivate_resource(device_t, device_t, int, int, struct resource *); static int simplebus_release_resource(device_t, device_t, int, int, struct resource *); static device_t simplebus_get_interrupt_parent(device_t); static struct resource_list *simplebus_get_resource_list(device_t, device_t); static ofw_bus_get_devinfo_t simplebus_get_devinfo; /* * Bus interface definition. */ static device_method_t simplebus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, simplebus_probe), DEVMETHOD(device_attach, simplebus_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, simplebus_print_child), DEVMETHOD(bus_alloc_resource, simplebus_alloc_resource), DEVMETHOD(bus_release_resource, simplebus_release_resource), DEVMETHOD(bus_activate_resource, simplebus_activate_resource), DEVMETHOD(bus_deactivate_resource, simplebus_deactivate_resource), DEVMETHOD(bus_setup_intr, simplebus_setup_intr), DEVMETHOD(bus_teardown_intr, simplebus_teardown_intr), DEVMETHOD(bus_get_resource_list, simplebus_get_resource_list), /* OFW bus interface */ DEVMETHOD(ofw_bus_get_devinfo, simplebus_get_devinfo), DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), { 0, 0 } }; static driver_t simplebus_driver = { "simplebus", simplebus_methods, sizeof(struct simplebus_softc) }; devclass_t simplebus_devclass; DRIVER_MODULE(beri_simplebus, ofwbus, simplebus_driver, simplebus_devclass, 0, 0); DRIVER_MODULE(beri_simplebus, simplebus, simplebus_driver, simplebus_devclass, 0, 0); static int simplebus_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "simple-bus")) return (ENXIO); device_set_desc(dev, "Flattened device tree simple bus (BERI version)"); return (BUS_PROBE_SPECIFIC); } static int simplebus_attach(device_t dev) { device_t dev_child; struct simplebus_devinfo *di; struct simplebus_softc *sc; phandle_t dt_node, dt_child; sc = device_get_softc(dev); /* * Walk simple-bus and add direct subordinates as our children. */ dt_node = ofw_bus_get_node(dev); for (dt_child = OF_child(dt_node); dt_child != 0; dt_child = OF_peer(dt_child)) { /* Check and process 'status' property. */ if (!(fdt_is_enabled(dt_child))) continue; if (!(fdt_pm_is_enabled(dt_child))) continue; di = malloc(sizeof(*di), M_SIMPLEBUS, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&di->di_ofw, dt_child) != 0) { free(di, M_SIMPLEBUS); device_printf(dev, "could not set up devinfo\n"); continue; } resource_list_init(&di->di_res); if (fdt_reg_to_rl(dt_child, &di->di_res)) { device_printf(dev, "%s: could not process 'reg' " "property\n", di->di_ofw.obd_name); ofw_bus_gen_destroy_devinfo(&di->di_ofw); free(di, M_SIMPLEBUS); continue; } - if (ofw_bus_intr_to_rl(dev, dt_child, &di->di_res)) { + if (ofw_bus_intr_to_rl(dev, dt_child, &di->di_res, NULL)) { device_printf(dev, "%s: could not process " "'interrupts' property\n", di->di_ofw.obd_name); resource_list_free(&di->di_res); ofw_bus_gen_destroy_devinfo(&di->di_ofw); free(di, M_SIMPLEBUS); continue; } /* Add newbus device for this FDT node */ dev_child = device_add_child(dev, NULL, -1); if (dev_child == NULL) { device_printf(dev, "could not add child: %s\n", di->di_ofw.obd_name); resource_list_free(&di->di_res); ofw_bus_gen_destroy_devinfo(&di->di_ofw); free(di, M_SIMPLEBUS); continue; } #ifdef DEBUG device_printf(dev, "added child: %s\n\n", di->di_ofw.obd_name); #endif device_set_ivars(dev_child, di); } return (bus_generic_attach(dev)); } static int simplebus_print_child(device_t dev, device_t child) { device_t ip; struct simplebus_devinfo *di; struct resource_list *rl; int rv; di = device_get_ivars(child); rl = &di->di_res; rv = 0; rv += bus_print_child_header(dev, child); rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); if ((ip = simplebus_get_interrupt_parent(child)) != NULL) rv += printf(" (%s)", device_get_nameunit(ip)); rv += bus_print_child_footer(dev, child); return (rv); } static struct resource * simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { device_t ic; struct simplebus_devinfo *di; struct resource_list_entry *rle; /* * Request for the default allocation with a given rid: use resource * list stored in the local device info. */ if ((start == 0UL) && (end == ~0UL)) { if ((di = device_get_ivars(child)) == NULL) return (NULL); if (type == SYS_RES_IOPORT) type = SYS_RES_MEMORY; rle = resource_list_find(&di->di_res, type, *rid); if (rle == NULL) { if (bootverbose) device_printf(bus, "no default resources for " "rid = %d, type = %d\n", *rid, type); return (NULL); } start = rle->start; end = rle->end; count = rle->count; } if (type == SYS_RES_IRQ && (ic = simplebus_get_interrupt_parent(child)) != NULL) return(FDT_IC_ALLOC_INTR(ic, child, rid, start, flags)); return (bus_generic_alloc_resource(bus, child, type, rid, start, end, count, flags)); } static int simplebus_activate_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { device_t ic; if (type == SYS_RES_IRQ && (ic = simplebus_get_interrupt_parent(child)) != NULL) return (FDT_IC_ACTIVATE_INTR(ic, r)); return (bus_generic_activate_resource(dev, child, type, rid, r)); } static int simplebus_deactivate_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { device_t ic; if (type == SYS_RES_IRQ && (ic = simplebus_get_interrupt_parent(child)) != NULL) return (FDT_IC_DEACTIVATE_INTR(ic, r)); return (bus_generic_deactivate_resource(dev, child, type, rid, r)); } static int simplebus_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { device_t ic; if (type == SYS_RES_IRQ && (ic = simplebus_get_interrupt_parent(child)) != NULL) return (FDT_IC_RELEASE_INTR(ic, r)); return (bus_generic_release_resource(dev, child, type, rid, r)); } static struct resource_list * simplebus_get_resource_list(device_t bus, device_t child) { struct simplebus_devinfo *di; di = device_get_ivars(child); return (&di->di_res); } static device_t simplebus_get_interrupt_parent(device_t dev) { struct simplebus_devinfo *di; struct fdt_ic *ic; device_t ip; phandle_t ph, iph; ip = NULL; di = device_get_ivars(dev); if (di == NULL) return (NULL); if (OF_getencprop(di->di_ofw.obd_node, "interrupt-parent", &iph, sizeof(iph)) > 0) { ph = OF_node_from_xref(iph); SLIST_FOREACH(ic, &fdt_ic_list_head, fdt_ics) { if (ic->iph == ph) { ip = ic->dev; break; } } } return (ip); } static int simplebus_setup_intr(device_t bus, device_t child, struct resource *res, int flags, driver_filter_t *filter, driver_intr_t *ihand, void *arg, void **cookiep) { struct simplebus_devinfo *di; device_t ic; enum intr_trigger trig; enum intr_polarity pol; int error, irq, rid; di = device_get_ivars(child); if (di == NULL) return (ENXIO); if (res == NULL) return (EINVAL); rid = rman_get_rid(res); if (rid >= DI_MAX_INTR_NUM) return (ENOENT); ic = simplebus_get_interrupt_parent(child); trig = di->di_intr_sl[rid].trig; pol = di->di_intr_sl[rid].pol; if (trig != INTR_TRIGGER_CONFORM || pol != INTR_POLARITY_CONFORM) { irq = rman_get_start(res); if (ic != NULL) error = FDT_IC_CONFIG_INTR(ic, irq, trig, pol); else error = bus_generic_config_intr(bus, irq, trig, pol); if (error) return (error); } if (ic != NULL) error = FDT_IC_SETUP_INTR(ic, child, res, flags, filter, ihand, arg, cookiep); else error = bus_generic_setup_intr(bus, child, res, flags, filter, ihand, arg, cookiep); return (error); } static int simplebus_teardown_intr(device_t bus, device_t child, struct resource *res, void *cookie) { device_t ic; if ((ic = simplebus_get_interrupt_parent(child)) != NULL) return (FDT_IC_TEARDOWN_INTR(ic, child, res, cookie)); return (bus_generic_teardown_intr(bus, child, res, cookie)); } static const struct ofw_bus_devinfo * simplebus_get_devinfo(device_t bus, device_t child) { struct simplebus_devinfo *di; di = device_get_ivars(child); return (&di->di_ofw); } Index: projects/ci20_mips/sys/mips/include/intr_machdep.h =================================================================== --- projects/ci20_mips/sys/mips/include/intr_machdep.h (revision 283030) +++ projects/ci20_mips/sys/mips/include/intr_machdep.h (revision 283031) @@ -1,74 +1,75 @@ /*- * Copyright (c) 2004 Juli Mallett * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _MACHINE_INTR_MACHDEP_H_ #define _MACHINE_INTR_MACHDEP_H_ #include #if defined(CPU_RMI) || defined(CPU_NLM) #define XLR_MAX_INTR 64 #else #define NHARD_IRQS 6 #define NSOFT_IRQS 2 #endif struct trapframe; void cpu_init_interrupts(void); void cpu_establish_hardintr(const char *, driver_filter_t *, driver_intr_t *, void *, int, int, void **); void cpu_establish_softintr(const char *, driver_filter_t *, void (*)(void*), void *, int, int, void **); void cpu_intr(struct trapframe *); /* * Allow a platform to override the default hard interrupt mask and unmask * functions. The 'arg' can be cast safely to an 'int' and holds the mips * hard interrupt number to mask or unmask. */ typedef void (*cpu_intr_mask_t)(void *arg); typedef void (*cpu_intr_unmask_t)(void *arg); void cpu_set_hardintr_mask_func(cpu_intr_mask_t func); void cpu_set_hardintr_unmask_func(cpu_intr_unmask_t func); /* * Opaque datatype that represents intr counter */ typedef unsigned long* mips_intrcnt_t; mips_intrcnt_t mips_intrcnt_create(const char *); void mips_intrcnt_setname(mips_intrcnt_t, const char *); static __inline void mips_intrcnt_inc(mips_intrcnt_t counter) { if (counter) atomic_add_long(counter, 1); + PCPU_INC(cnt.v_intr); } #endif /* !_MACHINE_INTR_MACHDEP_H_ */ Index: projects/ci20_mips/sys/net/if_gif.h =================================================================== --- projects/ci20_mips/sys/net/if_gif.h (revision 283030) +++ projects/ci20_mips/sys/net/if_gif.h (revision 283031) @@ -1,133 +1,135 @@ /* $FreeBSD$ */ /* $KAME: if_gif.h,v 1.17 2000/09/11 11:36:41 sumikawa Exp $ */ /*- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _NET_IF_GIF_H_ #define _NET_IF_GIF_H_ #ifdef _KERNEL #include "opt_inet.h" #include "opt_inet6.h" #include struct ip; struct ip6_hdr; struct encaptab; extern void (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); extern void (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af); extern int (*ng_gif_output_p)(struct ifnet *ifp, struct mbuf **mp); extern void (*ng_gif_attach_p)(struct ifnet *ifp); extern void (*ng_gif_detach_p)(struct ifnet *ifp); struct gif_softc { struct ifnet *gif_ifp; struct rmlock gif_lock; const struct encaptab *gif_ecookie; int gif_family; int gif_flags; u_int gif_fibnum; u_int gif_options; void *gif_netgraph; /* netgraph node info */ union { void *hdr; struct ip *iphdr; #ifdef INET6 struct ip6_hdr *ip6hdr; #endif } gif_uhdr; LIST_ENTRY(gif_softc) gif_list; /* all gif's are linked */ }; #define GIF2IFP(sc) ((sc)->gif_ifp) #define GIF_LOCK_INIT(sc) rm_init(&(sc)->gif_lock, "gif softc") #define GIF_LOCK_DESTROY(sc) rm_destroy(&(sc)->gif_lock) #define GIF_RLOCK_TRACKER struct rm_priotracker gif_tracker #define GIF_RLOCK(sc) rm_rlock(&(sc)->gif_lock, &gif_tracker) #define GIF_RUNLOCK(sc) rm_runlock(&(sc)->gif_lock, &gif_tracker) #define GIF_RLOCK_ASSERT(sc) rm_assert(&(sc)->gif_lock, RA_RLOCKED) #define GIF_WLOCK(sc) rm_wlock(&(sc)->gif_lock) #define GIF_WUNLOCK(sc) rm_wunlock(&(sc)->gif_lock) #define GIF_WLOCK_ASSERT(sc) rm_assert(&(sc)->gif_lock, RA_WLOCKED) #define gif_iphdr gif_uhdr.iphdr #define gif_hdr gif_uhdr.hdr #ifdef INET6 #define gif_ip6hdr gif_uhdr.ip6hdr #endif #define GIF_MTU (1280) /* Default MTU */ #define GIF_MTU_MIN (1280) /* Minimum MTU */ #define GIF_MTU_MAX (8192) /* Maximum MTU */ struct etherip_header { #if BYTE_ORDER == LITTLE_ENDIAN u_int eip_resvl:4, /* reserved */ eip_ver:4; /* version */ #endif #if BYTE_ORDER == BIG_ENDIAN u_int eip_ver:4, /* version */ eip_resvl:4; /* reserved */ #endif u_int8_t eip_resvh; /* reserved */ } __packed; #define ETHERIP_VERSION 0x3 /* mbuf adjust factor to force 32-bit alignment of IP header */ #define ETHERIP_ALIGN 2 /* Prototypes */ void gif_input(struct mbuf *, struct ifnet *, int, uint8_t); int gif_output(struct ifnet *, struct mbuf *, const struct sockaddr *, struct route *); int gif_encapcheck(const struct mbuf *, int, int, void *); #ifdef INET int in_gif_output(struct ifnet *, struct mbuf *, int, uint8_t); int in_gif_encapcheck(const struct mbuf *, int, int, void *); int in_gif_attach(struct gif_softc *); #endif #ifdef INET6 int in6_gif_output(struct ifnet *, struct mbuf *, int, uint8_t); int in6_gif_encapcheck(const struct mbuf *, int, int, void *); int in6_gif_attach(struct gif_softc *); #endif #endif /* _KERNEL */ #define GIFGOPTS _IOWR('i', 150, struct ifreq) #define GIFSOPTS _IOW('i', 151, struct ifreq) #define GIF_ACCEPT_REVETHIP 0x0001 +#define GIF_IGNORE_SOURCE 0x0002 #define GIF_SEND_REVETHIP 0x0010 -#define GIF_OPTMASK (GIF_ACCEPT_REVETHIP|GIF_SEND_REVETHIP) +#define GIF_OPTMASK (GIF_ACCEPT_REVETHIP|GIF_SEND_REVETHIP| \ + GIF_IGNORE_SOURCE) #endif /* _NET_IF_GIF_H_ */ Index: projects/ci20_mips/sys/net/sff8436.h =================================================================== --- projects/ci20_mips/sys/net/sff8436.h (revision 283030) +++ projects/ci20_mips/sys/net/sff8436.h (revision 283031) @@ -1,211 +1,213 @@ /*- * Copyright (c) 2014 Yandex LLC. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * The following set of constants are from Document SFF-8436 * "QSFP+ 10 Gbs 4X PLUGGABLE TRANSCEIVER" revision 4.8 dated October 31, 2013 * * This SFF standard defines the following QSFP+ memory address module: * * 1) 256-byte addressable block and 128-byte pages * 2) Lower 128-bytes addresses always refer to the same page * 3) Upper address space may refer to different pages depending on * "page select" byte value. * * Map description: * * Serial address 0xA02: * * Lower bits * 0-127 Monitoring data & page select byte * 128-255: * * Page 00: * 128-191 Base ID Fields * 191-223 Extended ID * 223-255 Vendor Specific ID * * Page 01 (optional): * 128-255 App-specific data * * Page 02 (optional): * 128-255 User EEPROM Data * * Page 03 (optional for Cable Assmeblies) * 128-223 Thresholds * 225-237 Vendor Specific * 238-253 Channel Controls/Monitor * 254-255 Reserverd * * All these values are read across an I2C (i squared C) bus. */ #define SFF_8436_BASE 0xA0 /* Base address for all requests */ /* Table 17 - Lower Memory Map */ enum { SFF_8436_MID = 0, /* Copy of SFF_8436_ID field */ SFF_8436_STATUS = 1, /* 2-bytes status (Table 18) */ SFF_8436_INTR_START = 3, /* Interrupt flags (Tables 19-21) */ SFF_8436_INTR_END = 21, SFF_8436_MODMON_START = 22, /* Module monitors (Table 22 */ SFF_8436_TEMP = 22, /* Internally measured module temp */ SFF_8436_VCC = 26, /* Internally mesasure module * supplied voltage */ SFF_8436_MODMON_END = 33, SFF_8436_CHMON_START = 34, /* Channel monitors (Table 23) */ SFF_8436_RX_CH1_MSB = 34, /* Internally measured RX input power */ SFF_8436_RX_CH1_LSB = 35, /* for channel 1 */ SFF_8436_RX_CH2_MSB = 36, /* Internally measured RX input power */ SFF_8436_RX_CH2_LSB = 37, /* for channel 2 */ SFF_8436_RX_CH3_MSB = 38, /* Internally measured RX input power */ SFF_8436_RX_CH3_LSB = 39, /* for channel 3 */ SFF_8436_RX_CH4_MSB = 40, /* Internally measured RX input power */ SFF_8436_RX_CH4_LSB = 41, /* for channel 4 */ SFF_8436_TX_CH1_MSB = 42, /* Internally measured TX bias */ SFF_8436_TX_CH1_LSB = 43, /* for channel 1 */ SFF_8436_TX_CH2_MSB = 44, /* Internally measured TX bias */ SFF_8436_TX_CH2_LSB = 45, /* for channel 2 */ SFF_8436_TX_CH3_MSB = 46, /* Internally measured TX bias */ SFF_8436_TX_CH3_LSB = 47, /* for channel 3 */ SFF_8436_TX_CH4_MSB = 48, /* Internally measured TX bias */ SFF_8436_TX_CH4_LSB = 49, /* for channel 4 */ SFF_8436_CHANMON_END = 81, SFF_8436_CONTROL_START = 86, /* Control (Table 24) */ SFF_8436_CONTROL_END = 97, SFF_8436_MASKS_START = 100, /* Module/channel masks (Table 25) */ SFF_8436_MASKS_END = 106, SFF_8436_CHPASSWORD = 119, /* Password change entry (4 bytes) */ SFF_8436_PASSWORD = 123, /* Password entry area (4 bytes) */ SFF_8436_PAGESEL = 127, /* Page select byte */ }; /* Table 18 - Status Indicators bits */ /* Byte 1: all bits reserved */ /* Byte 2 bits */ #define SFF_8436_STATUS_FLATMEM (1 << 2) /* Upper memory flat or paged * 0 = paging, 1=Page 0 only */ #define SFF_8436_STATUS_INTL (1 << 1) /* Digital state of the intL * Interrupt output pin */ #define SFF_8436_STATUS_NOTREADY 1 /* Module has not yet achieved * power up and memory data is not * ready. 0=data is ready */ /* * Upper page 0 definitions: * Table 29 - Serial ID: Data fields. * * Note that this table is mostly the same as used in SFF-8472. * The only differenee is address shift: +128 bytes. */ enum { SFF_8436_ID = 128, /* Module Type (defined in sff8472.h) */ SFF_8436_EXT_ID = 129, /* Extended transceiver type * (Table 31) */ SFF_8436_CONNECTOR = 130, /* Connector type (Table 32) */ SFF_8436_TRANS_START = 131, /* Electric or Optical Compatibility * (Table 33) */ SFF_8436_CODE_E1040G = 131, /* 10/40G Ethernet Compliance Code */ SFF_8436_CODE_SONET = 132, /* SONET Compliance codes */ SFF_8436_CODE_SATA = 133, /* SAS/SATA compliance codes */ SFF_8436_CODE_E1G = 134, /* Gigabit Ethernet Compliant codes */ SFF_8436_CODE_FC_START = 135, /* FC link/media/speed */ SFF_8436_CODE_FC_END = 138, SFF_8436_TRANS_END = 138, SFF_8436_ENCODING = 139, /* Encoding Code for high speed * serial encoding algorithm (see * Table 34) */ SFF_8436_BITRATE = 140, /* Nominal signaling rate, units * of 100MBd. */ SFF_8436_RATEID = 141, /* Extended RateSelect Compliance * (see Table 35) */ SFF_8436_LEN_SMF_KM = 142, /* Link length supported for single * mode fiber, units of km */ SFF_8436_LEN_OM3 = 143, /* Link length supported for 850nm * 50um multimode fiber, units of 2 m */ SFF_8436_LEN_OM2 = 144, /* Link length supported for 50 um * OM2 fiber, units of 1 m */ SFF_8436_LEN_OM1 = 145, /* Link length supported for 1310 nm * 50um multi-mode fiber, units of 1m*/ SFF_8436_LEN_ASM = 144, /* Link length of passive cable assembly * Length is specified as in the INF * 8074, units of 1m. 0 means this is * not value assembly. Value of 255 * means thet the Module supports length * greater than 254 m. */ SFF_8436_DEV_TECH = 147, /* Device/transmitter technology, * see Table 36/37 */ SFF_8436_VENDOR_START = 148, /* Vendor name, 16 bytes, padded * right with 0x20 */ SFF_8436_VENDOR_END = 163, SFF_8436_EXTMODCODE = 164, /* Extended module code, Table 164 */ SFF_8436_VENDOR_OUI_START = 165 , /* Vendor OUI SFP vendor IEEE * company ID */ SFF_8436_VENDOR_OUI_END = 167, SFF_8436_PN_START = 168, /* Vendor PN, padded right with 0x20 */ SFF_8436_PN_END = 183, SFF_8436_REV_START = 184, /* Vendor Revision, padded right 0x20 */ SFF_8436_REV_END = 185, SFF_8436_WAVELEN_START = 186, /* Wavelength Laser wavelength * (Passive/Active Cable * Specification Compliance) */ SFF_8436_WAVELEN_END = 189, SFF_8436_MAX_CASE_TEMP = 190, /* Allows to specify maximum temp * above 70C. Maximum case temperature is * an 8-bit value in Degrees C. A value *of 0 implies the standard 70C rating.*/ SFF_8436_CC_BASE = 191, /* CC_BASE Check code for Base ID * Fields (first 63 bytes) */ /* Extended ID fields */ SFF_8436_OPTIONS_START = 192, /* Options Indicates which optional * transceiver signals are * implemented (see Table 39) */ SFF_8436_OPTIONS_END = 195, SFF_8436_SN_START = 196, /* Vendor SN, riwght padded with 0x20 */ SFF_8436_SN_END = 211, SFF_8436_DATE_START = 212, /* Vendor’s manufacturing date code * (see Table 40) */ SFF_8436_DATE_END = 219, SFF_8436_DIAG_TYPE = 220, /* Diagnostic Monitoring Type * Indicates which type of * diagnostic monitoring is * implemented (if any) in the * transceiver (see Table 41) */ SFF_8436_ENHANCED = 221, /* Enhanced Options Indicates which * optional features are implemented * (if any) in the transceiver * (see Table 42) */ - SFF_8436_CC_EXT = 222, /* Check code for the Extended ID + SFF_8636_BITRATE = 222, /* Nominal bit rate per channel, units + * of 250 Mbps */ + SFF_8436_CC_EXT = 223, /* Check code for the Extended ID * Fields (bytes 192-222 incl) */ SFF_8436_VENDOR_RSRVD_START = 224, SFF_8436_VENDOR_RSRVD_END = 255, }; Index: projects/ci20_mips/sys/net/sff8472.h =================================================================== --- projects/ci20_mips/sys/net/sff8472.h (revision 283030) +++ projects/ci20_mips/sys/net/sff8472.h (revision 283031) @@ -1,500 +1,508 @@ /*- * Copyright (c) 2013 George V. Neville-Neil * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * The following set of constants are from Document SFF-8472 * "Diagnostic Monitoring Interface for Optical Transceivers" revision * 11.3 published by the SFF Committee on June 11, 2013 * * The SFF standard defines two ranges of addresses, each 255 bytes * long for the storage of data and diagnostics on cables, such as * SFP+ optics and TwinAx cables. The ranges are defined in the * following way: * * Base Address 0xa0 (Identification Data) * 0-95 Serial ID Defined by SFP MSA * 96-127 Vendor Specific Data * 128-255 Reserved * * Base Address 0xa2 (Diagnostic Data) * 0-55 Alarm and Warning Thresholds * 56-95 Cal Constants * 96-119 Real Time Diagnostic Interface * 120-127 Vendor Specific * 128-247 User Writable EEPROM * 248-255 Vendor Specific * * Note that not all addresses are supported. Where support is * optional this is noted and instructions for checking for the * support are supplied. * * All these values are read across an I2C (i squared C) bus. Any * device wishing to read these addresses must first have support for * i2c calls. The Chelsio T4/T5 driver (dev/cxgbe) is one such * driver. */ /* Table 3.1 Two-wire interface ID: Data Fields */ enum { SFF_8472_BASE = 0xa0, /* Base address for all our queries. */ SFF_8472_ID = 0, /* Transceiver Type (Table 3.2) */ SFF_8472_EXT_ID = 1, /* Extended transceiver type (Table 3.3) */ SFF_8472_CONNECTOR = 2, /* Connector type (Table 3.4) */ SFF_8472_TRANS_START = 3, /* Elec or Optical Compatibility * (Table 3.5) */ SFF_8472_TRANS_END = 10, SFF_8472_ENCODING = 11, /* Encoding Code for high speed * serial encoding algorithm (see * Table 3.6) */ SFF_8472_BITRATE = 12, /* Nominal signaling rate, units * of 100MBd. (see details for * rates > 25.0Gb/s) */ SFF_8472_RATEID = 13, /* Type of rate select * functionality (see Table * 3.6a) */ SFF_8472_LEN_SMF_KM = 14, /* Link length supported for single * mode fiber, units of km */ SFF_8472_LEN_SMF = 15, /* Link length supported for single * mode fiber, units of 100 m */ SFF_8472_LEN_50UM = 16, /* Link length supported for 50 um * OM2 fiber, units of 10 m */ SFF_8472_LEN_625UM = 17, /* Link length supported for 62.5 * um OM1 fiber, units of 10 m */ SFF_8472_LEN_OM4 = 18, /* Link length supported for 50um * OM4 fiber, units of 10m. * Alternatively copper or direct * attach cable, units of m */ SFF_8472_LEN_OM3 = 19, /* Link length supported for 50 um OM3 fiber, units of 10 m */ SFF_8472_VENDOR_START = 20, /* Vendor name [Address A0h, Bytes * 20-35] */ SFF_8472_VENDOR_END = 35, SFF_8472_TRANS = 36, /* Transceiver Code for electronic * or optical compatibility (see * Table 3.5) */ SFF_8472_VENDOR_OUI_START = 37, /* Vendor OUI SFP vendor IEEE * company ID */ SFF_8472_VENDOR_OUI_END = 39, SFF_8472_PN_START = 40, /* Vendor PN */ SFF_8472_PN_END = 55, SFF_8472_REV_START = 56, /* Vendor Revision */ SFF_8472_REV_END = 59, SFF_8472_WAVELEN_START = 60, /* Wavelength Laser wavelength * (Passive/Active Cable * Specification Compliance) */ SFF_8472_WAVELEN_END = 61, SFF_8472_CC_BASE = 63, /* CC_BASE Check code for Base ID * Fields (addresses 0 to 62) */ /* * Extension Fields (optional) check the options before reading other * addresses. */ SFF_8472_OPTIONS_MSB = 64, /* Options Indicates which optional * transceiver signals are * implemented */ SFF_8472_OPTIONS_LSB = 65, /* (see Table 3.7) */ SFF_8472_BR_MAX = 66, /* BR max Upper bit rate margin, * units of % (see details for * rates > 25.0Gb/s) */ SFF_8472_BR_MIN = 67, /* Lower bit rate margin, units of * % (see details for rates > * 25.0Gb/s) */ SFF_8472_SN_START = 68, /* Vendor SN [Address A0h, Bytes 68-83] */ SFF_8472_SN_END = 83, SFF_8472_DATE_START = 84, /* Date code Vendor’s manufacturing * date code (see Table 3.8) */ SFF_8472_DATE_END = 91, SFF_8472_DIAG_TYPE = 92, /* Diagnostic Monitoring Type * Indicates which type of * diagnostic monitoring is * implemented (if any) in the * transceiver (see Table 3.9) */ SFF_8472_ENHANCED = 93, /* Enhanced Options Indicates which * optional enhanced features are * implemented (if any) in the * transceiver (see Table 3.10) */ SFF_8472_COMPLIANCE = 94, /* SFF-8472 Compliance Indicates * which revision of SFF-8472 the * transceiver complies with. (see * Table 3.12)*/ SFF_8472_CC_EXT = 95, /* Check code for the Extended ID * Fields (addresses 64 to 94) */ SFF_8472_VENDOR_RSRVD_START = 96, SFF_8472_VENDOR_RSRVD_END = 127, SFF_8472_RESERVED_START = 128, SFF_8472_RESERVED_END = 255 }; #define SFF_8472_DIAG_IMPL (1 << 6) /* Required to be 1 */ #define SFF_8472_DIAG_INTERNAL (1 << 5) /* Internal measurements. */ #define SFF_8472_DIAG_EXTERNAL (1 << 4) /* External measurements. */ #define SFF_8472_DIAG_POWER (1 << 3) /* Power measurement type */ #define SFF_8472_DIAG_ADDR_CHG (1 << 2) /* Address change required. * See SFF-8472 doc. */ /* * Diagnostics are available at the two wire address 0xa2. All * diagnostics are OPTIONAL so you should check 0xa0 registers 92 to * see which, if any are supported. */ enum {SFF_8472_DIAG = 0xa2}; /* Base address for diagnostics. */ /* * Table 3.15 Alarm and Warning Thresholds All values are 2 bytes * and MUST be read in a single read operation starting at the MSB */ enum { SFF_8472_TEMP_HIGH_ALM = 0, /* Temp High Alarm */ SFF_8472_TEMP_LOW_ALM = 2, /* Temp Low Alarm */ SFF_8472_TEMP_HIGH_WARN = 4, /* Temp High Warning */ SFF_8472_TEMP_LOW_WARN = 6, /* Temp Low Warning */ SFF_8472_VOLTAGE_HIGH_ALM = 8, /* Voltage High Alarm */ SFF_8472_VOLTAGE_LOW_ALM = 10, /* Voltage Low Alarm */ SFF_8472_VOLTAGE_HIGH_WARN = 12, /* Voltage High Warning */ SFF_8472_VOLTAGE_LOW_WARN = 14, /* Voltage Low Warning */ SFF_8472_BIAS_HIGH_ALM = 16, /* Bias High Alarm */ SFF_8472_BIAS_LOW_ALM = 18, /* Bias Low Alarm */ SFF_8472_BIAS_HIGH_WARN = 20, /* Bias High Warning */ SFF_8472_BIAS_LOW_WARN = 22, /* Bias Low Warning */ SFF_8472_TX_POWER_HIGH_ALM = 24, /* TX Power High Alarm */ SFF_8472_TX_POWER_LOW_ALM = 26, /* TX Power Low Alarm */ SFF_8472_TX_POWER_HIGH_WARN = 28, /* TX Power High Warning */ SFF_8472_TX_POWER_LOW_WARN = 30, /* TX Power Low Warning */ SFF_8472_RX_POWER_HIGH_ALM = 32, /* RX Power High Alarm */ SFF_8472_RX_POWER_LOW_ALM = 34, /* RX Power Low Alarm */ SFF_8472_RX_POWER_HIGH_WARN = 36, /* RX Power High Warning */ SFF_8472_RX_POWER_LOW_WARN = 38, /* RX Power Low Warning */ SFF_8472_RX_POWER4 = 56, /* Rx_PWR(4) Single precision * floating point calibration data * - Rx optical power. Bit 7 of * byte 56 is MSB. Bit 0 of byte * 59 is LSB. Rx_PWR(4) should be * set to zero for “internally * calibrated” devices. */ SFF_8472_RX_POWER3 = 60, /* Rx_PWR(3) Single precision * floating point calibration data * - Rx optical power. Bit 7 of * byte 60 is MSB. Bit 0 of byte 63 * is LSB. Rx_PWR(3) should be set * to zero for “internally * calibrated” devices.*/ SFF_8472_RX_POWER2 = 64, /* Rx_PWR(2) Single precision * floating point calibration data, * Rx optical power. Bit 7 of byte * 64 is MSB, bit 0 of byte 67 is * LSB. Rx_PWR(2) should be set to * zero for “internally calibrated” * devices. */ SFF_8472_RX_POWER1 = 68, /* Rx_PWR(1) Single precision * floating point calibration data, * Rx optical power. Bit 7 of byte * 68 is MSB, bit 0 of byte 71 is * LSB. Rx_PWR(1) should be set to * 1 for “internally calibrated” * devices. */ SFF_8472_RX_POWER0 = 72, /* Rx_PWR(0) Single precision * floating point calibration data, * Rx optical power. Bit 7 of byte * 72 is MSB, bit 0 of byte 75 is * LSB. Rx_PWR(0) should be set to * zero for “internally calibrated” * devices. */ SFF_8472_TX_I_SLOPE = 76, /* Tx_I(Slope) Fixed decimal * (unsigned) calibration data, * laser bias current. Bit 7 of * byte 76 is MSB, bit 0 of byte 77 * is LSB. Tx_I(Slope) should be * set to 1 for “internally * calibrated” devices. */ SFF_8472_TX_I_OFFSET = 78, /* Tx_I(Offset) Fixed decimal * (signed two’s complement) * calibration data, laser bias * current. Bit 7 of byte 78 is * MSB, bit 0 of byte 79 is * LSB. Tx_I(Offset) should be set * to zero for “internally * calibrated” devices. */ SFF_8472_TX_POWER_SLOPE = 80, /* Tx_PWR(Slope) Fixed decimal * (unsigned) calibration data, * transmitter coupled output * power. Bit 7 of byte 80 is MSB, * bit 0 of byte 81 is LSB. * Tx_PWR(Slope) should be set to 1 * for “internally calibrated” * devices. */ SFF_8472_TX_POWER_OFFSET = 82, /* Tx_PWR(Offset) Fixed decimal * (signed two’s complement) * calibration data, transmitter * coupled output power. Bit 7 of * byte 82 is MSB, bit 0 of byte 83 * is LSB. Tx_PWR(Offset) should be * set to zero for “internally * calibrated” devices. */ SFF_8472_T_SLOPE = 84, /* T (Slope) Fixed decimal * (unsigned) calibration data, * internal module temperature. Bit * 7 of byte 84 is MSB, bit 0 of * byte 85 is LSB. T(Slope) should * be set to 1 for “internally * calibrated” devices. */ SFF_8472_T_OFFSET = 86, /* T (Offset) Fixed decimal (signed * two’s complement) calibration * data, internal module * temperature. Bit 7 of byte 86 is * MSB, bit 0 of byte 87 is LSB. * T(Offset) should be set to zero * for “internally calibrated” * devices. */ SFF_8472_V_SLOPE = 88, /* V (Slope) Fixed decimal * (unsigned) calibration data, * internal module supply * voltage. Bit 7 of byte 88 is * MSB, bit 0 of byte 89 is * LSB. V(Slope) should be set to 1 * for “internally calibrated” * devices. */ SFF_8472_V_OFFSET = 90, /* V (Offset) Fixed decimal (signed * two’s complement) calibration * data, internal module supply * voltage. Bit 7 of byte 90 is * MSB. Bit 0 of byte 91 is * LSB. V(Offset) should be set to * zero for “internally calibrated” * devices. */ SFF_8472_CHECKSUM = 95, /* Checksum Byte 95 contains the * low order 8 bits of the sum of * bytes 0 – 94. */ /* Internal measurements. */ SFF_8472_TEMP = 96, /* Internally measured module temperature. */ SFF_8472_VCC = 98, /* Internally measured supply * voltage in transceiver. */ SFF_8472_TX_BIAS = 100, /* Internally measured TX Bias Current. */ SFF_8472_TX_POWER = 102, /* Measured TX output power. */ SFF_8472_RX_POWER = 104, /* Measured RX input power. */ SFF_8472_STATUS = 110 /* See below */ }; /* Status Bits Described */ /* * TX Disable State Digital state of the TX Disable Input Pin. Updated * within 100ms of change on pin. */ #define SFF_8472_STATUS_TX_DISABLE (1 << 7) /* * Select Read/write bit that allows software disable of * laser. Writing ‘1’ disables laser. See Table 3.11 for * enable/disable timing requirements. This bit is “OR”d with the hard * TX_DISABLE pin value. Note, per SFP MSA TX_DISABLE pin is default * enabled unless pulled low by hardware. If Soft TX Disable is not * implemented, the transceiver ignores the value of this bit. Default * power up value is zero/low. */ #define SFF_8472_STATUS_SOFT_TX_DISABLE (1 << 6) /* * RS(1) State Digital state of SFP input pin AS(1) per SFF-8079 or * RS(1) per SFF-8431. Updated within 100ms of change on pin. See A2h * Byte 118, Bit 3 for Soft RS(1) Select control information. */ #define SFF_8472_RS_STATE (1 << 5) /* * Rate_Select State [aka. “RS(0)”] Digital state of the SFP * Rate_Select Input Pin. Updated within 100ms of change on pin. Note: * This pin is also known as AS(0) in SFF-8079 and RS(0) in SFF-8431. */ #define SFF_8472_STATUS_SELECT_STATE (1 << 4) /* * Read/write bit that allows software rate select control. Writing * ‘1’ selects full bandwidth operation. This bit is “OR’d with the * hard Rate_Select, AS(0) or RS(0) pin value. See Table 3.11 for * timing requirements. Default at power up is logic zero/low. If Soft * Rate Select is not implemented, the transceiver ignores the value * of this bit. Note: Specific transceiver behaviors of this bit are * identified in Table 3.6a and referenced documents. See Table 3.18a, * byte 118, bit 3 for Soft RS(1) Select. */ #define SFF_8472_STATUS_SOFT_RATE_SELECT (1 << 3) /* * TX Fault State Digital state of the TX Fault Output Pin. Updated * within 100ms of change on pin. */ #define SFF_8472_STATUS_TX_FAULT_STATE (1 << 2) /* * Digital state of the RX_LOS Output Pin. Updated within 100ms of * change on pin. */ #define SFF_8472_STATUS_RX_LOS (1 << 1) /* * Indicates transceiver has achieved power up and data is ready. Bit * remains high until data is ready to be read at which time the * device sets the bit low. */ #define SFF_8472_STATUS_DATA_READY (1 << 0) /* * Table 3.2 Identifier values. - * Identifier constants has taken from SFF-8024 rev 2.2 table 4.1 + * Identifier constants has taken from SFF-8024 rev 2.9 table 4.1 * (as referenced by table 3.2 footer) * */ enum { SFF_8024_ID_UNKNOWN = 0x0, /* Unknown or unspecified */ SFF_8024_ID_GBIC = 0x1, /* GBIC */ SFF_8024_ID_SFF = 0x2, /* Module soldered to motherboard (ex: SFF)*/ SFF_8024_ID_SFP = 0x3, /* SFP or SFP “Plus” */ SFF_8024_ID_XBI = 0x4, /* 300 pin XBI */ SFF_8024_ID_XENPAK = 0x5, /* Xenpak */ SFF_8024_ID_XFP = 0x6, /* XFP */ SFF_8024_ID_XFF = 0x7, /* XFF */ SFF_8024_ID_XFPE = 0x8, /* XFP-E */ SFF_8024_ID_XPAK = 0x9, /* XPAk */ SFF_8024_ID_X2 = 0xA, /* X2 */ SFF_8024_ID_DWDM_SFP = 0xB, /* DWDM-SFP */ SFF_8024_ID_QSFP = 0xC, /* QSFP */ SFF_8024_ID_QSFPPLUS = 0xD, /* QSFP+ */ SFF_8024_ID_CXP = 0xE, /* CXP */ SFF_8024_ID_HD4X = 0xF, /* Shielded Mini Multilane HD 4X */ SFF_8024_ID_HD8X = 0x10, /* Shielded Mini Multilane HD 8X */ SFF_8024_ID_QSFP28 = 0x11, /* QSFP28 */ SFF_8024_ID_CXP2 = 0x12, /* CXP2 (aka CXP28) */ - SFF_8024_ID_LAST = SFF_8024_ID_CXP2 + SFF_8024_ID_CDFP = 0x13, /* CDFP (Style 1/Style 2) */ + SFF_8024_ID_SMM4 = 0x14, /* Shielded Mini Multilate HD 4X Fanout */ + SFF_8024_ID_SMM8 = 0x15, /* Shielded Mini Multilate HD 8X Fanout */ + SFF_8024_ID_CDFP3 = 0x16, /* CDFP (Style3) */ + SFF_8024_ID_LAST = SFF_8024_ID_CDFP3 }; static const char *sff_8024_id[SFF_8024_ID_LAST + 1] = {"Unknown", "GBIC", "SFF", - "SFP/SFP+", + "SFP/SFP+/SFP28", "XBI", "Xenpak", "XFP", "XFF", "XFP-E", - "XPAk", + "XPAK", "X2", - "DWDM-SFP", + "DWDM-SFP/SFP+", "QSFP", "QSFP+", "CXP", "HD4X", "HD8X", "QSFP28", - "CXP2"}; + "CXP2", + "CDFP", + "SMM4", + "SMM8", + "CDFP3"}; /* Keep compability with old definitions */ #define SFF_8472_ID_UNKNOWN SFF_8024_ID_UNKNOWN #define SFF_8472_ID_GBIC SFF_8024_ID_GBIC #define SFF_8472_ID_SFF SFF_8024_ID_SFF #define SFF_8472_ID_SFP SFF_8024_ID_SFP #define SFF_8472_ID_XBI SFF_8024_ID_XBI #define SFF_8472_ID_XENPAK SFF_8024_ID_XENPAK #define SFF_8472_ID_XFP SFF_8024_ID_XFP #define SFF_8472_ID_XFF SFF_8024_ID_XFF #define SFF_8472_ID_XFPE SFF_8024_ID_XFPE #define SFF_8472_ID_XPAK SFF_8024_ID_XPAK #define SFF_8472_ID_X2 SFF_8024_ID_X2 #define SFF_8472_ID_DWDM_SFP SFF_8024_ID_DWDM_SFP #define SFF_8472_ID_QSFP SFF_8024_ID_QSFP #define SFF_8472_ID_LAST SFF_8024_ID_LAST #define sff_8472_id sff_8024_id /* * Table 3.9 Diagnostic Monitoring Type (byte 92) * bits described. */ /* * Digital diagnostic monitoring implemented. * Set to 1 for transceivers implementing DDM. */ #define SFF_8472_DDM_DONE (1 << 6) /* * Measurements are internally calibrated. */ #define SFF_8472_DDM_INTERNAL (1 << 5) /* * Measurements are externally calibrated. */ #define SFF_8472_DDM_EXTERNAL (1 << 4) /* * Received power measurement type * 0 = OMA, 1 = average power */ #define SFF_8472_DDM_PMTYPE (1 << 3) /* Table 3.13 and 3.14 Temperature Conversion Values */ #define SFF_8472_TEMP_SIGN (1 << 15) #define SFF_8472_TEMP_SHIFT 8 #define SFF_8472_TEMP_MSK 0xEF00 #define SFF_8472_TEMP_FRAC 0x00FF /* Internal Callibration Conversion factors */ /* * Represented as a 16 bit unsigned integer with the voltage defined * as the full 16 bit value (0 – 65535) with LSB equal to 100 uVolt, * yielding a total range of 0 to +6.55 Volts. */ #define SFF_8472_VCC_FACTOR 10000.0 /* * Represented as a 16 bit unsigned integer with the current defined * as the full 16 bit value (0 – 65535) with LSB equal to 2 uA, * yielding a total range of 0 to 131 mA. */ #define SFF_8472_BIAS_FACTOR 2000.0 /* * Represented as a 16 bit unsigned integer with the power defined as * the full 16 bit value (0 – 65535) with LSB equal to 0.1 uW, * yielding a total range of 0 to 6.5535 mW (~ -40 to +8.2 dBm). */ #define SFF_8472_POWER_FACTOR 10000.0 Index: projects/ci20_mips/sys/netinet/in_gif.c =================================================================== --- projects/ci20_mips/sys/netinet/in_gif.c (revision 283030) +++ projects/ci20_mips/sys/netinet/in_gif.c (revision 283031) @@ -1,241 +1,247 @@ /*- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */ #include __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_inet6.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET6 #include #endif #include static int gif_validate4(const struct ip *, struct gif_softc *, struct ifnet *); static int in_gif_input(struct mbuf **, int *, int); extern struct domain inetdomain; static struct protosw in_gif_protosw = { .pr_type = SOCK_RAW, .pr_domain = &inetdomain, .pr_protocol = 0/* IPPROTO_IPV[46] */, .pr_flags = PR_ATOMIC|PR_ADDR, .pr_input = in_gif_input, .pr_output = rip_output, .pr_ctloutput = rip_ctloutput, .pr_usrreqs = &rip_usrreqs }; #define GIF_TTL 30 static VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL; #define V_ip_gif_ttl VNET(ip_gif_ttl) SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip_gif_ttl), 0, ""); int in_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn) { GIF_RLOCK_TRACKER; struct gif_softc *sc = ifp->if_softc; struct ip *ip; int len; /* prepend new IP header */ len = sizeof(struct ip); #ifndef __NO_STRICT_ALIGNMENT if (proto == IPPROTO_ETHERIP) len += ETHERIP_ALIGN; #endif M_PREPEND(m, len, M_NOWAIT); if (m == NULL) return (ENOBUFS); #ifndef __NO_STRICT_ALIGNMENT if (proto == IPPROTO_ETHERIP) { len = mtod(m, vm_offset_t) & 3; KASSERT(len == 0 || len == ETHERIP_ALIGN, ("in_gif_output: unexpected misalignment")); m->m_data += len; m->m_len -= ETHERIP_ALIGN; } #endif ip = mtod(m, struct ip *); GIF_RLOCK(sc); if (sc->gif_family != AF_INET) { m_freem(m); GIF_RUNLOCK(sc); return (ENETDOWN); } bcopy(sc->gif_iphdr, ip, sizeof(struct ip)); GIF_RUNLOCK(sc); ip->ip_p = proto; /* version will be set in ip_output() */ ip->ip_ttl = V_ip_gif_ttl; ip->ip_len = htons(m->m_pkthdr.len); ip->ip_tos = ecn; return (ip_output(m, NULL, NULL, 0, NULL, NULL)); } static int in_gif_input(struct mbuf **mp, int *offp, int proto) { struct mbuf *m = *mp; struct gif_softc *sc; struct ifnet *gifp; struct ip *ip; uint8_t ecn; sc = encap_getarg(m); if (sc == NULL) { m_freem(m); KMOD_IPSTAT_INC(ips_nogif); return (IPPROTO_DONE); } gifp = GIF2IFP(sc); if ((gifp->if_flags & IFF_UP) != 0) { ip = mtod(m, struct ip *); ecn = ip->ip_tos; m_adj(m, *offp); gif_input(m, gifp, proto, ecn); } else { m_freem(m); KMOD_IPSTAT_INC(ips_nogif); } return (IPPROTO_DONE); } /* * validate outer address. */ static int gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp) { + int ret; GIF_RLOCK_ASSERT(sc); /* check for address match */ - if (sc->gif_iphdr->ip_src.s_addr != ip->ip_dst.s_addr || - sc->gif_iphdr->ip_dst.s_addr != ip->ip_src.s_addr) + if (sc->gif_iphdr->ip_src.s_addr != ip->ip_dst.s_addr) return (0); + ret = 32; + if (sc->gif_iphdr->ip_dst.s_addr != ip->ip_src.s_addr) { + if ((sc->gif_options & GIF_IGNORE_SOURCE) == 0) + return (0); + } else + ret += 32; /* martian filters on outer source - NOT done in ip_input! */ if (IN_MULTICAST(ntohl(ip->ip_src.s_addr))) return (0); switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) { case 0: case 127: case 255: return (0); } /* ingress filters on outer source */ if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) { struct sockaddr_in sin; struct rtentry *rt; bzero(&sin, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_len = sizeof(struct sockaddr_in); sin.sin_addr = ip->ip_src; /* XXX MRT check for the interface we would use on output */ rt = in_rtalloc1((struct sockaddr *)&sin, 0, 0UL, sc->gif_fibnum); if (!rt || rt->rt_ifp != ifp) { if (rt) RTFREE_LOCKED(rt); return (0); } RTFREE_LOCKED(rt); } - return (32 * 2); + return (ret); } /* * we know that we are in IFF_UP, outer address available, and outer family * matched the physical addr family. see gif_encapcheck(). */ int in_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) { struct ip ip; struct gif_softc *sc; struct ifnet *ifp; /* sanity check done in caller */ sc = (struct gif_softc *)arg; GIF_RLOCK_ASSERT(sc); m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; return (gif_validate4(&ip, sc, ifp)); } int in_gif_attach(struct gif_softc *sc) { KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL")); sc->gif_ecookie = encap_attach_func(AF_INET, -1, gif_encapcheck, &in_gif_protosw, sc); if (sc->gif_ecookie == NULL) return (EEXIST); return (0); } Index: projects/ci20_mips/sys/netinet6/in6_gif.c =================================================================== --- projects/ci20_mips/sys/netinet6/in6_gif.c (revision 283030) +++ projects/ci20_mips/sys/netinet6/in6_gif.c (revision 283031) @@ -1,250 +1,256 @@ /*- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $KAME: in6_gif.c,v 1.49 2001/05/14 14:02:17 itojun Exp $ */ #include __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_inet6.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET #include #endif #include #ifdef INET6 #include #include #include #endif #include #ifdef INET6 #include #endif #include #define GIF_HLIM 30 static VNET_DEFINE(int, ip6_gif_hlim) = GIF_HLIM; #define V_ip6_gif_hlim VNET(ip6_gif_hlim) SYSCTL_DECL(_net_inet6_ip6); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM, gifhlim, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_gif_hlim), 0, ""); static int gif_validate6(const struct ip6_hdr *, struct gif_softc *, struct ifnet *); static int in6_gif_input(struct mbuf **, int *, int); extern struct domain inet6domain; static struct protosw in6_gif_protosw = { .pr_type = SOCK_RAW, .pr_domain = &inet6domain, .pr_protocol = 0, /* IPPROTO_IPV[46] */ .pr_flags = PR_ATOMIC|PR_ADDR, .pr_input = in6_gif_input, .pr_output = rip6_output, .pr_ctloutput = rip6_ctloutput, .pr_usrreqs = &rip6_usrreqs }; int in6_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn) { GIF_RLOCK_TRACKER; struct gif_softc *sc = ifp->if_softc; struct ip6_hdr *ip6; int len; /* prepend new IP header */ len = sizeof(struct ip6_hdr); #ifndef __NO_STRICT_ALIGNMENT if (proto == IPPROTO_ETHERIP) len += ETHERIP_ALIGN; #endif M_PREPEND(m, len, M_NOWAIT); if (m == NULL) return (ENOBUFS); #ifndef __NO_STRICT_ALIGNMENT if (proto == IPPROTO_ETHERIP) { len = mtod(m, vm_offset_t) & 3; KASSERT(len == 0 || len == ETHERIP_ALIGN, ("in6_gif_output: unexpected misalignment")); m->m_data += len; m->m_len -= ETHERIP_ALIGN; } #endif ip6 = mtod(m, struct ip6_hdr *); GIF_RLOCK(sc); if (sc->gif_family != AF_INET6) { m_freem(m); GIF_RUNLOCK(sc); return (ENETDOWN); } bcopy(sc->gif_ip6hdr, ip6, sizeof(struct ip6_hdr)); GIF_RUNLOCK(sc); ip6->ip6_flow |= htonl((uint32_t)ecn << 20); ip6->ip6_nxt = proto; ip6->ip6_hlim = V_ip6_gif_hlim; /* * force fragmentation to minimum MTU, to avoid path MTU discovery. * it is too painful to ask for resend of inner packet, to achieve * path MTU discovery for encapsulated packets. */ return (ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL, NULL)); } static int in6_gif_input(struct mbuf **mp, int *offp, int proto) { struct mbuf *m = *mp; struct ifnet *gifp; struct gif_softc *sc; struct ip6_hdr *ip6; uint8_t ecn; sc = encap_getarg(m); if (sc == NULL) { m_freem(m); IP6STAT_INC(ip6s_nogif); return (IPPROTO_DONE); } gifp = GIF2IFP(sc); if ((gifp->if_flags & IFF_UP) != 0) { ip6 = mtod(m, struct ip6_hdr *); ecn = (ntohl(ip6->ip6_flow) >> 20) & 0xff; m_adj(m, *offp); gif_input(m, gifp, proto, ecn); } else { m_freem(m); IP6STAT_INC(ip6s_nogif); } return (IPPROTO_DONE); } /* * validate outer address. */ static int gif_validate6(const struct ip6_hdr *ip6, struct gif_softc *sc, struct ifnet *ifp) { + int ret; GIF_RLOCK_ASSERT(sc); /* * Check for address match. Note that the check is for an incoming * packet. We should compare the *source* address in our configuration * and the *destination* address of the packet, and vice versa. */ - if (!IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_src, &ip6->ip6_dst) || - !IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_dst, &ip6->ip6_src)) + if (!IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_src, &ip6->ip6_dst)) return (0); + ret = 128; + if (!IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_dst, &ip6->ip6_src)) { + if ((sc->gif_options & GIF_IGNORE_SOURCE) == 0) + return (0); + } else + ret += 128; /* martian filters on outer source - done in ip6_input */ /* ingress filters on outer source */ if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) { struct sockaddr_in6 sin6; struct rtentry *rt; bzero(&sin6, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_addr = ip6->ip6_src; sin6.sin6_scope_id = 0; /* XXX */ rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL, sc->gif_fibnum); if (!rt || rt->rt_ifp != ifp) { if (rt) RTFREE_LOCKED(rt); return (0); } RTFREE_LOCKED(rt); } - return (128 * 2); + return (ret); } /* * we know that we are in IFF_UP, outer address available, and outer family * matched the physical addr family. see gif_encapcheck(). */ int in6_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg) { struct ip6_hdr ip6; struct gif_softc *sc; struct ifnet *ifp; /* sanity check done in caller */ sc = (struct gif_softc *)arg; GIF_RLOCK_ASSERT(sc); m_copydata(m, 0, sizeof(ip6), (caddr_t)&ip6); ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; return (gif_validate6(&ip6, sc, ifp)); } int in6_gif_attach(struct gif_softc *sc) { KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL")); sc->gif_ecookie = encap_attach_func(AF_INET6, -1, gif_encapcheck, (void *)&in6_gif_protosw, sc); if (sc->gif_ecookie == NULL) return (EEXIST); return (0); } Index: projects/ci20_mips/sys/netipsec/esp.h =================================================================== --- projects/ci20_mips/sys/netipsec/esp.h (revision 283030) +++ projects/ci20_mips/sys/netipsec/esp.h (revision 283031) @@ -1,69 +1,67 @@ /* $FreeBSD$ */ /* $KAME: esp.h,v 1.16 2000/10/18 21:28:00 itojun Exp $ */ /*- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * RFC1827/2406 Encapsulated Security Payload. */ #ifndef _NETIPSEC_ESP_H_ #define _NETIPSEC_ESP_H_ struct esp { u_int32_t esp_spi; /* ESP */ /*variable size, 32bit bound*/ /* Initialization Vector */ /*variable size*/ /* Payload data */ /*variable size*/ /* padding */ - /*8bit*/ /* pad size */ + /*8bit*/ /* pad length */ /*8bit*/ /* next header */ - /*8bit*/ /* next header */ /*variable size, 32bit bound*/ /* Authentication data (new IPsec) */ }; struct newesp { u_int32_t esp_spi; /* ESP */ u_int32_t esp_seq; /* Sequence number */ /*variable size*/ /* (IV and) Payload data */ /*variable size*/ /* padding */ - /*8bit*/ /* pad size */ - /*8bit*/ /* next header */ + /*8bit*/ /* pad length */ /*8bit*/ /* next header */ /*variable size, 32bit bound*/ /* Authentication data */ }; struct esptail { u_int8_t esp_padlen; /* pad length */ u_int8_t esp_nxt; /* Next header */ /*variable size, 32bit bound*/ /* Authentication data (new IPsec)*/ }; #define ESP_ALEN 12 /* 96-bit authenticator */ #endif /*_NETIPSEC_ESP_H_*/ Index: projects/ci20_mips/sys/powerpc/ofw/ofw_pcibus.c =================================================================== --- projects/ci20_mips/sys/powerpc/ofw/ofw_pcibus.c (revision 283030) +++ projects/ci20_mips/sys/powerpc/ofw/ofw_pcibus.c (revision 283031) @@ -1,354 +1,355 @@ /*- * Copyright (c) 1997, Stefan Esser * Copyright (c) 2000, Michael Smith * Copyright (c) 2000, BSDi * Copyright (c) 2003, Thomas Moestl * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ofw_pcibus.h" #include "pcib_if.h" #include "pci_if.h" typedef uint32_t ofw_pci_intr_t; /* Methods */ static device_probe_t ofw_pcibus_probe; static device_attach_t ofw_pcibus_attach; static pci_assign_interrupt_t ofw_pcibus_assign_interrupt; static ofw_bus_get_devinfo_t ofw_pcibus_get_devinfo; static int ofw_pcibus_child_pnpinfo_str_method(device_t cbdev, device_t child, char *buf, size_t buflen); static void ofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno); static void ofw_pcibus_enum_bus(device_t dev, u_int domain, u_int busno); static device_method_t ofw_pcibus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ofw_pcibus_probe), DEVMETHOD(device_attach, ofw_pcibus_attach), /* Bus interface */ DEVMETHOD(bus_child_pnpinfo_str, ofw_pcibus_child_pnpinfo_str_method), /* PCI interface */ DEVMETHOD(pci_assign_interrupt, ofw_pcibus_assign_interrupt), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, ofw_pcibus_get_devinfo), DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), DEVMETHOD_END }; static devclass_t pci_devclass; DEFINE_CLASS_1(pci, ofw_pcibus_driver, ofw_pcibus_methods, sizeof(struct pci_softc), pci_driver); DRIVER_MODULE(ofw_pcibus, pcib, ofw_pcibus_driver, pci_devclass, 0, 0); MODULE_VERSION(ofw_pcibus, 1); MODULE_DEPEND(ofw_pcibus, pci, 1, 1, 1); static int ofw_devices_only = 0; TUNABLE_INT("hw.pci.ofw_devices_only", &ofw_devices_only); static int ofw_pcibus_probe(device_t dev) { if (ofw_bus_get_node(dev) == -1) return (ENXIO); device_set_desc(dev, "OFW PCI bus"); return (BUS_PROBE_DEFAULT); } static int ofw_pcibus_attach(device_t dev) { u_int busno, domain; int error; error = pci_attach_common(dev); if (error) return (error); domain = pcib_get_domain(dev); busno = pcib_get_bus(dev); /* * Attach those children represented in the device tree. */ ofw_pcibus_enum_devtree(dev, domain, busno); /* * We now attach any laggard devices. FDT, for instance, allows * the device tree to enumerate only some PCI devices. Apple's * OF device tree on some Grackle-based hardware can also miss * functions on multi-function cards. */ if (!ofw_devices_only) ofw_pcibus_enum_bus(dev, domain, busno); return (bus_generic_attach(dev)); } static void ofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno) { device_t pcib; struct ofw_pci_register pcir; struct ofw_pcibus_devinfo *dinfo; phandle_t node, child; u_int func, slot; int intline; pcib = device_get_parent(dev); node = ofw_bus_get_node(dev); for (child = OF_child(node); child != 0; child = OF_peer(child)) { if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1) continue; slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi); func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi); /* Some OFW device trees contain dupes. */ if (pci_find_dbsf(domain, busno, slot, func) != NULL) continue; /* * The preset in the intline register is usually bogus. Reset * it such that the PCI code will reroute the interrupt if * needed. */ intline = PCI_INVALID_IRQ; if (OF_getproplen(child, "interrupts") > 0) intline = 0; PCIB_WRITE_CONFIG(pcib, busno, slot, func, PCIR_INTLINE, intline, 1); /* * Now set up the PCI and OFW bus layer devinfo and add it * to the PCI bus. */ dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib, domain, busno, slot, func, sizeof(*dinfo)); if (dinfo == NULL) continue; if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) != 0) { pci_freecfg((struct pci_devinfo *)dinfo); continue; } dinfo->opd_dma_tag = NULL; pci_add_child(dev, (struct pci_devinfo *)dinfo); /* * Some devices don't have an intpin set, but do have * interrupts. These are fully specified, and set in the * interrupts property, so add that value to the device's * resource list. */ if (dinfo->opd_dinfo.cfg.intpin == 0) - ofw_bus_intr_to_rl(dev, child, &dinfo->opd_dinfo.resources); + ofw_bus_intr_to_rl(dev, child, + &dinfo->opd_dinfo.resources, NULL); } } /* * The following is an almost exact clone of pci_add_children(), with the * addition that it (a) will not add children that have already been added, * and (b) will set up the OFW devinfo to point to invalid values. This is * to handle non-enumerated PCI children as exist in FDT and on the second * function of the Rage 128 in my Blue & White G3. */ static void ofw_pcibus_enum_bus(device_t dev, u_int domain, u_int busno) { device_t pcib; struct ofw_pcibus_devinfo *dinfo; int maxslots; int s, f, pcifunchigh; uint8_t hdrtype; pcib = device_get_parent(dev); maxslots = PCIB_MAXSLOTS(pcib); for (s = 0; s <= maxslots; s++) { pcifunchigh = 0; f = 0; DELAY(1); hdrtype = PCIB_READ_CONFIG(pcib, busno, s, f, PCIR_HDRTYPE, 1); if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) continue; if (hdrtype & PCIM_MFDEV) pcifunchigh = PCI_FUNCMAX; for (f = 0; f <= pcifunchigh; f++) { /* Filter devices we have already added */ if (pci_find_dbsf(domain, busno, s, f) != NULL) continue; dinfo = (struct ofw_pcibus_devinfo *)pci_read_device( pcib, domain, busno, s, f, sizeof(*dinfo)); if (dinfo == NULL) continue; dinfo->opd_dma_tag = NULL; dinfo->opd_obdinfo.obd_node = -1; dinfo->opd_obdinfo.obd_name = NULL; dinfo->opd_obdinfo.obd_compat = NULL; dinfo->opd_obdinfo.obd_type = NULL; dinfo->opd_obdinfo.obd_model = NULL; /* * For non OFW-devices, don't believe 0 * for an interrupt. */ if (dinfo->opd_dinfo.cfg.intline == 0) { dinfo->opd_dinfo.cfg.intline = PCI_INVALID_IRQ; PCIB_WRITE_CONFIG(pcib, busno, s, f, PCIR_INTLINE, PCI_INVALID_IRQ, 1); } pci_add_child(dev, (struct pci_devinfo *)dinfo); } } } static int ofw_pcibus_child_pnpinfo_str_method(device_t cbdev, device_t child, char *buf, size_t buflen) { pci_child_pnpinfo_str_method(cbdev, child, buf, buflen); if (ofw_bus_get_node(child) != -1) { strlcat(buf, " ", buflen); /* Separate info */ ofw_bus_gen_child_pnpinfo_str(cbdev, child, buf, buflen); } return (0); } static int ofw_pcibus_assign_interrupt(device_t dev, device_t child) { ofw_pci_intr_t intr[2]; phandle_t node, iparent; int isz, icells; node = ofw_bus_get_node(child); if (node == -1) { /* Non-firmware enumerated child, use standard routing */ intr[0] = pci_get_intpin(child); return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr[0])); } /* * Try to determine the node's interrupt parent so we know which * PIC to use. */ iparent = -1; if (OF_getprop(node, "interrupt-parent", &iparent, sizeof(iparent)) < 0) iparent = -1; icells = 1; if (iparent != -1) OF_getprop(OF_node_from_xref(iparent), "#interrupt-cells", &icells, sizeof(icells)); /* * Any AAPL,interrupts property gets priority and is * fully specified (i.e. does not need routing) */ isz = OF_getprop(node, "AAPL,interrupts", intr, sizeof(intr)); if (isz == sizeof(intr[0])*icells) return ((iparent == -1) ? intr[0] : ofw_bus_map_intr(dev, iparent, icells, intr)); isz = OF_getprop(node, "interrupts", intr, sizeof(intr)); if (isz == sizeof(intr[0])*icells) { if (iparent != -1) intr[0] = ofw_bus_map_intr(dev, iparent, icells, intr); } else { /* No property: our best guess is the intpin. */ intr[0] = pci_get_intpin(child); } /* * If we got intr from a property, it may or may not be an intpin. * For on-board devices, it frequently is not, and is completely out * of the valid intpin range. For PCI slots, it hopefully is, * otherwise we will have trouble interfacing with non-OFW buses * such as cardbus. * Since we cannot tell which it is without violating layering, we * will always use the route_interrupt method, and treat exceptions * on the level they become apparent. */ return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, intr[0])); } static const struct ofw_bus_devinfo * ofw_pcibus_get_devinfo(device_t bus, device_t dev) { struct ofw_pcibus_devinfo *dinfo; dinfo = device_get_ivars(dev); return (&dinfo->opd_obdinfo); } Index: projects/ci20_mips/sys/powerpc/pseries/vdevice.c =================================================================== --- projects/ci20_mips/sys/powerpc/pseries/vdevice.c (revision 283030) +++ projects/ci20_mips/sys/powerpc/pseries/vdevice.c (revision 283031) @@ -1,217 +1,217 @@ /*- * Copyright (c) 2011 Nathan Whitehorn * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "iommu_if.h" static int vdevice_probe(device_t); static int vdevice_attach(device_t); static const struct ofw_bus_devinfo *vdevice_get_devinfo(device_t dev, device_t child); static int vdevice_print_child(device_t dev, device_t child); static struct resource_list *vdevice_get_resource_list(device_t, device_t); static bus_dma_tag_t vdevice_get_dma_tag(device_t dev, device_t child); /* * VDevice devinfo */ struct vdevice_devinfo { struct ofw_bus_devinfo mdi_obdinfo; struct resource_list mdi_resources; bus_dma_tag_t mdi_dma_tag; }; static device_method_t vdevice_methods[] = { /* Device interface */ DEVMETHOD(device_probe, vdevice_probe), DEVMETHOD(device_attach, vdevice_attach), /* Bus interface */ DEVMETHOD(bus_add_child, bus_generic_add_child), DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), DEVMETHOD(bus_print_child, vdevice_print_child), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_get_resource_list, vdevice_get_resource_list), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, vdevice_get_devinfo), DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), /* IOMMU interface */ DEVMETHOD(bus_get_dma_tag, vdevice_get_dma_tag), DEVMETHOD(iommu_map, phyp_iommu_map), DEVMETHOD(iommu_unmap, phyp_iommu_unmap), DEVMETHOD_END }; static driver_t vdevice_driver = { "vdevice", vdevice_methods, 0 }; static devclass_t vdevice_devclass; DRIVER_MODULE(vdevice, ofwbus, vdevice_driver, vdevice_devclass, 0, 0); static int vdevice_probe(device_t dev) { const char *name; name = ofw_bus_get_name(dev); if (name == NULL || strcmp(name, "vdevice") != 0) return (ENXIO); if (!ofw_bus_is_compatible(dev, "IBM,vdevice")) return (ENXIO); device_set_desc(dev, "POWER Hypervisor Virtual Device Root"); return (0); } static int vdevice_attach(device_t dev) { phandle_t root, child; device_t cdev; struct vdevice_devinfo *dinfo; root = ofw_bus_get_node(dev); /* The XICP (root PIC) will handle all our interrupts */ powerpc_register_pic(root_pic, OF_xref_from_node(root), 1 << 24 /* 24-bit XIRR field */, 1 /* Number of IPIs */, FALSE); for (child = OF_child(root); child != 0; child = OF_peer(child)) { dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo, child) != 0) { free(dinfo, M_DEVBUF); continue; } resource_list_init(&dinfo->mdi_resources); - ofw_bus_intr_to_rl(dev, child, &dinfo->mdi_resources); + ofw_bus_intr_to_rl(dev, child, &dinfo->mdi_resources, NULL); cdev = device_add_child(dev, NULL, -1); if (cdev == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", dinfo->mdi_obdinfo.obd_name); ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo); free(dinfo, M_DEVBUF); continue; } device_set_ivars(cdev, dinfo); } return (bus_generic_attach(dev)); } static const struct ofw_bus_devinfo * vdevice_get_devinfo(device_t dev, device_t child) { return (device_get_ivars(child)); } static int vdevice_print_child(device_t dev, device_t child) { struct vdevice_devinfo *dinfo; struct resource_list *rl; int retval = 0; dinfo = device_get_ivars(child); rl = &dinfo->mdi_resources; retval += bus_print_child_header(dev, child); retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); retval += bus_print_child_footer(dev, child); return (retval); } static struct resource_list * vdevice_get_resource_list (device_t dev, device_t child) { struct vdevice_devinfo *dinfo; dinfo = device_get_ivars(child); return (&dinfo->mdi_resources); } static bus_dma_tag_t vdevice_get_dma_tag(device_t dev, device_t child) { struct vdevice_devinfo *dinfo; while (child != NULL && device_get_parent(child) != dev) child = device_get_parent(child); dinfo = device_get_ivars(child); if (dinfo->mdi_dma_tag == NULL) { bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, BUS_SPACE_MAXSIZE, BUS_SPACE_UNRESTRICTED, BUS_SPACE_MAXSIZE, 0, NULL, NULL, &dinfo->mdi_dma_tag); phyp_iommu_set_dma_tag(dev, child, dinfo->mdi_dma_tag); } return (dinfo->mdi_dma_tag); } Index: projects/ci20_mips/sys/sys/cdefs.h =================================================================== --- projects/ci20_mips/sys/sys/cdefs.h (revision 283030) +++ projects/ci20_mips/sys/sys/cdefs.h (revision 283031) @@ -1,852 +1,866 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Berkeley Software Design, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)cdefs.h 8.8 (Berkeley) 1/9/95 * $FreeBSD$ */ #ifndef _SYS_CDEFS_H_ #define _SYS_CDEFS_H_ /* * Testing against Clang-specific extensions. */ #ifndef __has_attribute #define __has_attribute(x) 0 #endif #ifndef __has_extension #define __has_extension __has_feature #endif #ifndef __has_feature #define __has_feature(x) 0 #endif #ifndef __has_include #define __has_include(x) 0 #endif #ifndef __has_builtin #define __has_builtin(x) 0 #endif #if defined(__cplusplus) #define __BEGIN_DECLS extern "C" { #define __END_DECLS } #else #define __BEGIN_DECLS #define __END_DECLS #endif /* * This code has been put in place to help reduce the addition of * compiler specific defines in FreeBSD code. It helps to aid in * having a compiler-agnostic source tree. */ #if defined(__GNUC__) || defined(__INTEL_COMPILER) #if __GNUC__ >= 3 || defined(__INTEL_COMPILER) #define __GNUCLIKE_ASM 3 #define __GNUCLIKE_MATH_BUILTIN_CONSTANTS #else #define __GNUCLIKE_ASM 2 #endif #define __GNUCLIKE___TYPEOF 1 #define __GNUCLIKE___OFFSETOF 1 #define __GNUCLIKE___SECTION 1 #ifndef __INTEL_COMPILER #define __GNUCLIKE_CTOR_SECTION_HANDLING 1 #endif #define __GNUCLIKE_BUILTIN_CONSTANT_P 1 #if defined(__INTEL_COMPILER) && defined(__cplusplus) && \ __INTEL_COMPILER < 800 #undef __GNUCLIKE_BUILTIN_CONSTANT_P #endif #if (__GNUC_MINOR__ > 95 || __GNUC__ >= 3) && !defined(__INTEL_COMPILER) #define __GNUCLIKE_BUILTIN_VARARGS 1 #define __GNUCLIKE_BUILTIN_STDARG 1 #define __GNUCLIKE_BUILTIN_VAALIST 1 #endif #if defined(__GNUC__) #define __GNUC_VA_LIST_COMPATIBILITY 1 #endif /* * Compiler memory barriers, specific to gcc and clang. */ #if defined(__GNUC__) #define __compiler_membar() __asm __volatile(" " : : : "memory") #endif #ifndef __INTEL_COMPILER #define __GNUCLIKE_BUILTIN_NEXT_ARG 1 #define __GNUCLIKE_MATH_BUILTIN_RELOPS #endif #define __GNUCLIKE_BUILTIN_MEMCPY 1 /* XXX: if __GNUC__ >= 2: not tested everywhere originally, where replaced */ #define __CC_SUPPORTS_INLINE 1 #define __CC_SUPPORTS___INLINE 1 #define __CC_SUPPORTS___INLINE__ 1 #define __CC_SUPPORTS___FUNC__ 1 #define __CC_SUPPORTS_WARNING 1 #define __CC_SUPPORTS_VARADIC_XXX 1 /* see varargs.h */ #define __CC_SUPPORTS_DYNAMIC_ARRAY_INIT 1 #endif /* __GNUC__ || __INTEL_COMPILER */ /* * Macro to test if we're using a specific version of gcc or later. */ #if defined(__GNUC__) && !defined(__INTEL_COMPILER) #define __GNUC_PREREQ__(ma, mi) \ (__GNUC__ > (ma) || __GNUC__ == (ma) && __GNUC_MINOR__ >= (mi)) #else #define __GNUC_PREREQ__(ma, mi) 0 #endif /* * The __CONCAT macro is used to concatenate parts of symbol names, e.g. * with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo. * The __CONCAT macro is a bit tricky to use if it must work in non-ANSI * mode -- there must be no spaces between its arguments, and for nested * __CONCAT's, all the __CONCAT's must be at the left. __CONCAT can also * concatenate double-quoted strings produced by the __STRING macro, but * this only works with ANSI C. * * __XSTRING is like __STRING, but it expands any macros in its argument * first. It is only available with ANSI C. */ #if defined(__STDC__) || defined(__cplusplus) #define __P(protos) protos /* full-blown ANSI C */ #define __CONCAT1(x,y) x ## y #define __CONCAT(x,y) __CONCAT1(x,y) #define __STRING(x) #x /* stringify without expanding x */ #define __XSTRING(x) __STRING(x) /* expand x, then stringify */ #define __const const /* define reserved names to standard */ #define __signed signed #define __volatile volatile #if defined(__cplusplus) #define __inline inline /* convert to C++ keyword */ #else #if !(defined(__CC_SUPPORTS___INLINE)) #define __inline /* delete GCC keyword */ #endif /* ! __CC_SUPPORTS___INLINE */ #endif /* !__cplusplus */ #else /* !(__STDC__ || __cplusplus) */ #define __P(protos) () /* traditional C preprocessor */ #define __CONCAT(x,y) x/**/y #define __STRING(x) "x" #if !defined(__CC_SUPPORTS___INLINE) #define __const /* delete pseudo-ANSI C keywords */ #define __inline #define __signed #define __volatile /* * In non-ANSI C environments, new programs will want ANSI-only C keywords * deleted from the program and old programs will want them left alone. * When using a compiler other than gcc, programs using the ANSI C keywords * const, inline etc. as normal identifiers should define -DNO_ANSI_KEYWORDS. * When using "gcc -traditional", we assume that this is the intent; if * __GNUC__ is defined but __STDC__ is not, we leave the new keywords alone. */ #ifndef NO_ANSI_KEYWORDS #define const /* delete ANSI C keywords */ #define inline #define signed #define volatile #endif /* !NO_ANSI_KEYWORDS */ #endif /* !__CC_SUPPORTS___INLINE */ #endif /* !(__STDC__ || __cplusplus) */ /* * Compiler-dependent macros to help declare dead (non-returning) and * pure (no side effects) functions, and unused variables. They are * null except for versions of gcc that are known to support the features * properly (old versions of gcc-2 supported the dead and pure features * in a different (wrong) way). If we do not provide an implementation * for a given compiler, let the compile fail if it is told to use * a feature that we cannot live without. */ #ifdef lint #define __dead2 #define __pure2 #define __unused #define __packed #define __aligned(x) #define __section(x) #define __weak #else #define __weak __attribute__((__weak__)) #if !__GNUC_PREREQ__(2, 5) && !defined(__INTEL_COMPILER) #define __dead2 #define __pure2 #define __unused #endif #if __GNUC__ == 2 && __GNUC_MINOR__ >= 5 && __GNUC_MINOR__ < 7 && !defined(__INTEL_COMPILER) #define __dead2 __attribute__((__noreturn__)) #define __pure2 __attribute__((__const__)) #define __unused /* XXX Find out what to do for __packed, __aligned and __section */ #endif #if __GNUC_PREREQ__(2, 7) #define __dead2 __attribute__((__noreturn__)) #define __pure2 __attribute__((__const__)) #define __unused __attribute__((__unused__)) #define __used __attribute__((__used__)) #define __packed __attribute__((__packed__)) #define __aligned(x) __attribute__((__aligned__(x))) #define __section(x) __attribute__((__section__(x))) #endif #if defined(__INTEL_COMPILER) #define __dead2 __attribute__((__noreturn__)) #define __pure2 __attribute__((__const__)) #define __unused __attribute__((__unused__)) #define __used __attribute__((__used__)) #define __packed __attribute__((__packed__)) #define __aligned(x) __attribute__((__aligned__(x))) #define __section(x) __attribute__((__section__(x))) #endif #endif /* lint */ #if !__GNUC_PREREQ__(2, 95) #define __alignof(x) __offsetof(struct { char __a; x __b; }, __b) #endif /* * Keywords added in C11. */ #if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L || defined(lint) #if !__has_extension(c_alignas) #if (defined(__cplusplus) && __cplusplus >= 201103L) || \ __has_extension(cxx_alignas) #define _Alignas(x) alignas(x) #else /* XXX: Only emulates _Alignas(constant-expression); not _Alignas(type-name). */ #define _Alignas(x) __aligned(x) #endif #endif #if defined(__cplusplus) && __cplusplus >= 201103L #define _Alignof(x) alignof(x) #else #define _Alignof(x) __alignof(x) #endif #if !__has_extension(c_atomic) && !__has_extension(cxx_atomic) /* * No native support for _Atomic(). Place object in structure to prevent * most forms of direct non-atomic access. */ #define _Atomic(T) struct { T volatile __val; } #endif #if defined(__cplusplus) && __cplusplus >= 201103L #define _Noreturn [[noreturn]] #else #define _Noreturn __dead2 #endif #if !__has_extension(c_static_assert) #if (defined(__cplusplus) && __cplusplus >= 201103L) || \ __has_extension(cxx_static_assert) #define _Static_assert(x, y) static_assert(x, y) #elif __GNUC_PREREQ__(4,6) /* Nothing, gcc 4.6 and higher has _Static_assert built-in */ #elif defined(__COUNTER__) #define _Static_assert(x, y) __Static_assert(x, __COUNTER__) #define __Static_assert(x, y) ___Static_assert(x, y) #define ___Static_assert(x, y) typedef char __assert_ ## y[(x) ? 1 : -1] \ __unused #else #define _Static_assert(x, y) struct __hack #endif #endif #if !__has_extension(c_thread_local) /* * XXX: Some compilers (Clang 3.3, GCC 4.7) falsely announce C++11 mode * without actually supporting the thread_local keyword. Don't check for * the presence of C++11 when defining _Thread_local. */ #if /* (defined(__cplusplus) && __cplusplus >= 201103L) || */ \ __has_extension(cxx_thread_local) #define _Thread_local thread_local #else #define _Thread_local __thread #endif #endif #endif /* __STDC_VERSION__ || __STDC_VERSION__ < 201112L */ /* * Emulation of C11 _Generic(). Unlike the previously defined C11 * keywords, it is not possible to implement this using exactly the same * syntax. Therefore implement something similar under the name * __generic(). Unlike _Generic(), this macro can only distinguish * between a single type, so it requires nested invocations to * distinguish multiple cases. */ #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \ __has_extension(c_generic_selections) #define __generic(expr, t, yes, no) \ _Generic(expr, t: yes, default: no) #elif __GNUC_PREREQ__(3, 1) && !defined(__cplusplus) #define __generic(expr, t, yes, no) \ __builtin_choose_expr( \ __builtin_types_compatible_p(__typeof(expr), t), yes, no) #endif #if __GNUC_PREREQ__(2, 96) #define __malloc_like __attribute__((__malloc__)) #define __pure __attribute__((__pure__)) #else #define __malloc_like #define __pure #endif #if __GNUC_PREREQ__(3, 1) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 800) #define __always_inline __attribute__((__always_inline__)) #else #define __always_inline #endif #if __GNUC_PREREQ__(3, 1) #define __noinline __attribute__ ((__noinline__)) #else #define __noinline #endif #if __GNUC_PREREQ__(3, 3) #define __nonnull(x) __attribute__((__nonnull__(x))) #define __nonnull_all __attribute__((__nonnull__)) #else #define __nonnull(x) #define __nonnull_all #endif #if __GNUC_PREREQ__(3, 4) #define __fastcall __attribute__((__fastcall__)) #define __result_use_check __attribute__((__warn_unused_result__)) #else #define __fastcall #define __result_use_check #endif #if __GNUC_PREREQ__(4, 1) -#define __gnu_inline __attribute__((__gnu_inline__)) #define __returns_twice __attribute__((__returns_twice__)) #else -#define __gnu_inline #define __returns_twice #endif #if __has_attribute(alloc_size) || __GNUC_PREREQ__(4, 3) #define __alloc_size(x) __attribute__((__alloc_size__(x))) #else #define __alloc_size(x) #endif #if __has_builtin(__builtin_unreachable) || __GNUC_PREREQ__(4, 6) #define __unreachable() __builtin_unreachable() #else -#define __unreachable() do {} while (/*CONSTCOND*/0) +#define __unreachable() ((void)0) #endif #if __has_attribute(alloc_align) || __GNUC_PREREQ__(4, 9) #define __alloc_align(x) __attribute__((__alloc_align__(x))) #else #define __alloc_align(x) #endif /* XXX: should use `#if __STDC_VERSION__ < 199901'. */ #if !__GNUC_PREREQ__(2, 7) && !defined(__INTEL_COMPILER) #define __func__ NULL #endif #if (defined(__INTEL_COMPILER) || (defined(__GNUC__) && __GNUC__ >= 2)) && !defined(__STRICT_ANSI__) || __STDC_VERSION__ >= 199901 #define __LONG_LONG_SUPPORTED #endif /* C++11 exposes a load of C99 stuff */ #if defined(__cplusplus) && __cplusplus >= 201103L #define __LONG_LONG_SUPPORTED #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS #endif #ifndef __STDC_CONSTANT_MACROS #define __STDC_CONSTANT_MACROS #endif #endif /* * GCC 2.95 provides `__restrict' as an extension to C90 to support the * C99-specific `restrict' type qualifier. We happen to use `__restrict' as * a way to define the `restrict' type qualifier without disturbing older * software that is unaware of C99 keywords. */ #if !(__GNUC__ == 2 && __GNUC_MINOR__ == 95) #if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901 || defined(lint) #define __restrict #else #define __restrict restrict #endif #endif /* * GNU C version 2.96 adds explicit branch prediction so that * the CPU back-end can hint the processor and also so that * code blocks can be reordered such that the predicted path * sees a more linear flow, thus improving cache behavior, etc. * * The following two macros provide us with a way to utilize this * compiler feature. Use __predict_true() if you expect the expression * to evaluate to true, and __predict_false() if you expect the * expression to evaluate to false. * * A few notes about usage: * * * Generally, __predict_false() error condition checks (unless * you have some _strong_ reason to do otherwise, in which case * document it), and/or __predict_true() `no-error' condition * checks, assuming you want to optimize for the no-error case. * * * Other than that, if you don't know the likelihood of a test * succeeding from empirical or other `hard' evidence, don't * make predictions. * * * These are meant to be used in places that are run `a lot'. * It is wasteful to make predictions in code that is run * seldomly (e.g. at subsystem initialization time) as the * basic block reordering that this affects can often generate * larger code. */ #if __GNUC_PREREQ__(2, 96) #define __predict_true(exp) __builtin_expect((exp), 1) #define __predict_false(exp) __builtin_expect((exp), 0) #else #define __predict_true(exp) (exp) #define __predict_false(exp) (exp) #endif #if __GNUC_PREREQ__(4, 0) #define __hidden __attribute__((__visibility__("hidden"))) #define __exported __attribute__((__visibility__("default"))) #else #define __hidden #define __exported #endif /* * We define this here since , , and * require it. */ #if __GNUC_PREREQ__(4, 1) #define __offsetof(type, field) __builtin_offsetof(type, field) #else #ifndef __cplusplus #define __offsetof(type, field) \ ((__size_t)(__uintptr_t)((const volatile void *)&((type *)0)->field)) #else #define __offsetof(type, field) \ (__offsetof__ (reinterpret_cast <__size_t> \ (&reinterpret_cast \ (static_cast (0)->field)))) #endif #endif #define __rangeof(type, start, end) \ (__offsetof(type, end) - __offsetof(type, start)) /* * Given the pointer x to the member m of the struct s, return * a pointer to the containing structure. When using GCC, we first * assign pointer x to a local variable, to check that its type is * compatible with member m. */ #if __GNUC_PREREQ__(3, 1) #define __containerof(x, s, m) ({ \ const volatile __typeof(((s *)0)->m) *__x = (x); \ __DEQUALIFY(s *, (const volatile char *)__x - __offsetof(s, m));\ }) #else #define __containerof(x, s, m) \ __DEQUALIFY(s *, (const volatile char *)(x) - __offsetof(s, m)) #endif /* * Compiler-dependent macros to declare that functions take printf-like * or scanf-like arguments. They are null except for versions of gcc * that are known to support the features properly (old versions of gcc-2 * didn't permit keeping the keywords out of the application namespace). */ #if !__GNUC_PREREQ__(2, 7) && !defined(__INTEL_COMPILER) #define __printflike(fmtarg, firstvararg) #define __scanflike(fmtarg, firstvararg) #define __format_arg(fmtarg) #define __strfmonlike(fmtarg, firstvararg) #define __strftimelike(fmtarg, firstvararg) #else #define __printflike(fmtarg, firstvararg) \ __attribute__((__format__ (__printf__, fmtarg, firstvararg))) #define __scanflike(fmtarg, firstvararg) \ __attribute__((__format__ (__scanf__, fmtarg, firstvararg))) #define __format_arg(fmtarg) __attribute__((__format_arg__ (fmtarg))) #define __strfmonlike(fmtarg, firstvararg) \ __attribute__((__format__ (__strfmon__, fmtarg, firstvararg))) #define __strftimelike(fmtarg, firstvararg) \ __attribute__((__format__ (__strftime__, fmtarg, firstvararg))) +#endif + +/* + * FORTIFY_SOURCE, and perhaps other compiler-specific features, require + * the use of non-standard inlining. In general we should try to avoid + * using these but GCC-compatible compilers tend to support the extensions + * well enough to use them in limited cases. + */ +#if __GNUC_PREREQ__(4, 1) +#if __has_attribute(artificial) || __GNUC_PREREQ__(4, 3) +#define __gnu_inline __attribute__((__gnu_inline__, __artificial__)) +#else +#define __gnu_inline __attribute__((__gnu_inline__)) +#endif /* artificial */ +#else +#define __gnu_inline #endif /* Compiler-dependent macros that rely on FreeBSD-specific extensions. */ #if defined(__FreeBSD_cc_version) && __FreeBSD_cc_version >= 300001 && \ defined(__GNUC__) && !defined(__INTEL_COMPILER) #define __printf0like(fmtarg, firstvararg) \ __attribute__((__format__ (__printf0__, fmtarg, firstvararg))) #else #define __printf0like(fmtarg, firstvararg) #endif #if defined(__GNUC__) || defined(__INTEL_COMPILER) #ifndef __INTEL_COMPILER #define __strong_reference(sym,aliassym) \ extern __typeof (sym) aliassym __attribute__ ((__alias__ (#sym))) #endif #ifdef __STDC__ #define __weak_reference(sym,alias) \ __asm__(".weak " #alias); \ __asm__(".equ " #alias ", " #sym) #define __warn_references(sym,msg) \ __asm__(".section .gnu.warning." #sym); \ __asm__(".asciz \"" msg "\""); \ __asm__(".previous") #define __sym_compat(sym,impl,verid) \ __asm__(".symver " #impl ", " #sym "@" #verid) #define __sym_default(sym,impl,verid) \ __asm__(".symver " #impl ", " #sym "@@" #verid) #else #define __weak_reference(sym,alias) \ __asm__(".weak alias"); \ __asm__(".equ alias, sym") #define __warn_references(sym,msg) \ __asm__(".section .gnu.warning.sym"); \ __asm__(".asciz \"msg\""); \ __asm__(".previous") #define __sym_compat(sym,impl,verid) \ __asm__(".symver impl, sym@verid") #define __sym_default(impl,sym,verid) \ __asm__(".symver impl, sym@@verid") #endif /* __STDC__ */ #endif /* __GNUC__ || __INTEL_COMPILER */ #define __GLOBL1(sym) __asm__(".globl " #sym) #define __GLOBL(sym) __GLOBL1(sym) #if defined(__GNUC__) || defined(__INTEL_COMPILER) #define __IDSTRING(name,string) __asm__(".ident\t\"" string "\"") #else /* * The following definition might not work well if used in header files, * but it should be better than nothing. If you want a "do nothing" * version, then it should generate some harmless declaration, such as: * #define __IDSTRING(name,string) struct __hack */ #define __IDSTRING(name,string) static const char name[] __unused = string #endif /* * Embed the rcs id of a source file in the resulting library. Note that in * more recent ELF binutils, we use .ident allowing the ID to be stripped. * Usage: * __FBSDID("$FreeBSD$"); */ #ifndef __FBSDID #if !defined(lint) && !defined(STRIP_FBSDID) #define __FBSDID(s) __IDSTRING(__CONCAT(__rcsid_,__LINE__),s) #else #define __FBSDID(s) struct __hack #endif #endif #ifndef __RCSID #ifndef NO__RCSID #define __RCSID(s) __IDSTRING(__CONCAT(__rcsid_,__LINE__),s) #else #define __RCSID(s) struct __hack #endif #endif #ifndef __RCSID_SOURCE #ifndef NO__RCSID_SOURCE #define __RCSID_SOURCE(s) __IDSTRING(__CONCAT(__rcsid_source_,__LINE__),s) #else #define __RCSID_SOURCE(s) struct __hack #endif #endif #ifndef __SCCSID #ifndef NO__SCCSID #define __SCCSID(s) __IDSTRING(__CONCAT(__sccsid_,__LINE__),s) #else #define __SCCSID(s) struct __hack #endif #endif #ifndef __COPYRIGHT #ifndef NO__COPYRIGHT #define __COPYRIGHT(s) __IDSTRING(__CONCAT(__copyright_,__LINE__),s) #else #define __COPYRIGHT(s) struct __hack #endif #endif #ifndef __DECONST #define __DECONST(type, var) ((type)(__uintptr_t)(const void *)(var)) #endif #ifndef __DEVOLATILE #define __DEVOLATILE(type, var) ((type)(__uintptr_t)(volatile void *)(var)) #endif #ifndef __DEQUALIFY #define __DEQUALIFY(type, var) ((type)(__uintptr_t)(const volatile void *)(var)) #endif /*- * The following definitions are an extension of the behavior originally * implemented in , but with a different level of granularity. * POSIX.1 requires that the macros we test be defined before any standard * header file is included. * * Here's a quick run-down of the versions: * defined(_POSIX_SOURCE) 1003.1-1988 * _POSIX_C_SOURCE == 1 1003.1-1990 * _POSIX_C_SOURCE == 2 1003.2-1992 C Language Binding Option * _POSIX_C_SOURCE == 199309 1003.1b-1993 * _POSIX_C_SOURCE == 199506 1003.1c-1995, 1003.1i-1995, * and the omnibus ISO/IEC 9945-1: 1996 * _POSIX_C_SOURCE == 200112 1003.1-2001 * _POSIX_C_SOURCE == 200809 1003.1-2008 * * In addition, the X/Open Portability Guide, which is now the Single UNIX * Specification, defines a feature-test macro which indicates the version of * that specification, and which subsumes _POSIX_C_SOURCE. * * Our macros begin with two underscores to avoid namespace screwage. */ /* Deal with IEEE Std. 1003.1-1990, in which _POSIX_C_SOURCE == 1. */ #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE == 1 #undef _POSIX_C_SOURCE /* Probably illegal, but beyond caring now. */ #define _POSIX_C_SOURCE 199009 #endif /* Deal with IEEE Std. 1003.2-1992, in which _POSIX_C_SOURCE == 2. */ #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE == 2 #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 199209 #endif /* Deal with various X/Open Portability Guides and Single UNIX Spec. */ #ifdef _XOPEN_SOURCE #if _XOPEN_SOURCE - 0 >= 700 #define __XSI_VISIBLE 700 #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200809 #elif _XOPEN_SOURCE - 0 >= 600 #define __XSI_VISIBLE 600 #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200112 #elif _XOPEN_SOURCE - 0 >= 500 #define __XSI_VISIBLE 500 #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 199506 #endif #endif /* * Deal with all versions of POSIX. The ordering relative to the tests above is * important. */ #if defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) #define _POSIX_C_SOURCE 198808 #endif #ifdef _POSIX_C_SOURCE #if _POSIX_C_SOURCE >= 200809 #define __POSIX_VISIBLE 200809 #define __ISO_C_VISIBLE 1999 #elif _POSIX_C_SOURCE >= 200112 #define __POSIX_VISIBLE 200112 #define __ISO_C_VISIBLE 1999 #elif _POSIX_C_SOURCE >= 199506 #define __POSIX_VISIBLE 199506 #define __ISO_C_VISIBLE 1990 #elif _POSIX_C_SOURCE >= 199309 #define __POSIX_VISIBLE 199309 #define __ISO_C_VISIBLE 1990 #elif _POSIX_C_SOURCE >= 199209 #define __POSIX_VISIBLE 199209 #define __ISO_C_VISIBLE 1990 #elif _POSIX_C_SOURCE >= 199009 #define __POSIX_VISIBLE 199009 #define __ISO_C_VISIBLE 1990 #else #define __POSIX_VISIBLE 198808 #define __ISO_C_VISIBLE 0 #endif /* _POSIX_C_SOURCE */ #else /*- * Deal with _ANSI_SOURCE: * If it is defined, and no other compilation environment is explicitly * requested, then define our internal feature-test macros to zero. This * makes no difference to the preprocessor (undefined symbols in preprocessing * expressions are defined to have value zero), but makes it more convenient for * a test program to print out the values. * * If a program mistakenly defines _ANSI_SOURCE and some other macro such as * _POSIX_C_SOURCE, we will assume that it wants the broader compilation * environment (and in fact we will never get here). */ #if defined(_ANSI_SOURCE) /* Hide almost everything. */ #define __POSIX_VISIBLE 0 #define __XSI_VISIBLE 0 #define __BSD_VISIBLE 0 #define __ISO_C_VISIBLE 1990 #elif defined(_C99_SOURCE) /* Localism to specify strict C99 env. */ #define __POSIX_VISIBLE 0 #define __XSI_VISIBLE 0 #define __BSD_VISIBLE 0 #define __ISO_C_VISIBLE 1999 #elif defined(_C11_SOURCE) /* Localism to specify strict C11 env. */ #define __POSIX_VISIBLE 0 #define __XSI_VISIBLE 0 #define __BSD_VISIBLE 0 #define __ISO_C_VISIBLE 2011 #else /* Default environment: show everything. */ #define __POSIX_VISIBLE 200809 #define __XSI_VISIBLE 700 #define __BSD_VISIBLE 1 #define __ISO_C_VISIBLE 2011 #endif #endif #if defined(__mips) || defined(__powerpc64__) #define __NO_TLS 1 #endif /* * Type Safety Checking * * Clang provides additional attributes to enable checking type safety * properties that cannot be enforced by the C type system. */ #if __has_attribute(argument_with_type_tag) && \ __has_attribute(type_tag_for_datatype) && !defined(lint) #define __arg_type_tag(arg_kind, arg_idx, type_tag_idx) \ __attribute__((__argument_with_type_tag__(arg_kind, arg_idx, type_tag_idx))) #define __datatype_type_tag(kind, type) \ __attribute__((__type_tag_for_datatype__(kind, type))) #else #define __arg_type_tag(arg_kind, arg_idx, type_tag_idx) #define __datatype_type_tag(kind, type) #endif /* * Lock annotations. * * Clang provides support for doing basic thread-safety tests at * compile-time, by marking which locks will/should be held when * entering/leaving a functions. * * Furthermore, it is also possible to annotate variables and structure * members to enforce that they are only accessed when certain locks are * held. */ #if __has_extension(c_thread_safety_attributes) #define __lock_annotate(x) __attribute__((x)) #else #define __lock_annotate(x) #endif /* Structure implements a lock. */ #define __lockable __lock_annotate(lockable) /* Function acquires an exclusive or shared lock. */ #define __locks_exclusive(...) \ __lock_annotate(exclusive_lock_function(__VA_ARGS__)) #define __locks_shared(...) \ __lock_annotate(shared_lock_function(__VA_ARGS__)) /* Function attempts to acquire an exclusive or shared lock. */ #define __trylocks_exclusive(...) \ __lock_annotate(exclusive_trylock_function(__VA_ARGS__)) #define __trylocks_shared(...) \ __lock_annotate(shared_trylock_function(__VA_ARGS__)) /* Function releases a lock. */ #define __unlocks(...) __lock_annotate(unlock_function(__VA_ARGS__)) /* Function asserts that an exclusive or shared lock is held. */ #define __asserts_exclusive(...) \ __lock_annotate(assert_exclusive_lock(__VA_ARGS__)) #define __asserts_shared(...) \ __lock_annotate(assert_shared_lock(__VA_ARGS__)) /* Function requires that an exclusive or shared lock is or is not held. */ #define __requires_exclusive(...) \ __lock_annotate(exclusive_locks_required(__VA_ARGS__)) #define __requires_shared(...) \ __lock_annotate(shared_locks_required(__VA_ARGS__)) #define __requires_unlocked(...) \ __lock_annotate(locks_excluded(__VA_ARGS__)) /* Function should not be analyzed. */ #define __no_lock_analysis __lock_annotate(no_thread_safety_analysis) /* Guard variables and structure members by lock. */ #define __guarded_by(x) __lock_annotate(guarded_by(x)) #define __pt_guarded_by(x) __lock_annotate(pt_guarded_by(x)) #endif /* !_SYS_CDEFS_H_ */ Index: projects/ci20_mips/sys/sys/condvar.h =================================================================== --- projects/ci20_mips/sys/sys/condvar.h (revision 283030) +++ projects/ci20_mips/sys/sys/condvar.h (revision 283031) @@ -1,89 +1,89 @@ /*- * Copyright (c) 2000 Jake Burkholder . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _SYS_CONDVAR_H_ #define _SYS_CONDVAR_H_ #ifndef LOCORE #include struct lock_object; struct thread; TAILQ_HEAD(cv_waitq, thread); /* * Condition variable. The waiters count is protected by the mutex that * protects the condition; that is, the mutex that is passed to cv_wait*() * and is held across calls to cv_signal() and cv_broadcast(). It is an * optimization to avoid looking up the sleep queue if there are no waiters. */ struct cv { const char *cv_description; - int cv_waiters; + volatile int cv_waiters; }; #ifdef _KERNEL void cv_init(struct cv *cvp, const char *desc); void cv_destroy(struct cv *cvp); void _cv_wait(struct cv *cvp, struct lock_object *lock); void _cv_wait_unlock(struct cv *cvp, struct lock_object *lock); int _cv_wait_sig(struct cv *cvp, struct lock_object *lock); int _cv_timedwait_sbt(struct cv *cvp, struct lock_object *lock, sbintime_t sbt, sbintime_t pr, int flags); int _cv_timedwait_sig_sbt(struct cv *cvp, struct lock_object *lock, sbintime_t sbt, sbintime_t pr, int flags); void cv_signal(struct cv *cvp); void cv_broadcastpri(struct cv *cvp, int pri); #define cv_wait(cvp, lock) \ _cv_wait((cvp), &(lock)->lock_object) #define cv_wait_unlock(cvp, lock) \ _cv_wait_unlock((cvp), &(lock)->lock_object) #define cv_wait_sig(cvp, lock) \ _cv_wait_sig((cvp), &(lock)->lock_object) #define cv_timedwait(cvp, lock, timo) \ _cv_timedwait_sbt((cvp), &(lock)->lock_object, \ tick_sbt * (timo), 0, C_HARDCLOCK) #define cv_timedwait_sbt(cvp, lock, sbt, pr, flags) \ _cv_timedwait_sbt((cvp), &(lock)->lock_object, (sbt), (pr), (flags)) #define cv_timedwait_sig(cvp, lock, timo) \ _cv_timedwait_sig_sbt((cvp), &(lock)->lock_object, \ tick_sbt * (timo), 0, C_HARDCLOCK) #define cv_timedwait_sig_sbt(cvp, lock, sbt, pr, flags) \ _cv_timedwait_sig_sbt((cvp), &(lock)->lock_object, (sbt), (pr), (flags)) #define cv_broadcast(cvp) cv_broadcastpri(cvp, 0) #define cv_wmesg(cvp) ((cvp)->cv_description) #endif /* _KERNEL */ #endif /* !LOCORE */ #endif /* _SYS_CONDVAR_H_ */ Index: projects/ci20_mips/sys/sys/malloc.h =================================================================== --- projects/ci20_mips/sys/sys/malloc.h (revision 283030) +++ projects/ci20_mips/sys/sys/malloc.h (revision 283031) @@ -1,195 +1,195 @@ /*- * Copyright (c) 1987, 1993 * The Regents of the University of California. * Copyright (c) 2005, 2009 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)malloc.h 8.5 (Berkeley) 5/3/95 * $FreeBSD$ */ #ifndef _SYS_MALLOC_H_ #define _SYS_MALLOC_H_ #include #include #include #include #define MINALLOCSIZE UMA_SMALLEST_UNIT /* * flags to malloc. */ #define M_NOWAIT 0x0001 /* do not block */ #define M_WAITOK 0x0002 /* ok to block */ #define M_ZERO 0x0100 /* bzero the allocation */ #define M_NOVM 0x0200 /* don't ask VM for pages */ #define M_USE_RESERVE 0x0400 /* can alloc out of reserve memory */ #define M_NODUMP 0x0800 /* don't dump pages in this allocation */ #define M_FIRSTFIT 0x1000 /* Only for vmem, fast fit. */ #define M_BESTFIT 0x2000 /* Only for vmem, low fragmentation. */ #define M_MAGIC 877983977 /* time when first defined :-) */ /* * Two malloc type structures are present: malloc_type, which is used by a * type owner to declare the type, and malloc_type_internal, which holds * malloc-owned statistics and other ABI-sensitive fields, such as the set of * malloc statistics indexed by the compile-time MAXCPU constant. * Applications should avoid introducing dependence on the allocator private * data layout and size. * * The malloc_type ks_next field is protected by malloc_mtx. Other fields in * malloc_type are static after initialization so unsynchronized. * * Statistics in malloc_type_stats are written only when holding a critical * section and running on the CPU associated with the index into the stat * array, but read lock-free resulting in possible (minor) races, which the * monitoring app should take into account. */ struct malloc_type_stats { uint64_t mts_memalloced; /* Bytes allocated on CPU. */ uint64_t mts_memfreed; /* Bytes freed on CPU. */ uint64_t mts_numallocs; /* Number of allocates on CPU. */ uint64_t mts_numfrees; /* number of frees on CPU. */ uint64_t mts_size; /* Bitmask of sizes allocated on CPU. */ uint64_t _mts_reserved1; /* Reserved field. */ uint64_t _mts_reserved2; /* Reserved field. */ uint64_t _mts_reserved3; /* Reserved field. */ }; /* * Index definitions for the mti_probes[] array. */ #define DTMALLOC_PROBE_MALLOC 0 #define DTMALLOC_PROBE_FREE 1 #define DTMALLOC_PROBE_MAX 2 struct malloc_type_internal { uint32_t mti_probes[DTMALLOC_PROBE_MAX]; /* DTrace probe ID array. */ u_char mti_zone; struct malloc_type_stats mti_stats[MAXCPU]; }; /* * Public data structure describing a malloc type. Private data is hung off * of ks_handle to avoid encoding internal malloc(9) data structures in * modules, which will statically allocate struct malloc_type. */ struct malloc_type { struct malloc_type *ks_next; /* Next in global chain. */ u_long ks_magic; /* Detect programmer error. */ const char *ks_shortdesc; /* Printable type name. */ void *ks_handle; /* Priv. data, was lo_class. */ }; /* * Statistics structure headers for user space. The kern.malloc sysctl * exposes a structure stream consisting of a stream header, then a series of * malloc type headers and statistics structures (quantity maxcpus). For * convenience, the kernel will provide the current value of maxcpus at the * head of the stream. */ #define MALLOC_TYPE_STREAM_VERSION 0x00000001 struct malloc_type_stream_header { uint32_t mtsh_version; /* Stream format version. */ uint32_t mtsh_maxcpus; /* Value of MAXCPU for stream. */ uint32_t mtsh_count; /* Number of records. */ uint32_t _mtsh_pad; /* Pad/reserved field. */ }; #define MALLOC_MAX_NAME 32 struct malloc_type_header { char mth_name[MALLOC_MAX_NAME]; }; #ifdef _KERNEL #define MALLOC_DEFINE(type, shortdesc, longdesc) \ struct malloc_type type[1] = { \ { NULL, M_MAGIC, shortdesc, NULL } \ }; \ SYSINIT(type##_init, SI_SUB_KMEM, SI_ORDER_THIRD, malloc_init, \ type); \ SYSUNINIT(type##_uninit, SI_SUB_KMEM, SI_ORDER_ANY, \ malloc_uninit, type) #define MALLOC_DECLARE(type) \ extern struct malloc_type type[1] MALLOC_DECLARE(M_CACHE); MALLOC_DECLARE(M_DEVBUF); MALLOC_DECLARE(M_TEMP); MALLOC_DECLARE(M_IP6OPT); /* for INET6 */ MALLOC_DECLARE(M_IP6NDP); /* for INET6 */ /* * Deprecated macro versions of not-quite-malloc() and free(). */ #define MALLOC(space, cast, size, type, flags) \ ((space) = (cast)malloc((u_long)(size), (type), (flags))) #define FREE(addr, type) free((addr), (type)) /* * XXX this should be declared in , but that tends to fail * because is included in a header before the source file * has a chance to include to get MALLOC_DECLARE() defined. */ MALLOC_DECLARE(M_IOV); extern struct mtx malloc_mtx; /* * Function type used when iterating over the list of malloc types. */ typedef void malloc_type_list_func_t(struct malloc_type *, void *); void contigfree(void *addr, unsigned long size, struct malloc_type *type); void *contigmalloc(unsigned long size, struct malloc_type *type, int flags, vm_paddr_t low, vm_paddr_t high, unsigned long alignment, vm_paddr_t boundary) __malloc_like __result_use_check - __alloc_size(1); + __alloc_size(1) __alloc_align(6); void free(void *addr, struct malloc_type *type); void *malloc(unsigned long size, struct malloc_type *type, int flags) __malloc_like __result_use_check __alloc_size(1); void malloc_init(void *); int malloc_last_fail(void); void malloc_type_allocated(struct malloc_type *type, unsigned long size); void malloc_type_freed(struct malloc_type *type, unsigned long size); void malloc_type_list(malloc_type_list_func_t *, void *); void malloc_uninit(void *); void *realloc(void *addr, unsigned long size, struct malloc_type *type, int flags) __result_use_check __alloc_size(2); void *reallocf(void *addr, unsigned long size, struct malloc_type *type, int flags) __alloc_size(2); struct malloc_type *malloc_desc2type(const char *desc); #endif /* _KERNEL */ #endif /* !_SYS_MALLOC_H_ */ Index: projects/ci20_mips/sys/sys/proc.h =================================================================== --- projects/ci20_mips/sys/sys/proc.h (revision 283030) +++ projects/ci20_mips/sys/sys/proc.h (revision 283031) @@ -1,1022 +1,1021 @@ /*- * Copyright (c) 1986, 1989, 1991, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)proc.h 8.15 (Berkeley) 5/19/95 * $FreeBSD$ */ #ifndef _SYS_PROC_H_ #define _SYS_PROC_H_ #include /* For struct callout. */ #include /* For struct klist. */ #include #ifndef _KERNEL #include #endif #include #include #include #include #include #include #include /* XXX. */ #include #include #include #include #include #ifndef _KERNEL #include /* For structs itimerval, timeval. */ #else #include #endif #include #include #include /* Machine-dependent proc substruct. */ /* * One structure allocated per session. * * List of locks * (m) locked by s_mtx mtx * (e) locked by proctree_lock sx * (c) const until freeing */ struct session { u_int s_count; /* Ref cnt; pgrps in session - atomic. */ struct proc *s_leader; /* (m + e) Session leader. */ struct vnode *s_ttyvp; /* (m) Vnode of controlling tty. */ struct cdev_priv *s_ttydp; /* (m) Device of controlling tty. */ struct tty *s_ttyp; /* (e) Controlling tty. */ pid_t s_sid; /* (c) Session ID. */ /* (m) Setlogin() name: */ char s_login[roundup(MAXLOGNAME, sizeof(long))]; struct mtx s_mtx; /* Mutex to protect members. */ }; /* * One structure allocated per process group. * * List of locks * (m) locked by pg_mtx mtx * (e) locked by proctree_lock sx * (c) const until freeing */ struct pgrp { LIST_ENTRY(pgrp) pg_hash; /* (e) Hash chain. */ LIST_HEAD(, proc) pg_members; /* (m + e) Pointer to pgrp members. */ struct session *pg_session; /* (c) Pointer to session. */ struct sigiolst pg_sigiolst; /* (m) List of sigio sources. */ pid_t pg_id; /* (c) Process group id. */ int pg_jobc; /* (m) Job control process count. */ struct mtx pg_mtx; /* Mutex to protect members */ }; /* * pargs, used to hold a copy of the command line, if it had a sane length. */ struct pargs { u_int ar_ref; /* Reference count. */ u_int ar_length; /* Length. */ u_char ar_args[1]; /* Arguments. */ }; /*- * Description of a process. * * This structure contains the information needed to manage a thread of * control, known in UN*X as a process; it has references to substructures * containing descriptions of things that the process uses, but may share * with related processes. The process structure and the substructures * are always addressable except for those marked "(CPU)" below, * which might be addressable only on a processor on which the process * is running. * * Below is a key of locks used to protect each member of struct proc. The * lock is indicated by a reference to a specific character in parens in the * associated comment. * * - not yet protected * a - only touched by curproc or parent during fork/wait * b - created at fork, never changes * (exception aiods switch vmspaces, but they are also * marked 'P_SYSTEM' so hopefully it will be left alone) * c - locked by proc mtx * d - locked by allproc_lock lock * e - locked by proctree_lock lock * f - session mtx * g - process group mtx * h - callout_lock mtx * i - by curproc or the master session mtx * j - locked by proc slock * k - only accessed by curthread * k*- only accessed by curthread and from an interrupt * l - the attaching proc or attaching proc parent * m - Giant * n - not locked, lazy * o - ktrace lock * q - td_contested lock * r - p_peers lock * t - thread lock * u - process stat lock * w - process timer lock * x - created at fork, only changes during single threading in exec * y - created at first aio, doesn't change until exit or exec at which * point we are single-threaded and only curthread changes it * z - zombie threads lock * * If the locking key specifies two identifiers (for example, p_pptr) then * either lock is sufficient for read access, but both locks must be held * for write access. */ struct cpuset; struct kaioinfo; struct kaudit_record; struct kdtrace_proc; struct kdtrace_thread; struct mqueue_notifier; struct nlminfo; struct p_sched; struct proc; struct procdesc; struct racct; struct sbuf; struct sleepqueue; struct td_sched; struct thread; struct trapframe; struct turnstile; /* * XXX: Does this belong in resource.h or resourcevar.h instead? * Resource usage extension. The times in rusage structs in the kernel are * never up to date. The actual times are kept as runtimes and tick counts * (with control info in the "previous" times), and are converted when * userland asks for rusage info. Backwards compatibility prevents putting * this directly in the user-visible rusage struct. * * Locking for p_rux: (cu) means (u) for p_rux and (c) for p_crux. * Locking for td_rux: (t) for all fields. */ struct rusage_ext { uint64_t rux_runtime; /* (cu) Real time. */ uint64_t rux_uticks; /* (cu) Statclock hits in user mode. */ uint64_t rux_sticks; /* (cu) Statclock hits in sys mode. */ uint64_t rux_iticks; /* (cu) Statclock hits in intr mode. */ uint64_t rux_uu; /* (c) Previous user time in usec. */ uint64_t rux_su; /* (c) Previous sys time in usec. */ uint64_t rux_tu; /* (c) Previous total time in usec. */ }; /* * Kernel runnable context (thread). * This is what is put to sleep and reactivated. * Thread context. Processes may have multiple threads. */ struct thread { struct mtx *volatile td_lock; /* replaces sched lock */ struct proc *td_proc; /* (*) Associated process. */ TAILQ_ENTRY(thread) td_plist; /* (*) All threads in this proc. */ TAILQ_ENTRY(thread) td_runq; /* (t) Run queue. */ TAILQ_ENTRY(thread) td_slpq; /* (t) Sleep queue. */ TAILQ_ENTRY(thread) td_lockq; /* (t) Lock queue. */ LIST_ENTRY(thread) td_hash; /* (d) Hash chain. */ struct cpuset *td_cpuset; /* (t) CPU affinity mask. */ struct seltd *td_sel; /* Select queue/channel. */ struct sleepqueue *td_sleepqueue; /* (k) Associated sleep queue. */ struct turnstile *td_turnstile; /* (k) Associated turnstile. */ struct rl_q_entry *td_rlqe; /* (k) Associated range lock entry. */ struct umtx_q *td_umtxq; /* (c?) Link for when we're blocked. */ lwpid_t td_tid; /* (b) Thread ID. */ sigqueue_t td_sigqueue; /* (c) Sigs arrived, not delivered. */ #define td_siglist td_sigqueue.sq_signals u_char td_lend_user_pri; /* (t) Lend user pri. */ /* Cleared during fork1() */ #define td_startzero td_flags int td_flags; /* (t) TDF_* flags. */ int td_inhibitors; /* (t) Why can not run. */ int td_pflags; /* (k) Private thread (TDP_*) flags. */ int td_dupfd; /* (k) Ret value from fdopen. XXX */ int td_sqqueue; /* (t) Sleepqueue queue blocked on. */ void *td_wchan; /* (t) Sleep address. */ const char *td_wmesg; /* (t) Reason for sleep. */ int td_lastcpu; /* (t) Last cpu we were on. */ int td_oncpu; /* (t) Which cpu we are on. */ volatile u_char td_owepreempt; /* (k*) Preempt on last critical_exit */ u_char td_tsqueue; /* (t) Turnstile queue blocked on. */ short td_locks; /* (k) Count of non-spin locks. */ short td_rw_rlocks; /* (k) Count of rwlock read locks. */ short td_lk_slocks; /* (k) Count of lockmgr shared locks. */ short td_stopsched; /* (k) Scheduler stopped. */ struct turnstile *td_blocked; /* (t) Lock thread is blocked on. */ const char *td_lockname; /* (t) Name of lock blocked on. */ LIST_HEAD(, turnstile) td_contested; /* (q) Contested locks. */ struct lock_list_entry *td_sleeplocks; /* (k) Held sleep locks. */ int td_intr_nesting_level; /* (k) Interrupt recursion. */ int td_pinned; /* (k) Temporary cpu pin count. */ struct ucred *td_ucred; /* (k) Reference to credentials. */ u_int td_estcpu; /* (t) estimated cpu utilization */ int td_slptick; /* (t) Time at sleep. */ int td_blktick; /* (t) Time spent blocked. */ int td_swvoltick; /* (t) Time at last SW_VOL switch. */ u_int td_cow; /* (*) Number of copy-on-write faults */ struct rusage td_ru; /* (t) rusage information. */ struct rusage_ext td_rux; /* (t) Internal rusage information. */ uint64_t td_incruntime; /* (t) Cpu ticks to transfer to proc. */ uint64_t td_runtime; /* (t) How many cpu ticks we've run. */ u_int td_pticks; /* (t) Statclock hits for profiling */ u_int td_sticks; /* (t) Statclock hits in system mode. */ u_int td_iticks; /* (t) Statclock hits in intr mode. */ u_int td_uticks; /* (t) Statclock hits in user mode. */ int td_intrval; /* (t) Return value for sleepq. */ sigset_t td_oldsigmask; /* (k) Saved mask from pre sigpause. */ volatile u_int td_generation; /* (k) For detection of preemption */ stack_t td_sigstk; /* (k) Stack ptr and on-stack flag. */ int td_xsig; /* (c) Signal for ptrace */ u_long td_profil_addr; /* (k) Temporary addr until AST. */ u_int td_profil_ticks; /* (k) Temporary ticks until AST. */ char td_name[MAXCOMLEN + 1]; /* (*) Thread name. */ struct file *td_fpop; /* (k) file referencing cdev under op */ int td_dbgflags; /* (c) Userland debugger flags */ struct ksiginfo td_dbgksi; /* (c) ksi reflected to debugger. */ int td_ng_outbound; /* (k) Thread entered ng from above. */ struct osd td_osd; /* (k) Object specific data. */ struct vm_map_entry *td_map_def_user; /* (k) Deferred entries. */ pid_t td_dbg_forked; /* (c) Child pid for debugger. */ u_int td_vp_reserv; /* (k) Count of reserved vnodes. */ int td_no_sleeping; /* (k) Sleeping disabled count. */ int td_dom_rr_idx; /* (k) RR Numa domain selection. */ #define td_endzero td_sigmask /* Copied during fork1() or create_thread(). */ #define td_startcopy td_endzero sigset_t td_sigmask; /* (c) Current signal mask. */ u_char td_rqindex; /* (t) Run queue index. */ u_char td_base_pri; /* (t) Thread base kernel priority. */ u_char td_priority; /* (t) Thread active priority. */ u_char td_pri_class; /* (t) Scheduling class. */ u_char td_user_pri; /* (t) User pri from estcpu and nice. */ u_char td_base_user_pri; /* (t) Base user pri */ #define td_endcopy td_pcb /* * Fields that must be manually set in fork1() or create_thread() * or already have been set in the allocator, constructor, etc. */ struct pcb *td_pcb; /* (k) Kernel VA of pcb and kstack. */ enum { TDS_INACTIVE = 0x0, TDS_INHIBITED, TDS_CAN_RUN, TDS_RUNQ, TDS_RUNNING } td_state; /* (t) thread state */ union { register_t tdu_retval[2]; off_t tdu_off; } td_uretoff; /* (k) Syscall aux returns. */ #define td_retval td_uretoff.tdu_retval struct callout td_slpcallout; /* (h) Callout for sleep. */ struct trapframe *td_frame; /* (k) */ struct vm_object *td_kstack_obj;/* (a) Kstack object. */ vm_offset_t td_kstack; /* (a) Kernel VA of kstack. */ int td_kstack_pages; /* (a) Size of the kstack. */ volatile u_int td_critnest; /* (k*) Critical section nest level. */ struct mdthread td_md; /* (k) Any machine-dependent fields. */ struct td_sched *td_sched; /* (*) Scheduler-specific data. */ struct kaudit_record *td_ar; /* (k) Active audit record, if any. */ struct lpohead td_lprof[2]; /* (a) lock profiling objects. */ struct kdtrace_thread *td_dtrace; /* (*) DTrace-specific data. */ int td_errno; /* Error returned by last syscall. */ struct vnet *td_vnet; /* (k) Effective vnet. */ const char *td_vnet_lpush; /* (k) Debugging vnet push / pop. */ struct trapframe *td_intr_frame;/* (k) Frame of the current irq */ struct proc *td_rfppwait_p; /* (k) The vforked child */ struct vm_page **td_ma; /* (k) uio pages held */ int td_ma_cnt; /* (k) size of *td_ma */ }; struct mtx *thread_lock_block(struct thread *); void thread_lock_unblock(struct thread *, struct mtx *); void thread_lock_set(struct thread *, struct mtx *); #define THREAD_LOCK_ASSERT(td, type) \ do { \ struct mtx *__m = (td)->td_lock; \ if (__m != &blocked_lock) \ mtx_assert(__m, (type)); \ } while (0) #ifdef INVARIANTS #define THREAD_LOCKPTR_ASSERT(td, lock) \ do { \ struct mtx *__m = (td)->td_lock; \ KASSERT((__m == &blocked_lock || __m == (lock)), \ ("Thread %p lock %p does not match %p", td, __m, (lock))); \ } while (0) #else #define THREAD_LOCKPTR_ASSERT(td, lock) #endif /* * Flags kept in td_flags: * To change these you MUST have the scheduler lock. */ #define TDF_BORROWING 0x00000001 /* Thread is borrowing pri from another. */ #define TDF_INPANIC 0x00000002 /* Caused a panic, let it drive crashdump. */ #define TDF_INMEM 0x00000004 /* Thread's stack is in memory. */ #define TDF_SINTR 0x00000008 /* Sleep is interruptible. */ #define TDF_TIMEOUT 0x00000010 /* Timing out during sleep. */ #define TDF_IDLETD 0x00000020 /* This is a per-CPU idle thread. */ #define TDF_CANSWAP 0x00000040 /* Thread can be swapped. */ #define TDF_SLEEPABORT 0x00000080 /* sleepq_abort was called. */ #define TDF_KTH_SUSP 0x00000100 /* kthread is suspended */ #define TDF_ALLPROCSUSP 0x00000200 /* suspended by SINGLE_ALLPROC */ #define TDF_BOUNDARY 0x00000400 /* Thread suspended at user boundary */ #define TDF_ASTPENDING 0x00000800 /* Thread has some asynchronous events. */ #define TDF_TIMOFAIL 0x00001000 /* Timeout from sleep after we were awake. */ #define TDF_SBDRY 0x00002000 /* Stop only on usermode boundary. */ #define TDF_UPIBLOCKED 0x00004000 /* Thread blocked on user PI mutex. */ #define TDF_NEEDSUSPCHK 0x00008000 /* Thread may need to suspend. */ #define TDF_NEEDRESCHED 0x00010000 /* Thread needs to yield. */ #define TDF_NEEDSIGCHK 0x00020000 /* Thread may need signal delivery. */ #define TDF_NOLOAD 0x00040000 /* Ignore during load avg calculations. */ #define TDF_UNUSED19 0x00080000 /* --available-- */ #define TDF_THRWAKEUP 0x00100000 /* Libthr thread must not suspend itself. */ #define TDF_UNUSED21 0x00200000 /* --available-- */ #define TDF_SWAPINREQ 0x00400000 /* Swapin request due to wakeup. */ #define TDF_UNUSED23 0x00800000 /* --available-- */ #define TDF_SCHED0 0x01000000 /* Reserved for scheduler private use */ #define TDF_SCHED1 0x02000000 /* Reserved for scheduler private use */ #define TDF_SCHED2 0x04000000 /* Reserved for scheduler private use */ #define TDF_SCHED3 0x08000000 /* Reserved for scheduler private use */ #define TDF_ALRMPEND 0x10000000 /* Pending SIGVTALRM needs to be posted. */ #define TDF_PROFPEND 0x20000000 /* Pending SIGPROF needs to be posted. */ #define TDF_MACPEND 0x40000000 /* AST-based MAC event pending. */ /* Userland debug flags */ #define TDB_SUSPEND 0x00000001 /* Thread is suspended by debugger */ #define TDB_XSIG 0x00000002 /* Thread is exchanging signal under trace */ #define TDB_USERWR 0x00000004 /* Debugger modified memory or registers */ #define TDB_SCE 0x00000008 /* Thread performs syscall enter */ #define TDB_SCX 0x00000010 /* Thread performs syscall exit */ #define TDB_EXEC 0x00000020 /* TDB_SCX from exec(2) family */ #define TDB_FORK 0x00000040 /* TDB_SCX from fork(2) that created new process */ #define TDB_STOPATFORK 0x00000080 /* Stop at the return from fork (child only) */ #define TDB_CHILD 0x00000100 /* New child indicator for ptrace() */ /* * "Private" flags kept in td_pflags: * These are only written by curthread and thus need no locking. */ #define TDP_OLDMASK 0x00000001 /* Need to restore mask after suspend. */ #define TDP_INKTR 0x00000002 /* Thread is currently in KTR code. */ #define TDP_INKTRACE 0x00000004 /* Thread is currently in KTRACE code. */ #define TDP_BUFNEED 0x00000008 /* Do not recurse into the buf flush */ #define TDP_COWINPROGRESS 0x00000010 /* Snapshot copy-on-write in progress. */ #define TDP_ALTSTACK 0x00000020 /* Have alternate signal stack. */ #define TDP_DEADLKTREAT 0x00000040 /* Lock aquisition - deadlock treatment. */ #define TDP_NOFAULTING 0x00000080 /* Do not handle page faults. */ #define TDP_UNUSED9 0x00000100 /* --available-- */ #define TDP_OWEUPC 0x00000200 /* Call addupc() at next AST. */ #define TDP_ITHREAD 0x00000400 /* Thread is an interrupt thread. */ #define TDP_SYNCIO 0x00000800 /* Local override, disable async i/o. */ #define TDP_SCHED1 0x00001000 /* Reserved for scheduler private use */ #define TDP_SCHED2 0x00002000 /* Reserved for scheduler private use */ #define TDP_SCHED3 0x00004000 /* Reserved for scheduler private use */ #define TDP_SCHED4 0x00008000 /* Reserved for scheduler private use */ #define TDP_GEOM 0x00010000 /* Settle GEOM before finishing syscall */ #define TDP_SOFTDEP 0x00020000 /* Stuck processing softdep worklist */ #define TDP_NORUNNINGBUF 0x00040000 /* Ignore runningbufspace check */ #define TDP_WAKEUP 0x00080000 /* Don't sleep in umtx cond_wait */ #define TDP_INBDFLUSH 0x00100000 /* Already in BO_BDFLUSH, do not recurse */ #define TDP_KTHREAD 0x00200000 /* This is an official kernel thread */ #define TDP_CALLCHAIN 0x00400000 /* Capture thread's callchain */ #define TDP_IGNSUSP 0x00800000 /* Permission to ignore the MNTK_SUSPEND* */ #define TDP_AUDITREC 0x01000000 /* Audit record pending on thread */ #define TDP_RFPPWAIT 0x02000000 /* Handle RFPPWAIT on syscall exit */ #define TDP_RESETSPUR 0x04000000 /* Reset spurious page fault history. */ #define TDP_NERRNO 0x08000000 /* Last errno is already in td_errno */ #define TDP_UIOHELD 0x10000000 /* Current uio has pages held in td_ma */ #define TDP_UNUSED29 0x20000000 /* --available-- */ #define TDP_EXECVMSPC 0x40000000 /* Execve destroyed old vmspace */ /* * Reasons that the current thread can not be run yet. * More than one may apply. */ #define TDI_SUSPENDED 0x0001 /* On suspension queue. */ #define TDI_SLEEPING 0x0002 /* Actually asleep! (tricky). */ #define TDI_SWAPPED 0x0004 /* Stack not in mem. Bad juju if run. */ #define TDI_LOCK 0x0008 /* Stopped on a lock. */ #define TDI_IWAIT 0x0010 /* Awaiting interrupt. */ #define TD_IS_SLEEPING(td) ((td)->td_inhibitors & TDI_SLEEPING) #define TD_ON_SLEEPQ(td) ((td)->td_wchan != NULL) #define TD_IS_SUSPENDED(td) ((td)->td_inhibitors & TDI_SUSPENDED) #define TD_IS_SWAPPED(td) ((td)->td_inhibitors & TDI_SWAPPED) #define TD_ON_LOCK(td) ((td)->td_inhibitors & TDI_LOCK) #define TD_AWAITING_INTR(td) ((td)->td_inhibitors & TDI_IWAIT) #define TD_IS_RUNNING(td) ((td)->td_state == TDS_RUNNING) #define TD_ON_RUNQ(td) ((td)->td_state == TDS_RUNQ) #define TD_CAN_RUN(td) ((td)->td_state == TDS_CAN_RUN) #define TD_IS_INHIBITED(td) ((td)->td_state == TDS_INHIBITED) #define TD_ON_UPILOCK(td) ((td)->td_flags & TDF_UPIBLOCKED) #define TD_IS_IDLETHREAD(td) ((td)->td_flags & TDF_IDLETD) #define TD_SET_INHIB(td, inhib) do { \ (td)->td_state = TDS_INHIBITED; \ (td)->td_inhibitors |= (inhib); \ } while (0) #define TD_CLR_INHIB(td, inhib) do { \ if (((td)->td_inhibitors & (inhib)) && \ (((td)->td_inhibitors &= ~(inhib)) == 0)) \ (td)->td_state = TDS_CAN_RUN; \ } while (0) #define TD_SET_SLEEPING(td) TD_SET_INHIB((td), TDI_SLEEPING) #define TD_SET_SWAPPED(td) TD_SET_INHIB((td), TDI_SWAPPED) #define TD_SET_LOCK(td) TD_SET_INHIB((td), TDI_LOCK) #define TD_SET_SUSPENDED(td) TD_SET_INHIB((td), TDI_SUSPENDED) #define TD_SET_IWAIT(td) TD_SET_INHIB((td), TDI_IWAIT) #define TD_SET_EXITING(td) TD_SET_INHIB((td), TDI_EXITING) #define TD_CLR_SLEEPING(td) TD_CLR_INHIB((td), TDI_SLEEPING) #define TD_CLR_SWAPPED(td) TD_CLR_INHIB((td), TDI_SWAPPED) #define TD_CLR_LOCK(td) TD_CLR_INHIB((td), TDI_LOCK) #define TD_CLR_SUSPENDED(td) TD_CLR_INHIB((td), TDI_SUSPENDED) #define TD_CLR_IWAIT(td) TD_CLR_INHIB((td), TDI_IWAIT) #define TD_SET_RUNNING(td) (td)->td_state = TDS_RUNNING #define TD_SET_RUNQ(td) (td)->td_state = TDS_RUNQ #define TD_SET_CAN_RUN(td) (td)->td_state = TDS_CAN_RUN /* * Process structure. */ struct proc { LIST_ENTRY(proc) p_list; /* (d) List of all processes. */ TAILQ_HEAD(, thread) p_threads; /* (c) all threads. */ struct mtx p_slock; /* process spin lock */ struct ucred *p_ucred; /* (c) Process owner's identity. */ struct filedesc *p_fd; /* (b) Open files. */ struct filedesc_to_leader *p_fdtol; /* (b) Tracking node */ struct pstats *p_stats; /* (b) Accounting/statistics (CPU). */ struct plimit *p_limit; /* (c) Process limits. */ struct callout p_limco; /* (c) Limit callout handle */ struct sigacts *p_sigacts; /* (x) Signal actions, state (CPU). */ int p_flag; /* (c) P_* flags. */ int p_flag2; /* (c) P2_* flags. */ enum { PRS_NEW = 0, /* In creation */ PRS_NORMAL, /* threads can be run. */ PRS_ZOMBIE } p_state; /* (j/c) Process status. */ pid_t p_pid; /* (b) Process identifier. */ LIST_ENTRY(proc) p_hash; /* (d) Hash chain. */ LIST_ENTRY(proc) p_pglist; /* (g + e) List of processes in pgrp. */ struct proc *p_pptr; /* (c + e) Pointer to parent process. */ LIST_ENTRY(proc) p_sibling; /* (e) List of sibling processes. */ LIST_HEAD(, proc) p_children; /* (e) Pointer to list of children. */ struct proc *p_reaper; /* (e) My reaper. */ LIST_HEAD(, proc) p_reaplist; /* (e) List of my descendants (if I am reaper). */ LIST_ENTRY(proc) p_reapsibling; /* (e) List of siblings - descendants of the same reaper. */ struct mtx p_mtx; /* (n) Lock for this struct. */ struct mtx p_statmtx; /* Lock for the stats */ struct mtx p_itimmtx; /* Lock for the virt/prof timers */ struct mtx p_profmtx; /* Lock for the profiling */ struct ksiginfo *p_ksi; /* Locked by parent proc lock */ sigqueue_t p_sigqueue; /* (c) Sigs not delivered to a td. */ #define p_siglist p_sigqueue.sq_signals /* The following fields are all zeroed upon creation in fork. */ #define p_startzero p_oppid pid_t p_oppid; /* (c + e) Save ppid in ptrace. XXX */ struct vmspace *p_vmspace; /* (b) Address space. */ u_int p_swtick; /* (c) Tick when swapped in or out. */ struct itimerval p_realtimer; /* (c) Alarm timer. */ struct rusage p_ru; /* (a) Exit information. */ struct rusage_ext p_rux; /* (cu) Internal resource usage. */ struct rusage_ext p_crux; /* (c) Internal child resource usage. */ int p_profthreads; /* (c) Num threads in addupc_task. */ volatile int p_exitthreads; /* (j) Number of threads exiting */ int p_traceflag; /* (o) Kernel trace points. */ struct vnode *p_tracevp; /* (c + o) Trace to vnode. */ struct ucred *p_tracecred; /* (o) Credentials to trace with. */ struct vnode *p_textvp; /* (b) Vnode of executable. */ u_int p_lock; /* (c) Proclock (prevent swap) count. */ struct sigiolst p_sigiolst; /* (c) List of sigio sources. */ int p_sigparent; /* (c) Signal to parent on exit. */ int p_sig; /* (n) For core dump/debugger XXX. */ u_long p_code; /* (n) For core dump/debugger XXX. */ u_int p_stops; /* (c) Stop event bitmask. */ u_int p_stype; /* (c) Stop event type. */ char p_step; /* (c) Process is stopped. */ u_char p_pfsflags; /* (c) Procfs flags. */ struct nlminfo *p_nlminfo; /* (?) Only used by/for lockd. */ struct kaioinfo *p_aioinfo; /* (y) ASYNC I/O info. */ struct thread *p_singlethread;/* (c + j) If single threading this is it */ int p_suspcount; /* (j) Num threads in suspended mode. */ struct thread *p_xthread; /* (c) Trap thread */ int p_boundary_count;/* (j) Num threads at user boundary */ int p_pendingcnt; /* how many signals are pending */ struct itimers *p_itimers; /* (c) POSIX interval timers. */ struct procdesc *p_procdesc; /* (e) Process descriptor, if any. */ u_int p_treeflag; /* (e) P_TREE flags */ /* End area that is zeroed on creation. */ #define p_endzero p_magic /* The following fields are all copied upon creation in fork. */ #define p_startcopy p_endzero u_int p_magic; /* (b) Magic number. */ int p_osrel; /* (x) osreldate for the binary (from ELF note, if any) */ char p_comm[MAXCOMLEN + 1]; /* (b) Process name. */ struct pgrp *p_pgrp; /* (c + e) Pointer to process group. */ struct sysentvec *p_sysent; /* (b) Syscall dispatch info. */ struct pargs *p_args; /* (c) Process arguments. */ rlim_t p_cpulimit; /* (c) Current CPU limit in seconds. */ signed char p_nice; /* (c) Process "nice" value. */ int p_fibnum; /* in this routing domain XXX MRT */ pid_t p_reapsubtree; /* (e) Pid of the direct child of the reaper which spawned our subtree. */ /* End area that is copied on creation. */ #define p_endcopy p_xstat u_short p_xstat; /* (c) Exit status; also stop sig. */ struct knlist p_klist; /* (c) Knotes attached to this proc. */ int p_numthreads; /* (c) Number of threads. */ struct mdproc p_md; /* Any machine-dependent fields. */ struct callout p_itcallout; /* (h + c) Interval timer callout. */ u_short p_acflag; /* (c) Accounting flags. */ struct proc *p_peers; /* (r) */ struct proc *p_leader; /* (b) */ void *p_emuldata; /* (c) Emulator state data. */ struct label *p_label; /* (*) Proc (not subject) MAC label. */ struct p_sched *p_sched; /* (*) Scheduler-specific data. */ STAILQ_HEAD(, ktr_request) p_ktr; /* (o) KTR event queue. */ LIST_HEAD(, mqueue_notifier) p_mqnotifier; /* (c) mqueue notifiers.*/ struct kdtrace_proc *p_dtrace; /* (*) DTrace-specific data. */ struct cv p_pwait; /* (*) wait cv for exit/exec. */ struct cv p_dbgwait; /* (*) wait cv for debugger attach after fork. */ uint64_t p_prev_runtime; /* (c) Resource usage accounting. */ struct racct *p_racct; /* (b) Resource accounting. */ u_char p_throttled; /* (c) Flag for racct pcpu throttling */ /* * An orphan is the child that has beed re-parented to the * debugger as a result of attaching to it. Need to keep * track of them for parent to be able to collect the exit * status of what used to be children. */ LIST_ENTRY(proc) p_orphan; /* (e) List of orphan processes. */ LIST_HEAD(, proc) p_orphans; /* (e) Pointer to list of orphans. */ }; #define p_session p_pgrp->pg_session #define p_pgid p_pgrp->pg_id #define NOCPU (-1) /* For when we aren't on a CPU. */ #define NOCPU_OLD (255) #define MAXCPU_OLD (254) #define PROC_SLOCK(p) mtx_lock_spin(&(p)->p_slock) #define PROC_SUNLOCK(p) mtx_unlock_spin(&(p)->p_slock) #define PROC_SLOCK_ASSERT(p, type) mtx_assert(&(p)->p_slock, (type)) #define PROC_STATLOCK(p) mtx_lock_spin(&(p)->p_statmtx) #define PROC_STATUNLOCK(p) mtx_unlock_spin(&(p)->p_statmtx) #define PROC_STATLOCK_ASSERT(p, type) mtx_assert(&(p)->p_statmtx, (type)) #define PROC_ITIMLOCK(p) mtx_lock_spin(&(p)->p_itimmtx) #define PROC_ITIMUNLOCK(p) mtx_unlock_spin(&(p)->p_itimmtx) #define PROC_ITIMLOCK_ASSERT(p, type) mtx_assert(&(p)->p_itimmtx, (type)) #define PROC_PROFLOCK(p) mtx_lock_spin(&(p)->p_profmtx) #define PROC_PROFUNLOCK(p) mtx_unlock_spin(&(p)->p_profmtx) #define PROC_PROFLOCK_ASSERT(p, type) mtx_assert(&(p)->p_profmtx, (type)) /* These flags are kept in p_flag. */ #define P_ADVLOCK 0x00001 /* Process may hold a POSIX advisory lock. */ #define P_CONTROLT 0x00002 /* Has a controlling terminal. */ #define P_KTHREAD 0x00004 /* Kernel thread (*). */ #define P_FOLLOWFORK 0x00008 /* Attach parent debugger to children. */ #define P_PPWAIT 0x00010 /* Parent is waiting for child to exec/exit. */ #define P_PROFIL 0x00020 /* Has started profiling. */ #define P_STOPPROF 0x00040 /* Has thread requesting to stop profiling. */ #define P_HADTHREADS 0x00080 /* Has had threads (no cleanup shortcuts) */ #define P_SUGID 0x00100 /* Had set id privileges since last exec. */ #define P_SYSTEM 0x00200 /* System proc: no sigs, stats or swapping. */ #define P_SINGLE_EXIT 0x00400 /* Threads suspending should exit, not wait. */ #define P_TRACED 0x00800 /* Debugged process being traced. */ #define P_WAITED 0x01000 /* Someone is waiting for us. */ #define P_WEXIT 0x02000 /* Working on exiting. */ #define P_EXEC 0x04000 /* Process called exec. */ #define P_WKILLED 0x08000 /* Killed, go to kernel/user boundary ASAP. */ #define P_CONTINUED 0x10000 /* Proc has continued from a stopped state. */ #define P_STOPPED_SIG 0x20000 /* Stopped due to SIGSTOP/SIGTSTP. */ #define P_STOPPED_TRACE 0x40000 /* Stopped because of tracing. */ #define P_STOPPED_SINGLE 0x80000 /* Only 1 thread can continue (not to user). */ #define P_PROTECTED 0x100000 /* Do not kill on memory overcommit. */ #define P_SIGEVENT 0x200000 /* Process pending signals changed. */ #define P_SINGLE_BOUNDARY 0x400000 /* Threads should suspend at user boundary. */ #define P_HWPMC 0x800000 /* Process is using HWPMCs */ #define P_JAILED 0x1000000 /* Process is in jail. */ #define P_TOTAL_STOP 0x2000000 /* Stopped in proc_stop_total. */ #define P_INEXEC 0x4000000 /* Process is in execve(). */ #define P_STATCHILD 0x8000000 /* Child process stopped or exited. */ #define P_INMEM 0x10000000 /* Loaded into memory. */ #define P_SWAPPINGOUT 0x20000000 /* Process is being swapped out. */ #define P_SWAPPINGIN 0x40000000 /* Process is being swapped in. */ #define P_PPTRACE 0x80000000 /* PT_TRACEME by vforked child. */ #define P_STOPPED (P_STOPPED_SIG|P_STOPPED_SINGLE|P_STOPPED_TRACE) #define P_SHOULDSTOP(p) ((p)->p_flag & P_STOPPED) #define P_KILLED(p) ((p)->p_flag & P_WKILLED) /* These flags are kept in p_flag2. */ #define P2_INHERIT_PROTECTED 0x00000001 /* New children get P_PROTECTED. */ #define P2_NOTRACE 0x00000002 /* No ptrace(2) attach or coredumps. */ #define P2_NOTRACE_EXEC 0x00000004 /* Keep P2_NOPTRACE on exec(2). */ /* Flags protected by proctree_lock, kept in p_treeflags. */ #define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */ #define P_TREE_FIRST_ORPHAN 0x00000002 /* First element of orphan list */ #define P_TREE_REAPER 0x00000004 /* Reaper of subtree */ /* * These were process status values (p_stat), now they are only used in * legacy conversion code. */ #define SIDL 1 /* Process being created by fork. */ #define SRUN 2 /* Currently runnable. */ #define SSLEEP 3 /* Sleeping on an address. */ #define SSTOP 4 /* Process debugging or suspension. */ #define SZOMB 5 /* Awaiting collection by parent. */ #define SWAIT 6 /* Waiting for interrupt. */ #define SLOCK 7 /* Blocked on a lock. */ #define P_MAGIC 0xbeefface #ifdef _KERNEL /* Types and flags for mi_switch(). */ #define SW_TYPE_MASK 0xff /* First 8 bits are switch type */ #define SWT_NONE 0 /* Unspecified switch. */ #define SWT_PREEMPT 1 /* Switching due to preemption. */ #define SWT_OWEPREEMPT 2 /* Switching due to opepreempt. */ #define SWT_TURNSTILE 3 /* Turnstile contention. */ #define SWT_SLEEPQ 4 /* Sleepq wait. */ #define SWT_SLEEPQTIMO 5 /* Sleepq timeout wait. */ #define SWT_RELINQUISH 6 /* yield call. */ #define SWT_NEEDRESCHED 7 /* NEEDRESCHED was set. */ #define SWT_IDLE 8 /* Switching from the idle thread. */ #define SWT_IWAIT 9 /* Waiting for interrupts. */ #define SWT_SUSPEND 10 /* Thread suspended. */ #define SWT_REMOTEPREEMPT 11 /* Remote processor preempted. */ #define SWT_REMOTEWAKEIDLE 12 /* Remote processor preempted idle. */ #define SWT_COUNT 13 /* Number of switch types. */ /* Flags */ #define SW_VOL 0x0100 /* Voluntary switch. */ #define SW_INVOL 0x0200 /* Involuntary switch. */ #define SW_PREEMPT 0x0400 /* The invol switch is a preemption */ /* How values for thread_single(). */ #define SINGLE_NO_EXIT 0 #define SINGLE_EXIT 1 #define SINGLE_BOUNDARY 2 #define SINGLE_ALLPROC 3 #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_PARGS); MALLOC_DECLARE(M_PGRP); MALLOC_DECLARE(M_SESSION); MALLOC_DECLARE(M_SUBPROC); #endif #define FOREACH_PROC_IN_SYSTEM(p) \ LIST_FOREACH((p), &allproc, p_list) #define FOREACH_THREAD_IN_PROC(p, td) \ TAILQ_FOREACH((td), &(p)->p_threads, td_plist) #define FIRST_THREAD_IN_PROC(p) TAILQ_FIRST(&(p)->p_threads) /* * We use process IDs <= pid_max <= PID_MAX; PID_MAX + 1 must also fit * in a pid_t, as it is used to represent "no process group". */ #define PID_MAX 99999 #define NO_PID 100000 extern pid_t pid_max; #define SESS_LEADER(p) ((p)->p_session->s_leader == (p)) #define STOPEVENT(p, e, v) do { \ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, \ "checking stopevent %d", (e)); \ if ((p)->p_stops & (e)) { \ PROC_LOCK(p); \ stopevent((p), (e), (v)); \ PROC_UNLOCK(p); \ } \ } while (0) #define _STOPEVENT(p, e, v) do { \ PROC_LOCK_ASSERT(p, MA_OWNED); \ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &p->p_mtx.lock_object, \ "checking stopevent %d", (e)); \ if ((p)->p_stops & (e)) \ stopevent((p), (e), (v)); \ } while (0) /* Lock and unlock a process. */ #define PROC_LOCK(p) mtx_lock(&(p)->p_mtx) #define PROC_TRYLOCK(p) mtx_trylock(&(p)->p_mtx) #define PROC_UNLOCK(p) mtx_unlock(&(p)->p_mtx) #define PROC_LOCKED(p) mtx_owned(&(p)->p_mtx) #define PROC_LOCK_ASSERT(p, type) mtx_assert(&(p)->p_mtx, (type)) /* Lock and unlock a process group. */ #define PGRP_LOCK(pg) mtx_lock(&(pg)->pg_mtx) #define PGRP_UNLOCK(pg) mtx_unlock(&(pg)->pg_mtx) #define PGRP_LOCKED(pg) mtx_owned(&(pg)->pg_mtx) #define PGRP_LOCK_ASSERT(pg, type) mtx_assert(&(pg)->pg_mtx, (type)) #define PGRP_LOCK_PGSIGNAL(pg) do { \ if ((pg) != NULL) \ PGRP_LOCK(pg); \ } while (0) #define PGRP_UNLOCK_PGSIGNAL(pg) do { \ if ((pg) != NULL) \ PGRP_UNLOCK(pg); \ } while (0) /* Lock and unlock a session. */ #define SESS_LOCK(s) mtx_lock(&(s)->s_mtx) #define SESS_UNLOCK(s) mtx_unlock(&(s)->s_mtx) #define SESS_LOCKED(s) mtx_owned(&(s)->s_mtx) #define SESS_LOCK_ASSERT(s, type) mtx_assert(&(s)->s_mtx, (type)) /* Hold process U-area in memory, normally for ptrace/procfs work. */ #define PHOLD(p) do { \ PROC_LOCK(p); \ _PHOLD(p); \ PROC_UNLOCK(p); \ } while (0) #define _PHOLD(p) do { \ PROC_LOCK_ASSERT((p), MA_OWNED); \ KASSERT(!((p)->p_flag & P_WEXIT) || (p) == curproc, \ ("PHOLD of exiting process")); \ (p)->p_lock++; \ if (((p)->p_flag & P_INMEM) == 0) \ faultin((p)); \ } while (0) #define PROC_ASSERT_HELD(p) do { \ KASSERT((p)->p_lock > 0, ("process not held")); \ } while (0) #define PRELE(p) do { \ PROC_LOCK((p)); \ _PRELE((p)); \ PROC_UNLOCK((p)); \ } while (0) #define _PRELE(p) do { \ PROC_LOCK_ASSERT((p), MA_OWNED); \ PROC_ASSERT_HELD(p); \ (--(p)->p_lock); \ if (((p)->p_flag & P_WEXIT) && (p)->p_lock == 0) \ wakeup(&(p)->p_lock); \ } while (0) #define PROC_ASSERT_NOT_HELD(p) do { \ KASSERT((p)->p_lock == 0, ("process held")); \ } while (0) /* Check whether a thread is safe to be swapped out. */ #define thread_safetoswapout(td) ((td)->td_flags & TDF_CANSWAP) /* Control whether or not it is safe for curthread to sleep. */ #define THREAD_NO_SLEEPING() ((curthread)->td_no_sleeping++) #define THREAD_SLEEPING_OK() ((curthread)->td_no_sleeping--) #define THREAD_CAN_SLEEP() ((curthread)->td_no_sleeping == 0) #define PIDHASH(pid) (&pidhashtbl[(pid) & pidhash]) extern LIST_HEAD(pidhashhead, proc) *pidhashtbl; extern u_long pidhash; #define TIDHASH(tid) (&tidhashtbl[(tid) & tidhash]) extern LIST_HEAD(tidhashhead, thread) *tidhashtbl; extern u_long tidhash; extern struct rwlock tidhash_lock; #define PGRPHASH(pgid) (&pgrphashtbl[(pgid) & pgrphash]) extern LIST_HEAD(pgrphashhead, pgrp) *pgrphashtbl; extern u_long pgrphash; extern struct sx allproc_lock; extern int allproc_gen; extern struct sx proctree_lock; extern struct mtx ppeers_lock; extern struct proc proc0; /* Process slot for swapper. */ extern struct thread thread0; /* Primary thread in proc0. */ extern struct vmspace vmspace0; /* VM space for proc0. */ extern int hogticks; /* Limit on kernel cpu hogs. */ extern int lastpid; extern int nprocs, maxproc; /* Current and max number of procs. */ extern int maxprocperuid; /* Max procs per uid. */ extern u_long ps_arg_cache_limit; LIST_HEAD(proclist, proc); TAILQ_HEAD(procqueue, proc); TAILQ_HEAD(threadqueue, thread); extern struct proclist allproc; /* List of all processes. */ extern struct proclist zombproc; /* List of zombie processes. */ extern struct proc *initproc, *pageproc; /* Process slots for init, pager. */ extern struct uma_zone *proc_zone; struct proc *pfind(pid_t); /* Find process by id. */ struct proc *pfind_locked(pid_t pid); struct pgrp *pgfind(pid_t); /* Find process group by id. */ struct proc *zpfind(pid_t); /* Find zombie process by id. */ /* * pget() flags. */ #define PGET_HOLD 0x00001 /* Hold the process. */ #define PGET_CANSEE 0x00002 /* Check against p_cansee(). */ #define PGET_CANDEBUG 0x00004 /* Check against p_candebug(). */ #define PGET_ISCURRENT 0x00008 /* Check that the found process is current. */ #define PGET_NOTWEXIT 0x00010 /* Check that the process is not in P_WEXIT. */ #define PGET_NOTINEXEC 0x00020 /* Check that the process is not in P_INEXEC. */ #define PGET_NOTID 0x00040 /* Do not assume tid if pid > PID_MAX. */ #define PGET_WANTREAD (PGET_HOLD | PGET_CANDEBUG | PGET_NOTWEXIT) int pget(pid_t pid, int flags, struct proc **pp); void ast(struct trapframe *framep); struct thread *choosethread(void); int cr_cansignal(struct ucred *cred, struct proc *proc, int signum); int enterpgrp(struct proc *p, pid_t pgid, struct pgrp *pgrp, struct session *sess); int enterthispgrp(struct proc *p, struct pgrp *pgrp); void faultin(struct proc *p); void fixjobc(struct proc *p, struct pgrp *pgrp, int entering); int fork1(struct thread *, int, int, struct proc **, int *, int); void fork_exit(void (*)(void *, struct trapframe *), void *, struct trapframe *); void fork_return(struct thread *, struct trapframe *); int inferior(struct proc *p); void kern_yield(int); void kick_proc0(void); int leavepgrp(struct proc *p); int maybe_preempt(struct thread *td); void maybe_yield(void); void mi_switch(int flags, struct thread *newtd); int p_candebug(struct thread *td, struct proc *p); int p_cansee(struct thread *td, struct proc *p); int p_cansched(struct thread *td, struct proc *p); int p_cansignal(struct thread *td, struct proc *p, int signum); int p_canwait(struct thread *td, struct proc *p); struct pargs *pargs_alloc(int len); void pargs_drop(struct pargs *pa); void pargs_hold(struct pargs *pa); int proc_getargv(struct thread *td, struct proc *p, struct sbuf *sb); int proc_getauxv(struct thread *td, struct proc *p, struct sbuf *sb); int proc_getenvv(struct thread *td, struct proc *p, struct sbuf *sb); void procinit(void); void proc_linkup0(struct proc *p, struct thread *td); void proc_linkup(struct proc *p, struct thread *td); struct proc *proc_realparent(struct proc *child); void proc_reap(struct thread *td, struct proc *p, int *status, int options); void proc_reparent(struct proc *child, struct proc *newparent); struct pstats *pstats_alloc(void); void pstats_fork(struct pstats *src, struct pstats *dst); void pstats_free(struct pstats *ps); void reaper_abandon_children(struct proc *p, bool exiting); int securelevel_ge(struct ucred *cr, int level); int securelevel_gt(struct ucred *cr, int level); void sess_hold(struct session *); void sess_release(struct session *); int setrunnable(struct thread *); void setsugid(struct proc *p); int should_yield(void); int sigonstack(size_t sp); void stopevent(struct proc *, u_int, u_int); struct thread *tdfind(lwpid_t, pid_t); void threadinit(void); void tidhash_add(struct thread *); void tidhash_remove(struct thread *); void cpu_idle(int); int cpu_idle_wakeup(int); extern void (*cpu_idle_hook)(sbintime_t); /* Hook to machdep CPU idler. */ void cpu_switch(struct thread *, struct thread *, struct mtx *); void cpu_throw(struct thread *, struct thread *) __dead2; void unsleep(struct thread *); void userret(struct thread *, struct trapframe *); void cpu_exit(struct thread *); void exit1(struct thread *, int) __dead2; struct syscall_args; int cpu_fetch_syscall_args(struct thread *td, struct syscall_args *sa); void cpu_fork(struct thread *, struct proc *, struct thread *, int); void cpu_set_fork_handler(struct thread *, void (*)(void *), void *); void cpu_set_syscall_retval(struct thread *, int); void cpu_set_upcall(struct thread *td, struct thread *td0); void cpu_set_upcall_kse(struct thread *, void (*)(void *), void *, stack_t *); int cpu_set_user_tls(struct thread *, void *tls_base); void cpu_thread_alloc(struct thread *); void cpu_thread_clean(struct thread *); void cpu_thread_exit(struct thread *); void cpu_thread_free(struct thread *); void cpu_thread_swapin(struct thread *); void cpu_thread_swapout(struct thread *); struct thread *thread_alloc(int pages); int thread_alloc_stack(struct thread *, int pages); void thread_exit(void) __dead2; void thread_free(struct thread *td); void thread_link(struct thread *td, struct proc *p); void thread_reap(void); int thread_single(struct proc *p, int how); void thread_single_end(struct proc *p, int how); void thread_stash(struct thread *td); void thread_stopped(struct proc *p); void childproc_stopped(struct proc *child, int reason); void childproc_continued(struct proc *child); void childproc_exited(struct proc *child); int thread_suspend_check(int how); bool thread_suspend_check_needed(void); void thread_suspend_switch(struct thread *, struct proc *p); void thread_suspend_one(struct thread *td); void thread_unlink(struct thread *td); void thread_unsuspend(struct proc *p); -int thread_unsuspend_one(struct thread *td, struct proc *p); void thread_wait(struct proc *p); struct thread *thread_find(struct proc *p, lwpid_t tid); void stop_all_proc(void); void resume_all_proc(void); static __inline int curthread_pflags_set(int flags) { struct thread *td; int save; td = curthread; save = ~flags | (td->td_pflags & flags); td->td_pflags |= flags; return (save); } static __inline void curthread_pflags_restore(int save) { curthread->td_pflags &= save; } #endif /* _KERNEL */ #endif /* !_SYS_PROC_H_ */ Index: projects/ci20_mips/sys/x86/acpica/srat.c =================================================================== --- projects/ci20_mips/sys/x86/acpica/srat.c (revision 283030) +++ projects/ci20_mips/sys/x86/acpica/srat.c (revision 283031) @@ -1,506 +1,506 @@ /*- * Copyright (c) 2010 Hudson River Trading LLC * Written by: John H. Baldwin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if MAXMEMDOM > 1 struct cpu_info { int enabled:1; int has_memory:1; int domain; } cpus[MAX_APIC_ID + 1]; struct mem_affinity mem_info[VM_PHYSSEG_MAX + 1]; int num_mem; static ACPI_TABLE_SRAT *srat; static vm_paddr_t srat_physaddr; static int vm_domains[VM_PHYSSEG_MAX]; static ACPI_TABLE_SLIT *slit; static vm_paddr_t slit_physaddr; static int vm_locality_table[MAXMEMDOM * MAXMEMDOM]; static void srat_walk_table(acpi_subtable_handler *handler, void *arg); /* * SLIT parsing. */ static void slit_parse_table(ACPI_TABLE_SLIT *s) { int i, j; int i_domain, j_domain; int offset = 0; uint8_t e; /* * This maps the SLIT data into the VM-domain centric view. * There may be sparse entries in the PXM namespace, so * remap them to a VM-domain ID and if it doesn't exist, * skip it. * * It should result in a packed 2d array of VM-domain * locality information entries. */ if (bootverbose) printf("SLIT.Localities: %d\n", (int) s->LocalityCount); for (i = 0; i < s->LocalityCount; i++) { i_domain = acpi_map_pxm_to_vm_domainid(i); if (i_domain < 0) continue; if (bootverbose) printf("%d: ", i); for (j = 0; j < s->LocalityCount; j++) { j_domain = acpi_map_pxm_to_vm_domainid(j); if (j_domain < 0) continue; e = s->Entry[i * s->LocalityCount + j]; if (bootverbose) printf("%d ", (int) e); /* 255 == "no locality information" */ if (e == 255) vm_locality_table[offset] = -1; else vm_locality_table[offset] = e; offset++; } if (bootverbose) printf("\n"); } } /* * Look for an ACPI System Locality Distance Information Table ("SLIT") */ static int parse_slit(void) { if (resource_disabled("slit", 0)) { return (-1); } slit_physaddr = acpi_find_table(ACPI_SIG_SLIT); if (slit_physaddr == 0) { return (-1); } /* * Make a pass over the table to populate the cpus[] and * mem_info[] tables. */ slit = acpi_map_table(slit_physaddr, ACPI_SIG_SLIT); slit_parse_table(slit); acpi_unmap_table(slit); slit = NULL; /* Tell the VM about it! */ mem_locality = vm_locality_table; return (0); } /* * SRAT parsing. */ /* * Returns true if a memory range overlaps with at least one range in * phys_avail[]. */ static int overlaps_phys_avail(vm_paddr_t start, vm_paddr_t end) { int i; for (i = 0; phys_avail[i] != 0 && phys_avail[i + 1] != 0; i += 2) { if (phys_avail[i + 1] < start) continue; if (phys_avail[i] < end) return (1); break; } return (0); } static void srat_parse_entry(ACPI_SUBTABLE_HEADER *entry, void *arg) { ACPI_SRAT_CPU_AFFINITY *cpu; ACPI_SRAT_X2APIC_CPU_AFFINITY *x2apic; ACPI_SRAT_MEM_AFFINITY *mem; int domain, i, slot; switch (entry->Type) { case ACPI_SRAT_TYPE_CPU_AFFINITY: cpu = (ACPI_SRAT_CPU_AFFINITY *)entry; domain = cpu->ProximityDomainLo | cpu->ProximityDomainHi[0] << 8 | cpu->ProximityDomainHi[1] << 16 | cpu->ProximityDomainHi[2] << 24; if (bootverbose) printf("SRAT: Found CPU APIC ID %u domain %d: %s\n", cpu->ApicId, domain, (cpu->Flags & ACPI_SRAT_CPU_ENABLED) ? "enabled" : "disabled"); if (!(cpu->Flags & ACPI_SRAT_CPU_ENABLED)) break; KASSERT(!cpus[cpu->ApicId].enabled, ("Duplicate local APIC ID %u", cpu->ApicId)); cpus[cpu->ApicId].domain = domain; cpus[cpu->ApicId].enabled = 1; break; case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY: x2apic = (ACPI_SRAT_X2APIC_CPU_AFFINITY *)entry; if (bootverbose) printf("SRAT: Found CPU APIC ID %u domain %d: %s\n", x2apic->ApicId, x2apic->ProximityDomain, (x2apic->Flags & ACPI_SRAT_CPU_ENABLED) ? "enabled" : "disabled"); if (!(x2apic->Flags & ACPI_SRAT_CPU_ENABLED)) break; KASSERT(!cpus[x2apic->ApicId].enabled, ("Duplicate local APIC ID %u", x2apic->ApicId)); cpus[x2apic->ApicId].domain = x2apic->ProximityDomain; cpus[x2apic->ApicId].enabled = 1; break; case ACPI_SRAT_TYPE_MEMORY_AFFINITY: mem = (ACPI_SRAT_MEM_AFFINITY *)entry; if (bootverbose) printf( "SRAT: Found memory domain %d addr %jx len %jx: %s\n", mem->ProximityDomain, (uintmax_t)mem->BaseAddress, (uintmax_t)mem->Length, (mem->Flags & ACPI_SRAT_MEM_ENABLED) ? "enabled" : "disabled"); if (!(mem->Flags & ACPI_SRAT_MEM_ENABLED)) break; if (!overlaps_phys_avail(mem->BaseAddress, mem->BaseAddress + mem->Length)) { printf("SRAT: Ignoring memory at addr %jx\n", (uintmax_t)mem->BaseAddress); break; } if (num_mem == VM_PHYSSEG_MAX) { printf("SRAT: Too many memory regions\n"); *(int *)arg = ENXIO; break; } slot = num_mem; for (i = 0; i < num_mem; i++) { if (mem_info[i].end <= mem->BaseAddress) continue; if (mem_info[i].start < (mem->BaseAddress + mem->Length)) { printf("SRAT: Overlapping memory entries\n"); *(int *)arg = ENXIO; return; } slot = i; } for (i = num_mem; i > slot; i--) mem_info[i] = mem_info[i - 1]; mem_info[slot].start = mem->BaseAddress; mem_info[slot].end = mem->BaseAddress + mem->Length; mem_info[slot].domain = mem->ProximityDomain; num_mem++; break; } } /* * Ensure each memory domain has at least one CPU and that each CPU * has at least one memory domain. */ static int check_domains(void) { int found, i, j; for (i = 0; i < num_mem; i++) { found = 0; for (j = 0; j <= MAX_APIC_ID; j++) if (cpus[j].enabled && cpus[j].domain == mem_info[i].domain) { cpus[j].has_memory = 1; found++; } if (!found) { printf("SRAT: No CPU found for memory domain %d\n", mem_info[i].domain); return (ENXIO); } } for (i = 0; i <= MAX_APIC_ID; i++) if (cpus[i].enabled && !cpus[i].has_memory) { printf("SRAT: No memory found for CPU %d\n", i); return (ENXIO); } return (0); } /* * Check that the SRAT memory regions cover all of the regions in * phys_avail[]. */ static int check_phys_avail(void) { vm_paddr_t address; int i, j; /* j is the current offset into phys_avail[]. */ address = phys_avail[0]; j = 0; for (i = 0; i < num_mem; i++) { /* * Consume as many phys_avail[] entries as fit in this * region. */ while (address >= mem_info[i].start && address <= mem_info[i].end) { /* * If we cover the rest of this phys_avail[] entry, * advance to the next entry. */ if (phys_avail[j + 1] <= mem_info[i].end) { j += 2; if (phys_avail[j] == 0 && phys_avail[j + 1] == 0) { return (0); } address = phys_avail[j]; } else address = mem_info[i].end + 1; } } printf("SRAT: No memory region found for %jx - %jx\n", (uintmax_t)phys_avail[j], (uintmax_t)phys_avail[j + 1]); return (ENXIO); } /* * Renumber the memory domains to be compact and zero-based if not * already. Returns an error if there are too many domains. */ static int renumber_domains(void) { int i, j, slot; /* Enumerate all the domains. */ vm_ndomains = 0; for (i = 0; i < num_mem; i++) { /* See if this domain is already known. */ for (j = 0; j < vm_ndomains; j++) { if (vm_domains[j] >= mem_info[i].domain) break; } if (j < vm_ndomains && vm_domains[j] == mem_info[i].domain) continue; /* Insert the new domain at slot 'j'. */ slot = j; for (j = vm_ndomains; j > slot; j--) vm_domains[j] = vm_domains[j - 1]; vm_domains[slot] = mem_info[i].domain; vm_ndomains++; if (vm_ndomains > MAXMEMDOM) { vm_ndomains = 1; printf("SRAT: Too many memory domains\n"); return (EFBIG); } } /* Renumber each domain to its index in the sorted 'domains' list. */ for (i = 0; i < vm_ndomains; i++) { /* * If the domain is already the right value, no need * to renumber. */ if (vm_domains[i] == i) continue; /* Walk the cpu[] and mem_info[] arrays to renumber. */ for (j = 0; j < num_mem; j++) if (mem_info[j].domain == vm_domains[i]) mem_info[j].domain = i; for (j = 0; j <= MAX_APIC_ID; j++) if (cpus[j].enabled && cpus[j].domain == vm_domains[i]) cpus[j].domain = i; } KASSERT(vm_ndomains > 0, ("renumber_domains: invalid final vm_ndomains setup")); return (0); } /* * Look for an ACPI System Resource Affinity Table ("SRAT") */ static int parse_srat(void) { int error; if (resource_disabled("srat", 0)) return (-1); srat_physaddr = acpi_find_table(ACPI_SIG_SRAT); if (srat_physaddr == 0) return (-1); /* * Make a pass over the table to populate the cpus[] and * mem_info[] tables. */ srat = acpi_map_table(srat_physaddr, ACPI_SIG_SRAT); error = 0; srat_walk_table(srat_parse_entry, &error); acpi_unmap_table(srat); srat = NULL; if (error || check_domains() != 0 || check_phys_avail() != 0 || renumber_domains() != 0) { srat_physaddr = 0; return (-1); } /* Point vm_phys at our memory affinity table. */ mem_affinity = mem_info; return (0); } static void init_mem_locality(void) { int i; /* - * For now, assume 255 == "no locality information for + * For now, assume -1 == "no locality information for * this pairing. */ for (i = 0; i < MAXMEMDOM * MAXMEMDOM; i++) vm_locality_table[i] = -1; } static void parse_acpi_tables(void *dummy) { if (parse_srat() < 0) return; init_mem_locality(); (void) parse_slit(); } SYSINIT(parse_acpi_tables, SI_SUB_VM - 1, SI_ORDER_FIRST, parse_acpi_tables, NULL); static void srat_walk_table(acpi_subtable_handler *handler, void *arg) { acpi_walk_subtables(srat + 1, (char *)srat + srat->Header.Length, handler, arg); } /* * Setup per-CPU domain IDs. */ static void srat_set_cpus(void *dummy) { struct cpu_info *cpu; struct pcpu *pc; u_int i; if (srat_physaddr == 0) return; for (i = 0; i < MAXCPU; i++) { if (CPU_ABSENT(i)) continue; pc = pcpu_find(i); KASSERT(pc != NULL, ("no pcpu data for CPU %u", i)); cpu = &cpus[pc->pc_apic_id]; if (!cpu->enabled) panic("SRAT: CPU with APIC ID %u is not known", pc->pc_apic_id); pc->pc_domain = cpu->domain; CPU_SET(i, &cpuset_domain[cpu->domain]); if (bootverbose) printf("SRAT: CPU %u has memory domain %d\n", i, cpu->domain); } } SYSINIT(srat_set_cpus, SI_SUB_CPU, SI_ORDER_ANY, srat_set_cpus, NULL); /* * Map a _PXM value to a VM domain ID. * * Returns the domain ID, or -1 if no domain ID was found. */ int acpi_map_pxm_to_vm_domainid(int pxm) { int i; for (i = 0; i < vm_ndomains; i++) { if (vm_domains[i] == pxm) return (i); } return (-1); } #endif /* MAXMEMDOM > 1 */ Index: projects/ci20_mips/sys =================================================================== --- projects/ci20_mips/sys (revision 283030) +++ projects/ci20_mips/sys (revision 283031) Property changes on: projects/ci20_mips/sys ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head/sys:r282931-283030 Index: projects/ci20_mips/tools/build/Makefile =================================================================== --- projects/ci20_mips/tools/build/Makefile (revision 283030) +++ projects/ci20_mips/tools/build/Makefile (revision 283031) @@ -1,36 +1,44 @@ # $FreeBSD$ .PATH: ${.CURDIR}/../../include LIB= egacy SRC= INCSGROUPS= INCS INCS= BOOTSTRAPPING?= 0 _WITH_PWCACHEDB!= grep -c pwcache_groupdb /usr/include/grp.h || true .if ${_WITH_PWCACHEDB} == 0 .PATH: ${.CURDIR}/../../contrib/libc-pwcache CFLAGS+= -I${.CURDIR}/../../contrib/libc-pwcache \ -I${.CURDIR}/../../lib/libc/include SRCS+= pwcache.c .endif _WITH_STRSVIS!= grep -c strsvis /usr/include/vis.h || true .if ${_WITH_STRSVIS} == 0 .PATH: ${.CURDIR}/../../contrib/libc-vis SRCS+= vis.c CFLAGS+= -I${.CURDIR}/../../contrib/libc-vis \ -I${.CURDIR}/../../lib/libc/include .endif +_WITH_REALLOCARRAY!= grep -c reallocarray /usr/include/stdlib.h || true +.if ${_WITH_REALLOCARRAY} == 0 +.PATH: ${.CURDIR}/../../lib/libc/stdlib +INCS+= stdlib.h +SRCS+= reallocarray.c +CFLAGS+= -I${.CURDIR}/../../lib/libc/include +.endif + .if empty(SRCS) SRCS= dummy.c .endif .if defined(CROSS_BUILD_TESTING) SUBDIR= cross-build .endif .include Index: projects/ci20_mips/tools/build/mk/OptionalObsoleteFiles.inc =================================================================== --- projects/ci20_mips/tools/build/mk/OptionalObsoleteFiles.inc (revision 283030) +++ projects/ci20_mips/tools/build/mk/OptionalObsoleteFiles.inc (revision 283031) @@ -1,8425 +1,8430 @@ # # $FreeBSD$ # # This file add support for the WITHOUT_* and WITH_* knobs in src.conf(5) to # the check-old and delete-old* targets. # .if ${MK_ACCT} == no OLD_FILES+=etc/rc.d/accounting OLD_FILES+=etc/periodic/daily/310.accounting OLD_FILES+=usr/sbin/accton OLD_FILES+=usr/sbin/sa OLD_FILES+=usr/share/man/man8/accton.8.gz OLD_FILES+=usr/share/man/man8/sa.8.gz .endif .if ${MK_ACPI} == no OLD_FILES+=etc/devd/asus.conf OLD_FILES+=etc/rc.d/power_profile OLD_FILES+=usr/sbin/acpiconf OLD_FILES+=usr/sbin/acpidb OLD_FILES+=usr/sbin/acpidump OLD_FILES+=usr/sbin/iasl OLD_FILES+=usr/share/man/man8/acpiconf.8.gz OLD_FILES+=usr/share/man/man8/acpidb.8.gz OLD_FILES+=usr/share/man/man8/acpidump.8.gz OLD_FILES+=usr/share/man/man8/iasl.8.gz .endif .if ${MK_AMD} == no OLD_FILES+=etc/amd.map OLD_FILES+=etc/rc.d/amd OLD_FILES+=usr/bin/pawd OLD_FILES+=usr/sbin/amd OLD_FILES+=usr/sbin/amq OLD_FILES+=usr/sbin/fixmount OLD_FILES+=usr/sbin/fsinfo OLD_FILES+=usr/sbin/hlfsd OLD_FILES+=usr/sbin/mk-amd-map OLD_FILES+=usr/sbin/wire-test OLD_FILES+=usr/share/examples/etc/amd.map OLD_FILES+=usr/share/info/am-utils.info.gz OLD_FILES+=usr/share/man/man1/pawd.1.gz OLD_FILES+=usr/share/man/man5/amd.conf.5.gz OLD_FILES+=usr/share/man/man8/amd.8.gz OLD_FILES+=usr/share/man/man8/amq.8.gz OLD_FILES+=usr/share/man/man8/fixmount.8.gz OLD_FILES+=usr/share/man/man8/fsinfo.8.gz OLD_FILES+=usr/share/man/man8/hlfsd.8.gz OLD_FILES+=usr/share/man/man8/mk-amd-map.8.gz OLD_FILES+=usr/share/man/man8/wire-test.8.gz .endif .if ${MK_APM} == no OLD_FILES+=etc/rc.d/apm OLD_FILES+=etc/rc.d/apmd OLD_FILES+=etc/apmd.conf OLD_FILES+=usr/sbin/apm OLD_FILES+=usr/share/examples/etc/apmd.conf OLD_FILES+=usr/share/man/man8/amd64/apm.8.gz OLD_FILES+=usr/share/man/man8/amd64/apmconf.8.gz .endif .if ${MK_AT} == no OLD_FILES+=etc/pam.d/atrun OLD_FILES+=usr/bin/at OLD_FILES+=usr/bin/atq OLD_FILES+=usr/bin/atrm OLD_FILES+=usr/bin/batch OLD_FILES+=usr/libexec/atrun OLD_FILES+=usr/share/man/man1/at.1.gz OLD_FILES+=usr/share/man/man1/atq.1.gz OLD_FILES+=usr/share/man/man1/atrm.1.gz OLD_FILES+=usr/share/man/man1/batch.1.gz OLD_FILES+=usr/share/man/man8/atrun.8.gz .endif .if ${MK_ATM} == no OLD_FILES+=rescue/atmconfig OLD_FILES+=sbin/atmconfig OLD_FILES+=usr/bin/sscop OLD_FILES+=usr/include/bsnmp/snmp_atm.h OLD_FILES+=usr/include/netnatm/addr.h OLD_FILES+=usr/include/netnatm/api/atmapi.h OLD_FILES+=usr/include/netnatm/api/ccatm.h OLD_FILES+=usr/include/netnatm/api/unisap.h OLD_DIRS+=usr/include/netnatm/api OLD_FILES+=usr/include/netnatm/msg/uni_config.h OLD_FILES+=usr/include/netnatm/msg/uni_hdr.h OLD_FILES+=usr/include/netnatm/msg/uni_ie.h OLD_FILES+=usr/include/netnatm/msg/uni_msg.h OLD_FILES+=usr/include/netnatm/msg/unimsglib.h OLD_FILES+=usr/include/netnatm/msg/uniprint.h OLD_FILES+=usr/include/netnatm/msg/unistruct.h OLD_DIRS+=usr/include/netnatm/msg OLD_FILES+=usr/include/netnatm/saal/sscfu.h OLD_FILES+=usr/include/netnatm/saal/sscfudef.h OLD_FILES+=usr/include/netnatm/saal/sscop.h OLD_FILES+=usr/include/netnatm/saal/sscopdef.h OLD_DIRS+=usr/include/netnatm/saal OLD_FILES+=usr/include/netnatm/sig/uni.h OLD_FILES+=usr/include/netnatm/sig/unidef.h OLD_FILES+=usr/include/netnatm/sig/unisig.h OLD_DIRS+=usr/include/netnatm/sig OLD_FILES+=usr/include/netnatm/unimsg.h OLD_FILES+=usr/lib/libngatm.a OLD_FILES+=usr/lib/libngatm.so OLD_LIBS+=usr/lib/libngatm.so.4 OLD_FILES+=usr/lib/libngatm_p.a OLD_FILES+=usr/lib/snmp_atm.so OLD_LIBS+=usr/lib/snmp_atm.so.6 .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/lib32/libngatm.a OLD_FILES+=usr/lib32/libngatm.so OLD_LIBS+=usr/lib32/libngatm.so.4 OLD_FILES+=usr/lib32/libngatm_p.a .endif OLD_FILES+=usr/share/doc/atm/atmconfig.help OLD_FILES+=usr/share/doc/atm/atmconfig_device.help OLD_DIRS+=usr/share/doc/atm OLD_FILES+=usr/share/man/man1/sscop.1.gz OLD_FILES+=usr/share/man/man3/libngatm.3.gz OLD_FILES+=usr/share/man/man3/snmp_atm.3.gz OLD_FILES+=usr/share/man/man3/uniaddr.3.gz OLD_FILES+=usr/share/man/man3/unifunc.3.gz OLD_FILES+=usr/share/man/man3/unimsg.3.gz OLD_FILES+=usr/share/man/man3/unisap.3.gz OLD_FILES+=usr/share/man/man3/unistruct.3.gz OLD_FILES+=usr/share/man/man8/atmconfig.8.gz OLD_FILES+=usr/share/snmp/defs/atm_freebsd.def OLD_FILES+=usr/share/snmp/defs/atm_tree.def OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-ATM-FREEBSD-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-ATM.txt .endif .if ${MK_AUDIT} == no OLD_FILES+=usr/sbin/audit OLD_FILES+=usr/sbin/auditd OLD_FILES+=usr/sbin/auditreduce OLD_FILES+=usr/sbin/praudit OLD_FILES+=usr/share/man/man1/auditreduce.1.gz OLD_FILES+=usr/share/man/man1/praudit.1.gz OLD_FILES+=usr/share/man/man8/audit.8.gz OLD_FILES+=usr/share/man/man8/auditd.8.gz .endif .if ${MK_AUTHPF} == no OLD_FILES+=usr/sbin/authpf OLD_FILES+=usr/sbin/authpf-noip OLD_FILES+=usr/share/man/man8/authpf.8.gz OLD_FILES+=usr/share/man/man8/authpf-noip.8.gz .endif .if ${MK_AUTOFS} == no OLD_FILES+=etc/autofs/include_ldap OLD_FILES+=etc/autofs/special_hosts OLD_FILES+=etc/autofs/special_media OLD_FILES+=etc/autofs/special_null OLD_FILES+=etc/auto_master OLD_FILES+=etc/rc.d/automount OLD_FILES+=etc/rc.d/automountd OLD_FILES+=etc/rc.d/autounmountd OLD_FILES+=usr/sbin/automount OLD_FILES+=usr/sbin/automountd OLD_FILES+=usr/sbin/autounmountd OLD_FILES+=usr/share/man/man5/autofs.5.gz OLD_FILES+=usr/share/man/man5/auto_master.5.gz OLD_FILES+=usr/share/man/man8/automount.8.gz OLD_FILES+=usr/share/man/man8/automountd.8.gz OLD_FILES+=usr/share/man/man8/autounmountd.8.gz OLD_DIRS+=etc/autofs .endif .if ${MK_BHYVE} == no OLD_FILES+=usr/sbin/bhyve OLD_FILES+=usr/sbin/bhyvectl OLD_FILES+=usr/sbin/bhyveload OLD_FILES+=usr/share/examples/bhyve/vmrun.sh OLD_FILES+=usr/share/man/man8/bhyve.8.gz OLD_FILES+=usr/share/man/man8/bhyveload.8.gz OLD_DIRS+=usr/share/examples/bhyve .endif .if ${MK_BINUTILS} == no OLD_FILES+=usr/bin/as OLD_FILES+=usr/bin/ld OLD_FILES+=usr/bin/objcopy OLD_FILES+=usr/bin/objdump OLD_FILES+=usr/bin/readelf OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.x OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xbn OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xc OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xd OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xdc OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xdw OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xn OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xr OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xs OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xsc OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xsw OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xu OLD_FILES+=usr/libdata/ldscripts/elf_x86_64_fbsd.xw OLD_FILES+=usr/share/man/man1/as.1.gz OLD_FILES+=usr/share/man/man1/ld.1.gz OLD_FILES+=usr/share/man/man1/objcopy.1.gz OLD_FILES+=usr/share/man/man1/objdump.1.gz OLD_FILES+=usr/share/man/man1/readelf.1.gz OLD_FILES+=usr/share/man/man7/as.7.gz OLD_FILES+=usr/share/man/man7/ld.7.gz OLD_FILES+=usr/share/man/man7/ldint.7.gz OLD_FILES+=usr/share/man/man7/binutils.7.gz .endif .if ${MK_BLUETOOTH} == no OLD_FILES+=etc/bluetooth/hcsecd.conf OLD_FILES+=etc/bluetooth/hosts OLD_FILES+=etc/bluetooth/protocols OLD_FILES+=etc/defaults/bluetooth.device.conf OLD_DIRS+=etc/bluetooth OLD_FILES+=etc/rc.d/bluetooth OLD_FILES+=etc/rc.d/bthidd OLD_FILES+=etc/rc.d/hcsecd OLD_FILES+=etc/rc.d/ubthidhci OLD_FILES+=usr/bin/bthost OLD_FILES+=usr/bin/btsockstat OLD_FILES+=usr/bin/rfcomm_sppd OLD_FILES+=usr/include/bluetooth.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_bluetooth.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_bt3c.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_btsocket.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_btsocket_hci_raw.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_btsocket_l2cap.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_btsocket_rfcomm.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_btsocket_sco.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_h4.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_hci.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_l2cap.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_ubt.h OLD_DIRS+=usr/include/netgraph/bluetooth/include OLD_DIRS+=usr/include/netgraph/bluetooth OLD_FILES+=usr/include/sdp.h OLD_FILES+=usr/lib/libbluetooth.a OLD_FILES+=usr/lib/libbluetooth.so OLD_LIBS+=usr/lib/libbluetooth.so.4 OLD_FILES+=usr/lib/libbluetooth_p.a OLD_FILES+=usr/lib/libsdp.a OLD_FILES+=usr/lib/libsdp.so OLD_LIBS+=usr/lib/libsdp.so.4 OLD_FILES+=usr/lib/libsdp_p.a .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/lib32/libbluetooth.a OLD_FILES+=usr/lib32/libbluetooth.so OLD_LIBS+=usr/lib32/libbluetooth.so.4 OLD_FILES+=usr/lib32/libbluetooth_p.a OLD_FILES+=usr/lib32/libsdp.a OLD_FILES+=usr/lib32/libsdp.so OLD_LIBS+=usr/lib32/libsdp.so.4 OLD_FILES+=usr/lib32/libsdp_p.a .endif OLD_FILES+=usr/sbin/ath3kfw OLD_FILES+=usr/sbin/bcmfw OLD_FILES+=usr/sbin/bt3cfw OLD_FILES+=usr/sbin/bthidcontrol OLD_FILES+=usr/sbin/bthidd OLD_FILES+=usr/sbin/btpand OLD_FILES+=usr/sbin/hccontrol OLD_FILES+=usr/sbin/hcsecd OLD_FILES+=usr/sbin/hcseriald OLD_FILES+=usr/sbin/l2control OLD_FILES+=usr/sbin/l2ping OLD_FILES+=usr/sbin/rfcomm_pppd OLD_FILES+=usr/sbin/sdpcontrol OLD_FILES+=usr/sbin/sdpd OLD_FILES+=usr/share/examples/etc/defaults/bluetooth.device.conf OLD_FILES+=usr/share/man/man1/bthost.1.gz OLD_FILES+=usr/share/man/man1/btsockstat.1.gz OLD_FILES+=usr/share/man/man1/rfcomm_sppd.1.gz OLD_FILES+=usr/share/man/man3/SDP_GET128.3.gz OLD_FILES+=usr/share/man/man3/SDP_GET16.3.gz OLD_FILES+=usr/share/man/man3/SDP_GET32.3.gz OLD_FILES+=usr/share/man/man3/SDP_GET64.3.gz OLD_FILES+=usr/share/man/man3/SDP_GET8.3.gz OLD_FILES+=usr/share/man/man3/SDP_PUT128.3.gz OLD_FILES+=usr/share/man/man3/SDP_PUT16.3.gz OLD_FILES+=usr/share/man/man3/SDP_PUT32.3.gz OLD_FILES+=usr/share/man/man3/SDP_PUT64.3.gz OLD_FILES+=usr/share/man/man3/SDP_PUT8.3.gz OLD_FILES+=usr/share/man/man3/bdaddr_any.3.gz OLD_FILES+=usr/share/man/man3/bdaddr_copy.3.gz OLD_FILES+=usr/share/man/man3/bdaddr_same.3.gz OLD_FILES+=usr/share/man/man3/bluetooth.3.gz OLD_FILES+=usr/share/man/man3/bt_aton.3.gz OLD_FILES+=usr/share/man/man3/bt_devaddr.3.gz OLD_FILES+=usr/share/man/man3/bt_devclose.3.gz OLD_FILES+=usr/share/man/man3/bt_devenum.3.gz OLD_FILES+=usr/share/man/man3/bt_devfilter.3.gz OLD_FILES+=usr/share/man/man3/bt_devfilter_evt_clr.3.gz OLD_FILES+=usr/share/man/man3/bt_devfilter_evt_set.3.gz OLD_FILES+=usr/share/man/man3/bt_devfilter_evt_tst.3.gz OLD_FILES+=usr/share/man/man3/bt_devfilter_pkt_clr.3.gz OLD_FILES+=usr/share/man/man3/bt_devfilter_pkt_set.3.gz OLD_FILES+=usr/share/man/man3/bt_devfilter_pkt_tst.3.gz OLD_FILES+=usr/share/man/man3/bt_devinfo.3.gz OLD_FILES+=usr/share/man/man3/bt_devinquiry.3.gz OLD_FILES+=usr/share/man/man3/bt_devname.3.gz OLD_FILES+=usr/share/man/man3/bt_devopen.3.gz OLD_FILES+=usr/share/man/man3/bt_devreq.3.gz OLD_FILES+=usr/share/man/man3/bt_devsend.3.gz OLD_FILES+=usr/share/man/man3/bt_endhostent.3.gz OLD_FILES+=usr/share/man/man3/bt_endprotoent.3.gz OLD_FILES+=usr/share/man/man3/bt_gethostbyaddr.3.gz OLD_FILES+=usr/share/man/man3/bt_gethostbyname.3.gz OLD_FILES+=usr/share/man/man3/bt_gethostent.3.gz OLD_FILES+=usr/share/man/man3/bt_getprotobyname.3.gz OLD_FILES+=usr/share/man/man3/bt_getprotobynumber.3.gz OLD_FILES+=usr/share/man/man3/bt_getprotoent.3.gz OLD_FILES+=usr/share/man/man3/bt_ntoa.3.gz OLD_FILES+=usr/share/man/man3/bt_sethostent.3.gz OLD_FILES+=usr/share/man/man3/bt_setprotoent.3.gz OLD_FILES+=usr/share/man/man3/sdp.3.gz OLD_FILES+=usr/share/man/man3/sdp_attr2desc.3.gz OLD_FILES+=usr/share/man/man3/sdp_change_service.3.gz OLD_FILES+=usr/share/man/man3/sdp_close.3.gz OLD_FILES+=usr/share/man/man3/sdp_error.3.gz OLD_FILES+=usr/share/man/man3/sdp_open.3.gz OLD_FILES+=usr/share/man/man3/sdp_open_local.3.gz OLD_FILES+=usr/share/man/man3/sdp_register_service.3.gz OLD_FILES+=usr/share/man/man3/sdp_search.3.gz OLD_FILES+=usr/share/man/man3/sdp_unregister_service.3.gz OLD_FILES+=usr/share/man/man3/sdp_uuid2desc.3.gz OLD_FILES+=usr/share/man/man5/hcsecd.conf.5.gz OLD_FILES+=usr/share/man/man8/ath3kfw.8.gz OLD_FILES+=usr/share/man/man8/bcmfw.8.gz OLD_FILES+=usr/share/man/man8/bt3cfw.8.gz OLD_FILES+=usr/share/man/man8/bthidcontrol.8.gz OLD_FILES+=usr/share/man/man8/bthidd.8.gz OLD_FILES+=usr/share/man/man8/btpand.8.gz OLD_FILES+=usr/share/man/man8/hccontrol.8.gz OLD_FILES+=usr/share/man/man8/hcsecd.8.gz OLD_FILES+=usr/share/man/man8/hcseriald.8.gz OLD_FILES+=usr/share/man/man8/l2control.8.gz OLD_FILES+=usr/share/man/man8/l2ping.8.gz OLD_FILES+=usr/share/man/man8/rfcomm_pppd.8.gz OLD_FILES+=usr/share/man/man8/sdpcontrol.8.gz OLD_FILES+=usr/share/man/man8/sdpd.8.gz .endif .if ${MK_BOOT} == no OLD_FILES+=boot/beastie.4th OLD_FILES+=boot/boot OLD_FILES+=boot/boot0 OLD_FILES+=boot/boot0sio OLD_FILES+=boot/boot1 OLD_FILES+=boot/boot1.efi OLD_FILES+=boot/boot1.efifat OLD_FILES+=boot/boot2 OLD_FILES+=boot/brand.4th OLD_FILES+=boot/cdboot OLD_FILES+=boot/check-password.4th OLD_FILES+=boot/color.4th OLD_FILES+=boot/defaults/loader.conf OLD_FILES+=boot/delay.4th OLD_FILES+=boot/device.hints OLD_FILES+=boot/frames.4th OLD_FILES+=boot/gptboot OLD_FILES+=boot/gptzfsboot OLD_FILES+=boot/loader OLD_FILES+=boot/loader.4th OLD_FILES+=boot/loader.efi OLD_FILES+=boot/loader.help OLD_FILES+=boot/loader.rc OLD_FILES+=boot/mbr OLD_FILES+=boot/menu-commands.4th OLD_FILES+=boot/menu.4th OLD_FILES+=boot/menu.rc OLD_FILES+=boot/menusets.4th OLD_FILES+=boot/pcibios.4th OLD_FILES+=boot/pmbr OLD_FILES+=boot/pxeboot OLD_FILES+=boot/screen.4th OLD_FILES+=boot/shortcuts.4th OLD_FILES+=boot/support.4th OLD_FILES+=boot/userboot.so OLD_FILES+=boot/version.4th OLD_FILES+=boot/zfsboot OLD_FILES+=boot/zfsloader OLD_FILES+=usr/lib/kgzldr.o OLD_FILES+=usr/share/man/man5/loader.conf.5.gz OLD_FILES+=usr/share/man/man8/beastie.4th.8.gz OLD_FILES+=usr/share/man/man8/brand.4th.8.gz OLD_FILES+=usr/share/man/man8/check-password.4th.8.gz OLD_FILES+=usr/share/man/man8/color.4th.8.gz OLD_FILES+=usr/share/man/man8/delay.4th.8.gz OLD_FILES+=usr/share/man/man8/gptboot.8.gz OLD_FILES+=usr/share/man/man8/gptzfsboot.8.gz OLD_FILES+=usr/share/man/man8/loader.4th.8.gz OLD_FILES+=usr/share/man/man8/loader.8.gz OLD_FILES+=usr/share/man/man8/menu.4th.8.gz OLD_FILES+=usr/share/man/man8/menusets.4th.8.gz OLD_FILES+=usr/share/man/man8/pxeboot.8.gz OLD_FILES+=usr/share/man/man8/version.4th.8.gz OLD_FILES+=usr/share/man/man8/zfsboot.8.gz OLD_FILES+=usr/share/man/man8/zfsloader.8.gz .endif .if ${MK_BSD_CPIO} == no OLD_FILES+=usr/bin/bsdcpio OLD_FILES+=usr/bin/cpio OLD_FILES+=usr/share/man/man1/bsdcpio.1.gz OLD_FILES+=usr/share/man/man1/cpio.1.gz .endif .if ${MK_BSDINSTALL} == no OLD_FILES+=usr/libexec/bsdinstall/adduser OLD_FILES+=usr/libexec/bsdinstall/auto OLD_FILES+=usr/libexec/bsdinstall/autopart OLD_FILES+=usr/libexec/bsdinstall/checksum OLD_FILES+=usr/libexec/bsdinstall/config OLD_FILES+=usr/libexec/bsdinstall/distextract OLD_FILES+=usr/libexec/bsdinstall/distfetch OLD_FILES+=usr/libexec/bsdinstall/docsinstall OLD_FILES+=usr/libexec/bsdinstall/entropy OLD_FILES+=usr/libexec/bsdinstall/hostname OLD_FILES+=usr/libexec/bsdinstall/jail OLD_FILES+=usr/libexec/bsdinstall/keymap OLD_FILES+=usr/libexec/bsdinstall/mirrorselect OLD_FILES+=usr/libexec/bsdinstall/mount OLD_FILES+=usr/libexec/bsdinstall/netconfig OLD_FILES+=usr/libexec/bsdinstall/netconfig_ipv4 OLD_FILES+=usr/libexec/bsdinstall/netconfig_ipv6 OLD_FILES+=usr/libexec/bsdinstall/partedit OLD_FILES+=usr/libexec/bsdinstall/rootpass OLD_FILES+=usr/libexec/bsdinstall/script OLD_FILES+=usr/libexec/bsdinstall/scriptedpart OLD_FILES+=usr/libexec/bsdinstall/services OLD_FILES+=usr/libexec/bsdinstall/time OLD_FILES+=usr/libexec/bsdinstall/umount OLD_FILES+=usr/libexec/bsdinstall/wlanconfig OLD_FILES+=usr/libexec/bsdinstall/zfsboot OLD_FILES+=usr/sbin/bsdinstall OLD_FILES+=usr/share/man/man8/bsdinstall.8.gz OLD_FILES+=usr/share/man/man8/sade.8.gz OLD_DIRS+=usr/libexec/bsdinstall .endif .if ${MK_BSNMP} == no OLD_FILES+=etc/snmpd.config OLD_FILES+=etc/rc.d/bsnmpd OLD_FILES+=usr/bin/bsnmpget OLD_FILES+=usr/bin/bsnmpset OLD_FILES+=usr/bin/bsnmpwalk OLD_FILES+=usr/include/bsnmp/asn1.h OLD_FILES+=usr/include/bsnmp/bridge_snmp.h OLD_FILES+=usr/include/bsnmp/snmp.h OLD_FILES+=usr/include/bsnmp/snmp_atm.h OLD_FILES+=usr/include/bsnmp/snmp_mibII.h OLD_FILES+=usr/include/bsnmp/snmp_netgraph.h OLD_FILES+=usr/include/bsnmp/snmpagent.h OLD_FILES+=usr/include/bsnmp/snmpclient.h OLD_FILES+=usr/include/bsnmp/snmpmod.h OLD_FILES+=usr/lib/libbsnmp.a OLD_FILES+=usr/lib/libbsnmp.so OLD_LIBS+=usr/lib/libbsnmp.so.6 OLD_FILES+=usr/lib/libbsnmp_p.a OLD_FILES+=usr/lib/libbsnmptools.a OLD_FILES+=usr/lib/libbsnmptools.so OLD_LIBS+=usr/lib/libbsnmptools.so.0 OLD_FILES+=usr/lib/libbsnmptools_p.a OLD_FILES+=usr/lib/snmp_atm.so OLD_LIBS+=usr/lib/snmp_atm.so.6 OLD_FILES+=usr/lib/snmp_bridge.so OLD_LIBS+=usr/lib/snmp_bridge.so.6 OLD_FILES+=usr/lib/snmp_hast.so OLD_LIBS+=usr/lib/snmp_hast.so.6 OLD_FILES+=usr/lib/snmp_hostres.so OLD_LIBS+=usr/lib/snmp_hostres.so.6 OLD_FILES+=usr/lib/snmp_lm75.so OLD_LIBS+=usr/lib/snmp_lm75.so.6 OLD_FILES+=usr/lib/snmp_mibII.so OLD_LIBS+=usr/lib/snmp_mibII.so.6 OLD_FILES+=usr/lib/snmp_netgraph.so OLD_LIBS+=usr/lib/snmp_netgraph.so.6 OLD_FILES+=usr/lib/snmp_pf.so OLD_LIBS+=usr/lib/snmp_pf.so.6 OLD_FILES+=usr/lib/snmp_target.so OLD_LIBS+=usr/lib/snmp_target.so.6 OLD_FILES+=usr/lib/snmp_usm.so OLD_LIBS+=usr/lib/snmp_usm.so.6 OLD_FILES+=usr/lib/snmp_vacm.so OLD_LIBS+=usr/lib/snmp_vacm.so.6 OLD_FILES+=usr/lib/snmp_wlan.so OLD_LIBS+=usr/lib/snmp_wlan.so.6 OLD_FILES+=usr/lib32/libbsnmp.a OLD_FILES+=usr/lib32/libbsnmp.so OLD_LIBS+=usr/lib32/libbsnmp.so.6 OLD_FILES+=usr/lib32/libbsnmp_p.a OLD_FILES+=usr/sbin/bsnmpd OLD_FILES+=usr/sbin/gensnmptree OLD_FILES+=usr/share/examples/etc/snmpd.config OLD_FILES+=usr/share/man/man1/bsnmpd.1.gz OLD_FILES+=usr/share/man/man1/bsnmpget.1.gz OLD_FILES+=usr/share/man/man1/bsnmpset.1.gz OLD_FILES+=usr/share/man/man1/bsnmpwalk.1.gz OLD_FILES+=usr/share/man/man1/gensnmptree.1.gz OLD_FILES+=usr/share/man/man3/asn1.3.gz OLD_FILES+=usr/share/man/man3/bsnmpagent.3.gz OLD_FILES+=usr/share/man/man3/bsnmpclient.3.gz OLD_FILES+=usr/share/man/man3/bsnmplib.3.gz OLD_FILES+=usr/share/man/man3/snmp_atm.3.gz OLD_FILES+=usr/share/man/man3/snmp_bridge.3.gz OLD_FILES+=usr/share/man/man3/snmp_hast.3.gz OLD_FILES+=usr/share/man/man3/snmp_hostres.3.gz OLD_FILES+=usr/share/man/man3/snmp_lm75.3.gz OLD_FILES+=usr/share/man/man3/snmp_mibII.3.gz OLD_FILES+=usr/share/man/man3/snmp_netgraph.3.gz OLD_FILES+=usr/share/man/man3/snmp_target.3.gz OLD_FILES+=usr/share/man/man3/snmp_usm.3.gz OLD_FILES+=usr/share/man/man3/snmp_vacm.3.gz OLD_FILES+=usr/share/man/man3/snmp_wlan.3.gz OLD_FILES+=usr/share/man/man3/snmpmod.3.gz OLD_FILES+=usr/share/snmp/defs/atm_freebsd.def OLD_FILES+=usr/share/snmp/defs/atm_tree.def OLD_FILES+=usr/share/snmp/defs/bridge_tree.def OLD_FILES+=usr/share/snmp/defs/hast_tree.def OLD_FILES+=usr/share/snmp/defs/hostres_tree.def OLD_FILES+=usr/share/snmp/defs/lm75_tree.def OLD_FILES+=usr/share/snmp/defs/mibII_tree.def OLD_FILES+=usr/share/snmp/defs/netgraph_tree.def OLD_FILES+=usr/share/snmp/defs/pf_tree.def OLD_FILES+=usr/share/snmp/defs/target_tree.def OLD_FILES+=usr/share/snmp/defs/tree.def OLD_FILES+=usr/share/snmp/defs/usm_tree.def OLD_FILES+=usr/share/snmp/defs/vacm_tree.def OLD_FILES+=usr/share/snmp/defs/wlan_tree.def OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-ATM-FREEBSD-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-ATM.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-BRIDGE-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-HAST-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-HOSTRES-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-IP-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-LM75-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-MIB2-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-NETGRAPH.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-PF-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-SNMPD.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-WIRELESS-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BRIDGE-MIB.txt OLD_FILES+=usr/share/snmp/mibs/FOKUS-MIB.txt OLD_FILES+=usr/share/snmp/mibs/FREEBSD-MIB.txt OLD_FILES+=usr/share/snmp/mibs/RSTP-MIB.txt OLD_DIRS+=usr/include/bsnmp OLD_DIRS+=usr/share/snmp OLD_DIRS+=usr/share/snmp/defs OLD_DIRS+=usr/share/snmp/mibs .endif .if ${MK_CALENDAR} == no OLD_FILES+=etc/periodic/daily/300.calendar OLD_FILES+=usr/bin/calendar OLD_FILES+=usr/share/calendar/calendar.all OLD_FILES+=usr/share/calendar/calendar.australia OLD_FILES+=usr/share/calendar/calendar.birthday OLD_FILES+=usr/share/calendar/calendar.brazilian OLD_FILES+=usr/share/calendar/calendar.christian OLD_FILES+=usr/share/calendar/calendar.computer OLD_FILES+=usr/share/calendar/calendar.croatian OLD_FILES+=usr/share/calendar/calendar.dutch OLD_FILES+=usr/share/calendar/calendar.freebsd OLD_FILES+=usr/share/calendar/calendar.french OLD_FILES+=usr/share/calendar/calendar.german OLD_FILES+=usr/share/calendar/calendar.history OLD_FILES+=usr/share/calendar/calendar.holiday OLD_FILES+=usr/share/calendar/calendar.hungarian OLD_FILES+=usr/share/calendar/calendar.judaic OLD_FILES+=usr/share/calendar/calendar.lotr OLD_FILES+=usr/share/calendar/calendar.music OLD_FILES+=usr/share/calendar/calendar.newzealand OLD_FILES+=usr/share/calendar/calendar.russian OLD_FILES+=usr/share/calendar/calendar.southafrica OLD_FILES+=usr/share/calendar/calendar.ukrainian OLD_FILES+=usr/share/calendar/calendar.usholiday OLD_FILES+=usr/share/calendar/calendar.world OLD_FILES+=usr/share/calendar/de_AT.ISO_8859-15/calendar.feiertag OLD_DIRS+=usr/share/calendar/de_AT.ISO_8859-15 OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.all OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.feiertag OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.geschichte OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.kirche OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.literatur OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.musik OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.wissenschaft OLD_DIRS+=usr/share/calendar/de_DE.ISO8859-1 OLD_FILES+=usr/share/calendar/de_DE.ISO8859-15 OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.all OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.fetes OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.french OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.jferies OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.proverbes OLD_DIRS+=usr/share/calendar/fr_FR.ISO8859-1 OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-15 OLD_FILES+=usr/share/calendar/hr_HR.ISO8859-2/calendar.all OLD_FILES+=usr/share/calendar/hr_HR.ISO8859-2/calendar.praznici OLD_DIRS+=usr/share/calendar/hr_HR.ISO8859-2 OLD_FILES+=usr/share/calendar/hu_HU.ISO8859-2/calendar.all OLD_FILES+=usr/share/calendar/hu_HU.ISO8859-2/calendar.nevnapok OLD_FILES+=usr/share/calendar/hu_HU.ISO8859-2/calendar.unnepek OLD_DIRS+=usr/share/calendar/hu_HU.ISO8859-2 OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.all OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.commemorative OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.holidays OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.mcommemorative OLD_DIRS+=usr/share/calendar/pt_BR.ISO8859-1 OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.all OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.commemorative OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.holidays OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.mcommemorative OLD_DIRS+=usr/share/calendar/pt_BR.UTF-8 OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.all OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.common OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.holiday OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.military OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.orthodox OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.pagan OLD_DIRS+=usr/share/calendar/ru_RU.KOI8-R OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.all OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.common OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.holiday OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.military OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.orthodox OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.pagan OLD_DIRS+=usr/share/calendar/ru_RU.UTF-8 OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.all OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.holiday OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.misc OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.orthodox OLD_DIRS+=usr/share/calendar/uk_UA.KOI8-U OLD_DIRS+=usr/share/calendar OLD_FILES+=usr/share/man/man1/calendar.1.gz .endif .if ${MK_CASPER} == no OLD_FILES+=etc/casper/system.dns OLD_FILES+=etc/casper/system.grp OLD_FILES+=etc/casper/system.pwd OLD_FILES+=etc/casper/system.random OLD_FILES+=etc/casper/system.sysctl OLD_FILES+=etc/rc.d/casperd OLD_LIBS+=lib/libcapsicum.so.0 OLD_LIBS+=lib/libcasper.so.0 OLD_FILES+=libexec/casper/dns OLD_FILES+=libexec/casper/grp OLD_FILES+=libexec/casper/pwd OLD_FILES+=libexec/casper/random OLD_FILES+=libexec/casper/sysctl OLD_FILES+=sbin/casper OLD_FILES+=sbin/casperd OLD_FILES+=usr/include/libcapsicum.h OLD_FILES+=usr/include/libcapsicum_dns.h OLD_FILES+=usr/include/libcapsicum_grp.h OLD_FILES+=usr/include/libcapsicum_pwd.h OLD_FILES+=usr/include/libcapsicum_random.h OLD_FILES+=usr/include/libcapsicum_service.h OLD_FILES+=usr/include/libcapsicum_sysctl.h OLD_FILES+=usr/include/libcasper.h OLD_FILES+=usr/lib/libcapsicum.a OLD_FILES+=usr/lib/libcapsicum.so OLD_FILES+=usr/lib/libcapsicum_p.a OLD_FILES+=usr/lib/libcasper.a OLD_FILES+=usr/lib/libcasper.so OLD_FILES+=usr/lib/libcasper_p.a OLD_FILES+=usr/lib32/libcapsicum.a OLD_FILES+=usr/lib32/libcapsicum.so OLD_LIBS+=usr/lib32/libcapsicum.so.0 OLD_FILES+=usr/lib32/libcapsicum_p.a OLD_FILES+=usr/lib32/libcasper.a OLD_FILES+=usr/lib32/libcasper.so OLD_LIBS+=usr/lib32/libcasper.so.0 OLD_FILES+=usr/lib32/libcasper_p.a OLD_FILES+=usr/share/man/man3/cap_clone.3.gz OLD_FILES+=usr/share/man/man3/cap_close.3.gz OLD_FILES+=usr/share/man/man3/cap_init.3.gz OLD_FILES+=usr/share/man/man3/cap_limit_get.3.gz OLD_FILES+=usr/share/man/man3/cap_limit_set.3.gz OLD_FILES+=usr/share/man/man3/cap_recv_nvlist.3.gz OLD_FILES+=usr/share/man/man3/cap_send_nvlist.3.gz OLD_FILES+=usr/share/man/man3/cap_service_open.3.gz OLD_FILES+=usr/share/man/man3/cap_sock.3.gz OLD_FILES+=usr/share/man/man3/cap_unwrap.3.gz OLD_FILES+=usr/share/man/man3/cap_wrap.3.gz OLD_FILES+=usr/share/man/man3/cap_xfer_nvlist.3.gz OLD_FILES+=usr/share/man/man3/libcapsicum.3.gz OLD_FILES+=usr/share/man/man8/casperd.8.gz .endif .if ${MK_CCD} == no OLD_FILES+=etc/rc.d/ccd OLD_FILES+=sbin/ccdconfig OLD_FILES+=usr/share/man/man4/ccd.4.gz OLD_FILES+=usr/share/man/man8/ccdconfig.8.gz .endif .if ${MK_CDDL} == no OLD_LIBS+=lib/libavl.so.2 OLD_LIBS+=lib/libctf.so.2 OLD_LIBS+=lib/libdtrace.so.2 OLD_LIBS+=lib/libnvpair.so.2 OLD_LIBS+=lib/libumem.so.2 OLD_LIBS+=lib/libuutil.so.2 OLD_FILES+=usr/bin/ctfconvert OLD_FILES+=usr/bin/ctfdump OLD_FILES+=usr/bin/ctfmerge OLD_FILES+=usr/bin/sgsmsg OLD_FILES+=usr/lib/dtrace/drti.o OLD_FILES+=usr/lib/dtrace/errno.d OLD_FILES+=usr/lib/dtrace/io.d OLD_FILES+=usr/lib/dtrace/ip.d OLD_FILES+=usr/lib/dtrace/psinfo.d .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386" OLD_FILES+=usr/lib/dtrace/regs_x86.d .endif OLD_FILES+=usr/lib/dtrace/signal.d OLD_FILES+=usr/lib/dtrace/tcp.d OLD_FILES+=usr/lib/dtrace/udp.d OLD_FILES+=usr/lib/dtrace/unistd.d OLD_FILES+=usr/lib/libavl.a OLD_FILES+=usr/lib/libavl.so OLD_FILES+=usr/lib/libavl_p.a OLD_FILES+=usr/lib/libctf.a OLD_FILES+=usr/lib/libctf.so OLD_FILES+=usr/lib/libctf_p.a OLD_FILES+=usr/lib/libdtrace.a OLD_FILES+=usr/lib/libdtrace.so OLD_FILES+=usr/lib/libdtrace_p.a OLD_FILES+=usr/lib/libnvpair.a OLD_FILES+=usr/lib/libnvpair.so OLD_FILES+=usr/lib/libnvpair_p.a OLD_FILES+=usr/lib/libumem.a OLD_FILES+=usr/lib/libumem.so OLD_FILES+=usr/lib/libumem_p.a OLD_FILES+=usr/lib/libuutil.a OLD_FILES+=usr/lib/libuutil.so OLD_FILES+=usr/lib/libuutil_p.a .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/lib32/dtrace/drti.o OLD_FILES+=usr/lib32/libavl.a OLD_FILES+=usr/lib32/libavl.so OLD_LIBS+=usr/lib32/libavl.so.2 OLD_FILES+=usr/lib32/libavl_p.a OLD_FILES+=usr/lib32/libctf.a OLD_FILES+=usr/lib32/libctf.so OLD_LIBS+=usr/lib32/libctf.so.2 OLD_FILES+=usr/lib32/libctf_p.a OLD_FILES+=usr/lib32/libdtrace.a OLD_FILES+=usr/lib32/libdtrace.so OLD_LIBS+=usr/lib32/libdtrace.so.2 OLD_FILES+=usr/lib32/libdtrace_p.a OLD_FILES+=usr/lib32/libnvpair.a OLD_FILES+=usr/lib32/libnvpair.so OLD_LIBS+=usr/lib32/libnvpair.so.2 OLD_FILES+=usr/lib32/libnvpair_p.a OLD_FILES+=usr/lib32/libumem.a OLD_FILES+=usr/lib32/libumem.so OLD_LIBS+=usr/lib32/libumem.so.2 OLD_FILES+=usr/lib32/libumem_p.a OLD_FILES+=usr/lib32/libuutil.a OLD_FILES+=usr/lib32/libuutil.so OLD_LIBS+=usr/lib32/libuutil.so.2 OLD_FILES+=usr/lib32/libuutil_p.a .endif OLD_LIBS+=lib/libdtrace.so.2 OLD_FILES+=usr/sbin/dtrace OLD_FILES+=usr/sbin/lockstat OLD_FILES+=usr/share/man/man1/dtrace.1.gz OLD_FILES+=usr/share/dtrace/disklatency OLD_FILES+=usr/share/dtrace/disklatencycmd OLD_FILES+=usr/share/dtrace/hotopen OLD_FILES+=usr/share/dtrace/nfsclienttime OLD_FILES+=usr/share/dtrace/toolkit/execsnoop OLD_FILES+=usr/share/dtrace/toolkit/hotkernel OLD_FILES+=usr/share/dtrace/toolkit/hotuser OLD_FILES+=usr/share/dtrace/toolkit/opensnoop OLD_FILES+=usr/share/dtrace/toolkit/procsystime OLD_FILES+=usr/share/man/man1/dtrace.1.gz OLD_DIRS+=usr/lib/dtrace OLD_DIRS+=usr/lib32/dtrace OLD_DIRS+=usr/share/dtrace/toolkit OLD_DIRS+=usr/share/dtrace .endif .if ${MK_ZFS} == no OLD_FILES+=boot/gptzfsboot OLD_FILES+=boot/zfsboot OLD_FILES+=boot/zfsloader OLD_FILES+=etc/devd/zfs.conf OLD_FILES+=etc/periodic/daily/404.status-zfs OLD_FILES+=etc/periodic/daily/800.scrub-zfs OLD_LIBS+=lib/libzfs.so.2 OLD_LIBS+=lib/libzfs_core.so.2 OLD_LIBS+=lib/libzpool.so.2 OLD_FILES+=rescue/zfs OLD_FILES+=rescue/zpool OLD_FILES+=sbin/zfs OLD_FILES+=sbin/zpool OLD_FILES+=usr/bin/zinject OLD_FILES+=usr/bin/ztest OLD_FILES+=usr/lib/libzfs.a OLD_FILES+=usr/lib/libzfs.so OLD_FILES+=usr/lib/libzfs_core.a OLD_FILES+=usr/lib/libzfs_core.so OLD_FILES+=usr/lib/libzfs_core_p.a OLD_FILES+=usr/lib/libzfs_p.a OLD_FILES+=usr/lib/libzpool.a OLD_FILES+=usr/lib/libzpool.so .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/lib32/libzfs.a OLD_FILES+=usr/lib32/libzfs.so OLD_LIBS+=usr/lib32/libzfs.so.2 OLD_FILES+=usr/lib32/libzfs_core.a OLD_FILES+=usr/lib32/libzfs_core.so OLD_LIBS+=usr/lib32/libzfs_core.so.2 OLD_FILES+=usr/lib32/libzfs_core_p.a OLD_FILES+=usr/lib32/libzfs_p.a OLD_FILES+=usr/lib32/libzpool.a OLD_FILES+=usr/lib32/libzpool.so OLD_LIBS+=usr/lib32/libzpool.so.2 .endif OLD_FILES+=usr/sbin/zdb OLD_FILES+=usr/share/man/man8/zdb.8.gz OLD_FILES+=usr/share/man/man8/zfs.8.gz OLD_FILES+=usr/share/man/man8/zpool.8.gz .endif .if ${MK_CLANG} == no OLD_FILES+=usr/bin/clang OLD_FILES+=usr/bin/clang++ OLD_FILES+=usr/bin/clang-cpp OLD_FILES+=usr/bin/clang-tblgen OLD_FILES+=usr/bin/tblgen OLD_FILES+=usr/lib/clang/3.6.0/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/3.6.0/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/3.6.0/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/3.6.0/include/adxintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/altivec.h OLD_FILES+=usr/lib/clang/3.6.0/include/ammintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/arm_acle.h OLD_FILES+=usr/lib/clang/3.6.0/include/arm_neon.h OLD_FILES+=usr/lib/clang/3.6.0/include/avx2intrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/avxintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/bmiintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/cpuid.h OLD_FILES+=usr/lib/clang/3.6.0/include/emmintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/f16cintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/fma4intrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/fmaintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/ia32intrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/immintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/mm3dnow.h OLD_FILES+=usr/lib/clang/3.6.0/include/mm_malloc.h OLD_FILES+=usr/lib/clang/3.6.0/include/mmintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/module.modulemap OLD_FILES+=usr/lib/clang/3.6.0/include/nmmintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/pmmintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/popcntintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/rtmintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/shaintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/smmintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/tbmintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/tmmintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/wmmintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/x86intrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/xmmintrin.h OLD_FILES+=usr/lib/clang/3.6.0/include/xopintrin.h OLD_DIRS+=usr/lib/clang/3.6.0/include OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.san-i386.a OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.san-x86_64.a OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.ubsan-i386.a OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.ubsan-x86_64.a OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.ubsan_cxx-i386.a OLD_FILES+=usr/lib/clang/3.6.0/lib/freebsd/libclang_rt.ubsan_cxx-x86_64.a OLD_DIRS+=usr/lib/clang/3.6.0/lib/freebsd OLD_DIRS+=usr/lib/clang/3.6.0/lib OLD_DIRS+=usr/lib/clang/3.6.0 OLD_DIRS+=usr/lib/clang OLD_FILES+=usr/share/doc/llvm/clang/LICENSE.TXT OLD_DIRS+=usr/share/doc/llvm/clang OLD_FILES+=usr/share/doc/llvm/COPYRIGHT.regex OLD_FILES+=usr/share/doc/llvm/LICENSE.TXT OLD_DIRS+=usr/share/doc/llvm OLD_FILES+=usr/share/man/man1/clang.1.gz OLD_FILES+=usr/share/man/man1/clang++.1.gz OLD_FILES+=usr/share/man/man1/clang-cpp.1.gz OLD_FILES+=usr/share/man/man1/tblgen.1.gz .endif .if ${MK_CLANG_EXTRAS} == no OLD_FILES+=usr/bin/bugpoint OLD_FILES+=usr/bin/llc OLD_FILES+=usr/bin/lli OLD_FILES+=usr/bin/llvm-ar OLD_FILES+=usr/bin/llvm-as OLD_FILES+=usr/bin/llvm-bcanalyzer OLD_FILES+=usr/bin/llvm-diff OLD_FILES+=usr/bin/llvm-dis OLD_FILES+=usr/bin/llvm-extract OLD_FILES+=usr/bin/llvm-link OLD_FILES+=usr/bin/llvm-mc OLD_FILES+=usr/bin/llvm-nm OLD_FILES+=usr/bin/llvm-objdump OLD_FILES+=usr/bin/llvm-rtdyld OLD_FILES+=usr/bin/llvm-symbolizer OLD_FILES+=usr/bin/macho-dump OLD_FILES+=usr/bin/opt OLD_FILES+=usr/share/man/man1/bugpoint.1.gz OLD_FILES+=usr/share/man/man1/llc.1.gz OLD_FILES+=usr/share/man/man1/lli.1.gz OLD_FILES+=usr/share/man/man1/llvm-ar.1.gz OLD_FILES+=usr/share/man/man1/llvm-as.1.gz OLD_FILES+=usr/share/man/man1/llvm-bcanalyzer.1.gz OLD_FILES+=usr/share/man/man1/llvm-diff.1.gz OLD_FILES+=usr/share/man/man1/llvm-dis.1.gz OLD_FILES+=usr/share/man/man1/llvm-extract.1.gz OLD_FILES+=usr/share/man/man1/llvm-link.1.gz OLD_FILES+=usr/share/man/man1/llvm-nm.1.gz OLD_FILES+=usr/share/man/man1/llvm-symbolizer.1.gz OLD_FILES+=usr/share/man/man1/opt.1.gz .endif .if ${MK_CPP} == no OLD_FILES+=usr/bin/cpp OLD_FILES+=usr/share/man/man1/cpp.1.gz .endif #.if ${MK_CRYPT} == no # to be filled in #.endif .if ${MK_CTM} == no OLD_FILES+=usr/sbin/ctm OLD_FILES+=usr/sbin/ctm_dequeue OLD_FILES+=usr/sbin/ctm_rmail OLD_FILES+=usr/sbin/ctm_smail OLD_FILES+=usr/share/man/man1/ctm.1.gz OLD_FILES+=usr/share/man/man1/ctm_dequeue.1.gz OLD_FILES+=usr/share/man/man1/ctm_rmail.1.gz OLD_FILES+=usr/share/man/man1/ctm_smail.1.gz OLD_FILES+=usr/share/man/man5/ctm.5.gz .endif .if ${MK_CUSE} == no OLD_FILES+=usr/include/fs/cuse/cuse_defs.h OLD_FILES+=usr/include/fs/cuse/cuse_ioctl.h OLD_FILES+=usr/include/cuse.h OLD_FILES+=usr/lib/libcuse.a OLD_LIBS+=usr/lib/libcuse.so.1 OLD_FILES+=usr/lib/libcuse_p.a OLD_FILES+=usr/share/man/man3/cuse.3.gz OLD_FILES+=usr/share/man/man3/cuse_alloc_unit_number.3.gz OLD_FILES+=usr/share/man/man3/cuse_alloc_unit_number_by_id.3.gz OLD_FILES+=usr/share/man/man3/cuse_copy_in.3.gz OLD_FILES+=usr/share/man/man3/cuse_copy_out.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_create.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_destroy.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_get_current.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_get_per_file_handle.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_get_priv0.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_get_priv1.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_set_per_file_handle.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_set_priv0.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_set_priv1.3.gz OLD_FILES+=usr/share/man/man3/cuse_free_unit_number.3.gz OLD_FILES+=usr/share/man/man3/cuse_free_unit_number_by_id.3.gz OLD_FILES+=usr/share/man/man3/cuse_get_local.3.gz OLD_FILES+=usr/share/man/man3/cuse_got_peer_signal.3.gz OLD_FILES+=usr/share/man/man3/cuse_init.3.gz OLD_FILES+=usr/share/man/man3/cuse_is_vmalloc_addr.3.gz OLD_FILES+=usr/share/man/man3/cuse_poll_wakeup.3.gz OLD_FILES+=usr/share/man/man3/cuse_set_local.3.gz OLD_FILES+=usr/share/man/man3/cuse_uninit.3.gz OLD_FILES+=usr/share/man/man3/cuse_vmalloc.3.gz OLD_FILES+=usr/share/man/man3/cuse_vmfree.3.gz OLD_FILES+=usr/share/man/man3/cuse_vmoffset.3.gz OLD_FILES+=usr/share/man/man3/cuse_wait_and_process.3.gz OLD_DIRS+=usr/include/fs/cuse .endif # devd(8) not listed here on purpose .if ${MK_CXX} == no OLD_FILES+=usr/bin/CC OLD_FILES+=usr/bin/c++ .if ${MK_ELFTOOLCHAIN_TOOLS} == no OLD_FILES+=usr/bin/c++filt .endif OLD_FILES+=usr/bin/g++ OLD_FILES+=usr/libexec/cc1plus .endif .if ${MK_FMTREE} == no OLD_FILES+=usr/sbin/fmtree OLD_FILES+=usr/share/man/man8/fmtree.8.gz .endif .if ${MK_GNUCXX} == no OLD_FILES+=usr/bin/g++ OLD_FILES+=usr/include/c++/4.2/algorithm OLD_FILES+=usr/include/c++/4.2/backward/algo.h OLD_FILES+=usr/include/c++/4.2/backward/algobase.h OLD_FILES+=usr/include/c++/4.2/backward/alloc.h OLD_FILES+=usr/include/c++/4.2/backward/backward_warning.h OLD_FILES+=usr/include/c++/4.2/backward/bvector.h OLD_FILES+=usr/include/c++/4.2/backward/complex.h OLD_FILES+=usr/include/c++/4.2/backward/defalloc.h OLD_FILES+=usr/include/c++/4.2/backward/deque.h OLD_FILES+=usr/include/c++/4.2/backward/fstream.h OLD_FILES+=usr/include/c++/4.2/backward/function.h OLD_FILES+=usr/include/c++/4.2/backward/hash_map.h OLD_FILES+=usr/include/c++/4.2/backward/hash_set.h OLD_FILES+=usr/include/c++/4.2/backward/hashtable.h OLD_FILES+=usr/include/c++/4.2/backward/heap.h OLD_FILES+=usr/include/c++/4.2/backward/iomanip.h OLD_FILES+=usr/include/c++/4.2/backward/iostream.h OLD_FILES+=usr/include/c++/4.2/backward/istream.h OLD_FILES+=usr/include/c++/4.2/backward/iterator.h OLD_FILES+=usr/include/c++/4.2/backward/list.h OLD_FILES+=usr/include/c++/4.2/backward/map.h OLD_FILES+=usr/include/c++/4.2/backward/multimap.h OLD_FILES+=usr/include/c++/4.2/backward/multiset.h OLD_FILES+=usr/include/c++/4.2/backward/new.h OLD_FILES+=usr/include/c++/4.2/backward/ostream.h OLD_FILES+=usr/include/c++/4.2/backward/pair.h OLD_FILES+=usr/include/c++/4.2/backward/queue.h OLD_FILES+=usr/include/c++/4.2/backward/rope.h OLD_FILES+=usr/include/c++/4.2/backward/set.h OLD_FILES+=usr/include/c++/4.2/backward/slist.h OLD_FILES+=usr/include/c++/4.2/backward/stack.h OLD_FILES+=usr/include/c++/4.2/backward/stream.h OLD_FILES+=usr/include/c++/4.2/backward/streambuf.h OLD_FILES+=usr/include/c++/4.2/backward/strstream OLD_FILES+=usr/include/c++/4.2/backward/tempbuf.h OLD_FILES+=usr/include/c++/4.2/backward/tree.h OLD_FILES+=usr/include/c++/4.2/backward/vector.h OLD_FILES+=usr/include/c++/4.2/bits/allocator.h OLD_FILES+=usr/include/c++/4.2/bits/atomic_word.h OLD_FILES+=usr/include/c++/4.2/bits/basic_file.h OLD_FILES+=usr/include/c++/4.2/bits/basic_ios.h OLD_FILES+=usr/include/c++/4.2/bits/basic_ios.tcc OLD_FILES+=usr/include/c++/4.2/bits/basic_string.h OLD_FILES+=usr/include/c++/4.2/bits/basic_string.tcc OLD_FILES+=usr/include/c++/4.2/bits/boost_concept_check.h OLD_FILES+=usr/include/c++/4.2/bits/c++allocator.h OLD_FILES+=usr/include/c++/4.2/bits/c++config.h OLD_FILES+=usr/include/c++/4.2/bits/c++io.h OLD_FILES+=usr/include/c++/4.2/bits/c++locale.h OLD_FILES+=usr/include/c++/4.2/bits/c++locale_internal.h OLD_FILES+=usr/include/c++/4.2/bits/char_traits.h OLD_FILES+=usr/include/c++/4.2/bits/cmath.tcc OLD_FILES+=usr/include/c++/4.2/bits/codecvt.h OLD_FILES+=usr/include/c++/4.2/bits/compatibility.h OLD_FILES+=usr/include/c++/4.2/bits/concept_check.h OLD_FILES+=usr/include/c++/4.2/bits/cpp_type_traits.h OLD_FILES+=usr/include/c++/4.2/bits/cpu_defines.h OLD_FILES+=usr/include/c++/4.2/bits/ctype_base.h OLD_FILES+=usr/include/c++/4.2/bits/ctype_inline.h OLD_FILES+=usr/include/c++/4.2/bits/ctype_noninline.h OLD_FILES+=usr/include/c++/4.2/bits/cxxabi_tweaks.h OLD_FILES+=usr/include/c++/4.2/bits/deque.tcc OLD_FILES+=usr/include/c++/4.2/bits/fstream.tcc OLD_FILES+=usr/include/c++/4.2/bits/functexcept.h OLD_FILES+=usr/include/c++/4.2/bits/gslice.h OLD_FILES+=usr/include/c++/4.2/bits/gslice_array.h OLD_FILES+=usr/include/c++/4.2/bits/gthr-default.h OLD_FILES+=usr/include/c++/4.2/bits/gthr-posix.h OLD_FILES+=usr/include/c++/4.2/bits/gthr-single.h OLD_FILES+=usr/include/c++/4.2/bits/gthr-tpf.h OLD_FILES+=usr/include/c++/4.2/bits/gthr.h OLD_FILES+=usr/include/c++/4.2/bits/indirect_array.h OLD_FILES+=usr/include/c++/4.2/bits/ios_base.h OLD_FILES+=usr/include/c++/4.2/bits/istream.tcc OLD_FILES+=usr/include/c++/4.2/bits/list.tcc OLD_FILES+=usr/include/c++/4.2/bits/locale_classes.h OLD_FILES+=usr/include/c++/4.2/bits/locale_facets.h OLD_FILES+=usr/include/c++/4.2/bits/locale_facets.tcc OLD_FILES+=usr/include/c++/4.2/bits/localefwd.h OLD_FILES+=usr/include/c++/4.2/bits/mask_array.h OLD_FILES+=usr/include/c++/4.2/bits/messages_members.h OLD_FILES+=usr/include/c++/4.2/bits/os_defines.h OLD_FILES+=usr/include/c++/4.2/bits/ostream.tcc OLD_FILES+=usr/include/c++/4.2/bits/ostream_insert.h OLD_FILES+=usr/include/c++/4.2/bits/postypes.h OLD_FILES+=usr/include/c++/4.2/bits/slice_array.h OLD_FILES+=usr/include/c++/4.2/bits/sstream.tcc OLD_FILES+=usr/include/c++/4.2/bits/stl_algo.h OLD_FILES+=usr/include/c++/4.2/bits/stl_algobase.h OLD_FILES+=usr/include/c++/4.2/bits/stl_bvector.h OLD_FILES+=usr/include/c++/4.2/bits/stl_construct.h OLD_FILES+=usr/include/c++/4.2/bits/stl_deque.h OLD_FILES+=usr/include/c++/4.2/bits/stl_function.h OLD_FILES+=usr/include/c++/4.2/bits/stl_heap.h OLD_FILES+=usr/include/c++/4.2/bits/stl_iterator.h OLD_FILES+=usr/include/c++/4.2/bits/stl_iterator_base_funcs.h OLD_FILES+=usr/include/c++/4.2/bits/stl_iterator_base_types.h OLD_FILES+=usr/include/c++/4.2/bits/stl_list.h OLD_FILES+=usr/include/c++/4.2/bits/stl_map.h OLD_FILES+=usr/include/c++/4.2/bits/stl_multimap.h OLD_FILES+=usr/include/c++/4.2/bits/stl_multiset.h OLD_FILES+=usr/include/c++/4.2/bits/stl_numeric.h OLD_FILES+=usr/include/c++/4.2/bits/stl_pair.h OLD_FILES+=usr/include/c++/4.2/bits/stl_queue.h OLD_FILES+=usr/include/c++/4.2/bits/stl_raw_storage_iter.h OLD_FILES+=usr/include/c++/4.2/bits/stl_relops.h OLD_FILES+=usr/include/c++/4.2/bits/stl_set.h OLD_FILES+=usr/include/c++/4.2/bits/stl_stack.h OLD_FILES+=usr/include/c++/4.2/bits/stl_tempbuf.h OLD_FILES+=usr/include/c++/4.2/bits/stl_tree.h OLD_FILES+=usr/include/c++/4.2/bits/stl_uninitialized.h OLD_FILES+=usr/include/c++/4.2/bits/stl_vector.h OLD_FILES+=usr/include/c++/4.2/bits/stream_iterator.h OLD_FILES+=usr/include/c++/4.2/bits/streambuf.tcc OLD_FILES+=usr/include/c++/4.2/bits/streambuf_iterator.h OLD_FILES+=usr/include/c++/4.2/bits/stringfwd.h OLD_FILES+=usr/include/c++/4.2/bits/time_members.h OLD_FILES+=usr/include/c++/4.2/bits/valarray_after.h OLD_FILES+=usr/include/c++/4.2/bits/valarray_array.h OLD_FILES+=usr/include/c++/4.2/bits/valarray_array.tcc OLD_FILES+=usr/include/c++/4.2/bits/valarray_before.h OLD_FILES+=usr/include/c++/4.2/bits/vector.tcc OLD_FILES+=usr/include/c++/4.2/bitset OLD_FILES+=usr/include/c++/4.2/cassert OLD_FILES+=usr/include/c++/4.2/cctype OLD_FILES+=usr/include/c++/4.2/cerrno OLD_FILES+=usr/include/c++/4.2/cfloat OLD_FILES+=usr/include/c++/4.2/ciso646 OLD_FILES+=usr/include/c++/4.2/climits OLD_FILES+=usr/include/c++/4.2/clocale OLD_FILES+=usr/include/c++/4.2/cmath OLD_FILES+=usr/include/c++/4.2/complex OLD_FILES+=usr/include/c++/4.2/csetjmp OLD_FILES+=usr/include/c++/4.2/csignal OLD_FILES+=usr/include/c++/4.2/cstdarg OLD_FILES+=usr/include/c++/4.2/cstddef OLD_FILES+=usr/include/c++/4.2/cstdio OLD_FILES+=usr/include/c++/4.2/cstdlib OLD_FILES+=usr/include/c++/4.2/cstring OLD_FILES+=usr/include/c++/4.2/ctime OLD_FILES+=usr/include/c++/4.2/cwchar OLD_FILES+=usr/include/c++/4.2/cwctype OLD_FILES+=usr/include/c++/4.2/cxxabi.h OLD_FILES+=usr/include/c++/4.2/debug/bitset OLD_FILES+=usr/include/c++/4.2/debug/debug.h OLD_FILES+=usr/include/c++/4.2/debug/deque OLD_FILES+=usr/include/c++/4.2/debug/formatter.h OLD_FILES+=usr/include/c++/4.2/debug/functions.h OLD_FILES+=usr/include/c++/4.2/debug/hash_map OLD_FILES+=usr/include/c++/4.2/debug/hash_map.h OLD_FILES+=usr/include/c++/4.2/debug/hash_multimap.h OLD_FILES+=usr/include/c++/4.2/debug/hash_multiset.h OLD_FILES+=usr/include/c++/4.2/debug/hash_set OLD_FILES+=usr/include/c++/4.2/debug/hash_set.h OLD_FILES+=usr/include/c++/4.2/debug/list OLD_FILES+=usr/include/c++/4.2/debug/macros.h OLD_FILES+=usr/include/c++/4.2/debug/map OLD_FILES+=usr/include/c++/4.2/debug/map.h OLD_FILES+=usr/include/c++/4.2/debug/multimap.h OLD_FILES+=usr/include/c++/4.2/debug/multiset.h OLD_FILES+=usr/include/c++/4.2/debug/safe_base.h OLD_FILES+=usr/include/c++/4.2/debug/safe_iterator.h OLD_FILES+=usr/include/c++/4.2/debug/safe_iterator.tcc OLD_FILES+=usr/include/c++/4.2/debug/safe_sequence.h OLD_FILES+=usr/include/c++/4.2/debug/set OLD_FILES+=usr/include/c++/4.2/debug/set.h OLD_FILES+=usr/include/c++/4.2/debug/string OLD_FILES+=usr/include/c++/4.2/debug/vector OLD_FILES+=usr/include/c++/4.2/deque OLD_FILES+=usr/include/c++/4.2/exception OLD_FILES+=usr/include/c++/4.2/exception_defines.h OLD_FILES+=usr/include/c++/4.2/ext/algorithm OLD_FILES+=usr/include/c++/4.2/ext/array_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/atomicity.h OLD_FILES+=usr/include/c++/4.2/ext/bitmap_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/codecvt_specializations.h OLD_FILES+=usr/include/c++/4.2/ext/concurrence.h OLD_FILES+=usr/include/c++/4.2/ext/debug_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/functional OLD_FILES+=usr/include/c++/4.2/ext/hash_fun.h OLD_FILES+=usr/include/c++/4.2/ext/hash_map OLD_FILES+=usr/include/c++/4.2/ext/hash_set OLD_FILES+=usr/include/c++/4.2/ext/hashtable.h OLD_FILES+=usr/include/c++/4.2/ext/iterator OLD_FILES+=usr/include/c++/4.2/ext/malloc_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/memory OLD_FILES+=usr/include/c++/4.2/ext/mt_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/new_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/numeric OLD_FILES+=usr/include/c++/4.2/ext/numeric_traits.h OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/assoc_container.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/basic_tree_policy/basic_tree_policy_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/basic_tree_policy/null_node_metadata.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/basic_tree_policy/traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/basic_types.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/bin_search_tree_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/cond_dtor_entry_dealtor.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/cond_key_dtor_entry_dealtor.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/iterators_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/node_iterators.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/point_iterators.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/policy_access_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/r_erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/rotate_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/bin_search_tree_/traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/binary_heap_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/const_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/const_point_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/entry_cmp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/entry_pred.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/iterators_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/policy_access_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/resize_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binary_heap_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_/binomial_heap_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/binomial_heap_base_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/binomial_heap_base_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/cc_ht_map_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/cmp_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/cond_key_dtor_entry_dealtor.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/constructor_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/constructor_destructor_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/constructor_destructor_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/debug_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/debug_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/entry_list_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/erase_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/erase_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/find_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/insert_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/insert_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/iterators_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/policy_access_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/resize_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/resize_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/resize_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/size_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/standard_policies.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cc_hash_table_map_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/cond_dealtor.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/container_base_dispatch.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/eq_fn/eq_by_less.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/eq_fn/hash_eq_fn.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/constructor_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/constructor_destructor_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/constructor_destructor_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/debug_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/debug_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/erase_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/erase_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/find_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/find_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/gp_ht_map_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/insert_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/insert_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/iterator_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/policy_access_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/resize_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/resize_no_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/resize_store_hash_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/standard_policies.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/gp_hash_table_map_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/direct_mask_range_hashing_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/direct_mod_range_hashing_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/linear_probe_fn_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/mask_based_range_hashing.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/mod_based_range_hashing.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/probe_fn_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/quadratic_probe_fn_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/ranged_hash_fn.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/ranged_probe_fn.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/sample_probe_fn.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/sample_range_hashing.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/sample_ranged_hash_fn.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/hash_fn/sample_ranged_probe_fn.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/const_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/const_point_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/iterators_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/left_child_next_sibling_heap_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/node.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/null_metadata.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/policy_access_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/left_child_next_sibling_heap_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/constructor_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/entry_metadata_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/iterators_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/lu_map_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_map_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_policy/counter_lu_metadata.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_policy/counter_lu_policy_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_policy/mtf_lu_policy_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/list_update_policy/sample_update_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/map_debug_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/cond_dtor.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/iterators_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/node_iterators.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/ov_tree_map_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/policy_access_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/ov_tree_map_/traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/pairing_heap_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pairing_heap_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/child_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/cond_dtor_entry_dealtor.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/const_child_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/head.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/insert_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/internal_node.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/iterators_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/leaf.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/node_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/node_iterators.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/node_metadata_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/pat_trie_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/point_iterators.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/policy_access_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/r_erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/rotate_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/split_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/split_join_branch_bag.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/synth_e_access_traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/pat_trie_/update_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/priority_queue_base_dispatch.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/node.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/rb_tree_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rb_tree_map_/traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/rc.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/rc_binomial_heap_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/rc_binomial_heap_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/cc_hash_max_collision_check_resize_trigger_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/hash_exponential_size_policy_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/hash_load_check_resize_trigger_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/hash_load_check_resize_trigger_size_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/hash_prime_size_policy_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/hash_standard_resize_policy_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/sample_resize_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/sample_resize_trigger.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/resize_policy/sample_size_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/info_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/node.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/splay_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/splay_tree_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/splay_tree_/traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/standard_policies.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/constructors_destructor_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/debug_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/erase_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/find_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/insert_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/split_join_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/thin_heap_.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/thin_heap_/trace_fn_imps.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/tree_policy/node_metadata_selector.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/tree_policy/null_node_update_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/tree_policy/order_statistics_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/tree_policy/sample_tree_node_update.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/tree_trace_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/node_metadata_selector.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/null_node_update_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/order_statistics_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/prefix_search_node_update_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/sample_trie_e_access_traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/sample_trie_node_update.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/string_trie_e_access_traits_imp.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/trie_policy/trie_policy_base.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/type_utils.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/types_traits.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/unordered_iterator/const_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/unordered_iterator/const_point_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/unordered_iterator/iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/detail/unordered_iterator/point_iterator.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/exception.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/hash_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/list_update_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/priority_queue.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/tag_and_trait.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/tree_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pb_ds/trie_policy.hpp OLD_FILES+=usr/include/c++/4.2/ext/pod_char_traits.h OLD_FILES+=usr/include/c++/4.2/ext/pool_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/rb_tree OLD_FILES+=usr/include/c++/4.2/ext/rc_string_base.h OLD_FILES+=usr/include/c++/4.2/ext/rope OLD_FILES+=usr/include/c++/4.2/ext/ropeimpl.h OLD_FILES+=usr/include/c++/4.2/ext/slist OLD_FILES+=usr/include/c++/4.2/ext/sso_string_base.h OLD_FILES+=usr/include/c++/4.2/ext/stdio_filebuf.h OLD_FILES+=usr/include/c++/4.2/ext/stdio_sync_filebuf.h OLD_FILES+=usr/include/c++/4.2/ext/throw_allocator.h OLD_FILES+=usr/include/c++/4.2/ext/type_traits.h OLD_FILES+=usr/include/c++/4.2/ext/typelist.h OLD_FILES+=usr/include/c++/4.2/ext/vstring.h OLD_FILES+=usr/include/c++/4.2/ext/vstring.tcc OLD_FILES+=usr/include/c++/4.2/ext/vstring_fwd.h OLD_FILES+=usr/include/c++/4.2/ext/vstring_util.h OLD_FILES+=usr/include/c++/4.2/fstream OLD_FILES+=usr/include/c++/4.2/functional OLD_FILES+=usr/include/c++/4.2/iomanip OLD_FILES+=usr/include/c++/4.2/ios OLD_FILES+=usr/include/c++/4.2/iosfwd OLD_FILES+=usr/include/c++/4.2/iostream OLD_FILES+=usr/include/c++/4.2/istream OLD_FILES+=usr/include/c++/4.2/iterator OLD_FILES+=usr/include/c++/4.2/limits OLD_FILES+=usr/include/c++/4.2/list OLD_FILES+=usr/include/c++/4.2/locale OLD_FILES+=usr/include/c++/4.2/map OLD_FILES+=usr/include/c++/4.2/memory OLD_FILES+=usr/include/c++/4.2/new OLD_FILES+=usr/include/c++/4.2/numeric OLD_FILES+=usr/include/c++/4.2/ostream OLD_FILES+=usr/include/c++/4.2/queue OLD_FILES+=usr/include/c++/4.2/set OLD_FILES+=usr/include/c++/4.2/sstream OLD_FILES+=usr/include/c++/4.2/stack OLD_FILES+=usr/include/c++/4.2/stdexcept OLD_FILES+=usr/include/c++/4.2/streambuf OLD_FILES+=usr/include/c++/4.2/string OLD_FILES+=usr/include/c++/4.2/tr1/array OLD_FILES+=usr/include/c++/4.2/tr1/bind_iterate.h OLD_FILES+=usr/include/c++/4.2/tr1/bind_repeat.h OLD_FILES+=usr/include/c++/4.2/tr1/boost_shared_ptr.h OLD_FILES+=usr/include/c++/4.2/tr1/cctype OLD_FILES+=usr/include/c++/4.2/tr1/cfenv OLD_FILES+=usr/include/c++/4.2/tr1/cfloat OLD_FILES+=usr/include/c++/4.2/tr1/cinttypes OLD_FILES+=usr/include/c++/4.2/tr1/climits OLD_FILES+=usr/include/c++/4.2/tr1/cmath OLD_FILES+=usr/include/c++/4.2/tr1/common.h OLD_FILES+=usr/include/c++/4.2/tr1/complex OLD_FILES+=usr/include/c++/4.2/tr1/cstdarg OLD_FILES+=usr/include/c++/4.2/tr1/cstdbool OLD_FILES+=usr/include/c++/4.2/tr1/cstdint OLD_FILES+=usr/include/c++/4.2/tr1/cstdio OLD_FILES+=usr/include/c++/4.2/tr1/cstdlib OLD_FILES+=usr/include/c++/4.2/tr1/ctgmath OLD_FILES+=usr/include/c++/4.2/tr1/ctime OLD_FILES+=usr/include/c++/4.2/tr1/ctype.h OLD_FILES+=usr/include/c++/4.2/tr1/cwchar OLD_FILES+=usr/include/c++/4.2/tr1/cwctype OLD_FILES+=usr/include/c++/4.2/tr1/fenv.h OLD_FILES+=usr/include/c++/4.2/tr1/float.h OLD_FILES+=usr/include/c++/4.2/tr1/functional OLD_FILES+=usr/include/c++/4.2/tr1/functional_hash.h OLD_FILES+=usr/include/c++/4.2/tr1/functional_iterate.h OLD_FILES+=usr/include/c++/4.2/tr1/hashtable OLD_FILES+=usr/include/c++/4.2/tr1/hashtable_policy.h OLD_FILES+=usr/include/c++/4.2/tr1/inttypes.h OLD_FILES+=usr/include/c++/4.2/tr1/limits.h OLD_FILES+=usr/include/c++/4.2/tr1/math.h OLD_FILES+=usr/include/c++/4.2/tr1/memory OLD_FILES+=usr/include/c++/4.2/tr1/mu_iterate.h OLD_FILES+=usr/include/c++/4.2/tr1/random OLD_FILES+=usr/include/c++/4.2/tr1/random.tcc OLD_FILES+=usr/include/c++/4.2/tr1/ref_fwd.h OLD_FILES+=usr/include/c++/4.2/tr1/ref_wrap_iterate.h OLD_FILES+=usr/include/c++/4.2/tr1/repeat.h OLD_FILES+=usr/include/c++/4.2/tr1/stdarg.h OLD_FILES+=usr/include/c++/4.2/tr1/stdbool.h OLD_FILES+=usr/include/c++/4.2/tr1/stdint.h OLD_FILES+=usr/include/c++/4.2/tr1/stdio.h OLD_FILES+=usr/include/c++/4.2/tr1/stdlib.h OLD_FILES+=usr/include/c++/4.2/tr1/tgmath.h OLD_FILES+=usr/include/c++/4.2/tr1/tuple OLD_FILES+=usr/include/c++/4.2/tr1/tuple_defs.h OLD_FILES+=usr/include/c++/4.2/tr1/tuple_iterate.h OLD_FILES+=usr/include/c++/4.2/tr1/type_traits OLD_FILES+=usr/include/c++/4.2/tr1/type_traits_fwd.h OLD_FILES+=usr/include/c++/4.2/tr1/unordered_map OLD_FILES+=usr/include/c++/4.2/tr1/unordered_set OLD_FILES+=usr/include/c++/4.2/tr1/utility OLD_FILES+=usr/include/c++/4.2/tr1/wchar.h OLD_FILES+=usr/include/c++/4.2/tr1/wctype.h OLD_FILES+=usr/include/c++/4.2/typeinfo OLD_FILES+=usr/include/c++/4.2/utility OLD_FILES+=usr/include/c++/4.2/valarray OLD_FILES+=usr/include/c++/4.2/vector OLD_FILES+=usr/lib/libstdc++.a OLD_FILES+=usr/lib/libstdc++.so OLD_LIBS+=usr/lib/libstdc++.so.6 OLD_FILES+=usr/lib/libstdc++_p.a OLD_FILES+=usr/lib/libsupc++.a OLD_FILES+=usr/lib/libsupc++.so OLD_LIBS+=usr/lib/libsupc++.so.1 OLD_FILES+=usr/lib/libsupc++_p.a .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/lib32/libstdc++.a OLD_FILES+=usr/lib32/libstdc++.so OLD_LIBS+=usr/lib32/libstdc++.so.6 OLD_FILES+=usr/lib32/libstdc++_p.a OLD_FILES+=usr/lib32/libsupc++.a OLD_FILES+=usr/lib32/libsupc++.so OLD_LIBS+=usr/lib32/libsupc++.so.1 OLD_FILES+=usr/lib32/libsupc++_p.a .endif OLD_FILES+=usr/libexec/cc1plus .endif .if ${MK_DICT} == no OLD_FILES+=usr/share/dict/README OLD_FILES+=usr/share/dict/eign OLD_FILES+=usr/share/dict/freebsd OLD_FILES+=usr/share/dict/propernames OLD_FILES+=usr/share/dict/web2 OLD_FILES+=usr/share/dict/web2a OLD_FILES+=usr/share/dict/words OLD_DIRS+=usr/share/dict .endif .if ${MK_DMAGENT} == no OLD_FILES+=etc/dma/dma.conf OLD_FILES+=usr/libexec/dma OLD_FILES+=usr/libexec/dma-mbox-create OLD_FILES+=usr/share/man/man8/dma.8.gz OLD_FILES+=usr/share/examples/dma/mailer.conf .endif .if ${MK_EE} == no OLD_FILES+=usr/bin/edit OLD_FILES+=usr/bin/ee OLD_FILES+=usr/bin/ree OLD_FILES+=usr/share/man/man1/edit.1.gz OLD_FILES+=usr/share/man/man1/ee.1.gz OLD_FILES+=usr/share/man/man1/ree.1.gz OLD_FILES+=usr/share/nls/C/ee.cat OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/ee.cat OLD_FILES+=usr/share/nls/pl_PL.ISO8859-2/ee.cat OLD_FILES+=usr/share/nls/pt_BR.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/ee.cat OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/ee.cat .endif .if ${MK_ELFTOOLCHAIN_TOOLS} == no OLD_FILES+=usr/bin/elfcopy OLD_FILES+=usr/share/man/man1/elfcopy.1.gz .endif #.if ${MK_EXAMPLES} == no # to be filled in #.endif .if ${MK_FLOPPY} == no OLD_FILES+=usr/sbin/fdcontrol OLD_FILES+=usr/sbin/fdformat OLD_FILES+=usr/sbin/fdread OLD_FILES+=usr/sbin/fdwrite OLD_FILES+=usr/share/man/man1/fdformat.1.gz OLD_FILES+=usr/share/man/man1/fdread.1.gz OLD_FILES+=usr/share/man/man1/fdwrite.1.gz OLD_FILES+=usr/share/man/man8/fdcontrol.8.gz .endif .if ${MK_FORTH} == no OLD_FILES+=usr/share/man/man5/loader.conf.5.gz OLD_FILES+=usr/share/man/man8/beastie.4th.8.gz OLD_FILES+=usr/share/man/man8/brand.4th.8.gz OLD_FILES+=usr/share/man/man8/check-password.4th.8.gz OLD_FILES+=usr/share/man/man8/color.4th.8.gz OLD_FILES+=usr/share/man/man8/delay.4th.8.gz OLD_FILES+=usr/share/man/man8/loader.4th.8.gz OLD_FILES+=usr/share/man/man8/menu.4th.8.gz OLD_FILES+=usr/share/man/man8/menusets.4th.8.gz OLD_FILES+=usr/share/man/man8/version.4th.8.gz .endif .if ${MK_FREEBSD_UPDATE} == no OLD_FILES+=etc/freebsd-update.conf OLD_FILES+=usr/sbin/freebsd-update OLD_FILES+=usr/share/examples/etc/freebsd-update.conf OLD_FILES+=usr/share/man/man5/freebsd-update.conf.5.gz OLD_FILES+=usr/share/man/man8/freebsd-update.8.gz .endif .if ${MK_GAMES} == no OLD_FILES+=usr/bin/caesar OLD_FILES+=usr/bin/factor OLD_FILES+=usr/bin/fortune OLD_FILES+=usr/bin/grdc OLD_FILES+=usr/bin/morse OLD_FILES+=usr/bin/number OLD_FILES+=usr/bin/pom OLD_FILES+=usr/bin/primes OLD_FILES+=usr/bin/random OLD_FILES+=usr/bin/rot13 OLD_FILES+=usr/bin/strfile OLD_FILES+=usr/bin/unstr OLD_FILES+=usr/share/games/fortune/fortunes OLD_FILES+=usr/share/games/fortune/fortunes.dat OLD_FILES+=usr/share/games/fortune/freebsd-tips OLD_FILES+=usr/share/games/fortune/freebsd-tips.dat OLD_FILES+=usr/share/games/fortune/gerrold.limerick OLD_FILES+=usr/share/games/fortune/gerrold.limerick.dat OLD_FILES+=usr/share/games/fortune/limerick OLD_FILES+=usr/share/games/fortune/limerick.dat OLD_FILES+=usr/share/games/fortune/murphy OLD_FILES+=usr/share/games/fortune/murphy-o OLD_FILES+=usr/share/games/fortune/murphy-o.dat OLD_FILES+=usr/share/games/fortune/murphy.dat OLD_FILES+=usr/share/games/fortune/startrek OLD_FILES+=usr/share/games/fortune/startrek.dat OLD_FILES+=usr/share/games/fortune/zippy OLD_FILES+=usr/share/games/fortune/zippy.dat OLD_DIRS+=usr/share/games/fortune OLD_DIRS+=usr/share/games OLD_FILES+=usr/share/man/man6/caesar.6.gz OLD_FILES+=usr/share/man/man6/factor.6.gz OLD_FILES+=usr/share/man/man6/fortune.6.gz OLD_FILES+=usr/share/man/man6/grdc.6.gz OLD_FILES+=usr/share/man/man6/morse.6.gz OLD_FILES+=usr/share/man/man6/number.6.gz OLD_FILES+=usr/share/man/man6/pom.6.gz OLD_FILES+=usr/share/man/man6/primes.6.gz OLD_FILES+=usr/share/man/man6/random.6.gz OLD_FILES+=usr/share/man/man6/rot13.6.gz OLD_FILES+=usr/share/man/man8/strfile.8.gz OLD_FILES+=usr/share/man/man8/unstr.8.gz .endif .if ${MK_GCC} == no .if ${MK_ELFTOOLCHAIN_TOOLS} == no OLD_FILES+=usr/bin/c++filt .endif OLD_FILES+=usr/bin/g++ OLD_FILES+=usr/bin/gcc OLD_FILES+=usr/bin/gcov OLD_FILES+=usr/bin/gcpp OLD_FILES+=usr/bin/gperf .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386" OLD_FILES+=usr/include/gcc/4.2/__wmmintrin_aes.h OLD_FILES+=usr/include/gcc/4.2/__wmmintrin_pclmul.h OLD_FILES+=usr/include/gcc/4.2/ammintrin.h OLD_FILES+=usr/include/gcc/4.2/emmintrin.h OLD_FILES+=usr/include/gcc/4.2/mm3dnow.h OLD_FILES+=usr/include/gcc/4.2/mm_malloc.h OLD_FILES+=usr/include/gcc/4.2/mmintrin.h OLD_FILES+=usr/include/gcc/4.2/pmmintrin.h OLD_FILES+=usr/include/gcc/4.2/tmmintrin.h OLD_FILES+=usr/include/gcc/4.2/wmmintrin.h OLD_FILES+=usr/include/gcc/4.2/xmmintrin.h .elif ${TARGET_ARCH} == "arm" OLD_FILES+=usr/include/gcc/4.2/mmintrin.h .elif ${TARGET_ARCH} == "powerpc" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/include/gcc/4.2/altivec.h OLD_FILES+=usr/include/gcc/4.2/ppc-asm.h OLD_FILES+=usr/include/gcc/4.2/spe.h .endif +OLD_FILES+=usr/include/omp.h +OLD_FILES+=usr/lib/libgomp.a +OLD_FILES+=usr/lib/libgomp.so +OLD_FILES+=usr/lib/libgomp.so.1 +OLD_FILES+=usr/lib/libgomp_p.a OLD_FILES+=usr/libexec/cc1 OLD_FILES+=usr/libexec/cc1plus OLD_FILES+=usr/share/info/cpp.info.gz OLD_FILES+=usr/share/info/cppinternals.info.gz OLD_FILES+=usr/share/info/gcc.info.gz OLD_FILES+=usr/share/info/gccint.info.gz OLD_FILES+=usr/share/info/gperf.info.gz OLD_FILES+=usr/share/man/man1/g++.1.gz OLD_FILES+=usr/share/man/man1/gcc.1.gz OLD_FILES+=usr/share/man/man1/gcov.1.gz OLD_FILES+=usr/share/man/man1/gcpp.1.gz OLD_FILES+=usr/share/man/man1/gperf.1.gz OLD_FILES+=usr/share/man/man1/gperf.7.gz .endif .if ${MK_GCOV} == no OLD_FILES+=usr/bin/gcov OLD_FILES+=usr/share/man/man1/gcov.1.gz .endif .if ${MK_GDB} == no OLD_FILES+=usr/bin/gdb OLD_FILES+=usr/bin/gdbserver OLD_FILES+=usr/bin/gdbtui OLD_FILES+=usr/bin/kgdb OLD_FILES+=usr/share/info/gdb.info.gz OLD_FILES+=usr/share/info/gdbint.info.gz OLD_FILES+=usr/share/info/stabs.info.gz OLD_FILES+=usr/share/man/man1/gdb.1.gz OLD_FILES+=usr/share/man/man1/gdbserver.1.gz OLD_FILES+=usr/share/man/man1/kgdb.1.gz .endif .if ${MK_GPIO} == no OLD_FILES+=usr/include/libgpio.h OLD_FILES+=usr/lib/libgpio.a OLD_FILES+=usr/lib/libgpio.so OLD_LIBS+=usr/lib/libgpio.so.0 OLD_FILES+=usr/lib/libgpio_p.a OLD_FILES+=usr/lib32/libgpio.a OLD_FILES+=usr/lib32/libgpio.so OLD_LIBS+=usr/lib32/libgpio.so.0 OLD_FILES+=usr/lib32/libgpio_p.a OLD_FILES+=usr/sbin/gpioctl OLD_FILES+=usr/share/man/man3/gpio.3.gz OLD_FILES+=usr/share/man/man3/gpio_close.3.gz OLD_FILES+=usr/share/man/man3/gpio_open.3.gz OLD_FILES+=usr/share/man/man3/gpio_open_device.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_config.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_get.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_high.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_input.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_invin.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_invout.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_list.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_low.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_opendrain.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_output.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_pulldown.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_pullup.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_pulsate.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_pushpull.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_set.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_set_flags.3.gz OLD_FILES+=usr/share/man/man3/gpio_pin_tristate.3.gz OLD_FILES+=usr/share/man/man8/gpioctl.8.gz .endif # Also includes vgrind(1) .if ${MK_GROFF} == no OLD_FILES+=usr/bin/addftinfo OLD_FILES+=usr/bin/afmtodit OLD_FILES+=usr/bin/eqn OLD_FILES+=usr/bin/grn OLD_FILES+=usr/bin/grodvi OLD_FILES+=usr/bin/groff OLD_FILES+=usr/bin/grog OLD_FILES+=usr/bin/grolbp OLD_FILES+=usr/bin/grolj4 OLD_FILES+=usr/bin/grops OLD_FILES+=usr/bin/grotty OLD_FILES+=usr/bin/hpftodit OLD_FILES+=usr/bin/indxbib OLD_FILES+=usr/bin/lkbib OLD_FILES+=usr/bin/lookbib OLD_FILES+=usr/bin/mmroff OLD_FILES+=usr/bin/neqn OLD_FILES+=usr/bin/nroff OLD_FILES+=usr/bin/pfbtops OLD_FILES+=usr/bin/pic OLD_FILES+=usr/bin/post-grohtml OLD_FILES+=usr/bin/pre-grohtml OLD_FILES+=usr/bin/psroff OLD_FILES+=usr/bin/refer OLD_FILES+=usr/bin/tbl OLD_FILES+=usr/bin/tfmtodit OLD_FILES+=usr/bin/troff OLD_FILES+=usr/bin/vgrind OLD_FILES+=usr/libexec/vfontedpr OLD_FILES+=usr/share/dict/eign OLD_FILES+=usr/share/doc/papers/beyond43.ascii.gz OLD_FILES+=usr/share/doc/papers/bio.ascii.gz OLD_FILES+=usr/share/doc/papers/contents.ascii.gz OLD_FILES+=usr/share/doc/papers/devfs.ascii.gz OLD_FILES+=usr/share/doc/papers/diskperf.ascii.gz OLD_FILES+=usr/share/doc/papers/fsinterface.ascii.gz OLD_FILES+=usr/share/doc/papers/hwpmc.ascii.gz OLD_FILES+=usr/share/doc/papers/jail.ascii.gz OLD_FILES+=usr/share/doc/papers/kernmalloc.ascii.gz OLD_FILES+=usr/share/doc/papers/kerntune.ascii.gz OLD_FILES+=usr/share/doc/papers/malloc.ascii.gz OLD_FILES+=usr/share/doc/papers/newvm.ascii.gz OLD_FILES+=usr/share/doc/papers/releng.ascii.gz OLD_FILES+=usr/share/doc/papers/sysperf.ascii.gz OLD_FILES+=usr/share/doc/papers/timecounter.ascii.gz OLD_FILES+=usr/share/doc/psd/01.cacm/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/02.implement/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/03.iosys/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/04.uprog/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/05.sysman/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/06.Clang/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/12.make/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/13.rcs/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/13.rcs/rcs_func.ascii.gz OLD_FILES+=usr/share/doc/psd/15.yacc/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/16.lex/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/17.m4/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/18.gprof/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/20.ipctut/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/21.ipc/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/22.rpcgen/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/23.rpc/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/24.xdr/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/25.xdrrfc/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/26.rpcrfc/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/27.nfsrfc/paper.ascii.gz OLD_FILES+=usr/share/doc/psd/Title.ascii.gz OLD_FILES+=usr/share/doc/psd/contents.ascii.gz OLD_FILES+=usr/share/doc/smm/01.setup/paper.ascii.gz OLD_FILES+=usr/share/doc/smm/02.config/paper.ascii.gz OLD_FILES+=usr/share/doc/smm/03.fsck/paper.ascii.gz OLD_FILES+=usr/share/doc/smm/04.quotas/paper.ascii.gz OLD_FILES+=usr/share/doc/smm/05.fastfs/paper.ascii.gz OLD_FILES+=usr/share/doc/smm/06.nfs/paper.ascii.gz OLD_FILES+=usr/share/doc/smm/07.lpd/paper.ascii.gz OLD_FILES+=usr/share/doc/smm/08.sendmailop/paper.ascii.gz OLD_FILES+=usr/share/doc/smm/11.timedop/paper.ascii.gz OLD_FILES+=usr/share/doc/smm/12.timed/paper.ascii.gz OLD_FILES+=usr/share/doc/smm/18.net/paper.ascii.gz OLD_FILES+=usr/share/doc/smm/Title.ascii.gz OLD_FILES+=usr/share/doc/smm/contents.ascii.gz OLD_FILES+=usr/share/doc/usd/04.csh/paper.ascii.gz OLD_FILES+=usr/share/doc/usd/05.dc/paper.ascii.gz OLD_FILES+=usr/share/doc/usd/06.bc/paper.ascii.gz OLD_FILES+=usr/share/doc/usd/07.mail/paper.ascii.gz OLD_FILES+=usr/share/doc/usd/10.exref/paper.ascii.gz OLD_FILES+=usr/share/doc/usd/10.exref/summary.ascii.gz OLD_FILES+=usr/share/doc/usd/11.edit/paper.ascii.gz OLD_FILES+=usr/share/doc/usd/12.vi/paper.ascii.gz OLD_FILES+=usr/share/doc/usd/12.vi/summary.ascii.gz OLD_FILES+=usr/share/doc/usd/12.vi/viapwh.ascii.gz OLD_FILES+=usr/share/doc/usd/13.viref/paper.ascii.gz OLD_FILES+=usr/share/doc/usd/18.msdiffs/paper.ascii.gz OLD_FILES+=usr/share/doc/usd/19.memacros/paper.ascii.gz OLD_FILES+=usr/share/doc/usd/20.meref/paper.ascii.gz OLD_FILES+=usr/share/doc/usd/21.troff/paper.ascii.gz OLD_FILES+=usr/share/doc/usd/22.trofftut/paper.ascii.gz OLD_FILES+=usr/share/doc/usd/Title.ascii.gz OLD_FILES+=usr/share/doc/usd/contents.ascii.gz OLD_FILES+=usr/share/groff_font/devX100-12/CB OLD_FILES+=usr/share/groff_font/devX100-12/CBI OLD_FILES+=usr/share/groff_font/devX100-12/CI OLD_FILES+=usr/share/groff_font/devX100-12/CR OLD_FILES+=usr/share/groff_font/devX100-12/DESC OLD_FILES+=usr/share/groff_font/devX100-12/HB OLD_FILES+=usr/share/groff_font/devX100-12/HBI OLD_FILES+=usr/share/groff_font/devX100-12/HI OLD_FILES+=usr/share/groff_font/devX100-12/HR OLD_FILES+=usr/share/groff_font/devX100-12/NB OLD_FILES+=usr/share/groff_font/devX100-12/NBI OLD_FILES+=usr/share/groff_font/devX100-12/NI OLD_FILES+=usr/share/groff_font/devX100-12/NR OLD_FILES+=usr/share/groff_font/devX100-12/S OLD_FILES+=usr/share/groff_font/devX100-12/TB OLD_FILES+=usr/share/groff_font/devX100-12/TBI OLD_FILES+=usr/share/groff_font/devX100-12/TI OLD_FILES+=usr/share/groff_font/devX100-12/TR OLD_DIRS+=usr/share/groff_font/devX100-12 OLD_FILES+=usr/share/groff_font/devX100/CB OLD_FILES+=usr/share/groff_font/devX100/CBI OLD_FILES+=usr/share/groff_font/devX100/CI OLD_FILES+=usr/share/groff_font/devX100/CR OLD_FILES+=usr/share/groff_font/devX100/DESC OLD_FILES+=usr/share/groff_font/devX100/HB OLD_FILES+=usr/share/groff_font/devX100/HBI OLD_FILES+=usr/share/groff_font/devX100/HI OLD_FILES+=usr/share/groff_font/devX100/HR OLD_FILES+=usr/share/groff_font/devX100/NB OLD_FILES+=usr/share/groff_font/devX100/NBI OLD_FILES+=usr/share/groff_font/devX100/NI OLD_FILES+=usr/share/groff_font/devX100/NR OLD_FILES+=usr/share/groff_font/devX100/S OLD_FILES+=usr/share/groff_font/devX100/TB OLD_FILES+=usr/share/groff_font/devX100/TBI OLD_FILES+=usr/share/groff_font/devX100/TI OLD_FILES+=usr/share/groff_font/devX100/TR OLD_DIRS+=usr/share/groff_font/devX100 OLD_FILES+=usr/share/groff_font/devX75-12/CB OLD_FILES+=usr/share/groff_font/devX75-12/CBI OLD_FILES+=usr/share/groff_font/devX75-12/CI OLD_FILES+=usr/share/groff_font/devX75-12/CR OLD_FILES+=usr/share/groff_font/devX75-12/DESC OLD_FILES+=usr/share/groff_font/devX75-12/HB OLD_FILES+=usr/share/groff_font/devX75-12/HBI OLD_FILES+=usr/share/groff_font/devX75-12/HI OLD_FILES+=usr/share/groff_font/devX75-12/HR OLD_FILES+=usr/share/groff_font/devX75-12/NB OLD_FILES+=usr/share/groff_font/devX75-12/NBI OLD_FILES+=usr/share/groff_font/devX75-12/NI OLD_FILES+=usr/share/groff_font/devX75-12/NR OLD_FILES+=usr/share/groff_font/devX75-12/S OLD_FILES+=usr/share/groff_font/devX75-12/TB OLD_FILES+=usr/share/groff_font/devX75-12/TBI OLD_FILES+=usr/share/groff_font/devX75-12/TI OLD_FILES+=usr/share/groff_font/devX75-12/TR OLD_DIRS+=usr/share/groff_font/devX75-12 OLD_FILES+=usr/share/groff_font/devX75/CB OLD_FILES+=usr/share/groff_font/devX75/CBI OLD_FILES+=usr/share/groff_font/devX75/CI OLD_FILES+=usr/share/groff_font/devX75/CR OLD_FILES+=usr/share/groff_font/devX75/DESC OLD_FILES+=usr/share/groff_font/devX75/HB OLD_FILES+=usr/share/groff_font/devX75/HBI OLD_FILES+=usr/share/groff_font/devX75/HI OLD_FILES+=usr/share/groff_font/devX75/HR OLD_FILES+=usr/share/groff_font/devX75/NB OLD_FILES+=usr/share/groff_font/devX75/NBI OLD_FILES+=usr/share/groff_font/devX75/NI OLD_FILES+=usr/share/groff_font/devX75/NR OLD_FILES+=usr/share/groff_font/devX75/S OLD_FILES+=usr/share/groff_font/devX75/TB OLD_FILES+=usr/share/groff_font/devX75/TBI OLD_FILES+=usr/share/groff_font/devX75/TI OLD_FILES+=usr/share/groff_font/devX75/TR OLD_DIRS+=usr/share/groff_font/devX75 OLD_FILES+=usr/share/groff_font/devascii/B OLD_FILES+=usr/share/groff_font/devascii/BI OLD_FILES+=usr/share/groff_font/devascii/CW OLD_FILES+=usr/share/groff_font/devascii/DESC OLD_FILES+=usr/share/groff_font/devascii/I OLD_FILES+=usr/share/groff_font/devascii/L OLD_FILES+=usr/share/groff_font/devascii/R OLD_FILES+=usr/share/groff_font/devascii/S OLD_DIRS+=usr/share/groff_font/devascii OLD_FILES+=usr/share/groff_font/devcp1047/B OLD_FILES+=usr/share/groff_font/devcp1047/BI OLD_FILES+=usr/share/groff_font/devcp1047/CW OLD_FILES+=usr/share/groff_font/devcp1047/DESC OLD_FILES+=usr/share/groff_font/devcp1047/I OLD_FILES+=usr/share/groff_font/devcp1047/L OLD_FILES+=usr/share/groff_font/devcp1047/R OLD_FILES+=usr/share/groff_font/devcp1047/S OLD_DIRS+=usr/share/groff_font/devcp1047 OLD_FILES+=usr/share/groff_font/devdvi/CW OLD_FILES+=usr/share/groff_font/devdvi/CWEC OLD_FILES+=usr/share/groff_font/devdvi/CWI OLD_FILES+=usr/share/groff_font/devdvi/CWIEC OLD_FILES+=usr/share/groff_font/devdvi/CWITC OLD_FILES+=usr/share/groff_font/devdvi/CWTC OLD_FILES+=usr/share/groff_font/devdvi/CompileFonts OLD_FILES+=usr/share/groff_font/devdvi/DESC OLD_FILES+=usr/share/groff_font/devdvi/EX OLD_FILES+=usr/share/groff_font/devdvi/HB OLD_FILES+=usr/share/groff_font/devdvi/HBEC OLD_FILES+=usr/share/groff_font/devdvi/HBI OLD_FILES+=usr/share/groff_font/devdvi/HBIEC OLD_FILES+=usr/share/groff_font/devdvi/HBITC OLD_FILES+=usr/share/groff_font/devdvi/HBTC OLD_FILES+=usr/share/groff_font/devdvi/HI OLD_FILES+=usr/share/groff_font/devdvi/HIEC OLD_FILES+=usr/share/groff_font/devdvi/HITC OLD_FILES+=usr/share/groff_font/devdvi/HR OLD_FILES+=usr/share/groff_font/devdvi/HREC OLD_FILES+=usr/share/groff_font/devdvi/HRTC OLD_FILES+=usr/share/groff_font/devdvi/MI OLD_FILES+=usr/share/groff_font/devdvi/Makefile OLD_FILES+=usr/share/groff_font/devdvi/S OLD_FILES+=usr/share/groff_font/devdvi/SA OLD_FILES+=usr/share/groff_font/devdvi/SB OLD_FILES+=usr/share/groff_font/devdvi/SC OLD_FILES+=usr/share/groff_font/devdvi/TB OLD_FILES+=usr/share/groff_font/devdvi/TBEC OLD_FILES+=usr/share/groff_font/devdvi/TBI OLD_FILES+=usr/share/groff_font/devdvi/TBIEC OLD_FILES+=usr/share/groff_font/devdvi/TBITC OLD_FILES+=usr/share/groff_font/devdvi/TBTC OLD_FILES+=usr/share/groff_font/devdvi/TI OLD_FILES+=usr/share/groff_font/devdvi/TIEC OLD_FILES+=usr/share/groff_font/devdvi/TITC OLD_FILES+=usr/share/groff_font/devdvi/TR OLD_FILES+=usr/share/groff_font/devdvi/TREC OLD_FILES+=usr/share/groff_font/devdvi/TRTC OLD_FILES+=usr/share/groff_font/devdvi/ec.map OLD_FILES+=usr/share/groff_font/devdvi/msam.map OLD_FILES+=usr/share/groff_font/devdvi/msbm.map OLD_FILES+=usr/share/groff_font/devdvi/tc.map OLD_FILES+=usr/share/groff_font/devdvi/texb.map OLD_FILES+=usr/share/groff_font/devdvi/texex.map OLD_FILES+=usr/share/groff_font/devdvi/texi.map OLD_FILES+=usr/share/groff_font/devdvi/texmi.map OLD_FILES+=usr/share/groff_font/devdvi/texr.map OLD_FILES+=usr/share/groff_font/devdvi/texsy.map OLD_FILES+=usr/share/groff_font/devdvi/textex.map OLD_FILES+=usr/share/groff_font/devdvi/textt.map OLD_DIRS+=usr/share/groff_font/devdvi OLD_FILES+=usr/share/groff_font/devhtml/B OLD_FILES+=usr/share/groff_font/devhtml/BI OLD_FILES+=usr/share/groff_font/devhtml/CB OLD_FILES+=usr/share/groff_font/devhtml/CBI OLD_FILES+=usr/share/groff_font/devhtml/CI OLD_FILES+=usr/share/groff_font/devhtml/CR OLD_FILES+=usr/share/groff_font/devhtml/DESC OLD_FILES+=usr/share/groff_font/devhtml/I OLD_FILES+=usr/share/groff_font/devhtml/R OLD_FILES+=usr/share/groff_font/devhtml/S OLD_DIRS+=usr/share/groff_font/devhtml OLD_FILES+=usr/share/groff_font/devkoi8-r/B OLD_FILES+=usr/share/groff_font/devkoi8-r/BI OLD_FILES+=usr/share/groff_font/devkoi8-r/CW OLD_FILES+=usr/share/groff_font/devkoi8-r/DESC OLD_FILES+=usr/share/groff_font/devkoi8-r/I OLD_FILES+=usr/share/groff_font/devkoi8-r/L OLD_FILES+=usr/share/groff_font/devkoi8-r/R OLD_FILES+=usr/share/groff_font/devkoi8-r/S OLD_DIRS+=usr/share/groff_font/devkoi8-r OLD_FILES+=usr/share/groff_font/devlatin1/B OLD_FILES+=usr/share/groff_font/devlatin1/BI OLD_FILES+=usr/share/groff_font/devlatin1/CW OLD_FILES+=usr/share/groff_font/devlatin1/DESC OLD_FILES+=usr/share/groff_font/devlatin1/I OLD_FILES+=usr/share/groff_font/devlatin1/L OLD_FILES+=usr/share/groff_font/devlatin1/R OLD_FILES+=usr/share/groff_font/devlatin1/S OLD_DIRS+=usr/share/groff_font/devlatin1 OLD_FILES+=usr/share/groff_font/devlbp/CB OLD_FILES+=usr/share/groff_font/devlbp/CI OLD_FILES+=usr/share/groff_font/devlbp/CR OLD_FILES+=usr/share/groff_font/devlbp/DESC OLD_FILES+=usr/share/groff_font/devlbp/EB OLD_FILES+=usr/share/groff_font/devlbp/EI OLD_FILES+=usr/share/groff_font/devlbp/ER OLD_FILES+=usr/share/groff_font/devlbp/HB OLD_FILES+=usr/share/groff_font/devlbp/HBI OLD_FILES+=usr/share/groff_font/devlbp/HI OLD_FILES+=usr/share/groff_font/devlbp/HNB OLD_FILES+=usr/share/groff_font/devlbp/HNBI OLD_FILES+=usr/share/groff_font/devlbp/HNI OLD_FILES+=usr/share/groff_font/devlbp/HNR OLD_FILES+=usr/share/groff_font/devlbp/HR OLD_FILES+=usr/share/groff_font/devlbp/TB OLD_FILES+=usr/share/groff_font/devlbp/TBI OLD_FILES+=usr/share/groff_font/devlbp/TI OLD_FILES+=usr/share/groff_font/devlbp/TR OLD_DIRS+=usr/share/groff_font/devlbp OLD_FILES+=usr/share/groff_font/devlj4/AB OLD_FILES+=usr/share/groff_font/devlj4/ABI OLD_FILES+=usr/share/groff_font/devlj4/AI OLD_FILES+=usr/share/groff_font/devlj4/ALBB OLD_FILES+=usr/share/groff_font/devlj4/ALBR OLD_FILES+=usr/share/groff_font/devlj4/AOB OLD_FILES+=usr/share/groff_font/devlj4/AOI OLD_FILES+=usr/share/groff_font/devlj4/AOR OLD_FILES+=usr/share/groff_font/devlj4/AR OLD_FILES+=usr/share/groff_font/devlj4/CB OLD_FILES+=usr/share/groff_font/devlj4/CBI OLD_FILES+=usr/share/groff_font/devlj4/CI OLD_FILES+=usr/share/groff_font/devlj4/CLARENDON OLD_FILES+=usr/share/groff_font/devlj4/CORONET OLD_FILES+=usr/share/groff_font/devlj4/CR OLD_FILES+=usr/share/groff_font/devlj4/DESC OLD_FILES+=usr/share/groff_font/devlj4/GB OLD_FILES+=usr/share/groff_font/devlj4/GBI OLD_FILES+=usr/share/groff_font/devlj4/GI OLD_FILES+=usr/share/groff_font/devlj4/GR OLD_FILES+=usr/share/groff_font/devlj4/LGB OLD_FILES+=usr/share/groff_font/devlj4/LGI OLD_FILES+=usr/share/groff_font/devlj4/LGR OLD_FILES+=usr/share/groff_font/devlj4/MARIGOLD OLD_FILES+=usr/share/groff_font/devlj4/OB OLD_FILES+=usr/share/groff_font/devlj4/OBI OLD_FILES+=usr/share/groff_font/devlj4/OI OLD_FILES+=usr/share/groff_font/devlj4/OR OLD_FILES+=usr/share/groff_font/devlj4/S OLD_FILES+=usr/share/groff_font/devlj4/SYMBOL OLD_FILES+=usr/share/groff_font/devlj4/TB OLD_FILES+=usr/share/groff_font/devlj4/TBI OLD_FILES+=usr/share/groff_font/devlj4/TI OLD_FILES+=usr/share/groff_font/devlj4/TNRB OLD_FILES+=usr/share/groff_font/devlj4/TNRBI OLD_FILES+=usr/share/groff_font/devlj4/TNRI OLD_FILES+=usr/share/groff_font/devlj4/TNRR OLD_FILES+=usr/share/groff_font/devlj4/TR OLD_FILES+=usr/share/groff_font/devlj4/UB OLD_FILES+=usr/share/groff_font/devlj4/UBI OLD_FILES+=usr/share/groff_font/devlj4/UCB OLD_FILES+=usr/share/groff_font/devlj4/UCBI OLD_FILES+=usr/share/groff_font/devlj4/UCI OLD_FILES+=usr/share/groff_font/devlj4/UCR OLD_FILES+=usr/share/groff_font/devlj4/UI OLD_FILES+=usr/share/groff_font/devlj4/UR OLD_FILES+=usr/share/groff_font/devlj4/WINGDINGS OLD_DIRS+=usr/share/groff_font/devlj4 OLD_FILES+=usr/share/groff_font/devps/AB OLD_FILES+=usr/share/groff_font/devps/ABI OLD_FILES+=usr/share/groff_font/devps/AI OLD_FILES+=usr/share/groff_font/devps/AR OLD_FILES+=usr/share/groff_font/devps/BMB OLD_FILES+=usr/share/groff_font/devps/BMBI OLD_FILES+=usr/share/groff_font/devps/BMI OLD_FILES+=usr/share/groff_font/devps/BMR OLD_FILES+=usr/share/groff_font/devps/CB OLD_FILES+=usr/share/groff_font/devps/CBI OLD_FILES+=usr/share/groff_font/devps/CI OLD_FILES+=usr/share/groff_font/devps/CR OLD_FILES+=usr/share/groff_font/devps/DESC OLD_FILES+=usr/share/groff_font/devps/EURO OLD_FILES+=usr/share/groff_font/devps/HB OLD_FILES+=usr/share/groff_font/devps/HBI OLD_FILES+=usr/share/groff_font/devps/HI OLD_FILES+=usr/share/groff_font/devps/HNB OLD_FILES+=usr/share/groff_font/devps/HNBI OLD_FILES+=usr/share/groff_font/devps/HNI OLD_FILES+=usr/share/groff_font/devps/HNR OLD_FILES+=usr/share/groff_font/devps/HR OLD_FILES+=usr/share/groff_font/devps/Makefile OLD_FILES+=usr/share/groff_font/devps/NB OLD_FILES+=usr/share/groff_font/devps/NBI OLD_FILES+=usr/share/groff_font/devps/NI OLD_FILES+=usr/share/groff_font/devps/NR OLD_FILES+=usr/share/groff_font/devps/PB OLD_FILES+=usr/share/groff_font/devps/PBI OLD_FILES+=usr/share/groff_font/devps/PI OLD_FILES+=usr/share/groff_font/devps/PR OLD_FILES+=usr/share/groff_font/devps/S OLD_FILES+=usr/share/groff_font/devps/SS OLD_FILES+=usr/share/groff_font/devps/TB OLD_FILES+=usr/share/groff_font/devps/TBI OLD_FILES+=usr/share/groff_font/devps/TI OLD_FILES+=usr/share/groff_font/devps/TR OLD_FILES+=usr/share/groff_font/devps/ZCMI OLD_FILES+=usr/share/groff_font/devps/ZD OLD_FILES+=usr/share/groff_font/devps/ZDR OLD_FILES+=usr/share/groff_font/devps/afmname OLD_FILES+=usr/share/groff_font/devps/dingbats.map OLD_FILES+=usr/share/groff_font/devps/dingbats.rmap OLD_FILES+=usr/share/groff_font/devps/download OLD_FILES+=usr/share/groff_font/devps/freeeuro.pfa OLD_FILES+=usr/share/groff_font/devps/lgreekmap OLD_FILES+=usr/share/groff_font/devps/prologue OLD_FILES+=usr/share/groff_font/devps/symbol.sed OLD_FILES+=usr/share/groff_font/devps/symbolchars OLD_FILES+=usr/share/groff_font/devps/symbolsl.afm OLD_FILES+=usr/share/groff_font/devps/symbolsl.pfa OLD_FILES+=usr/share/groff_font/devps/text.enc OLD_FILES+=usr/share/groff_font/devps/textmap OLD_FILES+=usr/share/groff_font/devps/zapfdr.pfa OLD_DIRS+=usr/share/groff_font/devps OLD_FILES+=usr/share/groff_font/devutf8/B OLD_FILES+=usr/share/groff_font/devutf8/BI OLD_FILES+=usr/share/groff_font/devutf8/CW OLD_FILES+=usr/share/groff_font/devutf8/DESC OLD_FILES+=usr/share/groff_font/devutf8/I OLD_FILES+=usr/share/groff_font/devutf8/L OLD_FILES+=usr/share/groff_font/devutf8/R OLD_FILES+=usr/share/groff_font/devutf8/S OLD_DIRS+=usr/share/groff_font/devutf8 OLD_DIRS+=usr/share/groff_font OLD_FILES+=usr/share/info/groff.info.gz OLD_FILES+=usr/share/man/man1/addftinfo.1.gz OLD_FILES+=usr/share/man/man1/afmtodit.1.gz OLD_FILES+=usr/share/man/man1/eqn.1.gz OLD_FILES+=usr/share/man/man1/grn.1.gz OLD_FILES+=usr/share/man/man1/grodvi.1.gz OLD_FILES+=usr/share/man/man1/groff.1.gz OLD_FILES+=usr/share/man/man1/grog.1.gz OLD_FILES+=usr/share/man/man1/grolbp.1.gz OLD_FILES+=usr/share/man/man1/grolj4.1.gz OLD_FILES+=usr/share/man/man1/grops.1.gz OLD_FILES+=usr/share/man/man1/grotty.1.gz OLD_FILES+=usr/share/man/man1/hpftodit.1.gz OLD_FILES+=usr/share/man/man1/indxbib.1.gz OLD_FILES+=usr/share/man/man1/lkbib.1.gz OLD_FILES+=usr/share/man/man1/lookbib.1.gz OLD_FILES+=usr/share/man/man1/mmroff.1.gz OLD_FILES+=usr/share/man/man1/neqn.1.gz OLD_FILES+=usr/share/man/man1/nroff.1.gz OLD_FILES+=usr/share/man/man1/pfbtops.1.gz OLD_FILES+=usr/share/man/man1/pic.1.gz OLD_FILES+=usr/share/man/man1/psroff.1.gz OLD_FILES+=usr/share/man/man1/refer.1.gz OLD_FILES+=usr/share/man/man1/tbl.1.gz OLD_FILES+=usr/share/man/man1/tfmtodit.1.gz OLD_FILES+=usr/share/man/man1/troff.1.gz OLD_FILES+=usr/share/man/man1/vgrind.1.gz OLD_FILES+=usr/share/man/man5/groff_font.5.gz OLD_FILES+=usr/share/man/man5/groff_out.5.gz OLD_FILES+=usr/share/man/man5/groff_tmac.5.gz OLD_FILES+=usr/share/man/man5/lj4_font.5.gz OLD_FILES+=usr/share/man/man5/tmac.5.gz OLD_FILES+=usr/share/man/man5/vgrindefs.5.gz OLD_FILES+=usr/share/man/man7/ditroff.7.gz OLD_FILES+=usr/share/man/man7/groff.7.gz OLD_FILES+=usr/share/man/man7/groff_char.7.gz OLD_FILES+=usr/share/man/man7/groff_diff.7.gz OLD_FILES+=usr/share/man/man7/groff_man.7.gz OLD_FILES+=usr/share/man/man7/groff_mdoc.7.gz OLD_FILES+=usr/share/man/man7/groff_me.7.gz OLD_FILES+=usr/share/man/man7/groff_mm.7.gz OLD_FILES+=usr/share/man/man7/groff_mmse.7.gz OLD_FILES+=usr/share/man/man7/groff_ms.7.gz OLD_FILES+=usr/share/man/man7/groff_trace.7.gz OLD_FILES+=usr/share/man/man7/groff_www.7.gz OLD_FILES+=usr/share/man/man7/mdoc.samples.7.gz OLD_FILES+=usr/share/man/man7/me.7.gz OLD_FILES+=usr/share/man/man7/mm.7.gz OLD_FILES+=usr/share/man/man7/mmse.7.gz OLD_FILES+=usr/share/man/man7/ms.7.gz OLD_FILES+=usr/share/man/man7/orig_me.7.gz OLD_FILES+=usr/share/man/man7/roff.7.gz OLD_FILES+=usr/share/me/acm.me OLD_FILES+=usr/share/me/chars.me OLD_FILES+=usr/share/me/deltext.me OLD_FILES+=usr/share/me/eqn.me OLD_FILES+=usr/share/me/float.me OLD_FILES+=usr/share/me/footnote.me OLD_FILES+=usr/share/me/index.me OLD_FILES+=usr/share/me/letterhead.me OLD_FILES+=usr/share/me/local.me OLD_FILES+=usr/share/me/null.me OLD_FILES+=usr/share/me/refer.me OLD_FILES+=usr/share/me/revisions OLD_FILES+=usr/share/me/sh.me OLD_FILES+=usr/share/me/tbl.me OLD_FILES+=usr/share/me/thesis.me OLD_DIRS+=usr/share/me OLD_FILES+=usr/share/misc/vgrindefs OLD_FILES+=usr/share/misc/vgrindefs.db OLD_FILES+=usr/share/tmac/X.tmac OLD_FILES+=usr/share/tmac/Xps.tmac OLD_FILES+=usr/share/tmac/a4.tmac OLD_FILES+=usr/share/tmac/an-old.tmac OLD_FILES+=usr/share/tmac/an.tmac OLD_FILES+=usr/share/tmac/andoc.tmac OLD_FILES+=usr/share/tmac/composite.tmac OLD_FILES+=usr/share/tmac/cp1047.tmac OLD_FILES+=usr/share/tmac/devtag.tmac OLD_FILES+=usr/share/tmac/doc.tmac OLD_FILES+=usr/share/tmac/dvi.tmac OLD_FILES+=usr/share/tmac/e.tmac OLD_FILES+=usr/share/tmac/ec.tmac OLD_FILES+=usr/share/tmac/eqnrc OLD_FILES+=usr/share/tmac/europs.tmac OLD_FILES+=usr/share/tmac/html-end.tmac OLD_FILES+=usr/share/tmac/html.tmac OLD_FILES+=usr/share/tmac/hyphen.ru OLD_FILES+=usr/share/tmac/hyphen.us OLD_FILES+=usr/share/tmac/hyphenex.us OLD_FILES+=usr/share/tmac/koi8-r.tmac OLD_FILES+=usr/share/tmac/latin1.tmac OLD_FILES+=usr/share/tmac/latin2.tmac OLD_FILES+=usr/share/tmac/latin9.tmac OLD_FILES+=usr/share/tmac/lbp.tmac OLD_FILES+=usr/share/tmac/lj4.tmac OLD_FILES+=usr/share/tmac/m.tmac OLD_FILES+=usr/share/tmac/man.local OLD_FILES+=usr/share/tmac/man.tmac OLD_FILES+=usr/share/tmac/mandoc.tmac OLD_FILES+=usr/share/tmac/mdoc.local OLD_FILES+=usr/share/tmac/mdoc.tmac OLD_FILES+=usr/share/tmac/mdoc/doc-common OLD_FILES+=usr/share/tmac/mdoc/doc-ditroff OLD_FILES+=usr/share/tmac/mdoc/doc-nroff OLD_FILES+=usr/share/tmac/mdoc/doc-syms OLD_FILES+=usr/share/tmac/mdoc/fr.ISO8859-1 OLD_FILES+=usr/share/tmac/mdoc/ru.KOI8-R OLD_DIRS+=usr/share/tmac/mdoc OLD_FILES+=usr/share/tmac/me.tmac OLD_FILES+=usr/share/tmac/mm/0.MT OLD_FILES+=usr/share/tmac/mm/4.MT OLD_FILES+=usr/share/tmac/mm/5.MT OLD_FILES+=usr/share/tmac/mm/locale OLD_FILES+=usr/share/tmac/mm/mm.tmac OLD_FILES+=usr/share/tmac/mm/mmse.tmac OLD_FILES+=usr/share/tmac/mm/ms.cov OLD_FILES+=usr/share/tmac/mm/se_locale OLD_FILES+=usr/share/tmac/mm/se_ms.cov OLD_DIRS+=usr/share/tmac/mm OLD_FILES+=usr/share/tmac/ms.tmac OLD_FILES+=usr/share/tmac/mse.tmac OLD_FILES+=usr/share/tmac/papersize.tmac OLD_FILES+=usr/share/tmac/pic.tmac OLD_FILES+=usr/share/tmac/ps.tmac OLD_FILES+=usr/share/tmac/psatk.tmac OLD_FILES+=usr/share/tmac/psold.tmac OLD_FILES+=usr/share/tmac/pspic.tmac OLD_FILES+=usr/share/tmac/s.tmac OLD_FILES+=usr/share/tmac/safer.tmac OLD_FILES+=usr/share/tmac/tmac.orig_me OLD_FILES+=usr/share/tmac/tmac.vgrind OLD_FILES+=usr/share/tmac/trace.tmac OLD_FILES+=usr/share/tmac/troffrc OLD_FILES+=usr/share/tmac/troffrc-end OLD_FILES+=usr/share/tmac/tty-char.tmac OLD_FILES+=usr/share/tmac/tty.tmac OLD_FILES+=usr/share/tmac/unicode.tmac OLD_FILES+=usr/share/tmac/www.tmac OLD_DIRS+=usr/share/tmac .endif .if ${MK_GSSAPI} == no OLD_FILES+=usr/include/gssapi/gssapi.h OLD_DIRS+=usr/include/gssapi OLD_FILES+=usr/include/gssapi.h OLD_FILES+=usr/lib/libgssapi.a OLD_FILES+=usr/lib/libgssapi.so OLD_LIBS+=usr/lib/libgssapi.so.10 OLD_FILES+=usr/lib/libgssapi_p.a OLD_FILES+=usr/lib/librpcsec_gss.a OLD_FILES+=usr/lib/librpcsec_gss.so OLD_LIBS+=usr/lib/librpcsec_gss.so.1 .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/lib32/libgssapi.a OLD_FILES+=usr/lib32/libgssapi.so OLD_LIBS+=usr/lib32/libgssapi.so.10 OLD_FILES+=usr/lib32/libgssapi_p.a OLD_FILES+=usr/lib32/librpcsec_gss.a OLD_FILES+=usr/lib32/librpcsec_gss.so OLD_LIBS+=usr/lib32/librpcsec_gss.so.1 .endif OLD_FILES+=usr/sbin/gssd OLD_FILES+=usr/share/man/man3/gss_accept_sec_context.3.gz OLD_FILES+=usr/share/man/man3/gss_acquire_cred.3.gz OLD_FILES+=usr/share/man/man3/gss_add_cred.3.gz OLD_FILES+=usr/share/man/man3/gss_add_oid_set_member.3.gz OLD_FILES+=usr/share/man/man3/gss_canonicalize_name.3.gz OLD_FILES+=usr/share/man/man3/gss_compare_name.3.gz OLD_FILES+=usr/share/man/man3/gss_context_time.3.gz OLD_FILES+=usr/share/man/man3/gss_create_empty_oid_set.3.gz OLD_FILES+=usr/share/man/man3/gss_delete_sec_context.3.gz OLD_FILES+=usr/share/man/man3/gss_display_name.3.gz OLD_FILES+=usr/share/man/man3/gss_display_status.3.gz OLD_FILES+=usr/share/man/man3/gss_duplicate_name.3.gz OLD_FILES+=usr/share/man/man3/gss_export_name.3.gz OLD_FILES+=usr/share/man/man3/gss_export_sec_context.3.gz OLD_FILES+=usr/share/man/man3/gss_get_mic.3.gz OLD_FILES+=usr/share/man/man3/gss_import_name.3.gz OLD_FILES+=usr/share/man/man3/gss_import_sec_context.3.gz OLD_FILES+=usr/share/man/man3/gss_indicate_mechs.3.gz OLD_FILES+=usr/share/man/man3/gss_init_sec_context.3.gz OLD_FILES+=usr/share/man/man3/gss_inquire_context.3.gz OLD_FILES+=usr/share/man/man3/gss_inquire_cred.3.gz OLD_FILES+=usr/share/man/man3/gss_inquire_cred_by_mech.3.gz OLD_FILES+=usr/share/man/man3/gss_inquire_mechs_for_name.3.gz OLD_FILES+=usr/share/man/man3/gss_inquire_names_for_mech.3.gz OLD_FILES+=usr/share/man/man3/gss_process_context_token.3.gz OLD_FILES+=usr/share/man/man3/gss_release_buffer.3.gz OLD_FILES+=usr/share/man/man3/gss_release_cred.3.gz OLD_FILES+=usr/share/man/man3/gss_release_name.3.gz OLD_FILES+=usr/share/man/man3/gss_release_oid_set.3.gz OLD_FILES+=usr/share/man/man3/gss_seal.3.gz OLD_FILES+=usr/share/man/man3/gss_sign.3.gz OLD_FILES+=usr/share/man/man3/gss_test_oid_set_member.3.gz OLD_FILES+=usr/share/man/man3/gss_unseal.3.gz OLD_FILES+=usr/share/man/man3/gss_unwrap.3.gz OLD_FILES+=usr/share/man/man3/gss_verify.3.gz OLD_FILES+=usr/share/man/man3/gss_verify_mic.3.gz OLD_FILES+=usr/share/man/man3/gss_wrap.3.gz OLD_FILES+=usr/share/man/man3/gss_wrap_size_limit.3.gz OLD_FILES+=usr/share/man/man3/gssapi.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_get_error.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_get_mech_info.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_get_mechanisms.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_get_principal_name.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_get_versions.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_getcred.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_is_installed.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_max_data_length.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_mech_to_oid.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_oid_to_mech.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_qop_to_num.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_seccreate.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_set_callback.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_set_defaults.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_set_svc_name.3.gz OLD_FILES+=usr/share/man/man3/rpc_gss_svc_max_data_length.3.gz OLD_FILES+=usr/share/man/man3/rpcsec_gss.3.gz OLD_FILES+=usr/share/man/man5/mech.5.gz OLD_FILES+=usr/share/man/man5/qop.5.gz OLD_FILES+=usr/share/man/man8/gssd.8.gz .endif .if ${MK_HAST} == no OLD_FILES+=sbin/hastctl OLD_FILES+=sbin/hastd OLD_FILES+=usr/share/examples/hast/ucarp.sh OLD_FILES+=usr/share/examples/hast/ucarp_down.sh OLD_FILES+=usr/share/examples/hast/ucarp_up.sh OLD_FILES+=usr/share/examples/hast/vip-down.sh OLD_FILES+=usr/share/examples/hast/vip-up.sh OLD_FILES+=usr/share/man/man5/hast.conf.5.gz OLD_FILES+=usr/share/man/man8/hastctl.8.gz OLD_FILES+=usr/share/man/man8/hastd.8.gz OLD_DIRS+=usr/share/examples/hast .endif .if ${MK_HESIOD} == no OLD_FILES+=usr/bin/hesinfo OLD_FILES+=usr/include/hesiod.h OLD_FILES+=usr/share/man/man1/hesinfo.1.gz OLD_FILES+=usr/share/man/man3/hesiod.3.gz OLD_FILES+=usr/share/man/man5/hesiod.conf.5.gz .endif .if ${MK_HTML} == no OLD_FILES+=usr/share/doc/ncurses/hackguide.html OLD_FILES+=usr/share/doc/ncurses/ncurses-intro.html OLD_FILES+=usr/share/doc/ntp/accopt.html OLD_FILES+=usr/share/doc/ntp/assoc.html OLD_FILES+=usr/share/doc/ntp/audio.html OLD_FILES+=usr/share/doc/ntp/authopt.html OLD_FILES+=usr/share/doc/ntp/build.html OLD_FILES+=usr/share/doc/ntp/clockopt.html OLD_FILES+=usr/share/doc/ntp/config.html OLD_FILES+=usr/share/doc/ntp/confopt.html OLD_FILES+=usr/share/doc/ntp/copyright.html OLD_FILES+=usr/share/doc/ntp/debug.html OLD_FILES+=usr/share/doc/ntp/driver1.html OLD_FILES+=usr/share/doc/ntp/driver10.html OLD_FILES+=usr/share/doc/ntp/driver11.html OLD_FILES+=usr/share/doc/ntp/driver12.html OLD_FILES+=usr/share/doc/ntp/driver16.html OLD_FILES+=usr/share/doc/ntp/driver18.html OLD_FILES+=usr/share/doc/ntp/driver19.html OLD_FILES+=usr/share/doc/ntp/driver2.html OLD_FILES+=usr/share/doc/ntp/driver20.html OLD_FILES+=usr/share/doc/ntp/driver22.html OLD_FILES+=usr/share/doc/ntp/driver26.html OLD_FILES+=usr/share/doc/ntp/driver27.html OLD_FILES+=usr/share/doc/ntp/driver28.html OLD_FILES+=usr/share/doc/ntp/driver29.html OLD_FILES+=usr/share/doc/ntp/driver3.html OLD_FILES+=usr/share/doc/ntp/driver30.html OLD_FILES+=usr/share/doc/ntp/driver32.html OLD_FILES+=usr/share/doc/ntp/driver33.html OLD_FILES+=usr/share/doc/ntp/driver34.html OLD_FILES+=usr/share/doc/ntp/driver35.html OLD_FILES+=usr/share/doc/ntp/driver36.html OLD_FILES+=usr/share/doc/ntp/driver37.html OLD_FILES+=usr/share/doc/ntp/driver4.html OLD_FILES+=usr/share/doc/ntp/driver5.html OLD_FILES+=usr/share/doc/ntp/driver6.html OLD_FILES+=usr/share/doc/ntp/driver7.html OLD_FILES+=usr/share/doc/ntp/driver8.html OLD_FILES+=usr/share/doc/ntp/driver9.html OLD_FILES+=usr/share/doc/ntp/extern.html OLD_FILES+=usr/share/doc/ntp/hints.html OLD_FILES+=usr/share/doc/ntp/howto.html OLD_FILES+=usr/share/doc/ntp/index.html OLD_FILES+=usr/share/doc/ntp/kern.html OLD_FILES+=usr/share/doc/ntp/ldisc.html OLD_FILES+=usr/share/doc/ntp/measure.html OLD_FILES+=usr/share/doc/ntp/miscopt.html OLD_FILES+=usr/share/doc/ntp/monopt.html OLD_FILES+=usr/share/doc/ntp/mx4200data.html OLD_FILES+=usr/share/doc/ntp/notes.html OLD_FILES+=usr/share/doc/ntp/ntpd.html OLD_FILES+=usr/share/doc/ntp/ntpdate.html OLD_FILES+=usr/share/doc/ntp/ntpdc.html OLD_FILES+=usr/share/doc/ntp/ntpq.html OLD_FILES+=usr/share/doc/ntp/ntptime.html OLD_FILES+=usr/share/doc/ntp/ntptrace.html OLD_FILES+=usr/share/doc/ntp/parsedata.html OLD_FILES+=usr/share/doc/ntp/parsenew.html OLD_FILES+=usr/share/doc/ntp/patches.html OLD_FILES+=usr/share/doc/ntp/porting.html OLD_FILES+=usr/share/doc/ntp/pps.html OLD_FILES+=usr/share/doc/ntp/prefer.html OLD_FILES+=usr/share/doc/ntp/quick.html OLD_FILES+=usr/share/doc/ntp/rdebug.html OLD_FILES+=usr/share/doc/ntp/refclock.html OLD_FILES+=usr/share/doc/ntp/release.html OLD_FILES+=usr/share/doc/ntp/tickadj.html .endif .if ${MK_ICONV} == no OLD_FILES+=usr/bin/iconv OLD_FILES+=usr/bin/mkcsmapper OLD_FILES+=usr/bin/mkesdb OLD_FILES+=usr/include/_libiconv_compat.h OLD_FILES+=usr/include/iconv.h OLD_FILES+=usr/share/man/man1/iconv.1.gz OLD_FILES+=usr/share/man/man1/mkcsmapper.1.gz OLD_FILES+=usr/share/man/man1/mkesdb.1.gz OLD_FILES+=usr/share/man/man3/__iconv.3.gz OLD_FILES+=usr/share/man/man3/__iconv_free_list.3.gz OLD_FILES+=usr/share/man/man3/__iconv_get_list.3.gz OLD_FILES+=usr/share/man/man3/iconv.3.gz OLD_FILES+=usr/share/man/man3/iconv_canonicalize.3.gz OLD_FILES+=usr/share/man/man3/iconv_close.3.gz OLD_FILES+=usr/share/man/man3/iconv_open.3.gz OLD_FILES+=usr/share/man/man3/iconv_open_into.3.gz OLD_FILES+=usr/share/man/man3/iconvctl.3.gz OLD_FILES+=usr/share/man/man3/iconvlist.3.gz .endif .if ${MK_INET6} == no OLD_FILES+=sbin/ping6 OLD_FILES+=sbin/rtsol OLD_FILES+=usr/sbin/ip6addrctl OLD_FILES+=usr/sbin/mld6query OLD_FILES+=usr/sbin/ndp OLD_FILES+=usr/sbin/rip6query OLD_FILES+=usr/sbin/route6d OLD_FILES+=usr/sbin/rrenumd OLD_FILES+=usr/sbin/rtadvctl OLD_FILES+=usr/sbin/rtadvd OLD_FILES+=usr/sbin/rtsold OLD_FILES+=usr/sbin/traceroute6 OLD_FILES+=usr/share/doc/IPv6/IMPLEMENTATION OLD_FILES+=usr/share/man/man5/rrenumd.conf.5.gz OLD_FILES+=usr/share/man/man5/rtadvd.conf.5.gz OLD_FILES+=usr/share/man/man8/ip6addrctl.8.gz OLD_FILES+=usr/share/man/man8/mld6query.8.gz OLD_FILES+=usr/share/man/man8/ndp.8.gz OLD_FILES+=usr/share/man/man8/ping6.8.gz OLD_FILES+=usr/share/man/man8/rip6query.8.gz OLD_FILES+=usr/share/man/man8/route6d.8.gz OLD_FILES+=usr/share/man/man8/rrenumd.8.gz OLD_FILES+=usr/share/man/man8/rtadvctl.8.gz OLD_FILES+=usr/share/man/man8/rtadvd.8.gz OLD_FILES+=usr/share/man/man8/rtsol.8.gz OLD_FILES+=usr/share/man/man8/rtsold.8.gz OLD_FILES+=usr/share/man/man8/traceroute6.8.gz .endif .if ${MK_INET6_SUPPORT} == no OLD_FILES+=rescue/ping6 .endif .if ${MK_IPFILTER} == no OLD_FILES+=etc/periodic/security/510.ipfdenied OLD_FILES+=etc/periodic/security/610.ipf6denied OLD_FILES+=rescue/ipf OLD_FILES+=sbin/ipf OLD_FILES+=sbin/ipfs OLD_FILES+=sbin/ipfstat OLD_FILES+=sbin/ipftest OLD_FILES+=sbin/ipmon OLD_FILES+=sbin/ipnat OLD_FILES+=sbin/ippool OLD_FILES+=sbin/ipresend OLD_FILES+=usr/include/netinet/ip_auth.h OLD_FILES+=usr/include/netinet/ip_compat.h OLD_FILES+=usr/include/netinet/ip_fil.h OLD_FILES+=usr/include/netinet/ip_frag.h OLD_FILES+=usr/include/netinet/ip_htable.h OLD_FILES+=usr/include/netinet/ip_lookup.h OLD_FILES+=usr/include/netinet/ip_nat.h OLD_FILES+=usr/include/netinet/ip_pool.h OLD_FILES+=usr/include/netinet/ip_proxy.h OLD_FILES+=usr/include/netinet/ip_rules.h OLD_FILES+=usr/include/netinet/ip_scan.h OLD_FILES+=usr/include/netinet/ip_state.h OLD_FILES+=usr/include/netinet/ip_sync.h OLD_FILES+=usr/include/netinet/ipl.h OLD_FILES+=usr/share/examples/ipfilter/README OLD_FILES+=usr/share/examples/ipfilter/BASIC.NAT OLD_FILES+=usr/share/examples/ipfilter/BASIC_1.FW OLD_FILES+=usr/share/examples/ipfilter/BASIC_2.FW OLD_FILES+=usr/share/examples/ipfilter/example.1 OLD_FILES+=usr/share/examples/ipfilter/example.2 OLD_FILES+=usr/share/examples/ipfilter/example.3 OLD_FILES+=usr/share/examples/ipfilter/example.4 OLD_FILES+=usr/share/examples/ipfilter/example.5 OLD_FILES+=usr/share/examples/ipfilter/example.6 OLD_FILES+=usr/share/examples/ipfilter/example.7 OLD_FILES+=usr/share/examples/ipfilter/example.8 OLD_FILES+=usr/share/examples/ipfilter/example.9 OLD_FILES+=usr/share/examples/ipfilter/example.10 OLD_FILES+=usr/share/examples/ipfilter/example.11 OLD_FILES+=usr/share/examples/ipfilter/example.12 OLD_FILES+=usr/share/examples/ipfilter/example.13 OLD_FILES+=usr/share/examples/ipfilter/example.sr OLD_FILES+=usr/share/examples/ipfilter/firewall OLD_FILES+=usr/share/examples/ipfilter/ftp-proxy OLD_FILES+=usr/share/examples/ipfilter/ftppxy OLD_FILES+=usr/share/examples/ipfilter/nat-setup OLD_FILES+=usr/share/examples/ipfilter/nat.eg OLD_FILES+=usr/share/examples/ipfilter/server OLD_FILES+=usr/share/examples/ipfilter/tcpstate OLD_FILES+=usr/share/examples/ipfilter/example.14 OLD_FILES+=usr/share/examples/ipfilter/firewall.1 OLD_FILES+=usr/share/examples/ipfilter/firewall.2 OLD_FILES+=usr/share/examples/ipfilter/ipf.conf.permissive OLD_FILES+=usr/share/examples/ipfilter/ipf.conf.restrictive OLD_FILES+=usr/share/examples/ipfilter/ipf.conf.sample OLD_FILES+=usr/share/examples/ipfilter/ipnat.conf.sample OLD_FILES+=usr/share/examples/ipfilter/ipf-howto.txt OLD_FILES+=usr/share/examples/ipfilter/examples.txt OLD_FILES+=usr/share/examples/ipfilter/rules.txt OLD_FILES+=usr/share/examples/ipfilter/mkfilters OLD_DIRS+=usr/share/examples/ipfilter OLD_FILES+=usr/share/man/man1/ipftest.1.gz OLD_FILES+=usr/share/man/man1/ipresend.1.gz OLD_FILES+=usr/share/man/man4/ipf.4.gz OLD_FILES+=usr/share/man/man4/ipl.4.gz OLD_FILES+=usr/share/man/man4/ipfilter.4.gz OLD_FILES+=usr/share/man/man4/ipnat.4.gz OLD_FILES+=usr/share/man/man5/ipf.5.gz OLD_FILES+=usr/share/man/man5/ipf.conf.5.gz OLD_FILES+=usr/share/man/man5/ipf6.conf.5.gz OLD_FILES+=usr/share/man/man5/ipnat.5.gz OLD_FILES+=usr/share/man/man5/ipnat.conf.5.gz OLD_FILES+=usr/share/man/man5/ippool.5.gz OLD_FILES+=usr/share/man/man8/ipf.8.gz OLD_FILES+=usr/share/man/man8/ipfs.8.gz OLD_FILES+=usr/share/man/man8/ipfstat.8.gz OLD_FILES+=usr/share/man/man8/ipmon.8.gz OLD_FILES+=usr/share/man/man8/ipnat.8.gz OLD_FILES+=usr/share/man/man8/ippool.8.gz .endif .if ${MK_IPFW} == no OLD_FILES+=etc/periodic/security/500.ipfwdenied OLD_FILES+=etc/periodic/security/550.ipfwlimit OLD_FILES+=sbin/ipfw OLD_FILES+=sbin/natd OLD_FILES+=usr/sbin/ipfwpcap OLD_FILES+=usr/share/man/man8/ipfw.8.gz OLD_FILES+=usr/share/man/man8/ipfwpcap.8.gz OLD_FILES+=usr/share/man/man8/natd.8.gz .endif .if ${MK_ISCSI} == no OLD_FILES+=etc/rc.d/iscsictl OLD_FILES+=etc/rc.d/iscsid OLD_FILES+=sbin/iscontrol OLD_FILES+=usr/bin/iscsictl OLD_FILES+=usr/sbin/iscsid OLD_FILES+=usr/share/man/man4/iscsi.4.gz OLD_FILES+=usr/share/man/man4/iscsi_initiator.4.gz OLD_FILES+=usr/share/man/man5/iscsi.conf.5.gz OLD_FILES+=usr/share/man/man8/iscontrol.8.gz OLD_FILES+=usr/share/man/man8/iscsictl.8.gz OLD_FILES+=usr/share/man/man8/iscsid.8.gz .endif .if ${MK_JAIL} == no OLD_FILES+=etc/rc.d/jail OLD_FILES+=usr/sbin/jail OLD_FILES+=usr/sbin/jexec OLD_FILES+=usr/sbin/jls OLD_FILES+=usr/share/man/man5/jail.conf.5.gz OLD_FILES+=usr/share/man/man8/jail.8.gz OLD_FILES+=usr/share/man/man8/jexec.8.gz OLD_FILES+=usr/share/man/man8/jls.8.gz .endif .if ${MK_KDUMP} == no OLD_FILES+=usr/bin/kdump OLD_FILES+=usr/bin/truss OLD_FILES+=usr/share/man/man1/kdump.1.gz OLD_FILES+=usr/share/man/man1/truss.1.gz .endif .if ${MK_KERBEROS} == no OLD_FILES+=etc/rc.d/ipropd_master OLD_FILES+=etc/rc.d/ipropd_slave OLD_FILES+=usr/bin/compile_et OLD_FILES+=usr/bin/hxtool OLD_FILES+=usr/bin/kadmin OLD_FILES+=usr/bin/kdestroy OLD_FILES+=usr/bin/kf OLD_FILES+=usr/bin/kgetcred OLD_FILES+=usr/bin/kinit OLD_FILES+=usr/bin/klist OLD_FILES+=usr/bin/kpasswd OLD_FILES+=usr/bin/krb5-config OLD_FILES+=usr/bin/ksu OLD_FILES+=usr/bin/kswitch OLD_FILES+=usr/bin/string2key OLD_FILES+=usr/bin/verify_krb5_conf OLD_FILES+=usr/include/asn1-common.h OLD_FILES+=usr/include/asn1_err.h OLD_FILES+=usr/include/base64.h OLD_FILES+=usr/include/cms_asn1.h OLD_FILES+=usr/include/crmf_asn1.h OLD_FILES+=usr/include/der-private.h OLD_FILES+=usr/include/der-protos.h OLD_FILES+=usr/include/der.h OLD_FILES+=usr/include/digest_asn1.h OLD_FILES+=usr/include/getarg.h OLD_FILES+=usr/include/gssapi/gssapi_krb5.h OLD_FILES+=usr/include/hdb-protos.h OLD_FILES+=usr/include/hdb.h OLD_FILES+=usr/include/hdb_asn1.h OLD_FILES+=usr/include/hdb_err.h OLD_FILES+=usr/include/heim_asn1.h OLD_FILES+=usr/include/heim_err.h OLD_FILES+=usr/include/heim_threads.h OLD_FILES+=usr/include/heimbase.h OLD_FILES+=usr/include/heimntlm-protos.h OLD_FILES+=usr/include/heimntlm.h OLD_FILES+=usr/include/hex.h OLD_FILES+=usr/include/hx509-private.h OLD_FILES+=usr/include/hx509-protos.h OLD_FILES+=usr/include/hx509.h OLD_FILES+=usr/include/hx509_err.h OLD_FILES+=usr/include/k524_err.h OLD_FILES+=usr/include/kadm5/admin.h OLD_FILES+=usr/include/kadm5/kadm5-private.h OLD_FILES+=usr/include/kadm5/kadm5-protos.h OLD_FILES+=usr/include/kadm5/kadm5-pwcheck.h OLD_FILES+=usr/include/kadm5/kadm5_err.h OLD_FILES+=usr/include/kadm5/private.h OLD_DIRS+=usr/include/kadm5 OLD_FILES+=usr/include/kafs.h OLD_FILES+=usr/include/kdc-protos.h OLD_FILES+=usr/include/kdc.h OLD_FILES+=usr/include/krb5-private.h OLD_FILES+=usr/include/krb5-protos.h OLD_FILES+=usr/include/krb5-types.h OLD_FILES+=usr/include/krb5.h OLD_FILES+=usr/include/krb5/ccache_plugin.h OLD_FILES+=usr/include/krb5/locate_plugin.h OLD_FILES+=usr/include/krb5/send_to_kdc_plugin.h OLD_FILES+=usr/include/krb5/windc_plugin.h OLD_DIRS+=usr/include/krb5 OLD_FILES+=usr/include/krb5_asn1.h OLD_FILES+=usr/include/krb5_ccapi.h OLD_FILES+=usr/include/krb5_err.h OLD_FILES+=usr/include/kx509_asn1.h OLD_FILES+=usr/include/ntlm_err.h OLD_FILES+=usr/include/ocsp_asn1.h OLD_FILES+=usr/include/parse_bytes.h OLD_FILES+=usr/include/parse_time.h OLD_FILES+=usr/include/parse_units.h OLD_FILES+=usr/include/pkcs10_asn1.h OLD_FILES+=usr/include/pkcs12_asn1.h OLD_FILES+=usr/include/pkcs8_asn1.h OLD_FILES+=usr/include/pkcs9_asn1.h OLD_FILES+=usr/include/pkinit_asn1.h OLD_FILES+=usr/include/resolve.h OLD_FILES+=usr/include/rfc2459_asn1.h OLD_FILES+=usr/include/roken-common.h OLD_FILES+=usr/include/rtbl.h OLD_FILES+=usr/include/wind.h OLD_FILES+=usr/include/wind_err.h OLD_FILES+=usr/include/xdbm.h OLD_FILES+=usr/lib/libasn1.a OLD_FILES+=usr/lib/libasn1.so OLD_LIBS+=usr/lib/libasn1.so.11 OLD_FILES+=usr/lib/libasn1_p.a OLD_FILES+=usr/lib/libcom_err.a OLD_FILES+=usr/lib/libcom_err.so OLD_LIBS+=usr/lib/libcom_err.so.5 OLD_FILES+=usr/lib/libcom_err_p.a OLD_FILES+=usr/lib/libgssapi_krb5.a OLD_FILES+=usr/lib/libgssapi_krb5.so OLD_LIBS+=usr/lib/libgssapi_krb5.so.10 OLD_FILES+=usr/lib/libgssapi_krb5_p.a OLD_FILES+=usr/lib/libgssapi_ntlm.a OLD_FILES+=usr/lib/libgssapi_ntlm.so OLD_LIBS+=usr/lib/libgssapi_ntlm.so.10 OLD_FILES+=usr/lib/libgssapi_ntlm_p.a OLD_FILES+=usr/lib/libgssapi_spnego.a OLD_FILES+=usr/lib/libgssapi_spnego.so OLD_LIBS+=usr/lib/libgssapi_spnego.so.10 OLD_FILES+=usr/lib/libgssapi_spnego_p.a OLD_FILES+=usr/lib/libhdb.a OLD_FILES+=usr/lib/libhdb.so OLD_LIBS+=usr/lib/libhdb.so.11 OLD_FILES+=usr/lib/libhdb_p.a OLD_FILES+=usr/lib/libheimbase.a OLD_FILES+=usr/lib/libheimbase.so OLD_LIBS+=usr/lib/libheimbase.so.11 OLD_FILES+=usr/lib/libheimbase_p.a OLD_FILES+=usr/lib/libheimntlm.a OLD_FILES+=usr/lib/libheimntlm.so OLD_LIBS+=usr/lib/libheimntlm.so.11 OLD_FILES+=usr/lib/libheimntlm_p.a OLD_FILES+=usr/lib/libheimsqlite.a OLD_FILES+=usr/lib/libheimsqlite.so OLD_LIBS+=usr/lib/libheimsqlite.so.11 OLD_FILES+=usr/lib/libheimsqlite_p.a OLD_FILES+=usr/lib/libhx509.a OLD_FILES+=usr/lib/libhx509.so OLD_LIBS+=usr/lib/libhx509.so.11 OLD_FILES+=usr/lib/libhx509_p.a OLD_FILES+=usr/lib/libkadm5clnt.a OLD_FILES+=usr/lib/libkadm5clnt.so OLD_LIBS+=usr/lib/libkadm5clnt.so.11 OLD_FILES+=usr/lib/libkadm5clnt_p.a OLD_FILES+=usr/lib/libkadm5srv.a OLD_FILES+=usr/lib/libkadm5srv.so OLD_LIBS+=usr/lib/libkadm5srv.so.11 OLD_FILES+=usr/lib/libkadm5srv_p.a OLD_FILES+=usr/lib/libkafs5.a OLD_FILES+=usr/lib/libkafs5.so OLD_LIBS+=usr/lib/libkafs5.so.11 OLD_FILES+=usr/lib/libkafs5_p.a OLD_FILES+=usr/lib/libkdc.a OLD_FILES+=usr/lib/libkdc.so OLD_LIBS+=usr/lib/libkdc.so.11 OLD_FILES+=usr/lib/libkdc_p.a OLD_FILES+=usr/lib/libkrb5.a OLD_FILES+=usr/lib/libkrb5.so OLD_LIBS+=usr/lib/libkrb5.so.11 OLD_FILES+=usr/lib/libkrb5_p.a OLD_FILES+=usr/lib/libroken.a OLD_FILES+=usr/lib/libroken.so OLD_LIBS+=usr/lib/libroken.so.11 OLD_FILES+=usr/lib/libroken_p.a OLD_FILES+=usr/lib/libwind.a OLD_FILES+=usr/lib/libwind.so OLD_LIBS+=usr/lib/libwind.so.11 OLD_FILES+=usr/lib/libwind_p.a OLD_FILES+=usr/lib/pam_krb5.so OLD_LIBS+=usr/lib/pam_krb5.so.5 OLD_FILES+=usr/lib/pam_ksu.so OLD_LIBS+=usr/lib/pam_ksu.so.5 OLD_FILES+=usr/lib/private/libheimipcc.a OLD_FILES+=usr/lib/private/libheimipcc.so OLD_LIBS+=usr/lib/private/libheimipcc.so.11 OLD_FILES+=usr/lib/private/libheimipcc_p.a OLD_FILES+=usr/lib/private/libheimipcs.a OLD_FILES+=usr/lib/private/libheimipcs.so OLD_LIBS+=usr/lib/private/libheimipcs.so.11 OLD_FILES+=usr/lib/private/libheimipcs_p.a .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/lib32/libasn1.a OLD_FILES+=usr/lib32/libasn1.so OLD_LIBS+=usr/lib32/libasn1.so.11 OLD_FILES+=usr/lib32/libasn1_p.a OLD_FILES+=usr/lib32/libgssapi_krb5.a OLD_FILES+=usr/lib32/libgssapi_krb5.so OLD_LIBS+=usr/lib32/libgssapi_krb5.so.10 OLD_FILES+=usr/lib32/libgssapi_krb5_p.a OLD_FILES+=usr/lib32/libgssapi_ntlm.a OLD_FILES+=usr/lib32/libgssapi_ntlm.so OLD_LIBS+=usr/lib32/libgssapi_ntlm.so.10 OLD_FILES+=usr/lib32/libgssapi_ntlm_p.a OLD_FILES+=usr/lib32/libgssapi_spnego.a OLD_FILES+=usr/lib32/libgssapi_spnego.so OLD_LIBS+=usr/lib32/libgssapi_spnego.so.10 OLD_FILES+=usr/lib32/libgssapi_spnego_p.a OLD_FILES+=usr/lib32/libhdb.a OLD_FILES+=usr/lib32/libhdb.so OLD_LIBS+=usr/lib32/libhdb.so.11 OLD_FILES+=usr/lib32/libhdb_p.a OLD_FILES+=usr/lib32/libheimbase.a OLD_FILES+=usr/lib32/libheimbase.so OLD_LIBS+=usr/lib32/libheimbase.so.11 OLD_FILES+=usr/lib32/libheimbase_p.a OLD_FILES+=usr/lib32/libheimntlm.a OLD_FILES+=usr/lib32/libheimntlm.so OLD_LIBS+=usr/lib32/libheimntlm.so.11 OLD_FILES+=usr/lib32/libheimntlm_p.a OLD_FILES+=usr/lib32/libheimsqlite.a OLD_FILES+=usr/lib32/libheimsqlite.so OLD_LIBS+=usr/lib32/libheimsqlite.so.11 OLD_FILES+=usr/lib32/libheimsqlite_p.a OLD_FILES+=usr/lib32/libhx509.a OLD_FILES+=usr/lib32/libhx509.so OLD_LIBS+=usr/lib32/libhx509.so.11 OLD_FILES+=usr/lib32/libhx509_p.a OLD_FILES+=usr/lib32/libkadm5clnt.a OLD_FILES+=usr/lib32/libkadm5clnt.so OLD_LIBS+=usr/lib32/libkadm5clnt.so.11 OLD_FILES+=usr/lib32/libkadm5clnt_p.a OLD_FILES+=usr/lib32/libkadm5srv.a OLD_FILES+=usr/lib32/libkadm5srv.so OLD_LIBS+=usr/lib32/libkadm5srv.so.11 OLD_FILES+=usr/lib32/libkadm5srv_p.a OLD_FILES+=usr/lib32/libkafs5.a OLD_FILES+=usr/lib32/libkafs5.so OLD_LIBS+=usr/lib32/libkafs5.so.11 OLD_FILES+=usr/lib32/libkafs5_p.a OLD_FILES+=usr/lib32/libkdc.a OLD_FILES+=usr/lib32/libkdc.so OLD_LIBS+=usr/lib32/libkdc.so.11 OLD_FILES+=usr/lib32/libkdc_p.a OLD_FILES+=usr/lib32/libkrb5.a OLD_FILES+=usr/lib32/libkrb5.so OLD_LIBS+=usr/lib32/libkrb5.so.11 OLD_FILES+=usr/lib32/libkrb5_p.a OLD_FILES+=usr/lib32/libroken.a OLD_FILES+=usr/lib32/libroken.so OLD_LIBS+=usr/lib32/libroken.so.11 OLD_FILES+=usr/lib32/libroken_p.a OLD_FILES+=usr/lib32/libwind.a OLD_FILES+=usr/lib32/libwind.so OLD_LIBS+=usr/lib32/libwind.so.11 OLD_FILES+=usr/lib32/libwind_p.a OLD_FILES+=usr/lib32/pam_krb5.so OLD_LIBS+=usr/lib32/pam_krb5.so.5 OLD_FILES+=usr/lib32/pam_ksu.so OLD_LIBS+=usr/lib32/pam_ksu.so.5 OLD_FILES+=usr/lib32/private/libheimipcc.a OLD_FILES+=usr/lib32/private/libheimipcc.so OLD_LIBS+=usr/lib32/private/libheimipcc.so.11 OLD_FILES+=usr/lib32/private/libheimipcc_p.a OLD_FILES+=usr/lib32/private/libheimipcs.a OLD_FILES+=usr/lib32/private/libheimipcs.so OLD_LIBS+=usr/lib32/private/libheimipcs.so.11 OLD_FILES+=usr/lib32/private/libheimipcs_p.a .endif OLD_FILES+=usr/libexec/digest-service OLD_FILES+=usr/libexec/hprop OLD_FILES+=usr/libexec/hpropd OLD_FILES+=usr/libexec/ipropd-master OLD_FILES+=usr/libexec/ipropd-slave OLD_FILES+=usr/libexec/kadmind OLD_FILES+=usr/libexec/kcm OLD_FILES+=usr/libexec/kdc OLD_FILES+=usr/libexec/kdigest OLD_FILES+=usr/libexec/kfd OLD_FILES+=usr/libexec/kimpersonate OLD_FILES+=usr/libexec/kpasswdd OLD_FILES+=usr/sbin/kstash OLD_FILES+=usr/sbin/ktutil OLD_FILES+=usr/sbin/iprop-log OLD_FILES+=usr/share/info/heimdal.info.gz OLD_FILES+=usr/share/man/man1/kdestroy.1.gz OLD_FILES+=usr/share/man/man1/kf.1.gz OLD_FILES+=usr/share/man/man1/kinit.1.gz OLD_FILES+=usr/share/man/man1/klist.1.gz OLD_FILES+=usr/share/man/man1/kpasswd.1.gz OLD_FILES+=usr/share/man/man1/krb5-config.1.gz OLD_FILES+=usr/share/man/man1/kswitch.1.gz OLD_FILES+=usr/share/man/man3/HDB.3.gz OLD_FILES+=usr/share/man/man3/hdb__del.3.gz OLD_FILES+=usr/share/man/man3/hdb__get.3.gz OLD_FILES+=usr/share/man/man3/hdb__put.3.gz OLD_FILES+=usr/share/man/man3/hdb_auth_status.3.gz OLD_FILES+=usr/share/man/man3/hdb_check_constrained_delegation.3.gz OLD_FILES+=usr/share/man/man3/hdb_check_pkinit_ms_upn_match.3.gz OLD_FILES+=usr/share/man/man3/hdb_check_s4u2self.3.gz OLD_FILES+=usr/share/man/man3/hdb_close.3.gz OLD_FILES+=usr/share/man/man3/hdb_destroy.3.gz OLD_FILES+=usr/share/man/man3/hdb_entry_ex.3.gz OLD_FILES+=usr/share/man/man3/hdb_fetch_kvno.3.gz OLD_FILES+=usr/share/man/man3/hdb_firstkey.3.gz OLD_FILES+=usr/share/man/man3/hdb_free.3.gz OLD_FILES+=usr/share/man/man3/hdb_get_realms.3.gz OLD_FILES+=usr/share/man/man3/hdb_lock.3.gz OLD_FILES+=usr/share/man/man3/hdb_name.3.gz OLD_FILES+=usr/share/man/man3/hdb_nextkey.3.gz OLD_FILES+=usr/share/man/man3/hdb_open.3.gz OLD_FILES+=usr/share/man/man3/hdb_password.3.gz OLD_FILES+=usr/share/man/man3/hdb_remove.3.gz OLD_FILES+=usr/share/man/man3/hdb_rename.3.gz OLD_FILES+=usr/share/man/man3/hdb_store.3.gz OLD_FILES+=usr/share/man/man3/hdb_unlock.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_build_ntlm1_master.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_build_ntlm2_master.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_calculate_lm2.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_calculate_ntlm1.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_calculate_ntlm2.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_decode_targetinfo.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_encode_targetinfo.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_encode_type1.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_encode_type2.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_encode_type3.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_free_buf.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_free_targetinfo.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_free_type1.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_free_type2.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_free_type3.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_keyex_unwrap.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_nt_key.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_ntlmv2_key.3.gz OLD_FILES+=usr/share/man/man3/heim_ntlm_verify_ntlm2.3.gz OLD_FILES+=usr/share/man/man3/hx509.3.gz OLD_FILES+=usr/share/man/man3/hx509_bitstring_print.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_sign.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_sign_self.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_crl_dp_uri.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_eku.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_san_hostname.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_san_jid.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_san_ms_upn.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_san_otherName.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_san_pkinit.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_add_san_rfc822name.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_free.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_init.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_ca.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_domaincontroller.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_notAfter.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_notAfter_lifetime.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_notBefore.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_proxy.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_serialnumber.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_spki.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_subject.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_template.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_set_unique.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_subject_expand.3.gz OLD_FILES+=usr/share/man/man3/hx509_ca_tbs_template_units.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_binary.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_check_eku.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_cmp.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_find_subjectAltName_otherName.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_free.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_get_SPKI.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_get_SPKI_AlgorithmIdentifier.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_get_attribute.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_get_base_subject.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_get_friendly_name.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_get_issuer.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_get_issuer_unique_id.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_get_notAfter.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_get_notBefore.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_get_serialnumber.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_get_subject.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_get_subject_unique_id.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_init.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_init_data.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_keyusage_print.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_ref.3.gz OLD_FILES+=usr/share/man/man3/hx509_cert_set_friendly_name.3.gz OLD_FILES+=usr/share/man/man3/hx509_certs_add.3.gz OLD_FILES+=usr/share/man/man3/hx509_certs_append.3.gz OLD_FILES+=usr/share/man/man3/hx509_certs_end_seq.3.gz OLD_FILES+=usr/share/man/man3/hx509_certs_filter.3.gz OLD_FILES+=usr/share/man/man3/hx509_certs_find.3.gz OLD_FILES+=usr/share/man/man3/hx509_certs_free.3.gz OLD_FILES+=usr/share/man/man3/hx509_certs_info.3.gz OLD_FILES+=usr/share/man/man3/hx509_certs_init.3.gz OLD_FILES+=usr/share/man/man3/hx509_certs_iter_f.3.gz OLD_FILES+=usr/share/man/man3/hx509_certs_merge.3.gz OLD_FILES+=usr/share/man/man3/hx509_certs_next_cert.3.gz OLD_FILES+=usr/share/man/man3/hx509_certs_start_seq.3.gz OLD_FILES+=usr/share/man/man3/hx509_certs_store.3.gz OLD_FILES+=usr/share/man/man3/hx509_ci_print_names.3.gz OLD_FILES+=usr/share/man/man3/hx509_clear_error_string.3.gz OLD_FILES+=usr/share/man/man3/hx509_cms.3.gz OLD_FILES+=usr/share/man/man3/hx509_cms_create_signed_1.3.gz OLD_FILES+=usr/share/man/man3/hx509_cms_envelope_1.3.gz OLD_FILES+=usr/share/man/man3/hx509_cms_unenvelope.3.gz OLD_FILES+=usr/share/man/man3/hx509_cms_unwrap_ContentInfo.3.gz OLD_FILES+=usr/share/man/man3/hx509_cms_verify_signed.3.gz OLD_FILES+=usr/share/man/man3/hx509_cms_wrap_ContentInfo.3.gz OLD_FILES+=usr/share/man/man3/hx509_context_free.3.gz OLD_FILES+=usr/share/man/man3/hx509_context_init.3.gz OLD_FILES+=usr/share/man/man3/hx509_context_set_missing_revoke.3.gz OLD_FILES+=usr/share/man/man3/hx509_crl_add_revoked_certs.3.gz OLD_FILES+=usr/share/man/man3/hx509_crl_alloc.3.gz OLD_FILES+=usr/share/man/man3/hx509_crl_free.3.gz OLD_FILES+=usr/share/man/man3/hx509_crl_lifetime.3.gz OLD_FILES+=usr/share/man/man3/hx509_crl_sign.3.gz OLD_FILES+=usr/share/man/man3/hx509_crypto.3.gz OLD_FILES+=usr/share/man/man3/hx509_env.3.gz OLD_FILES+=usr/share/man/man3/hx509_env_add.3.gz OLD_FILES+=usr/share/man/man3/hx509_env_add_binding.3.gz OLD_FILES+=usr/share/man/man3/hx509_env_find.3.gz OLD_FILES+=usr/share/man/man3/hx509_env_find_binding.3.gz OLD_FILES+=usr/share/man/man3/hx509_env_free.3.gz OLD_FILES+=usr/share/man/man3/hx509_env_lfind.3.gz OLD_FILES+=usr/share/man/man3/hx509_err.3.gz OLD_FILES+=usr/share/man/man3/hx509_error.3.gz OLD_FILES+=usr/share/man/man3/hx509_free_error_string.3.gz OLD_FILES+=usr/share/man/man3/hx509_free_octet_string_list.3.gz OLD_FILES+=usr/share/man/man3/hx509_general_name_unparse.3.gz OLD_FILES+=usr/share/man/man3/hx509_get_error_string.3.gz OLD_FILES+=usr/share/man/man3/hx509_get_one_cert.3.gz OLD_FILES+=usr/share/man/man3/hx509_keyset.3.gz OLD_FILES+=usr/share/man/man3/hx509_lock.3.gz OLD_FILES+=usr/share/man/man3/hx509_misc.3.gz OLD_FILES+=usr/share/man/man3/hx509_name.3.gz OLD_FILES+=usr/share/man/man3/hx509_name_binary.3.gz OLD_FILES+=usr/share/man/man3/hx509_name_cmp.3.gz OLD_FILES+=usr/share/man/man3/hx509_name_copy.3.gz OLD_FILES+=usr/share/man/man3/hx509_name_expand.3.gz OLD_FILES+=usr/share/man/man3/hx509_name_free.3.gz OLD_FILES+=usr/share/man/man3/hx509_name_is_null_p.3.gz OLD_FILES+=usr/share/man/man3/hx509_name_to_Name.3.gz OLD_FILES+=usr/share/man/man3/hx509_name_to_string.3.gz OLD_FILES+=usr/share/man/man3/hx509_ocsp_request.3.gz OLD_FILES+=usr/share/man/man3/hx509_ocsp_verify.3.gz OLD_FILES+=usr/share/man/man3/hx509_oid_print.3.gz OLD_FILES+=usr/share/man/man3/hx509_oid_sprint.3.gz OLD_FILES+=usr/share/man/man3/hx509_parse_name.3.gz OLD_FILES+=usr/share/man/man3/hx509_peer.3.gz OLD_FILES+=usr/share/man/man3/hx509_peer_info_add_cms_alg.3.gz OLD_FILES+=usr/share/man/man3/hx509_peer_info_alloc.3.gz OLD_FILES+=usr/share/man/man3/hx509_peer_info_free.3.gz OLD_FILES+=usr/share/man/man3/hx509_peer_info_set_cert.3.gz OLD_FILES+=usr/share/man/man3/hx509_peer_info_set_cms_algs.3.gz OLD_FILES+=usr/share/man/man3/hx509_print.3.gz OLD_FILES+=usr/share/man/man3/hx509_print_cert.3.gz OLD_FILES+=usr/share/man/man3/hx509_print_stdout.3.gz OLD_FILES+=usr/share/man/man3/hx509_query.3.gz OLD_FILES+=usr/share/man/man3/hx509_query_alloc.3.gz OLD_FILES+=usr/share/man/man3/hx509_query_free.3.gz OLD_FILES+=usr/share/man/man3/hx509_query_match_cmp_func.3.gz OLD_FILES+=usr/share/man/man3/hx509_query_match_eku.3.gz OLD_FILES+=usr/share/man/man3/hx509_query_match_friendly_name.3.gz OLD_FILES+=usr/share/man/man3/hx509_query_match_issuer_serial.3.gz OLD_FILES+=usr/share/man/man3/hx509_query_match_option.3.gz OLD_FILES+=usr/share/man/man3/hx509_query_statistic_file.3.gz OLD_FILES+=usr/share/man/man3/hx509_query_unparse_stats.3.gz OLD_FILES+=usr/share/man/man3/hx509_revoke.3.gz OLD_FILES+=usr/share/man/man3/hx509_revoke_add_crl.3.gz OLD_FILES+=usr/share/man/man3/hx509_revoke_add_ocsp.3.gz OLD_FILES+=usr/share/man/man3/hx509_revoke_free.3.gz OLD_FILES+=usr/share/man/man3/hx509_revoke_init.3.gz OLD_FILES+=usr/share/man/man3/hx509_revoke_ocsp_print.3.gz OLD_FILES+=usr/share/man/man3/hx509_revoke_verify.3.gz OLD_FILES+=usr/share/man/man3/hx509_set_error_string.3.gz OLD_FILES+=usr/share/man/man3/hx509_set_error_stringv.3.gz OLD_FILES+=usr/share/man/man3/hx509_unparse_der_name.3.gz OLD_FILES+=usr/share/man/man3/hx509_validate_cert.3.gz OLD_FILES+=usr/share/man/man3/hx509_validate_ctx_add_flags.3.gz OLD_FILES+=usr/share/man/man3/hx509_validate_ctx_free.3.gz OLD_FILES+=usr/share/man/man3/hx509_validate_ctx_init.3.gz OLD_FILES+=usr/share/man/man3/hx509_validate_ctx_set_print.3.gz OLD_FILES+=usr/share/man/man3/hx509_verify.3.gz OLD_FILES+=usr/share/man/man3/hx509_verify_attach_anchors.3.gz OLD_FILES+=usr/share/man/man3/hx509_verify_attach_revoke.3.gz OLD_FILES+=usr/share/man/man3/hx509_verify_ctx_f_allow_default_trustanchors.3.gz OLD_FILES+=usr/share/man/man3/hx509_verify_destroy_ctx.3.gz OLD_FILES+=usr/share/man/man3/hx509_verify_hostname.3.gz OLD_FILES+=usr/share/man/man3/hx509_verify_init_ctx.3.gz OLD_FILES+=usr/share/man/man3/hx509_verify_path.3.gz OLD_FILES+=usr/share/man/man3/hx509_verify_set_max_depth.3.gz OLD_FILES+=usr/share/man/man3/hx509_verify_set_proxy_certificate.3.gz OLD_FILES+=usr/share/man/man3/hx509_verify_set_strict_rfc3280_verification.3.gz OLD_FILES+=usr/share/man/man3/hx509_verify_set_time.3.gz OLD_FILES+=usr/share/man/man3/hx509_verify_signature.3.gz OLD_FILES+=usr/share/man/man3/hx509_xfree.3.gz OLD_FILES+=usr/share/man/man3/k_afs_cell_of_file.3.gz OLD_FILES+=usr/share/man/man3/k_hasafs.3.gz OLD_FILES+=usr/share/man/man3/k_pioctl.3.gz OLD_FILES+=usr/share/man/man3/k_setpag.3.gz OLD_FILES+=usr/share/man/man3/k_unlog.3.gz OLD_FILES+=usr/share/man/man3/kadm5_pwcheck.3.gz OLD_FILES+=usr/share/man/man3/kafs.3.gz OLD_FILES+=usr/share/man/man3/kafs5.3.gz OLD_FILES+=usr/share/man/man3/kafs_set_verbose.3.gz OLD_FILES+=usr/share/man/man3/kafs_settoken.3.gz OLD_FILES+=usr/share/man/man3/kafs_settoken5.3.gz OLD_FILES+=usr/share/man/man3/kafs_settoken_rxkad.3.gz OLD_FILES+=usr/share/man/man3/krb5.3.gz OLD_FILES+=usr/share/man/man3/krb524_convert_creds_kdc.3.gz OLD_FILES+=usr/share/man/man3/krb524_convert_creds_kdc_ccache.3.gz OLD_FILES+=usr/share/man/man3/krb5_425_conv_principal.3.gz OLD_FILES+=usr/share/man/man3/krb5_425_conv_principal_ext.3.gz OLD_FILES+=usr/share/man/man3/krb5_524_conv_principal.3.gz OLD_FILES+=usr/share/man/man3/krb5_acc_ops.3.gz OLD_FILES+=usr/share/man/man3/krb5_acl_match_file.3.gz OLD_FILES+=usr/share/man/man3/krb5_acl_match_string.3.gz OLD_FILES+=usr/share/man/man3/krb5_add_et_list.3.gz OLD_FILES+=usr/share/man/man3/krb5_add_extra_addresses.3.gz OLD_FILES+=usr/share/man/man3/krb5_add_ignore_addresses.3.gz OLD_FILES+=usr/share/man/man3/krb5_addlog_dest.3.gz OLD_FILES+=usr/share/man/man3/krb5_addlog_func.3.gz OLD_FILES+=usr/share/man/man3/krb5_addr2sockaddr.3.gz OLD_FILES+=usr/share/man/man3/krb5_address.3.gz OLD_FILES+=usr/share/man/man3/krb5_address_compare.3.gz OLD_FILES+=usr/share/man/man3/krb5_address_order.3.gz OLD_FILES+=usr/share/man/man3/krb5_address_prefixlen_boundary.3.gz OLD_FILES+=usr/share/man/man3/krb5_address_search.3.gz OLD_FILES+=usr/share/man/man3/krb5_afslog.3.gz OLD_FILES+=usr/share/man/man3/krb5_afslog_uid.3.gz OLD_FILES+=usr/share/man/man3/krb5_allow_weak_crypto.3.gz OLD_FILES+=usr/share/man/man3/krb5_aname_to_localname.3.gz OLD_FILES+=usr/share/man/man3/krb5_anyaddr.3.gz OLD_FILES+=usr/share/man/man3/krb5_appdefault.3.gz OLD_FILES+=usr/share/man/man3/krb5_appdefault_boolean.3.gz OLD_FILES+=usr/share/man/man3/krb5_appdefault_string.3.gz OLD_FILES+=usr/share/man/man3/krb5_appdefault_time.3.gz OLD_FILES+=usr/share/man/man3/krb5_append_addresses.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_free.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_genaddrs.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_getaddrs.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_getflags.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_getkey.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_getlocalsubkey.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_getrcache.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_getremotesubkey.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_getuserkey.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_init.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_initivector.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_setaddrs.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_setaddrs_from_fd.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_setflags.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_setivector.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_setkey.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_setlocalsubkey.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_setrcache.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_setremotesubkey.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_con_setuserkey.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_context.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_getauthenticator.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_getcksumtype.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_getkeytype.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_getlocalseqnumber.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_getremoteseqnumber.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_setcksumtype.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_setkeytype.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_setlocalseqnumber.3.gz OLD_FILES+=usr/share/man/man3/krb5_auth_setremoteseqnumber.3.gz OLD_FILES+=usr/share/man/man3/krb5_build_principal.3.gz OLD_FILES+=usr/share/man/man3/krb5_build_principal_ext.3.gz OLD_FILES+=usr/share/man/man3/krb5_build_principal_va.3.gz OLD_FILES+=usr/share/man/man3/krb5_build_principal_va_ext.3.gz OLD_FILES+=usr/share/man/man3/krb5_c_enctype_compare.3.gz OLD_FILES+=usr/share/man/man3/krb5_c_make_checksum.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_cache_end_seq_get.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_cache_get_first.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_cache_match.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_cache_next.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_clear_mcred.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_close.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_copy_cache.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_copy_creds.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_copy_match_f.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_default.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_default_name.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_destroy.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_end_seq_get.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_gen_new.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_get_config.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_get_flags.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_get_friendly_name.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_get_full_name.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_get_kdc_offset.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_get_lifetime.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_get_name.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_get_ops.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_get_prefix_ops.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_get_principal.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_get_type.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_get_version.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_initialize.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_last_change_time.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_move.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_new_unique.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_next_cred.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_register.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_remove_cred.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_resolve.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_retrieve_cred.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_set_config.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_set_default_name.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_set_flags.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_set_friendly_name.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_set_kdc_offset.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_start_seq_get.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_store_cred.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_support_switch.3.gz OLD_FILES+=usr/share/man/man3/krb5_cc_switch.3.gz OLD_FILES+=usr/share/man/man3/krb5_ccache.3.gz OLD_FILES+=usr/share/man/man3/krb5_ccache_intro.3.gz OLD_FILES+=usr/share/man/man3/krb5_cccol_cursor_free.3.gz OLD_FILES+=usr/share/man/man3/krb5_cccol_cursor_new.3.gz OLD_FILES+=usr/share/man/man3/krb5_cccol_cursor_next.3.gz OLD_FILES+=usr/share/man/man3/krb5_cccol_last_change_time.3.gz OLD_FILES+=usr/share/man/man3/krb5_change_password.3.gz OLD_FILES+=usr/share/man/man3/krb5_check_transited.3.gz OLD_FILES+=usr/share/man/man3/krb5_checksum_is_collision_proof.3.gz OLD_FILES+=usr/share/man/man3/krb5_checksum_is_keyed.3.gz OLD_FILES+=usr/share/man/man3/krb5_checksumsize.3.gz OLD_FILES+=usr/share/man/man3/krb5_cksumtype_to_enctype.3.gz OLD_FILES+=usr/share/man/man3/krb5_clear_error_message.3.gz OLD_FILES+=usr/share/man/man3/krb5_clear_error_string.3.gz OLD_FILES+=usr/share/man/man3/krb5_closelog.3.gz OLD_FILES+=usr/share/man/man3/krb5_compare_creds.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_file_free.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_free_strings.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_get_bool.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_get_bool_default.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_get_list.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_get_string.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_get_string_default.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_get_strings.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_get_time.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_get_time_default.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_parse_file_multi.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_parse_string_multi.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_vget_bool.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_vget_bool_default.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_vget_list.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_vget_string.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_vget_string_default.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_vget_strings.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_vget_time.3.gz OLD_FILES+=usr/share/man/man3/krb5_config_vget_time_default.3.gz OLD_FILES+=usr/share/man/man3/krb5_copy_address.3.gz OLD_FILES+=usr/share/man/man3/krb5_copy_addresses.3.gz OLD_FILES+=usr/share/man/man3/krb5_copy_context.3.gz OLD_FILES+=usr/share/man/man3/krb5_copy_creds.3.gz OLD_FILES+=usr/share/man/man3/krb5_copy_creds_contents.3.gz OLD_FILES+=usr/share/man/man3/krb5_copy_data.3.gz OLD_FILES+=usr/share/man/man3/krb5_copy_host_realm.3.gz OLD_FILES+=usr/share/man/man3/krb5_copy_keyblock.3.gz OLD_FILES+=usr/share/man/man3/krb5_copy_keyblock_contents.3.gz OLD_FILES+=usr/share/man/man3/krb5_copy_principal.3.gz OLD_FILES+=usr/share/man/man3/krb5_copy_ticket.3.gz OLD_FILES+=usr/share/man/man3/krb5_create_checksum.3.gz OLD_FILES+=usr/share/man/man3/krb5_create_checksum_iov.3.gz OLD_FILES+=usr/share/man/man3/krb5_credential.3.gz OLD_FILES+=usr/share/man/man3/krb5_creds.3.gz OLD_FILES+=usr/share/man/man3/krb5_creds_get_ticket_flags.3.gz OLD_FILES+=usr/share/man/man3/krb5_crypto.3.gz OLD_FILES+=usr/share/man/man3/krb5_crypto_destroy.3.gz OLD_FILES+=usr/share/man/man3/krb5_crypto_fx_cf2.3.gz OLD_FILES+=usr/share/man/man3/krb5_crypto_getblocksize.3.gz OLD_FILES+=usr/share/man/man3/krb5_crypto_getconfoundersize.3.gz OLD_FILES+=usr/share/man/man3/krb5_crypto_getenctype.3.gz OLD_FILES+=usr/share/man/man3/krb5_crypto_getpadsize.3.gz OLD_FILES+=usr/share/man/man3/krb5_crypto_init.3.gz OLD_FILES+=usr/share/man/man3/krb5_crypto_iov.3.gz OLD_FILES+=usr/share/man/man3/krb5_data_alloc.3.gz OLD_FILES+=usr/share/man/man3/krb5_data_cmp.3.gz OLD_FILES+=usr/share/man/man3/krb5_data_copy.3.gz OLD_FILES+=usr/share/man/man3/krb5_data_ct_cmp.3.gz OLD_FILES+=usr/share/man/man3/krb5_data_free.3.gz OLD_FILES+=usr/share/man/man3/krb5_data_realloc.3.gz OLD_FILES+=usr/share/man/man3/krb5_data_zero.3.gz OLD_FILES+=usr/share/man/man3/krb5_decrypt.3.gz OLD_FILES+=usr/share/man/man3/krb5_decrypt_EncryptedData.3.gz OLD_FILES+=usr/share/man/man3/krb5_decrypt_iov_ivec.3.gz OLD_FILES+=usr/share/man/man3/krb5_deprecated.3.gz OLD_FILES+=usr/share/man/man3/krb5_digest.3.gz OLD_FILES+=usr/share/man/man3/krb5_digest_probe.3.gz OLD_FILES+=usr/share/man/man3/krb5_eai_to_heim_errno.3.gz OLD_FILES+=usr/share/man/man3/krb5_encrypt.3.gz OLD_FILES+=usr/share/man/man3/krb5_encrypt_EncryptedData.3.gz OLD_FILES+=usr/share/man/man3/krb5_encrypt_iov_ivec.3.gz OLD_FILES+=usr/share/man/man3/krb5_enctype_disable.3.gz OLD_FILES+=usr/share/man/man3/krb5_enctype_enable.3.gz OLD_FILES+=usr/share/man/man3/krb5_enctype_valid.3.gz OLD_FILES+=usr/share/man/man3/krb5_enctypes_compatible_keys.3.gz OLD_FILES+=usr/share/man/man3/krb5_error.3.gz OLD_FILES+=usr/share/man/man3/krb5_expand_hostname.3.gz OLD_FILES+=usr/share/man/man3/krb5_expand_hostname_realms.3.gz OLD_FILES+=usr/share/man/man3/krb5_fcc_ops.3.gz OLD_FILES+=usr/share/man/man3/krb5_fileformats.3.gz OLD_FILES+=usr/share/man/man3/krb5_find_padata.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_address.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_addresses.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_config_files.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_context.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_cred_contents.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_creds.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_creds_contents.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_data.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_data_contents.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_error_string.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_host_realm.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_keyblock.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_keyblock_contents.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_krbhst.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_principal.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_ticket.3.gz OLD_FILES+=usr/share/man/man3/krb5_free_unparsed_name.3.gz OLD_FILES+=usr/share/man/man3/krb5_fwd_tgt_creds.3.gz OLD_FILES+=usr/share/man/man3/krb5_generate_random_block.3.gz OLD_FILES+=usr/share/man/man3/krb5_generate_subkey.3.gz OLD_FILES+=usr/share/man/man3/krb5_generate_subkey_extended.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_all_client_addrs.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_all_server_addrs.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_cred_from_kdc.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_cred_from_kdc_opt.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_credentials.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_creds.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_default_config_files.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_default_in_tkt_etypes.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_default_principal.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_default_realm.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_default_realms.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_dns_canonicalize_hostname.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_extra_addresses.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_fcache_version.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_forwarded_creds.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_host_realm.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_ignore_addresses.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_in_cred.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_in_tkt_with_keytab.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_in_tkt_with_password.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_in_tkt_with_skey.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_init_creds.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_init_creds_keyblock.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_init_creds_keytab.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_init_creds_opt_alloc.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_init_creds_opt_free.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_init_creds_opt_get_error.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_init_creds_opt_init.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_init_creds_password.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_kdc_sec_offset.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_krb524hst.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_krb_admin_hst.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_krb_changepw_hst.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_krbhst.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_max_time_skew.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_use_admin_kdc.3.gz OLD_FILES+=usr/share/man/man3/krb5_get_validated_creds.3.gz OLD_FILES+=usr/share/man/man3/krb5_getportbyname.3.gz OLD_FILES+=usr/share/man/man3/krb5_h_addr2addr.3.gz OLD_FILES+=usr/share/man/man3/krb5_h_addr2sockaddr.3.gz OLD_FILES+=usr/share/man/man3/krb5_h_errno_to_heim_errno.3.gz OLD_FILES+=usr/share/man/man3/krb5_init_context.3.gz OLD_FILES+=usr/share/man/man3/krb5_init_creds_free.3.gz OLD_FILES+=usr/share/man/man3/krb5_init_creds_get.3.gz OLD_FILES+=usr/share/man/man3/krb5_init_creds_get_error.3.gz OLD_FILES+=usr/share/man/man3/krb5_init_creds_init.3.gz OLD_FILES+=usr/share/man/man3/krb5_init_creds_intro.3.gz OLD_FILES+=usr/share/man/man3/krb5_init_creds_set_keytab.3.gz OLD_FILES+=usr/share/man/man3/krb5_init_creds_set_password.3.gz OLD_FILES+=usr/share/man/man3/krb5_init_creds_set_service.3.gz OLD_FILES+=usr/share/man/man3/krb5_init_creds_step.3.gz OLD_FILES+=usr/share/man/man3/krb5_init_ets.3.gz OLD_FILES+=usr/share/man/man3/krb5_initlog.3.gz OLD_FILES+=usr/share/man/man3/krb5_introduction.3.gz OLD_FILES+=usr/share/man/man3/krb5_is_config_principal.3.gz OLD_FILES+=usr/share/man/man3/krb5_is_thread_safe.3.gz OLD_FILES+=usr/share/man/man3/krb5_kerberos_enctypes.3.gz OLD_FILES+=usr/share/man/man3/krb5_keyblock_get_enctype.3.gz OLD_FILES+=usr/share/man/man3/krb5_keyblock_init.3.gz OLD_FILES+=usr/share/man/man3/krb5_keyblock_zero.3.gz OLD_FILES+=usr/share/man/man3/krb5_keytab.3.gz OLD_FILES+=usr/share/man/man3/krb5_keytab_intro.3.gz OLD_FILES+=usr/share/man/man3/krb5_keytab_key_proc.3.gz OLD_FILES+=usr/share/man/man3/krb5_keytype_to_enctypes.3.gz OLD_FILES+=usr/share/man/man3/krb5_keytype_to_enctypes_default.3.gz OLD_FILES+=usr/share/man/man3/krb5_keytype_to_string.3.gz OLD_FILES+=usr/share/man/man3/krb5_krbhst_format_string.3.gz OLD_FILES+=usr/share/man/man3/krb5_krbhst_free.3.gz OLD_FILES+=usr/share/man/man3/krb5_krbhst_get_addrinfo.3.gz OLD_FILES+=usr/share/man/man3/krb5_krbhst_init.3.gz OLD_FILES+=usr/share/man/man3/krb5_krbhst_next.3.gz OLD_FILES+=usr/share/man/man3/krb5_krbhst_next_as_string.3.gz OLD_FILES+=usr/share/man/man3/krb5_krbhst_reset.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_add_entry.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_close.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_compare.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_copy_entry_contents.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_default.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_default_modify_name.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_default_name.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_destroy.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_end_seq_get.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_free_entry.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_get_entry.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_get_full_name.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_get_name.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_get_type.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_have_content.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_next_entry.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_read_service_key.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_register.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_remove_entry.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_resolve.3.gz OLD_FILES+=usr/share/man/man3/krb5_kt_start_seq_get.3.gz OLD_FILES+=usr/share/man/man3/krb5_kuserok.3.gz OLD_FILES+=usr/share/man/man3/krb5_log.3.gz OLD_FILES+=usr/share/man/man3/krb5_log_msg.3.gz OLD_FILES+=usr/share/man/man3/krb5_make_addrport.3.gz OLD_FILES+=usr/share/man/man3/krb5_make_principal.3.gz OLD_FILES+=usr/share/man/man3/krb5_max_sockaddr_size.3.gz OLD_FILES+=usr/share/man/man3/krb5_mcc_ops.3.gz OLD_FILES+=usr/share/man/man3/krb5_mk_req.3.gz OLD_FILES+=usr/share/man/man3/krb5_mk_safe.3.gz OLD_FILES+=usr/share/man/man3/krb5_openlog.3.gz OLD_FILES+=usr/share/man/man3/krb5_pac.3.gz OLD_FILES+=usr/share/man/man3/krb5_pac_get_buffer.3.gz OLD_FILES+=usr/share/man/man3/krb5_pac_verify.3.gz OLD_FILES+=usr/share/man/man3/krb5_parse_address.3.gz OLD_FILES+=usr/share/man/man3/krb5_parse_name.3.gz OLD_FILES+=usr/share/man/man3/krb5_parse_name_flags.3.gz OLD_FILES+=usr/share/man/man3/krb5_parse_nametype.3.gz OLD_FILES+=usr/share/man/man3/krb5_password_key_proc.3.gz OLD_FILES+=usr/share/man/man3/krb5_plugin_register.3.gz OLD_FILES+=usr/share/man/man3/krb5_prepend_config_files_default.3.gz OLD_FILES+=usr/share/man/man3/krb5_princ_realm.3.gz OLD_FILES+=usr/share/man/man3/krb5_princ_set_realm.3.gz OLD_FILES+=usr/share/man/man3/krb5_principal.3.gz OLD_FILES+=usr/share/man/man3/krb5_principal_compare.3.gz OLD_FILES+=usr/share/man/man3/krb5_principal_compare_any_realm.3.gz OLD_FILES+=usr/share/man/man3/krb5_principal_get_comp_string.3.gz OLD_FILES+=usr/share/man/man3/krb5_principal_get_num_comp.3.gz OLD_FILES+=usr/share/man/man3/krb5_principal_get_realm.3.gz OLD_FILES+=usr/share/man/man3/krb5_principal_get_type.3.gz OLD_FILES+=usr/share/man/man3/krb5_principal_intro.3.gz OLD_FILES+=usr/share/man/man3/krb5_principal_is_krbtgt.3.gz OLD_FILES+=usr/share/man/man3/krb5_principal_match.3.gz OLD_FILES+=usr/share/man/man3/krb5_principal_set_realm.3.gz OLD_FILES+=usr/share/man/man3/krb5_principal_set_type.3.gz OLD_FILES+=usr/share/man/man3/krb5_print_address.3.gz OLD_FILES+=usr/share/man/man3/krb5_random_to_key.3.gz OLD_FILES+=usr/share/man/man3/krb5_rcache.3.gz OLD_FILES+=usr/share/man/man3/krb5_rd_error.3.gz OLD_FILES+=usr/share/man/man3/krb5_rd_req_ctx.3.gz OLD_FILES+=usr/share/man/man3/krb5_rd_req_in_ctx_alloc.3.gz OLD_FILES+=usr/share/man/man3/krb5_rd_req_in_set_keytab.3.gz OLD_FILES+=usr/share/man/man3/krb5_rd_req_in_set_pac_check.3.gz OLD_FILES+=usr/share/man/man3/krb5_rd_req_out_ctx_free.3.gz OLD_FILES+=usr/share/man/man3/krb5_rd_req_out_get_server.3.gz OLD_FILES+=usr/share/man/man3/krb5_rd_safe.3.gz OLD_FILES+=usr/share/man/man3/krb5_realm_compare.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_address.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_addrs.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_authdata.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_creds.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_creds_tag.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_data.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_int16.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_int32.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_int8.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_keyblock.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_principal.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_string.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_stringz.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_times.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_uint16.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_uint32.3.gz OLD_FILES+=usr/share/man/man3/krb5_ret_uint8.3.gz OLD_FILES+=usr/share/man/man3/krb5_set_config_files.3.gz OLD_FILES+=usr/share/man/man3/krb5_set_default_in_tkt_etypes.3.gz OLD_FILES+=usr/share/man/man3/krb5_set_default_realm.3.gz OLD_FILES+=usr/share/man/man3/krb5_set_dns_canonicalize_hostname.3.gz OLD_FILES+=usr/share/man/man3/krb5_set_error_message.3.gz OLD_FILES+=usr/share/man/man3/krb5_set_error_string.3.gz OLD_FILES+=usr/share/man/man3/krb5_set_extra_addresses.3.gz OLD_FILES+=usr/share/man/man3/krb5_set_fcache_version.3.gz OLD_FILES+=usr/share/man/man3/krb5_set_home_dir_access.3.gz OLD_FILES+=usr/share/man/man3/krb5_set_ignore_addresses.3.gz OLD_FILES+=usr/share/man/man3/krb5_set_kdc_sec_offset.3.gz OLD_FILES+=usr/share/man/man3/krb5_set_max_time_skew.3.gz OLD_FILES+=usr/share/man/man3/krb5_set_password.3.gz OLD_FILES+=usr/share/man/man3/krb5_set_real_time.3.gz OLD_FILES+=usr/share/man/man3/krb5_set_use_admin_kdc.3.gz OLD_FILES+=usr/share/man/man3/krb5_sname_to_principal.3.gz OLD_FILES+=usr/share/man/man3/krb5_sock_to_principal.3.gz OLD_FILES+=usr/share/man/man3/krb5_sockaddr2address.3.gz OLD_FILES+=usr/share/man/man3/krb5_sockaddr2port.3.gz OLD_FILES+=usr/share/man/man3/krb5_sockaddr_uninteresting.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_clear_flags.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_emem.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_free.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_from_data.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_from_fd.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_from_mem.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_from_readonly_mem.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_get_byteorder.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_get_eof_code.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_is_flags.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_read.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_seek.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_set_byteorder.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_set_eof_code.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_set_flags.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_set_max_alloc.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_to_data.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_truncate.3.gz OLD_FILES+=usr/share/man/man3/krb5_storage_write.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_address.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_addrs.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_authdata.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_creds.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_creds_tag.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_data.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_int16.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_int32.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_int8.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_keyblock.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_principal.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_string.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_stringz.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_times.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_uint16.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_uint32.3.gz OLD_FILES+=usr/share/man/man3/krb5_store_uint8.3.gz OLD_FILES+=usr/share/man/man3/krb5_string_to_key.3.gz OLD_FILES+=usr/share/man/man3/krb5_string_to_keytype.3.gz OLD_FILES+=usr/share/man/man3/krb5_support.3.gz OLD_FILES+=usr/share/man/man3/krb5_ticket.3.gz OLD_FILES+=usr/share/man/man3/krb5_ticket_get_authorization_data_type.3.gz OLD_FILES+=usr/share/man/man3/krb5_ticket_get_client.3.gz OLD_FILES+=usr/share/man/man3/krb5_ticket_get_endtime.3.gz OLD_FILES+=usr/share/man/man3/krb5_ticket_get_flags.3.gz OLD_FILES+=usr/share/man/man3/krb5_ticket_get_server.3.gz OLD_FILES+=usr/share/man/man3/krb5_timeofday.3.gz OLD_FILES+=usr/share/man/man3/krb5_unparse_name.3.gz OLD_FILES+=usr/share/man/man3/krb5_unparse_name_fixed.3.gz OLD_FILES+=usr/share/man/man3/krb5_unparse_name_fixed_flags.3.gz OLD_FILES+=usr/share/man/man3/krb5_unparse_name_fixed_short.3.gz OLD_FILES+=usr/share/man/man3/krb5_unparse_name_flags.3.gz OLD_FILES+=usr/share/man/man3/krb5_unparse_name_short.3.gz OLD_FILES+=usr/share/man/man3/krb5_us_timeofday.3.gz OLD_FILES+=usr/share/man/man3/krb5_v4compat.3.gz OLD_FILES+=usr/share/man/man3/krb5_verify_checksum.3.gz OLD_FILES+=usr/share/man/man3/krb5_verify_checksum_iov.3.gz OLD_FILES+=usr/share/man/man3/krb5_verify_init_creds.3.gz OLD_FILES+=usr/share/man/man3/krb5_verify_opt_init.3.gz OLD_FILES+=usr/share/man/man3/krb5_verify_opt_set_flags.3.gz OLD_FILES+=usr/share/man/man3/krb5_verify_opt_set_keytab.3.gz OLD_FILES+=usr/share/man/man3/krb5_verify_opt_set_secure.3.gz OLD_FILES+=usr/share/man/man3/krb5_verify_opt_set_service.3.gz OLD_FILES+=usr/share/man/man3/krb5_verify_user.3.gz OLD_FILES+=usr/share/man/man3/krb5_verify_user_lrealm.3.gz OLD_FILES+=usr/share/man/man3/krb5_verify_user_opt.3.gz OLD_FILES+=usr/share/man/man3/krb5_vlog.3.gz OLD_FILES+=usr/share/man/man3/krb5_vlog_msg.3.gz OLD_FILES+=usr/share/man/man3/krb5_vset_error_string.3.gz OLD_FILES+=usr/share/man/man3/krb5_vwarn.3.gz OLD_FILES+=usr/share/man/man3/krb_afslog.3.gz OLD_FILES+=usr/share/man/man3/krb_afslog_uid.3.gz OLD_FILES+=usr/share/man/man3/ntlm_buf.3.gz OLD_FILES+=usr/share/man/man3/ntlm_core.3.gz OLD_FILES+=usr/share/man/man3/ntlm_type1.3.gz OLD_FILES+=usr/share/man/man3/ntlm_type2.3.gz OLD_FILES+=usr/share/man/man3/ntlm_type3.3.gz OLD_FILES+=usr/share/man/man5/krb5.conf.5.gz OLD_FILES+=usr/share/man/man8/hprop.8.gz OLD_FILES+=usr/share/man/man8/hpropd.8.gz OLD_FILES+=usr/share/man/man8/iprop-log.8.gz OLD_FILES+=usr/share/man/man8/iprop.8.gz OLD_FILES+=usr/share/man/man8/kadmin.8.gz OLD_FILES+=usr/share/man/man8/kadmind.8.gz OLD_FILES+=usr/share/man/man8/kcm.8.gz OLD_FILES+=usr/share/man/man8/kdc.8.gz OLD_FILES+=usr/share/man/man8/kdigest.8.gz OLD_FILES+=usr/share/man/man8/kerberos.8.gz OLD_FILES+=usr/share/man/man8/kimpersonate.8.gz OLD_FILES+=usr/share/man/man8/kpasswdd.8.gz OLD_FILES+=usr/share/man/man8/kstash.8.gz OLD_FILES+=usr/share/man/man8/ktutil.8.gz OLD_FILES+=usr/share/man/man8/pam_krb5.8.gz OLD_FILES+=usr/share/man/man8/pam_ksu.8.gz OLD_FILES+=usr/share/man/man8/string2key.8.gz OLD_FILES+=usr/share/man/man8/verify_krb5_conf.8.gz .endif .if ${MK_KERBEROS_SUPPORT} == no OLD_FILES+=usr/bin/compile_et OLD_FILES+=usr/include/com_err.h OLD_FILES+=usr/include/com_right.h OLD_FILES+=usr/lib/libcom_err.a OLD_FILES+=usr/lib/libcom_err.so OLD_LIBS+=usr/lib/libcom_err.so.5 OLD_FILES+=usr/lib/libcom_err_p.a OLD_FILES+=usr/lib32/libcom_err.a OLD_FILES+=usr/lib32/libcom_err.so OLD_LIBS+=usr/lib32/libcom_err.so.5 OLD_FILES+=usr/lib32/libcom_err_p.a OLD_FILES+=usr/share/man/man1/compile_et.1.gz OLD_FILES+=usr/share/man/man3/com_err.3.gz .endif .if ${MK_LDNS} == no OLD_FILES+=usr/lib/private/libldns.a OLD_FILES+=usr/lib/private/libldns.so OLD_LIBS+=usr/lib/private/libldns.so.5 OLD_FILES+=usr/lib/private/libldns_p.a .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/lib32/private/libldns.a OLD_FILES+=usr/lib32/private/libldns.so OLD_LIBS+=usr/lib32/private/libldns.so.5 OLD_FILES+=usr/lib32/private/libldns_p.a .endif .endif .if ${MK_LDNS_UTILS} == no OLD_FILES+=usr/bin/drill OLD_FILES+=usr/share/man/man1/drill.1.gz OLD_FILES+=usr/bin/host OLD_FILES+=usr/share/man/man1/host.1.gz .endif .if ${MK_LEGACY_CONSOLE} == no OLD_FILES+=usr/sbin/kbdcontrol OLD_FILES+=usr/sbin/kbdmap OLD_FILES+=usr/sbin/moused OLD_FILES+=usr/sbin/vidcontrol OLD_FILES+=usr/sbin/vidfont OLD_FILES+=usr/share/man/man1/kbdcontrol.1.gz OLD_FILES+=usr/share/man/man1/kbdmap.1.gz OLD_FILES+=usr/share/man/man1/vidcontrol.1.gz OLD_FILES+=usr/share/man/man1/vidfont.1.gz OLD_FILES+=usr/share/man/man5/kbdmap.5.gz OLD_FILES+=usr/share/man/man5/keymap.5.gz OLD_FILES+=usr/share/man/man8/moused.8.gz .endif #.if ${MK_LIB32} == no # to be filled in #.endif .if ${MK_LIBCPLUSPLUS} == no OLD_LIBS+=lib/libcxxrt.so.1 OLD_FILES+=usr/lib/libc++.a OLD_FILES+=usr/lib/libc++_p.a OLD_FILES+=usr/lib/libc++.so OLD_LIBS+=usr/lib/libc++.so.1 OLD_FILES+=usr/lib/libcxxrt.a OLD_FILES+=usr/lib/libcxxrt.so OLD_FILES+=usr/lib/libcxxrt_p.a OLD_FILES+=usr/include/c++/v1/__bit_reference OLD_FILES+=usr/include/c++/v1/__config OLD_FILES+=usr/include/c++/v1/__debug OLD_FILES+=usr/include/c++/v1/__functional_03 OLD_FILES+=usr/include/c++/v1/__functional_base OLD_FILES+=usr/include/c++/v1/__functional_base_03 OLD_FILES+=usr/include/c++/v1/__hash_table OLD_FILES+=usr/include/c++/v1/__locale OLD_FILES+=usr/include/c++/v1/__mutex_base OLD_FILES+=usr/include/c++/v1/__refstring OLD_FILES+=usr/include/c++/v1/__split_buffer OLD_FILES+=usr/include/c++/v1/__sso_allocator OLD_FILES+=usr/include/c++/v1/__std_stream OLD_FILES+=usr/include/c++/v1/__tree OLD_FILES+=usr/include/c++/v1/__tuple OLD_FILES+=usr/include/c++/v1/__tuple_03 OLD_FILES+=usr/include/c++/v1/__undef_min_max OLD_FILES+=usr/include/c++/v1/algorithm OLD_FILES+=usr/include/c++/v1/array OLD_FILES+=usr/include/c++/v1/atomic OLD_FILES+=usr/include/c++/v1/bitset OLD_FILES+=usr/include/c++/v1/cassert OLD_FILES+=usr/include/c++/v1/ccomplex OLD_FILES+=usr/include/c++/v1/cctype OLD_FILES+=usr/include/c++/v1/cerrno OLD_FILES+=usr/include/c++/v1/cfenv OLD_FILES+=usr/include/c++/v1/cfloat OLD_FILES+=usr/include/c++/v1/chrono OLD_FILES+=usr/include/c++/v1/cinttypes OLD_FILES+=usr/include/c++/v1/ciso646 OLD_FILES+=usr/include/c++/v1/climits OLD_FILES+=usr/include/c++/v1/clocale OLD_FILES+=usr/include/c++/v1/cmath OLD_FILES+=usr/include/c++/v1/codecvt OLD_FILES+=usr/include/c++/v1/complex OLD_FILES+=usr/include/c++/v1/complex.h OLD_FILES+=usr/include/c++/v1/condition_variable OLD_FILES+=usr/include/c++/v1/csetjmp OLD_FILES+=usr/include/c++/v1/csignal OLD_FILES+=usr/include/c++/v1/cstdarg OLD_FILES+=usr/include/c++/v1/cstdbool OLD_FILES+=usr/include/c++/v1/cstddef OLD_FILES+=usr/include/c++/v1/cstdint OLD_FILES+=usr/include/c++/v1/cstdio OLD_FILES+=usr/include/c++/v1/cstdlib OLD_FILES+=usr/include/c++/v1/cstring OLD_FILES+=usr/include/c++/v1/ctgmath OLD_FILES+=usr/include/c++/v1/ctime OLD_FILES+=usr/include/c++/v1/cwchar OLD_FILES+=usr/include/c++/v1/cwctype OLD_FILES+=usr/include/c++/v1/cxxabi.h OLD_FILES+=usr/include/c++/v1/deque OLD_FILES+=usr/include/c++/v1/exception OLD_FILES+=usr/include/c++/v1/experimental/__config OLD_FILES+=usr/include/c++/v1/experimental/dynarray OLD_FILES+=usr/include/c++/v1/experimental/optional OLD_FILES+=usr/include/c++/v1/experimental/string_view OLD_FILES+=usr/include/c++/v1/experimental/type_traits OLD_FILES+=usr/include/c++/v1/experimental/utility OLD_FILES+=usr/include/c++/v1/ext/__hash OLD_FILES+=usr/include/c++/v1/ext/hash_map OLD_FILES+=usr/include/c++/v1/ext/hash_set OLD_FILES+=usr/include/c++/v1/forward_list OLD_FILES+=usr/include/c++/v1/fstream OLD_FILES+=usr/include/c++/v1/functional OLD_FILES+=usr/include/c++/v1/future OLD_FILES+=usr/include/c++/v1/initializer_list OLD_FILES+=usr/include/c++/v1/iomanip OLD_FILES+=usr/include/c++/v1/ios OLD_FILES+=usr/include/c++/v1/iosfwd OLD_FILES+=usr/include/c++/v1/iostream OLD_FILES+=usr/include/c++/v1/istream OLD_FILES+=usr/include/c++/v1/iterator OLD_FILES+=usr/include/c++/v1/limits OLD_FILES+=usr/include/c++/v1/list OLD_FILES+=usr/include/c++/v1/locale OLD_FILES+=usr/include/c++/v1/map OLD_FILES+=usr/include/c++/v1/memory OLD_FILES+=usr/include/c++/v1/mutex OLD_FILES+=usr/include/c++/v1/new OLD_FILES+=usr/include/c++/v1/numeric OLD_FILES+=usr/include/c++/v1/ostream OLD_FILES+=usr/include/c++/v1/queue OLD_FILES+=usr/include/c++/v1/random OLD_FILES+=usr/include/c++/v1/ratio OLD_FILES+=usr/include/c++/v1/regex OLD_FILES+=usr/include/c++/v1/scoped_allocator OLD_FILES+=usr/include/c++/v1/set OLD_FILES+=usr/include/c++/v1/shared_mutex OLD_FILES+=usr/include/c++/v1/sstream OLD_FILES+=usr/include/c++/v1/stack OLD_FILES+=usr/include/c++/v1/stdexcept OLD_FILES+=usr/include/c++/v1/streambuf OLD_FILES+=usr/include/c++/v1/string OLD_FILES+=usr/include/c++/v1/strstream OLD_FILES+=usr/include/c++/v1/system_error OLD_FILES+=usr/include/c++/v1/tgmath.h OLD_FILES+=usr/include/c++/v1/thread OLD_FILES+=usr/include/c++/v1/tr1/__bit_reference OLD_FILES+=usr/include/c++/v1/tr1/__config OLD_FILES+=usr/include/c++/v1/tr1/__debug OLD_FILES+=usr/include/c++/v1/tr1/__functional_03 OLD_FILES+=usr/include/c++/v1/tr1/__functional_base OLD_FILES+=usr/include/c++/v1/tr1/__functional_base_03 OLD_FILES+=usr/include/c++/v1/tr1/__hash_table OLD_FILES+=usr/include/c++/v1/tr1/__locale OLD_FILES+=usr/include/c++/v1/tr1/__mutex_base OLD_FILES+=usr/include/c++/v1/tr1/__refstring OLD_FILES+=usr/include/c++/v1/tr1/__split_buffer OLD_FILES+=usr/include/c++/v1/tr1/__sso_allocator OLD_FILES+=usr/include/c++/v1/tr1/__std_stream OLD_FILES+=usr/include/c++/v1/tr1/__tree OLD_FILES+=usr/include/c++/v1/tr1/__tuple OLD_FILES+=usr/include/c++/v1/tr1/__tuple_03 OLD_FILES+=usr/include/c++/v1/tr1/__undef_min_max OLD_FILES+=usr/include/c++/v1/tr1/algorithm OLD_FILES+=usr/include/c++/v1/tr1/array OLD_FILES+=usr/include/c++/v1/tr1/atomic OLD_FILES+=usr/include/c++/v1/tr1/bitset OLD_FILES+=usr/include/c++/v1/tr1/cassert OLD_FILES+=usr/include/c++/v1/tr1/ccomplex OLD_FILES+=usr/include/c++/v1/tr1/cctype OLD_FILES+=usr/include/c++/v1/tr1/cerrno OLD_FILES+=usr/include/c++/v1/tr1/cfenv OLD_FILES+=usr/include/c++/v1/tr1/cfloat OLD_FILES+=usr/include/c++/v1/tr1/chrono OLD_FILES+=usr/include/c++/v1/tr1/cinttypes OLD_FILES+=usr/include/c++/v1/tr1/ciso646 OLD_FILES+=usr/include/c++/v1/tr1/climits OLD_FILES+=usr/include/c++/v1/tr1/clocale OLD_FILES+=usr/include/c++/v1/tr1/cmath OLD_FILES+=usr/include/c++/v1/tr1/codecvt OLD_FILES+=usr/include/c++/v1/tr1/complex OLD_FILES+=usr/include/c++/v1/tr1/complex.h OLD_FILES+=usr/include/c++/v1/tr1/condition_variable OLD_FILES+=usr/include/c++/v1/tr1/csetjmp OLD_FILES+=usr/include/c++/v1/tr1/csignal OLD_FILES+=usr/include/c++/v1/tr1/cstdarg OLD_FILES+=usr/include/c++/v1/tr1/cstdbool OLD_FILES+=usr/include/c++/v1/tr1/cstddef OLD_FILES+=usr/include/c++/v1/tr1/cstdint OLD_FILES+=usr/include/c++/v1/tr1/cstdio OLD_FILES+=usr/include/c++/v1/tr1/cstdlib OLD_FILES+=usr/include/c++/v1/tr1/cstring OLD_FILES+=usr/include/c++/v1/tr1/ctgmath OLD_FILES+=usr/include/c++/v1/tr1/ctime OLD_FILES+=usr/include/c++/v1/tr1/cwchar OLD_FILES+=usr/include/c++/v1/tr1/cwctype OLD_FILES+=usr/include/c++/v1/tr1/deque OLD_FILES+=usr/include/c++/v1/tr1/exception OLD_FILES+=usr/include/c++/v1/tr1/forward_list OLD_FILES+=usr/include/c++/v1/tr1/fstream OLD_FILES+=usr/include/c++/v1/tr1/functional OLD_FILES+=usr/include/c++/v1/tr1/future OLD_FILES+=usr/include/c++/v1/tr1/initializer_list OLD_FILES+=usr/include/c++/v1/tr1/iomanip OLD_FILES+=usr/include/c++/v1/tr1/ios OLD_FILES+=usr/include/c++/v1/tr1/iosfwd OLD_FILES+=usr/include/c++/v1/tr1/iostream OLD_FILES+=usr/include/c++/v1/tr1/istream OLD_FILES+=usr/include/c++/v1/tr1/iterator OLD_FILES+=usr/include/c++/v1/tr1/limits OLD_FILES+=usr/include/c++/v1/tr1/list OLD_FILES+=usr/include/c++/v1/tr1/locale OLD_FILES+=usr/include/c++/v1/tr1/map OLD_FILES+=usr/include/c++/v1/tr1/memory OLD_FILES+=usr/include/c++/v1/tr1/mutex OLD_FILES+=usr/include/c++/v1/tr1/new OLD_FILES+=usr/include/c++/v1/tr1/numeric OLD_FILES+=usr/include/c++/v1/tr1/ostream OLD_FILES+=usr/include/c++/v1/tr1/queue OLD_FILES+=usr/include/c++/v1/tr1/random OLD_FILES+=usr/include/c++/v1/tr1/ratio OLD_FILES+=usr/include/c++/v1/tr1/regex OLD_FILES+=usr/include/c++/v1/tr1/scoped_allocator OLD_FILES+=usr/include/c++/v1/tr1/set OLD_FILES+=usr/include/c++/v1/tr1/shared_mutex OLD_FILES+=usr/include/c++/v1/tr1/sstream OLD_FILES+=usr/include/c++/v1/tr1/stack OLD_FILES+=usr/include/c++/v1/tr1/stdexcept OLD_FILES+=usr/include/c++/v1/tr1/streambuf OLD_FILES+=usr/include/c++/v1/tr1/string OLD_FILES+=usr/include/c++/v1/tr1/strstream OLD_FILES+=usr/include/c++/v1/tr1/system_error OLD_FILES+=usr/include/c++/v1/tr1/tgmath.h OLD_FILES+=usr/include/c++/v1/tr1/thread OLD_FILES+=usr/include/c++/v1/tr1/tuple OLD_FILES+=usr/include/c++/v1/tr1/type_traits OLD_FILES+=usr/include/c++/v1/tr1/typeindex OLD_FILES+=usr/include/c++/v1/tr1/typeinfo OLD_FILES+=usr/include/c++/v1/tr1/unordered_map OLD_FILES+=usr/include/c++/v1/tr1/unordered_set OLD_FILES+=usr/include/c++/v1/tr1/utility OLD_FILES+=usr/include/c++/v1/tr1/valarray OLD_FILES+=usr/include/c++/v1/tr1/vector OLD_FILES+=usr/include/c++/v1/tuple OLD_FILES+=usr/include/c++/v1/type_traits OLD_FILES+=usr/include/c++/v1/typeindex OLD_FILES+=usr/include/c++/v1/typeinfo OLD_FILES+=usr/include/c++/v1/unordered_map OLD_FILES+=usr/include/c++/v1/unordered_set OLD_FILES+=usr/include/c++/v1/unwind-arm.h OLD_FILES+=usr/include/c++/v1/unwind-itanium.h OLD_FILES+=usr/include/c++/v1/unwind.h OLD_FILES+=usr/include/c++/v1/utility OLD_FILES+=usr/include/c++/v1/valarray OLD_FILES+=usr/include/c++/v1/vector OLD_FILES+=usr/lib32/libc++.a OLD_FILES+=usr/lib32/libc++.so OLD_LIBS+=usr/lib32/libc++.so.1 OLD_FILES+=usr/lib32/libc++_p.a OLD_FILES+=usr/lib32/libcxxrt.a OLD_FILES+=usr/lib32/libcxxrt.so OLD_LIBS+=usr/lib32/libcxxrt.so.1 OLD_FILES+=usr/lib32/libcxxrt_p.a OLD_DIRS+=usr/include/c++/v1/experimental OLD_DIRS+=usr/include/c++/v1/ext OLD_DIRS+=usr/include/c++/v1 .endif #.if ${MK_LIBTHR} == no # to be filled in #.endif .if ${MK_LOCALES} == no OLD_FILES+=usr/share/locale/UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_COLLATE OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_CTYPE OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_MESSAGES OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_MONETARY OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_NUMERIC OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_TIME OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_COLLATE OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_CTYPE OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_MESSAGES OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_MONETARY OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_NUMERIC OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_TIME OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_COLLATE OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_CTYPE OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_MESSAGES OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_MONETARY OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_NUMERIC OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_TIME OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_COLLATE OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_CTYPE OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_MESSAGES OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_MONETARY OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_NUMERIC OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_TIME OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_TIME OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_COLLATE OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_CTYPE OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_MESSAGES OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_MONETARY OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_NUMERIC OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_TIME OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_COLLATE OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_CTYPE OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_MESSAGES OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_MONETARY OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_NUMERIC OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_TIME OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_COLLATE OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_CTYPE OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_MESSAGES OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_MONETARY OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_NUMERIC OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_TIME OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_COLLATE OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_CTYPE OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_MESSAGES OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_MONETARY OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_NUMERIC OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_TIME OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_COLLATE OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_CTYPE OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_MESSAGES OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_MONETARY OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_NUMERIC OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_TIME OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_COLLATE OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_CTYPE OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_MESSAGES OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_MONETARY OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_NUMERIC OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_TIME OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_COLLATE OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_CTYPE OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_MESSAGES OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_MONETARY OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_NUMERIC OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_TIME OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_TIME OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_TIME OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_COLLATE OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_CTYPE OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_MESSAGES OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_MONETARY OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_NUMERIC OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_TIME OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_COLLATE OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_CTYPE OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_MESSAGES OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_MONETARY OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_NUMERIC OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_TIME OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_COLLATE OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_CTYPE OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_MESSAGES OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_MONETARY OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_NUMERIC OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_TIME OLD_FILES+=usr/share/locale/kk_KZ.PT154/LC_COLLATE OLD_FILES+=usr/share/locale/kk_KZ.PT154/LC_CTYPE OLD_FILES+=usr/share/locale/kk_KZ.PT154/LC_MESSAGES OLD_FILES+=usr/share/locale/kk_KZ.PT154/LC_MONETARY OLD_FILES+=usr/share/locale/kk_KZ.PT154/LC_NUMERIC OLD_FILES+=usr/share/locale/kk_KZ.PT154/LC_TIME OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_COLLATE OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_CTYPE OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_MESSAGES OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_MONETARY OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_NUMERIC OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_TIME OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_COLLATE OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_CTYPE OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_MESSAGES OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_MONETARY OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_NUMERIC OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_TIME OLD_FILES+=usr/share/locale/la_LN.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/la_LN.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/la_LN.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/la_LN.ISO8859-13/LC_COLLATE OLD_FILES+=usr/share/locale/la_LN.ISO8859-13/LC_CTYPE OLD_FILES+=usr/share/locale/la_LN.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/la_LN.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/la_LN.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/la_LN.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/la_LN.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/la_LN.ISO8859-2/LC_TIME OLD_FILES+=usr/share/locale/la_LN.ISO8859-4/LC_COLLATE OLD_FILES+=usr/share/locale/la_LN.ISO8859-4/LC_CTYPE OLD_FILES+=usr/share/locale/la_LN.ISO8859-4/LC_TIME OLD_FILES+=usr/share/locale/la_LN.US-ASCII/LC_COLLATE OLD_FILES+=usr/share/locale/la_LN.US-ASCII/LC_CTYPE OLD_FILES+=usr/share/locale/la_LN.US-ASCII/LC_TIME OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_COLLATE OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_CTYPE OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_MESSAGES OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_MONETARY OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_NUMERIC OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_TIME OLD_FILES+=usr/share/locale/lt_LT.ISO8859-4/LC_COLLATE OLD_FILES+=usr/share/locale/lt_LT.ISO8859-4/LC_CTYPE OLD_FILES+=usr/share/locale/lt_LT.ISO8859-4/LC_MESSAGES OLD_FILES+=usr/share/locale/lt_LT.ISO8859-4/LC_MONETARY OLD_FILES+=usr/share/locale/lt_LT.ISO8859-4/LC_NUMERIC OLD_FILES+=usr/share/locale/lt_LT.ISO8859-4/LC_TIME OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_COLLATE OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_CTYPE OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_MESSAGES OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_MONETARY OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_NUMERIC OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_TIME OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/no_NO.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/no_NO.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/no_NO.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/no_NO.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/no_NO.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/no_NO.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/no_NO.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/no_NO.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/no_NO.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/no_NO.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/no_NO.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/no_NO.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/no_NO.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/no_NO.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/no_NO.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/no_NO.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/no_NO.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/no_NO.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_TIME OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_TIME OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_COLLATE OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_CTYPE OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_MESSAGES OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_MONETARY OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_NUMERIC OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_TIME OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_COLLATE OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_CTYPE OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_MESSAGES OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_MONETARY OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_NUMERIC OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_TIME OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_COLLATE OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_CTYPE OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_MESSAGES OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_MONETARY OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_NUMERIC OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_TIME OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_COLLATE OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_CTYPE OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_MESSAGES OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_MONETARY OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_NUMERIC OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_TIME OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_TIME OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_TIME OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/sr_YU.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/sr_YU.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/sr_YU.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/sr_YU.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/sr_YU.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/sr_YU.ISO8859-2/LC_TIME OLD_FILES+=usr/share/locale/sr_YU.ISO8859-5/LC_COLLATE OLD_FILES+=usr/share/locale/sr_YU.ISO8859-5/LC_CTYPE OLD_FILES+=usr/share/locale/sr_YU.ISO8859-5/LC_MESSAGES OLD_FILES+=usr/share/locale/sr_YU.ISO8859-5/LC_MONETARY OLD_FILES+=usr/share/locale/sr_YU.ISO8859-5/LC_NUMERIC OLD_FILES+=usr/share/locale/sr_YU.ISO8859-5/LC_TIME OLD_FILES+=usr/share/locale/sr_YU.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/sr_YU.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/sr_YU.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/sr_YU.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/sr_YU.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/sr_YU.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_TIME OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_TIME OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_COLLATE OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_CTYPE OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_MESSAGES OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_MONETARY OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_NUMERIC OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_TIME OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_COLLATE OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_CTYPE OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_MESSAGES OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_MONETARY OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_NUMERIC OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_TIME OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_COLLATE OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_CTYPE OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_MESSAGES OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_MONETARY OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_NUMERIC OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_TIME OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_COLLATE OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_CTYPE OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_MESSAGES OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_MONETARY OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_NUMERIC OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_TIME OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_COLLATE OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_CTYPE OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_MONETARY OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_TIME OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_COLLATE OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_CTYPE OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_MONETARY OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_TIME OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_COLLATE OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_CTYPE OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_MONETARY OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_TIME OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_COLLATE OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_CTYPE OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_MONETARY OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_TIME OLD_FILES+=usr/share/locale/zh_HK.Big5HKSCS/LC_COLLATE OLD_FILES+=usr/share/locale/zh_HK.Big5HKSCS/LC_CTYPE OLD_FILES+=usr/share/locale/zh_HK.Big5HKSCS/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_HK.Big5HKSCS/LC_MONETARY OLD_FILES+=usr/share/locale/zh_HK.Big5HKSCS/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_HK.Big5HKSCS/LC_TIME OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_TIME OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_COLLATE OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_CTYPE OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_MONETARY OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_TIME OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_TIME OLD_FILES+=usr/tests/lib/libc/locale/Kyuafile OLD_FILES+=usr/tests/lib/libc/locale/io_test OLD_FILES+=usr/tests/lib/libc/locale/mbrtowc_test OLD_FILES+=usr/tests/lib/libc/locale/mbsnrtowcs_test OLD_FILES+=usr/tests/lib/libc/locale/mbstowcs_test OLD_FILES+=usr/tests/lib/libc/locale/mbtowc_test OLD_FILES+=usr/tests/lib/libc/locale/wcscspn_test OLD_FILES+=usr/tests/lib/libc/locale/wcspbrk_test OLD_FILES+=usr/tests/lib/libc/locale/wcsspn_test OLD_FILES+=usr/tests/lib/libc/locale/wcstod_test OLD_FILES+=usr/tests/lib/libc/locale/wctomb_test .endif .if ${MK_LOCATE} == no OLD_FILES+=etc/locate.rc OLD_FILES+=etc/periodic/weekly/310.locate OLD_FILES+=usr/bin/locate OLD_FILES+=usr/libexec/locate.bigram OLD_FILES+=usr/libexec/locate.code OLD_FILES+=usr/libexec/locate.concatdb OLD_FILES+=usr/libexec/locate.mklocatedb OLD_FILES+=usr/libexec/locate.updatedb OLD_FILES+=usr/share/man/man1/locate.1.gz OLD_FILES+=usr/share/man/man8/locate.updatedb.8.gz OLD_FILES+=usr/share/man/man8/updatedb.8.gz .endif .if ${MK_LPR} == no OLD_FILES+=etc/hosts.lpd OLD_FILES+=etc/printcap OLD_FILES+=etc/rc.d/lpd OLD_FILES+=usr/bin/lp OLD_FILES+=usr/bin/lpq OLD_FILES+=usr/bin/lpr OLD_FILES+=usr/bin/lprm OLD_FILES+=usr/libexec/lpr/ru/bjc-240.sh.sample OLD_FILES+=usr/libexec/lpr/ru/koi2alt OLD_FILES+=usr/libexec/lpr/ru/koi2855 OLD_DIRS+=usr/libexec/lpr/ru OLD_FILES+=usr/libexec/lpr/lpf OLD_DIRS+=usr/libexec/lpr OLD_FILES+=usr/sbin/chkprintcap OLD_FILES+=usr/sbin/lpc OLD_FILES+=usr/sbin/lpd OLD_FILES+=usr/sbin/lptest OLD_FILES+=usr/sbin/pac OLD_FILES+=usr/share/doc/smm/07.lpd/paper.ascii.gz OLD_DIRS+=usr/share/doc/smm/07.lpd OLD_FILES+=usr/share/examples/etc/hosts.lpd OLD_FILES+=usr/share/examples/etc/printcap OLD_FILES+=usr/share/man/man1/lp.1.gz OLD_FILES+=usr/share/man/man1/lpq.1.gz OLD_FILES+=usr/share/man/man1/lpr.1.gz OLD_FILES+=usr/share/man/man1/lprm.1.gz OLD_FILES+=usr/share/man/man1/lptest.1.gz OLD_FILES+=usr/share/man/man5/printcap.5.gz OLD_FILES+=usr/share/man/man8/chkprintcap.8.gz OLD_FILES+=usr/share/man/man8/lpc.8.gz OLD_FILES+=usr/share/man/man8/lpd.8.gz OLD_FILES+=usr/share/man/man8/pac.8.gz .endif .if ${MK_MAIL} == no OLD_FILES+=etc/aliases OLD_FILES+=etc/mail.rc OLD_FILES+=etc/mail/aliases OLD_FILES+=etc/mail/mailer.conf OLD_FILES+=etc/periodic/daily/130.clean-msgs OLD_FILES+=usr/bin/Mail OLD_FILES+=usr/bin/biff OLD_FILES+=usr/bin/from OLD_FILES+=usr/bin/mail OLD_FILES+=usr/bin/mailx OLD_FILES+=usr/bin/msgs OLD_FILES+=usr/libexec/comsat OLD_FILES+=usr/share/examples/etc/mail.rc OLD_FILES+=usr/share/man/man1/Mail.1.gz OLD_FILES+=usr/share/man/man1/biff.1.gz OLD_FILES+=usr/share/man/man1/from.1.gz OLD_FILES+=usr/share/man/man1/mail.1.gz OLD_FILES+=usr/share/man/man1/mailx.1.gz OLD_FILES+=usr/share/man/man1/msgs.1.gz OLD_FILES+=usr/share/man/man8/comsat.8.gz OLD_FILES+=usr/share/misc/mail.help OLD_FILES+=usr/share/misc/mail.tildehelp .endif .if ${MK_MAILWRAPPER} == no OLD_FILES+=etc/mail/mailer.conf .if ${MK_SENDMAIL} == no OLD_FILES+=usr/sbin/mailwrapper .endif OLD_FILES+=usr/share/man/man8/mailwrapper.8.gz .endif .if ${MK_MAKE} == no OLD_FILES+=usr/bin/make OLD_FILES+=usr/share/man/man1/make.1.gz OLD_FILES+=usr/share/mk/atf.test.mk OLD_FILES+=usr/share/mk/bsd.README OLD_FILES+=usr/share/mk/bsd.arch.inc.mk OLD_FILES+=usr/share/mk/bsd.compiler.mk OLD_FILES+=usr/share/mk/bsd.cpu.mk OLD_FILES+=usr/share/mk/bsd.crunchgen.mk OLD_FILES+=usr/share/mk/bsd.dep.mk OLD_FILES+=usr/share/mk/bsd.doc.mk OLD_FILES+=usr/share/mk/bsd.dtb.mk OLD_FILES+=usr/share/mk/bsd.endian.mk OLD_FILES+=usr/share/mk/bsd.files.mk OLD_FILES+=usr/share/mk/bsd.incs.mk OLD_FILES+=usr/share/mk/bsd.info.mk OLD_FILES+=usr/share/mk/bsd.init.mk OLD_FILES+=usr/share/mk/bsd.kmod.mk OLD_FILES+=usr/share/mk/bsd.lib.mk OLD_FILES+=usr/share/mk/bsd.libnames.mk OLD_FILES+=usr/share/mk/bsd.links.mk OLD_FILES+=usr/share/mk/bsd.man.mk OLD_FILES+=usr/share/mk/bsd.mkopt.mk OLD_FILES+=usr/share/mk/bsd.nls.mk OLD_FILES+=usr/share/mk/bsd.obj.mk OLD_FILES+=usr/share/mk/bsd.opts.mk OLD_FILES+=usr/share/mk/bsd.own.mk OLD_FILES+=usr/share/mk/bsd.port.mk OLD_FILES+=usr/share/mk/bsd.port.options.mk OLD_FILES+=usr/share/mk/bsd.port.post.mk OLD_FILES+=usr/share/mk/bsd.port.pre.mk OLD_FILES+=usr/share/mk/bsd.port.subdir.mk OLD_FILES+=usr/share/mk/bsd.prog.mk OLD_FILES+=usr/share/mk/bsd.progs.mk OLD_FILES+=usr/share/mk/bsd.snmpmod.mk OLD_FILES+=usr/share/mk/bsd.subdir.mk OLD_FILES+=usr/share/mk/bsd.symver.mk OLD_FILES+=usr/share/mk/bsd.sys.mk OLD_FILES+=usr/share/mk/bsd.test.mk OLD_FILES+=usr/share/mk/plain.test.mk OLD_FILES+=usr/share/mk/suite.test.mk OLD_FILES+=usr/share/mk/sys.mk OLD_FILES+=usr/share/mk/tap.test.mk OLD_FILES+=usr/share/mk/version_gen.awk OLD_FILES+=usr/tests/usr.bin/bmake/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/archives/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/libtest.a OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/libtest.a OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/libtest.a OLD_FILES+=usr/tests/usr.bin/bmake/basic/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/basic/t0/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/basic/t0/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t0/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t0/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t0/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/basic/t3/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/basic/t3/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t3/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t3/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t3/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/common.sh OLD_FILES+=usr/tests/usr.bin/bmake/execution/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/shell/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/sh OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/sh OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/sh OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/shell OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/shell OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/TEST1.a OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/TEST1.a OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/TEST2.a OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/TEST1.a OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/TEST2.a OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.status.3 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.status.4 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.status.5 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stderr.3 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stderr.4 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stderr.5 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stdout.3 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stdout.4 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stdout.5 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/mk/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/mk/sys.mk OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/cleanup OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/mk/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/mk/sys.mk OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/cleanup OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/mk/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/mk/sys.mk OLD_FILES+=usr/tests/usr.bin/bmake/test-new.mk OLD_FILES+=usr/tests/usr.bin/bmake/variables/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.status.3 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stderr.3 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stdout.3 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/legacy_test .endif .if ${MK_MAN} == no MAN_FILES!=find ${DESTDIR}/usr/share/man ${DESTDIR}/usr/share/openssl/man -type f | sed -e 's,^${DESTDIR}/,,'; echo OLD_FILES+=${MAN_FILES} .endif .if ${MK_MAN_UTILS} == no OLD_FILES+=etc/periodic/weekly/320.whatis OLD_FILES+=etc/periodic/weekly/330.catman OLD_FILES+=usr/bin/apropos OLD_FILES+=usr/bin/catman OLD_FILES+=usr/bin/makewhatis OLD_FILES+=usr/bin/man OLD_FILES+=usr/bin/manpath OLD_FILES+=usr/bin/whatis OLD_FILES+=usr/libexec/catman.local OLD_FILES+=usr/libexec/makewhatis.local OLD_FILES+=usr/sbin/manctl OLD_FILES+=usr/share/man/man1/apropos.1.gz OLD_FILES+=usr/share/man/man1/catman.1.gz OLD_FILES+=usr/share/man/man1/makewhatis.1.gz OLD_FILES+=usr/share/man/man1/man.1.gz OLD_FILES+=usr/share/man/man1/manpath.1.gz OLD_FILES+=usr/share/man/man1/whatis.1.gz OLD_FILES+=usr/share/man/man5/man.conf.5.gz OLD_FILES+=usr/share/man/man8/catman.local.8.gz OLD_FILES+=usr/share/man/man8/makewhatis.local.8.gz OLD_FILES+=usr/share/man/man8/manctl.8.gz OLD_FILES+=usr/share/man/whatis OLD_FILES+=usr/share/openssl/man/whatis .endif .if ${MK_NDIS} == no OLD_FILES+=usr/sbin/ndiscvt OLD_FILES+=usr/sbin/ndisgen OLD_FILES+=usr/share/man/man8/ndiscvt.8.gz OLD_FILES+=usr/share/man/man8/ndisgen.8.gz OLD_FILES+=usr/share/misc/windrv_stub.c .endif .if ${MK_NETCAT} == no OLD_FILES+=usr/bin/nc OLD_FILES+=usr/share/man/man1/nc.1.gz .endif .if ${MK_NETGRAPH} == no OLD_FILES+=usr/include/netgraph.h OLD_FILES+=usr/lib/libnetgraph.a OLD_FILES+=usr/lib/libnetgraph.so OLD_LIBS+=usr/lib/libnetgraph.so.4 OLD_FILES+=usr/lib/libnetgraph_p.a OLD_FILES+=usr/lib32/libnetgraph.a OLD_FILES+=usr/lib32/libnetgraph.so OLD_LIBS+=usr/lib32/libnetgraph.so.4 OLD_FILES+=usr/lib32/libnetgraph_p.a OLD_FILES+=usr/libexec/pppoed OLD_FILES+=usr/sbin/flowctl OLD_FILES+=usr/sbin/lmcconfig OLD_FILES+=usr/sbin/ngctl OLD_FILES+=usr/sbin/nghook OLD_FILES+=usr/share/man/man3/NgAllocRecvAsciiMsg.3.gz OLD_FILES+=usr/share/man/man3/NgAllocRecvData.3.gz OLD_FILES+=usr/share/man/man3/NgAllocRecvMsg.3.gz OLD_FILES+=usr/share/man/man3/NgMkSockNode.3.gz OLD_FILES+=usr/share/man/man3/NgNameNode.3.gz OLD_FILES+=usr/share/man/man3/NgRecvAsciiMsg.3.gz OLD_FILES+=usr/share/man/man3/NgRecvData.3.gz OLD_FILES+=usr/share/man/man3/NgRecvMsg.3.gz OLD_FILES+=usr/share/man/man3/NgSendAsciiMsg.3.gz OLD_FILES+=usr/share/man/man3/NgSendData.3.gz OLD_FILES+=usr/share/man/man3/NgSendMsg.3.gz OLD_FILES+=usr/share/man/man3/NgSendMsgReply.3.gz OLD_FILES+=usr/share/man/man3/NgSetDebug.3.gz OLD_FILES+=usr/share/man/man3/NgSetErrLog.3.gz OLD_FILES+=usr/share/man/man3/netgraph.3.gz OLD_FILES+=usr/share/man/man8/flowctl.8.gz OLD_FILES+=usr/share/man/man8/lmcconfig.8.gz OLD_FILES+=usr/share/man/man8/ngctl.8.gz OLD_FILES+=usr/share/man/man8/nghook.8.gz OLD_FILES+=usr/share/man/man8/pppoed.8.gz .endif .if ${MK_NETGRAPH_SUPPORT} == no OLD_FILES+=usr/include/bsnmp/snmp_netgraph.h OLD_FILES+=usr/lib/snmp_netgraph.so OLD_LIBS+=usr/lib/snmp_netgraph.so.6 OLD_FILES+=usr/share/man/man3/snmp_netgraph.3.gz OLD_FILES+=usr/share/snmp/defs/netgraph_tree.def OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-NETGRAPH.txt .endif .if ${MK_NIS} == no OLD_FILES+=usr/bin/ypcat OLD_FILES+=usr/bin/ypchfn OLD_FILES+=usr/bin/ypchpass OLD_FILES+=usr/bin/ypchsh OLD_FILES+=usr/bin/ypmatch OLD_FILES+=usr/bin/yppasswd OLD_FILES+=usr/bin/ypwhich OLD_FILES+=usr/include/ypclnt.h OLD_FILES+=usr/lib/libypclnt.a OLD_FILES+=usr/lib/libypclnt.so OLD_LIBS+=usr/lib/libypclnt.so.4 OLD_FILES+=usr/lib/libypclnt_p.a .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/lib32/libypclnt.a OLD_FILES+=usr/lib32/libypclnt.so OLD_LIBS+=usr/lib32/libypclnt.so.4 OLD_FILES+=usr/lib32/libypclnt_p.a .endif OLD_FILES+=usr/libexec/mknetid OLD_FILES+=usr/libexec/yppwupdate OLD_FILES+=usr/libexec/ypxfr OLD_FILES+=usr/sbin/rpc.yppasswdd OLD_FILES+=usr/sbin/rpc.ypupdated OLD_FILES+=usr/sbin/rpc.ypxfrd OLD_FILES+=usr/sbin/yp_mkdb OLD_FILES+=usr/sbin/ypbind OLD_FILES+=usr/sbin/ypinit OLD_FILES+=usr/sbin/yppoll OLD_FILES+=usr/sbin/yppush OLD_FILES+=usr/sbin/ypserv OLD_FILES+=usr/sbin/ypset OLD_FILES+=usr/share/man/man1/ypcat.1.gz OLD_FILES+=usr/share/man/man1/ypchfn.1.gz OLD_FILES+=usr/share/man/man1/ypchpass.1.gz OLD_FILES+=usr/share/man/man1/ypchsh.1.gz OLD_FILES+=usr/share/man/man1/ypmatch.1.gz OLD_FILES+=usr/share/man/man1/yppasswd.1.gz OLD_FILES+=usr/share/man/man1/ypwhich.1.gz OLD_FILES+=usr/share/man/man5/netid.5.gz OLD_FILES+=usr/share/man/man8/mknetid.8.gz OLD_FILES+=usr/share/man/man8/rpc.yppasswdd.8.gz OLD_FILES+=usr/share/man/man8/rpc.ypxfrd.8.gz OLD_FILES+=usr/share/man/man8/yp_mkdb.8.gz OLD_FILES+=usr/share/man/man8/ypbind.8.gz OLD_FILES+=usr/share/man/man8/ypinit.8.gz OLD_FILES+=usr/share/man/man8/yppoll.8.gz OLD_FILES+=usr/share/man/man8/yppush.8.gz OLD_FILES+=usr/share/man/man8/ypserv.8.gz OLD_FILES+=usr/share/man/man8/ypset.8.gz OLD_FILES+=usr/share/man/man8/ypxfr.8.gz OLD_FILES+=var/yp/Makefile OLD_FILES+=var/yp/Makefile.dist .endif .if ${MK_NLS} == no OLD_FILES+=usr/share/nls/C/ee.cat OLD_FILES+=usr/share/nls/be_BY.UTF-8/libc.cat OLD_FILES+=usr/share/nls/ca_ES.ISO8859-1/libc.cat OLD_FILES+=usr/share/nls/de_AT.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/de_AT.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/de_AT.ISO8859-15/ee.cat OLD_FILES+=usr/share/nls/de_AT.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/de_AT.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/de_CH.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/de_CH.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/de_CH.ISO8859-15/ee.cat OLD_FILES+=usr/share/nls/de_CH.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/de_CH.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/libc.cat OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/de_DE.ISO8859-15/ee.cat OLD_FILES+=usr/share/nls/de_DE.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/de_DE.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/el_GR.ISO8859-7/libc.cat OLD_FILES+=usr/share/nls/el_GR.ISO8859-7/tcsh.cat OLD_FILES+=usr/share/nls/el_GR.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/en_US.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/en_US.ISO8859-15/ee.cat OLD_FILES+=usr/share/nls/es_ES.ISO8859-1/grep.cat OLD_FILES+=usr/share/nls/es_ES.ISO8859-1/libc.cat OLD_FILES+=usr/share/nls/es_ES.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/es_ES.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/es_ES.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/et_EE.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/et_EE.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fi_FI.ISO8859-1/libc.cat OLD_FILES+=usr/share/nls/fi_FI.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/fi_FI.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/fi_FI.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_BE.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/fr_BE.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/fr_BE.ISO8859-15/ee.cat OLD_FILES+=usr/share/nls/fr_BE.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/fr_BE.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_CA.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/fr_CA.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/fr_CA.ISO8859-15/ee.cat OLD_FILES+=usr/share/nls/fr_CA.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/fr_CA.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_CH.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/fr_CH.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/fr_CH.ISO8859-15/ee.cat OLD_FILES+=usr/share/nls/fr_CH.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/fr_CH.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/libc.cat OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/fr_FR.ISO8859-15/ee.cat OLD_FILES+=usr/share/nls/fr_FR.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/fr_FR.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/gl_ES.ISO8859-1/grep.cat OLD_FILES+=usr/share/nls/gl_ES.ISO8859-1/libc.cat OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/ee.cat OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/grep.cat OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/libc.cat OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/sort.cat OLD_FILES+=usr/share/nls/it_CH.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/it_CH.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/it_CH.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/it_IT.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/it_IT.ISO8859-15/libc.cat OLD_FILES+=usr/share/nls/it_IT.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/it_IT.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/ja_JP.SJIS/grep.cat OLD_FILES+=usr/share/nls/ja_JP.SJIS/tcsh.cat OLD_FILES+=usr/share/nls/ja_JP.UTF-8/grep.cat OLD_FILES+=usr/share/nls/ja_JP.UTF-8/libc.cat OLD_FILES+=usr/share/nls/ja_JP.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/ja_JP.eucJP/grep.cat OLD_FILES+=usr/share/nls/ja_JP.eucJP/libc.cat OLD_FILES+=usr/share/nls/ja_JP.eucJP/tcsh.cat OLD_FILES+=usr/share/nls/ko_KR.UTF-8/libc.cat OLD_FILES+=usr/share/nls/ko_KR.eucKR/libc.cat OLD_FILES+=usr/share/nls/mn_MN.UTF-8/libc.cat OLD_FILES+=usr/share/nls/nl_NL.ISO8859-1/libc.cat OLD_FILES+=usr/share/nls/no_NO.ISO8859-1/libc.cat OLD_FILES+=usr/share/nls/pl_PL.ISO8859-2/ee.cat OLD_FILES+=usr/share/nls/pl_PL.ISO8859-2/libc.cat OLD_FILES+=usr/share/nls/pt_BR.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/pt_BR.ISO8859-1/grep.cat OLD_FILES+=usr/share/nls/pt_BR.ISO8859-1/libc.cat OLD_FILES+=usr/share/nls/pt_PT.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/ru_RU.CP1251/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.CP866/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.ISO8859-5/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/ee.cat OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/grep.cat OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/libc.cat OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/sk_SK.ISO8859-2/libc.cat OLD_FILES+=usr/share/nls/sv_SE.ISO8859-1/libc.cat OLD_FILES+=usr/share/nls/uk_UA.ISO8859-5/tcsh.cat OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/ee.cat OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/tcsh.cat OLD_FILES+=usr/share/nls/uk_UA.UTF-8/grep.cat OLD_FILES+=usr/share/nls/uk_UA.UTF-8/libc.cat OLD_FILES+=usr/share/nls/uk_UA.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/zh_CN.GB18030/libc.cat OLD_FILES+=usr/share/nls/zh_CN.GB2312/libc.cat OLD_FILES+=usr/share/nls/zh_CN.UTF-8/grep.cat OLD_FILES+=usr/share/nls/zh_CN.UTF-8/libc.cat OLD_FILES+=usr/tests/bin/sh/builtins/locale1.0 .endif .if ${MK_NLS_CATALOGS} == no OLD_FILES+=usr/share/nls/de_AT.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/de_CH.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/de_DE.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/el_GR.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/es_ES.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/et_EE.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fi_FI.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_BE.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_CA.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_CH.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_FR.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/it_CH.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/it_IT.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/ja_JP.SJIS/tcsh.cat OLD_FILES+=usr/share/nls/ja_JP.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.CP1251/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.CP866/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.ISO8859-5/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/uk_UA.ISO8859-5/tcsh.cat OLD_FILES+=usr/share/nls/uk_UA.UTF-8/tcsh.cat .endif .if ${MK_NS_CACHING} == no OLD_FILES+=etc/nscd.conf OLD_FILES+=etc/rc.d/nscd OLD_FILES+=usr/sbin/nscd OLD_FILES+=usr/share/examples/etc/nscd.conf OLD_FILES+=usr/share/man/man5/nscd.conf.5.gz OLD_FILES+=usr/share/man/man8/nscd.8.gz .endif .if ${MK_NTP} == no OLD_FILES+=etc/ntp.conf OLD_FILES+=etc/periodic/daily/480.status-ntpd OLD_FILES+=usr/bin/ntpq OLD_FILES+=usr/sbin/ntp-keygen OLD_FILES+=usr/sbin/ntpd OLD_FILES+=usr/sbin/ntpdate OLD_FILES+=usr/sbin/ntpdc OLD_FILES+=usr/sbin/ntptime OLD_FILES+=usr/sbin/sntp OLD_FILES+=usr/share/doc/ntp/accopt.html OLD_FILES+=usr/share/doc/ntp/assoc.html OLD_FILES+=usr/share/doc/ntp/audio.html OLD_FILES+=usr/share/doc/ntp/authopt.html OLD_FILES+=usr/share/doc/ntp/build.html OLD_FILES+=usr/share/doc/ntp/clockopt.html OLD_FILES+=usr/share/doc/ntp/config.html OLD_FILES+=usr/share/doc/ntp/confopt.html OLD_FILES+=usr/share/doc/ntp/copyright.html OLD_FILES+=usr/share/doc/ntp/debug.html OLD_FILES+=usr/share/doc/ntp/driver1.html OLD_FILES+=usr/share/doc/ntp/driver10.html OLD_FILES+=usr/share/doc/ntp/driver11.html OLD_FILES+=usr/share/doc/ntp/driver12.html OLD_FILES+=usr/share/doc/ntp/driver16.html OLD_FILES+=usr/share/doc/ntp/driver18.html OLD_FILES+=usr/share/doc/ntp/driver19.html OLD_FILES+=usr/share/doc/ntp/driver2.html OLD_FILES+=usr/share/doc/ntp/driver20.html OLD_FILES+=usr/share/doc/ntp/driver22.html OLD_FILES+=usr/share/doc/ntp/driver26.html OLD_FILES+=usr/share/doc/ntp/driver27.html OLD_FILES+=usr/share/doc/ntp/driver28.html OLD_FILES+=usr/share/doc/ntp/driver29.html OLD_FILES+=usr/share/doc/ntp/driver3.html OLD_FILES+=usr/share/doc/ntp/driver30.html OLD_FILES+=usr/share/doc/ntp/driver32.html OLD_FILES+=usr/share/doc/ntp/driver33.html OLD_FILES+=usr/share/doc/ntp/driver34.html OLD_FILES+=usr/share/doc/ntp/driver35.html OLD_FILES+=usr/share/doc/ntp/driver36.html OLD_FILES+=usr/share/doc/ntp/driver37.html OLD_FILES+=usr/share/doc/ntp/driver4.html OLD_FILES+=usr/share/doc/ntp/driver5.html OLD_FILES+=usr/share/doc/ntp/driver6.html OLD_FILES+=usr/share/doc/ntp/driver7.html OLD_FILES+=usr/share/doc/ntp/driver8.html OLD_FILES+=usr/share/doc/ntp/driver9.html OLD_FILES+=usr/share/doc/ntp/extern.html OLD_FILES+=usr/share/doc/ntp/hints.html OLD_FILES+=usr/share/doc/ntp/howto.html OLD_FILES+=usr/share/doc/ntp/index.html OLD_FILES+=usr/share/doc/ntp/kern.html OLD_FILES+=usr/share/doc/ntp/ldisc.html OLD_FILES+=usr/share/doc/ntp/measure.html OLD_FILES+=usr/share/doc/ntp/miscopt.html OLD_FILES+=usr/share/doc/ntp/monopt.html OLD_FILES+=usr/share/doc/ntp/mx4200data.html OLD_FILES+=usr/share/doc/ntp/notes.html OLD_FILES+=usr/share/doc/ntp/ntpd.html OLD_FILES+=usr/share/doc/ntp/ntpdate.html OLD_FILES+=usr/share/doc/ntp/ntpdc.html OLD_FILES+=usr/share/doc/ntp/ntpq.html OLD_FILES+=usr/share/doc/ntp/ntptime.html OLD_FILES+=usr/share/doc/ntp/ntptrace.html OLD_FILES+=usr/share/doc/ntp/parsedata.html OLD_FILES+=usr/share/doc/ntp/parsenew.html OLD_FILES+=usr/share/doc/ntp/patches.html OLD_FILES+=usr/share/doc/ntp/porting.html OLD_FILES+=usr/share/doc/ntp/pps.html OLD_FILES+=usr/share/doc/ntp/prefer.html OLD_FILES+=usr/share/doc/ntp/quick.html OLD_FILES+=usr/share/doc/ntp/rdebug.html OLD_FILES+=usr/share/doc/ntp/refclock.html OLD_FILES+=usr/share/doc/ntp/release.html OLD_FILES+=usr/share/doc/ntp/tickadj.html OLD_DIRS+=usr/share/doc/ntp OLD_FILES+=usr/share/examples/etc/ntp.conf OLD_FILES+=usr/share/man/man1/sntp.1.gz OLD_FILES+=usr/share/man/man5/ntp.conf.5.gz OLD_FILES+=usr/share/man/man5/ntp.keys.5.gz OLD_FILES+=usr/share/man/man8/ntp-keygen.8.gz OLD_FILES+=usr/share/man/man8/ntpd.8.gz OLD_FILES+=usr/share/man/man8/ntpdate.8.gz OLD_FILES+=usr/share/man/man8/ntpdc.8.gz OLD_FILES+=usr/share/man/man8/ntpq.8.gz OLD_FILES+=usr/share/man/man8/ntptime.8.gz .endif #.if ${MK_OBJC} == no # to be filled in #.endif .if ${MK_OPENSSH} == no OLD_FILES+=etc/rc.d/sshd OLD_FILES+=etc/ssh/moduli OLD_FILES+=etc/ssh/ssh_config OLD_FILES+=etc/ssh/sshd_config OLD_FILES+=usr/bin/scp OLD_FILES+=usr/bin/sftp OLD_FILES+=usr/bin/slogin OLD_FILES+=usr/bin/ssh OLD_FILES+=usr/bin/ssh-add OLD_FILES+=usr/bin/ssh-agent OLD_FILES+=usr/bin/ssh-copy-id OLD_FILES+=usr/bin/ssh-keygen OLD_FILES+=usr/bin/ssh-keyscan OLD_FILES+=usr/lib/pam_ssh.so OLD_LIBS+=usr/lib/pam_ssh.so.5 OLD_FILES+=usr/lib/private/libssh.a OLD_FILES+=usr/lib/private/libssh.so OLD_LIBS+=usr/lib/private/libssh.so.5 OLD_FILES+=usr/lib/private/libssh_p.a .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/lib32/pam_ssh.so OLD_LIBS+=usr/lib32/pam_ssh.so.5 OLD_FILES+=usr/lib32/private/libssh.a OLD_FILES+=usr/lib32/private/libssh.so OLD_LIBS+=usr/lib32/private/libssh.so.5 OLD_FILES+=usr/lib32/private/libssh_p.a .endif OLD_FILES+=usr/libexec/sftp-server OLD_FILES+=usr/libexec/ssh-keysign OLD_FILES+=usr/libexec/ssh-pkcs11-helper OLD_FILES+=usr/sbin/sshd OLD_FILES+=usr/share/man/man1/scp.1.gz OLD_FILES+=usr/share/man/man1/sftp.1.gz OLD_FILES+=usr/share/man/man1/slogin.1.gz OLD_FILES+=usr/share/man/man1/ssh-add.1.gz OLD_FILES+=usr/share/man/man1/ssh-agent.1.gz OLD_FILES+=usr/share/man/man1/ssh-copy-id.1.gz OLD_FILES+=usr/share/man/man1/ssh-keygen.1.gz OLD_FILES+=usr/share/man/man1/ssh-keyscan.1.gz OLD_FILES+=usr/share/man/man1/ssh.1.gz OLD_FILES+=usr/share/man/man5/ssh_config.5.gz OLD_FILES+=usr/share/man/man5/sshd_config.5.gz OLD_FILES+=usr/share/man/man8/pam_ssh.8.gz OLD_FILES+=usr/share/man/man8/sftp-server.8.gz OLD_FILES+=usr/share/man/man8/ssh-keysign.8.gz OLD_FILES+=usr/share/man/man8/ssh-pkcs11-helper.8.gz OLD_FILES+=usr/share/man/man8/sshd.8.gz .endif .if ${MK_OPENSSL} == no OLD_FILES+=etc/rc.d/keyserv .endif .if ${MK_PC_SYSINSTALL} == no # backend-partmanager OLD_FILES+=usr/share/pc-sysinstall/backend-partmanager/create-part.sh OLD_FILES+=usr/share/pc-sysinstall/backend-partmanager/delete-part.sh # backend-query OLD_FILES+=usr/share/pc-sysinstall/backend-query/detect-emulation.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/detect-laptop.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/detect-nics.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/disk-info.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/disk-list.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/disk-part.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/enable-net.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/get-packages.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-components.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-config.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-mirrors.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-packages.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-rsync-backups.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/list-tzones.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/query-langs.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/send-logs.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/setup-ssh-keys.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/set-mirror.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/sys-mem.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/test-live.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/test-netup.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/update-part-list.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/xkeyboard-layouts.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/xkeyboard-models.sh OLD_FILES+=usr/share/pc-sysinstall/backend-query/xkeyboard-variants.sh # backend OLD_FILES+=usr/share/pc-sysinstall/backend/functions-bsdlabel.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-cleanup.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-disk.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-extractimage.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-ftp.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-installcomponents.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-installpackages.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-localize.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-mountdisk.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-mountoptical.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-networking.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-newfs.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-parse.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-packages.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-runcommands.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-unmount.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-upgrade.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions-users.sh OLD_FILES+=usr/share/pc-sysinstall/backend/functions.sh OLD_FILES+=usr/share/pc-sysinstall/backend/installimage.sh OLD_FILES+=usr/share/pc-sysinstall/backend/parseconfig.sh OLD_FILES+=usr/share/pc-sysinstall/backend/startautoinstall.sh # conf OLD_FILES+=usr/share/pc-sysinstall/conf/avail-langs OLD_FILES+=usr/share/pc-sysinstall/conf/exclude-from-upgrade OLD_FILES+=usr/share/pc-sysinstall/conf/license/bsd-en.txt OLD_FILES+=usr/share/pc-sysinstall/conf/license/intel-en.txt OLD_FILES+=usr/share/pc-sysinstall/conf/license/nvidia-en.txt OLD_FILES+=usr/share/pc-sysinstall/conf/pc-sysinstall.conf # doc OLD_FILES+=usr/share/pc-sysinstall/doc/help-disk-list OLD_FILES+=usr/share/pc-sysinstall/doc/help-disk-size OLD_FILES+=usr/share/pc-sysinstall/doc/help-index OLD_FILES+=usr/share/pc-sysinstall/doc/help-start-autoinstall # examples OLD_FILES+=usr/share/examples/pc-sysinstall/README OLD_FILES+=usr/share/examples/pc-sysinstall/pc-autoinstall.conf OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.fbsd-netinstall OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.geli OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.gmirror OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.netinstall OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.restore OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.rsync OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.upgrade OLD_FILES+=usr/share/examples/pc-sysinstall/pcinstall.cfg.zfs # pc-sysinstall OLD_FILES+=usr/sbin/pc-sysinstall OLD_FILES+=usr/share/man/man8/pc-sysinstall.8.gz OLD_DIRS+=usr/share/pc-sysinstall/backend OLD_DIRS+=usr/share/pc-sysinstall/backend-partmanager OLD_DIRS+=usr/share/pc-sysinstall/backend-query OLD_DIRS+=usr/share/pc-sysinstall/conf/license OLD_DIRS+=usr/share/pc-sysinstall/conf OLD_DIRS+=usr/share/pc-sysinstall/doc OLD_DIRS+=usr/share/pc-sysinstall OLD_DIRS+=usr/share/examples/pc-sysinstall .endif .if ${MK_PF} == no OLD_FILES+=etc/periodic/security/520.pfdenied OLD_FILES+=etc/pf.os OLD_FILES+=etc/rc.d/ftp-proxy OLD_FILES+=sbin/pfctl OLD_FILES+=sbin/pflogd OLD_FILES+=usr/include/netpfil/pf/pf.h OLD_FILES+=usr/include/netpfil/pf/pf_altq.h OLD_FILES+=usr/include/netpfil/pf/pf_mtag.h OLD_FILES+=usr/lib/snmp_pf.so OLD_LIBS+=usr/lib/snmp_pf.so.6 OLD_FILES+=usr/libexec/tftp-proxy OLD_FILES+=usr/sbin/ftp-proxy OLD_FILES+=usr/share/examples/etc/pf.os OLD_FILES+=usr/share/examples/pf/ackpri OLD_FILES+=usr/share/examples/pf/faq-example1 OLD_FILES+=usr/share/examples/pf/faq-example2 OLD_FILES+=usr/share/examples/pf/faq-example3 OLD_FILES+=usr/share/examples/pf/pf.conf OLD_FILES+=usr/share/examples/pf/queue1 OLD_FILES+=usr/share/examples/pf/queue2 OLD_FILES+=usr/share/examples/pf/queue3 OLD_FILES+=usr/share/examples/pf/queue4 OLD_FILES+=usr/share/examples/pf/spamd OLD_DIRS+=usr/share/examples/pf OLD_FILES+=usr/share/man/man4/pf.4.gz OLD_FILES+=usr/share/man/man4/pflog.4.gz OLD_FILES+=usr/share/man/man4/pfsync.4.gz OLD_FILES+=usr/share/man/man5/pf.conf.5.gz OLD_FILES+=usr/share/man/man5/pf.os.5.gz OLD_FILES+=usr/share/man/man8/ftp-proxy.8.gz OLD_FILES+=usr/share/man/man8/pfctl.8.gz OLD_FILES+=usr/share/man/man8/pflogd.8.gz OLD_FILES+=usr/share/man/man8/tftp-proxy.8.gz OLD_FILES+=usr/share/snmp/defs/pf_tree.def OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-PF-MIB.txt .endif .if ${MK_PKGBOOTSTRAP} == no OLD_FILES+=usr/sbin/pkg OLD_FILES+=usr/share/man/man7/pkg.7.gz .endif .if ${MK_PMC} == no OLD_FILES+=usr/bin/pmcstudy OLD_FILES+=usr/include/pmc.h OLD_FILES+=usr/include/pmclog.h OLD_FILES+=usr/lib/libpmc.a OLD_FILES+=usr/lib/libpmc.so OLD_LIBS+=usr/lib/libpmc.so.5 OLD_FILES+=usr/lib/libpmc_p.a OLD_FILES+=usr/lib32/libpmc.a OLD_FILES+=usr/lib32/libpmc.so OLD_LIBS+=usr/lib32/libpmc.so.5 OLD_FILES+=usr/lib32/libpmc_p.a OLD_FILES+=usr/sbin/pmcannotate OLD_FILES+=usr/sbin/pmccontrol OLD_FILES+=usr/sbin/pmcstat OLD_FILES+=usr/share/man/man1/pmcstudy.1.gz OLD_FILES+=usr/share/man/man3/pmc.3.gz OLD_FILES+=usr/share/man/man3/pmc.atom.3.gz OLD_FILES+=usr/share/man/man3/pmc.atomsilvermont.3.gz OLD_FILES+=usr/share/man/man3/pmc.core.3.gz OLD_FILES+=usr/share/man/man3/pmc.core2.3.gz OLD_FILES+=usr/share/man/man3/pmc.corei7.3.gz OLD_FILES+=usr/share/man/man3/pmc.corei7uc.3.gz OLD_FILES+=usr/share/man/man3/pmc.haswell.3.gz OLD_FILES+=usr/share/man/man3/pmc.haswelluc.3.gz OLD_FILES+=usr/share/man/man3/pmc.iaf.3.gz OLD_FILES+=usr/share/man/man3/pmc.ivybridge.3.gz OLD_FILES+=usr/share/man/man3/pmc.ivybridgexeon.3.gz OLD_FILES+=usr/share/man/man3/pmc.k7.3.gz OLD_FILES+=usr/share/man/man3/pmc.k8.3.gz OLD_FILES+=usr/share/man/man3/pmc.mips24k.3.gz OLD_FILES+=usr/share/man/man3/pmc.octeon.3.gz OLD_FILES+=usr/share/man/man3/pmc.p4.3.gz OLD_FILES+=usr/share/man/man3/pmc.p5.3.gz OLD_FILES+=usr/share/man/man3/pmc.p6.3.gz OLD_FILES+=usr/share/man/man3/pmc.sandybridge.3.gz OLD_FILES+=usr/share/man/man3/pmc.sandybridgeuc.3.gz OLD_FILES+=usr/share/man/man3/pmc.sandybridgexeon.3.gz OLD_FILES+=usr/share/man/man3/pmc.soft.3.gz OLD_FILES+=usr/share/man/man3/pmc.tsc.3.gz OLD_FILES+=usr/share/man/man3/pmc.ucf.3.gz OLD_FILES+=usr/share/man/man3/pmc.westmere.3.gz OLD_FILES+=usr/share/man/man3/pmc.westmereuc.3.gz OLD_FILES+=usr/share/man/man3/pmc.xscale.3.gz OLD_FILES+=usr/share/man/man3/pmc_allocate.3.gz OLD_FILES+=usr/share/man/man3/pmc_attach.3.gz OLD_FILES+=usr/share/man/man3/pmc_capabilities.3.gz OLD_FILES+=usr/share/man/man3/pmc_configure_logfile.3.gz OLD_FILES+=usr/share/man/man3/pmc_cpuinfo.3.gz OLD_FILES+=usr/share/man/man3/pmc_detach.3.gz OLD_FILES+=usr/share/man/man3/pmc_disable.3.gz OLD_FILES+=usr/share/man/man3/pmc_enable.3.gz OLD_FILES+=usr/share/man/man3/pmc_event_names_of_class.3.gz OLD_FILES+=usr/share/man/man3/pmc_flush_logfile.3.gz OLD_FILES+=usr/share/man/man3/pmc_get_driver_stats.3.gz OLD_FILES+=usr/share/man/man3/pmc_get_msr.3.gz OLD_FILES+=usr/share/man/man3/pmc_init.3.gz OLD_FILES+=usr/share/man/man3/pmc_name_of_capability.3.gz OLD_FILES+=usr/share/man/man3/pmc_name_of_class.3.gz OLD_FILES+=usr/share/man/man3/pmc_name_of_cputype.3.gz OLD_FILES+=usr/share/man/man3/pmc_name_of_disposition.3.gz OLD_FILES+=usr/share/man/man3/pmc_name_of_event.3.gz OLD_FILES+=usr/share/man/man3/pmc_name_of_mode.3.gz OLD_FILES+=usr/share/man/man3/pmc_name_of_state.3.gz OLD_FILES+=usr/share/man/man3/pmc_ncpu.3.gz OLD_FILES+=usr/share/man/man3/pmc_npmc.3.gz OLD_FILES+=usr/share/man/man3/pmc_pmcinfo.3.gz OLD_FILES+=usr/share/man/man3/pmc_read.3.gz OLD_FILES+=usr/share/man/man3/pmc_release.3.gz OLD_FILES+=usr/share/man/man3/pmc_rw.3.gz OLD_FILES+=usr/share/man/man3/pmc_set.3.gz OLD_FILES+=usr/share/man/man3/pmc_start.3.gz OLD_FILES+=usr/share/man/man3/pmc_stop.3.gz OLD_FILES+=usr/share/man/man3/pmc_width.3.gz OLD_FILES+=usr/share/man/man3/pmc_write.3.gz OLD_FILES+=usr/share/man/man3/pmc_writelog.3.gz OLD_FILES+=usr/share/man/man3/pmclog.3.gz OLD_FILES+=usr/share/man/man3/pmclog_close.3.gz OLD_FILES+=usr/share/man/man3/pmclog_feed.3.gz OLD_FILES+=usr/share/man/man3/pmclog_open.3.gz OLD_FILES+=usr/share/man/man3/pmclog_read.3.gz OLD_FILES+=usr/share/man/man8/pmcannotate.8.gz OLD_FILES+=usr/share/man/man8/pmccontrol.8.gz OLD_FILES+=usr/share/man/man8/pmcstat.8.gz .endif .if ${MK_PORTSNAP} == no OLD_FILES+=etc/portsnap.conf OLD_FILES+=usr/libexec/make_index OLD_FILES+=usr/libexec/phttpget OLD_FILES+=usr/sbin/portsnap OLD_FILES+=usr/share/examples/etc/portsnap.conf OLD_FILES+=usr/share/man/man8/phttpget.8.gz OLD_FILES+=usr/share/man/man8/portsnap.8.gz .endif .if ${MK_PPP} == no OLD_FILES+=etc/ppp/ppp.conf OLD_DIRS+=etc/ppp OLD_FILES+=usr/sbin/ppp OLD_FILES+=usr/sbin/pppctl OLD_FILES+=usr/share/man/man8/ppp.8.gz OLD_FILES+=usr/share/man/man8/pppctl.8.gz .endif .if ${MK_PROFILE} == no OLD_FILES+=usr/lib/libalias_cuseeme_p.a OLD_FILES+=usr/lib/libalias_dummy_p.a OLD_FILES+=usr/lib/libalias_ftp_p.a OLD_FILES+=usr/lib/libalias_irc_p.a OLD_FILES+=usr/lib/libalias_nbt_p.a OLD_FILES+=usr/lib/libalias_p.a OLD_FILES+=usr/lib/libalias_pptp_p.a OLD_FILES+=usr/lib/libalias_skinny_p.a OLD_FILES+=usr/lib/libalias_smedia_p.a OLD_FILES+=usr/lib/libarchive_p.a OLD_FILES+=usr/lib/libasn1_p.a OLD_FILES+=usr/lib/libbegemot_p.a OLD_FILES+=usr/lib/libbluetooth_p.a OLD_FILES+=usr/lib/libbsdxml_p.a OLD_FILES+=usr/lib/libbsm_p.a OLD_FILES+=usr/lib/libbsnmp_p.a OLD_FILES+=usr/lib/libbz2_p.a OLD_FILES+=usr/lib/libc_p.a OLD_FILES+=usr/lib/libcalendar_p.a OLD_FILES+=usr/lib/libcam_p.a OLD_FILES+=usr/lib/libcom_err_p.a OLD_FILES+=usr/lib/libcompat_p.a OLD_FILES+=usr/lib/libcrypt_p.a OLD_FILES+=usr/lib/libcrypto_p.a OLD_FILES+=usr/lib/libcurses_p.a OLD_FILES+=usr/lib/libcursesw_p.a OLD_FILES+=usr/lib/libdevinfo_p.a OLD_FILES+=usr/lib/libdevstat_p.a OLD_FILES+=usr/lib/libdialog_p.a OLD_FILES+=usr/lib/libedit_p.a OLD_FILES+=usr/lib/libelf_p.a OLD_FILES+=usr/lib/libfetch_p.a OLD_FILES+=usr/lib/libfl_p.a OLD_FILES+=usr/lib/libform_p.a OLD_FILES+=usr/lib/libformw_p.a OLD_FILES+=usr/lib/libgcc_p.a OLD_FILES+=usr/lib/libgeom_p.a OLD_FILES+=usr/lib/libgnuregex_p.a OLD_FILES+=usr/lib/libgssapi_krb5_p.a OLD_FILES+=usr/lib/libgssapi_p.a OLD_FILES+=usr/lib/libhdb_p.a OLD_FILES+=usr/lib/libheimbase_p.a OLD_FILES+=usr/lib/libheimsqlite_p.a OLD_FILES+=usr/lib/libhistory_p.a OLD_FILES+=usr/lib/libipsec_p.a OLD_FILES+=usr/lib/libjail_p.a OLD_FILES+=usr/lib/libkadm5clnt_p.a OLD_FILES+=usr/lib/libkadm5srv_p.a OLD_FILES+=usr/lib/libkafs5_p.a OLD_FILES+=usr/lib/libkdc_p.a OLD_FILES+=usr/lib/libkiconv_p.a OLD_FILES+=usr/lib/libkrb5_p.a OLD_FILES+=usr/lib/libkvm_p.a OLD_FILES+=usr/lib/libl_p.a OLD_FILES+=usr/lib/libln_p.a OLD_FILES+=usr/lib/libm_p.a OLD_FILES+=usr/lib/libmagic_p.a OLD_FILES+=usr/lib/libmd_p.a OLD_FILES+=usr/lib/libmemstat_p.a OLD_FILES+=usr/lib/libmenu_p.a OLD_FILES+=usr/lib/libmenuw_p.a OLD_FILES+=usr/lib/libmilter_p.a OLD_FILES+=usr/lib/libmp_p.a OLD_FILES+=usr/lib/libncurses_p.a OLD_FILES+=usr/lib/libncursesw_p.a OLD_FILES+=usr/lib/libnetgraph_p.a OLD_FILES+=usr/lib/libngatm_p.a OLD_FILES+=usr/lib/libopie_p.a OLD_FILES+=usr/lib/libpanel_p.a OLD_FILES+=usr/lib/libpanelw_p.a OLD_FILES+=usr/lib/libpcap_p.a OLD_FILES+=usr/lib/libpmc_p.a OLD_FILES+=usr/lib/libpthread_p.a OLD_FILES+=usr/lib/libradius_p.a OLD_FILES+=usr/lib/libroken_p.a OLD_FILES+=usr/lib/librpcsvc_p.a OLD_FILES+=usr/lib/librt_p.a OLD_FILES+=usr/lib/libsbuf_p.a OLD_FILES+=usr/lib/libsdp_p.a OLD_FILES+=usr/lib/libsmb_p.a OLD_FILES+=usr/lib/libssl_p.a OLD_FILES+=usr/lib/libstdc++_p.a OLD_FILES+=usr/lib/libsupc++_p.a OLD_FILES+=usr/lib/libtacplus_p.a OLD_FILES+=usr/lib/libtermcap_p.a OLD_FILES+=usr/lib/libtermcapw_p.a OLD_FILES+=usr/lib/libtermlib_p.a OLD_FILES+=usr/lib/libtermlibw_p.a OLD_FILES+=usr/lib/libthr_p.a OLD_FILES+=usr/lib/libthread_db_p.a OLD_FILES+=usr/lib/libtinfo_p.a OLD_FILES+=usr/lib/libtinfow_p.a OLD_FILES+=usr/lib/libufs_p.a OLD_FILES+=usr/lib/libugidfw_p.a OLD_FILES+=usr/lib/libusbhid_p.a OLD_FILES+=usr/lib/libutil_p.a OLD_FILES+=usr/lib/libvgl_p.a OLD_FILES+=usr/lib/libwind_p.a OLD_FILES+=usr/lib/libwrap_p.a OLD_FILES+=usr/lib/liby_p.a OLD_FILES+=usr/lib/libypclnt_p.a OLD_FILES+=usr/lib/libz_p.a OLD_FILES+=usr/lib/private/libldns_p.a OLD_FILES+=usr/lib/private/libssh_p.a .endif .if ${MK_QUOTAS} == no OLD_FILES+=sbin/quotacheck OLD_FILES+=usr/bin/quota OLD_FILES+=usr/sbin/edquota OLD_FILES+=usr/sbin/quotaoff OLD_FILES+=usr/sbin/quotaon OLD_FILES+=usr/sbin/repquota OLD_FILES+=usr/share/man/man1/quota.1.gz OLD_FILES+=usr/share/man/man8/edquota.8.gz OLD_FILES+=usr/share/man/man8/quotacheck.8.gz OLD_FILES+=usr/share/man/man8/quotaoff.8.gz OLD_FILES+=usr/share/man/man8/quotaon.8.gz OLD_FILES+=usr/share/man/man8/repquota.8.gz .endif .if ${MK_RCMDS} == no OLD_FILES+=bin/rcp OLD_FILES+=etc/rc.d/rwho OLD_FILES+=etc/periodic/daily/140.clean-rwho OLD_FILES+=etc/periodic/daily/430.status-rwho OLD_FILES+=rescue/rcp OLD_FILES+=usr/bin/rlogin OLD_FILES+=usr/bin/rsh OLD_FILES+=usr/bin/ruptime OLD_FILES+=usr/bin/rwho OLD_FILES+=usr/libexec/rlogind OLD_FILES+=usr/libexec/rshd OLD_FILES+=usr/sbin/rwhod OLD_FILES+=usr/share/man/man1/rcp.1.gz OLD_FILES+=usr/share/man/man1/rlogin.1.gz OLD_FILES+=usr/share/man/man1/rsh.1.gz OLD_FILES+=usr/share/man/man1/ruptime.1.gz OLD_FILES+=usr/share/man/man1/rwho.1.gz OLD_FILES+=usr/share/man/man8/rlogind.8.gz OLD_FILES+=usr/share/man/man8/rshd.8.gz OLD_FILES+=usr/share/man/man8/rwhod.8.gz .endif .if ${MK_RCS} == no OLD_FILES+=usr/bin/ci OLD_FILES+=usr/bin/co OLD_FILES+=usr/bin/ident OLD_FILES+=usr/bin/merge OLD_FILES+=usr/bin/rcs OLD_FILES+=usr/bin/rcsclean OLD_FILES+=usr/bin/rcsdiff OLD_FILES+=usr/bin/rcsfreeze OLD_FILES+=usr/bin/rcsmerge OLD_FILES+=usr/bin/rlog OLD_FILES+=usr/sbin/etcupdate OLD_FILES+=usr/share/man/man1/ci.1.gz OLD_FILES+=usr/share/man/man1/co.1.gz OLD_FILES+=usr/share/man/man1/ident.1.gz OLD_FILES+=usr/share/man/man1/merge.1.gz OLD_FILES+=usr/share/man/man1/rcs.1.gz OLD_FILES+=usr/share/man/man1/rcsclean.1.gz OLD_FILES+=usr/share/man/man1/rcsdiff.1.gz OLD_FILES+=usr/share/man/man1/rcsfreeze.1.gz OLD_FILES+=usr/share/man/man1/rcsintro.1.gz OLD_FILES+=usr/share/man/man1/rcsmerge.1.gz OLD_FILES+=usr/share/man/man1/rlog.1.gz OLD_FILES+=usr/share/man/man5/rcsfile.5.gz OLD_FILES+=usr/share/man/man8/etcupdate.8.gz .endif #.if ${MK_RESCUE} == no # to be filled in or replaced with a special target #.endif .if ${MK_ROUTED} == no OLD_FILES+=sbin/routed OLD_FILES+=sbin/rtquery OLD_FILES+=usr/share/man/man8/routed.8.gz OLD_FILES+=usr/share/man/man8/rtquery.8.gz .endif .if ${MK_SENDMAIL} == no OLD_FILES+=etc/periodic/daily/150.clean-hoststat OLD_FILES+=etc/periodic/daily/440.status-mailq OLD_FILES+=etc/periodic/daily/460.status-mail-rejects OLD_FILES+=etc/periodic/daily/500.queuerun .if ${MK_MAILWRAPPER} == no OLD_FILES+=bin/rmail .endif OLD_FILES+=usr/bin/vacation OLD_FILES+=usr/include/libmilter/mfapi.h OLD_FILES+=usr/include/libmilter/mfdef.h OLD_DIRS+=usr/include/libmilter OLD_FILES+=usr/lib/libmilter.a OLD_FILES+=usr/lib/libmilter.so OLD_LIBS+=usr/lib/libmilter.so.5 OLD_FILES+=usr/lib/libmilter_p.a .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/lib32/libmilter.a OLD_FILES+=usr/lib32/libmilter.so OLD_LIBS+=usr/lib32/libmilter.so.5 OLD_FILES+=usr/lib32/libmilter_p.a .endif OLD_FILES+=usr/libexec/mail.local OLD_FILES+=usr/libexec/sendmail/sendmail OLD_FILES+=usr/libexec/smrsh OLD_FILES+=usr/sbin/editmap OLD_FILES+=usr/sbin/mailstats OLD_FILES+=usr/sbin/makemap OLD_FILES+=usr/sbin/praliases OLD_FILES+=usr/share/doc/smm/08.sendmailop/paper.ascii.gz OLD_DIRS+=usr/share/doc/smm/08.sendmailop OLD_FILES+=usr/share/man/man1/mailq.1.gz OLD_FILES+=usr/share/man/man1/newaliases.1.gz OLD_FILES+=usr/share/man/man1/vacation.1.gz OLD_FILES+=usr/share/man/man5/aliases.5.gz OLD_FILES+=usr/share/man/man8/editmap.8.gz OLD_FILES+=usr/share/man/man8/hoststat.8.gz OLD_FILES+=usr/share/man/man8/mail.local.8.gz OLD_FILES+=usr/share/man/man8/mailstats.8.gz OLD_FILES+=usr/share/man/man8/makemap.8.gz OLD_FILES+=usr/share/man/man8/praliases.8.gz OLD_FILES+=usr/share/man/man8/purgestat.8.gz OLD_FILES+=usr/share/man/man8/rmail.8.gz OLD_FILES+=usr/share/man/man8/sendmail.8.gz OLD_FILES+=usr/share/man/man8/smrsh.8.gz OLD_FILES+=usr/share/sendmail/cf/README OLD_FILES+=usr/share/sendmail/cf/cf/Makefile OLD_FILES+=usr/share/sendmail/cf/cf/README OLD_FILES+=usr/share/sendmail/cf/cf/chez.cs.mc OLD_FILES+=usr/share/sendmail/cf/cf/clientproto.mc OLD_FILES+=usr/share/sendmail/cf/cf/cs-hpux10.mc OLD_FILES+=usr/share/sendmail/cf/cf/cs-hpux9.mc OLD_FILES+=usr/share/sendmail/cf/cf/cs-osf1.mc OLD_FILES+=usr/share/sendmail/cf/cf/cs-solaris2.mc OLD_FILES+=usr/share/sendmail/cf/cf/cs-sunos4.1.mc OLD_FILES+=usr/share/sendmail/cf/cf/cs-ultrix4.mc OLD_FILES+=usr/share/sendmail/cf/cf/cyrusproto.mc OLD_FILES+=usr/share/sendmail/cf/cf/generic-bsd4.4.mc OLD_FILES+=usr/share/sendmail/cf/cf/generic-hpux10.mc OLD_FILES+=usr/share/sendmail/cf/cf/generic-hpux9.mc OLD_FILES+=usr/share/sendmail/cf/cf/generic-linux.mc OLD_FILES+=usr/share/sendmail/cf/cf/generic-mpeix.mc OLD_FILES+=usr/share/sendmail/cf/cf/generic-nextstep3.3.mc OLD_FILES+=usr/share/sendmail/cf/cf/generic-osf1.mc OLD_FILES+=usr/share/sendmail/cf/cf/generic-solaris.mc OLD_FILES+=usr/share/sendmail/cf/cf/generic-sunos4.1.mc OLD_FILES+=usr/share/sendmail/cf/cf/generic-ultrix4.mc OLD_FILES+=usr/share/sendmail/cf/cf/huginn.cs.mc OLD_FILES+=usr/share/sendmail/cf/cf/knecht.mc OLD_FILES+=usr/share/sendmail/cf/cf/mail.cs.mc OLD_FILES+=usr/share/sendmail/cf/cf/mail.eecs.mc OLD_FILES+=usr/share/sendmail/cf/cf/mailspool.cs.mc OLD_FILES+=usr/share/sendmail/cf/cf/python.cs.mc OLD_FILES+=usr/share/sendmail/cf/cf/s2k-osf1.mc OLD_FILES+=usr/share/sendmail/cf/cf/s2k-ultrix4.mc OLD_FILES+=usr/share/sendmail/cf/cf/submit.cf OLD_FILES+=usr/share/sendmail/cf/cf/submit.mc OLD_FILES+=usr/share/sendmail/cf/cf/tcpproto.mc OLD_FILES+=usr/share/sendmail/cf/cf/ucbarpa.mc OLD_FILES+=usr/share/sendmail/cf/cf/ucbvax.mc OLD_FILES+=usr/share/sendmail/cf/cf/uucpproto.mc OLD_FILES+=usr/share/sendmail/cf/cf/vangogh.cs.mc OLD_DIRS+=usr/share/sendmail/cf/cf OLD_FILES+=usr/share/sendmail/cf/domain/Berkeley.EDU.m4 OLD_FILES+=usr/share/sendmail/cf/domain/CS.Berkeley.EDU.m4 OLD_FILES+=usr/share/sendmail/cf/domain/EECS.Berkeley.EDU.m4 OLD_FILES+=usr/share/sendmail/cf/domain/S2K.Berkeley.EDU.m4 OLD_FILES+=usr/share/sendmail/cf/domain/berkeley-only.m4 OLD_FILES+=usr/share/sendmail/cf/domain/generic.m4 OLD_DIRS+=usr/share/sendmail/cf/domain OLD_FILES+=usr/share/sendmail/cf/feature/accept_unqualified_senders.m4 OLD_FILES+=usr/share/sendmail/cf/feature/accept_unresolvable_domains.m4 OLD_FILES+=usr/share/sendmail/cf/feature/access_db.m4 OLD_FILES+=usr/share/sendmail/cf/feature/allmasquerade.m4 OLD_FILES+=usr/share/sendmail/cf/feature/always_add_domain.m4 OLD_FILES+=usr/share/sendmail/cf/feature/authinfo.m4 OLD_FILES+=usr/share/sendmail/cf/feature/badmx.m4 OLD_FILES+=usr/share/sendmail/cf/feature/bestmx_is_local.m4 OLD_FILES+=usr/share/sendmail/cf/feature/bitdomain.m4 OLD_FILES+=usr/share/sendmail/cf/feature/blacklist_recipients.m4 OLD_FILES+=usr/share/sendmail/cf/feature/block_bad_helo.m4 OLD_FILES+=usr/share/sendmail/cf/feature/compat_check.m4 OLD_FILES+=usr/share/sendmail/cf/feature/conncontrol.m4 OLD_FILES+=usr/share/sendmail/cf/feature/delay_checks.m4 OLD_FILES+=usr/share/sendmail/cf/feature/dnsbl.m4 OLD_FILES+=usr/share/sendmail/cf/feature/domaintable.m4 OLD_FILES+=usr/share/sendmail/cf/feature/enhdnsbl.m4 OLD_FILES+=usr/share/sendmail/cf/feature/generics_entire_domain.m4 OLD_FILES+=usr/share/sendmail/cf/feature/genericstable.m4 OLD_FILES+=usr/share/sendmail/cf/feature/greet_pause.m4 OLD_FILES+=usr/share/sendmail/cf/feature/ldap_routing.m4 OLD_FILES+=usr/share/sendmail/cf/feature/limited_masquerade.m4 OLD_FILES+=usr/share/sendmail/cf/feature/local_lmtp.m4 OLD_FILES+=usr/share/sendmail/cf/feature/local_no_masquerade.m4 OLD_FILES+=usr/share/sendmail/cf/feature/local_procmail.m4 OLD_FILES+=usr/share/sendmail/cf/feature/lookupdotdomain.m4 OLD_FILES+=usr/share/sendmail/cf/feature/loose_relay_check.m4 OLD_FILES+=usr/share/sendmail/cf/feature/mailertable.m4 OLD_FILES+=usr/share/sendmail/cf/feature/masquerade_entire_domain.m4 OLD_FILES+=usr/share/sendmail/cf/feature/masquerade_envelope.m4 OLD_FILES+=usr/share/sendmail/cf/feature/msp.m4 OLD_FILES+=usr/share/sendmail/cf/feature/mtamark.m4 OLD_FILES+=usr/share/sendmail/cf/feature/no_default_msa.m4 OLD_FILES+=usr/share/sendmail/cf/feature/nocanonify.m4 OLD_FILES+=usr/share/sendmail/cf/feature/notsticky.m4 OLD_FILES+=usr/share/sendmail/cf/feature/nouucp.m4 OLD_FILES+=usr/share/sendmail/cf/feature/nullclient.m4 OLD_FILES+=usr/share/sendmail/cf/feature/preserve_local_plus_detail.m4 OLD_FILES+=usr/share/sendmail/cf/feature/preserve_luser_host.m4 OLD_FILES+=usr/share/sendmail/cf/feature/promiscuous_relay.m4 OLD_FILES+=usr/share/sendmail/cf/feature/queuegroup.m4 OLD_FILES+=usr/share/sendmail/cf/feature/ratecontrol.m4 OLD_FILES+=usr/share/sendmail/cf/feature/redirect.m4 OLD_FILES+=usr/share/sendmail/cf/feature/relay_based_on_MX.m4 OLD_FILES+=usr/share/sendmail/cf/feature/relay_entire_domain.m4 OLD_FILES+=usr/share/sendmail/cf/feature/relay_hosts_only.m4 OLD_FILES+=usr/share/sendmail/cf/feature/relay_local_from.m4 OLD_FILES+=usr/share/sendmail/cf/feature/relay_mail_from.m4 OLD_FILES+=usr/share/sendmail/cf/feature/require_rdns.m4 OLD_FILES+=usr/share/sendmail/cf/feature/smrsh.m4 OLD_FILES+=usr/share/sendmail/cf/feature/stickyhost.m4 OLD_FILES+=usr/share/sendmail/cf/feature/use_client_ptr.m4 OLD_FILES+=usr/share/sendmail/cf/feature/use_ct_file.m4 OLD_FILES+=usr/share/sendmail/cf/feature/use_cw_file.m4 OLD_FILES+=usr/share/sendmail/cf/feature/uucpdomain.m4 OLD_FILES+=usr/share/sendmail/cf/feature/virtuser_entire_domain.m4 OLD_FILES+=usr/share/sendmail/cf/feature/virtusertable.m4 OLD_DIRS+=usr/share/sendmail/cf/feature OLD_FILES+=usr/share/sendmail/cf/hack/cssubdomain.m4 OLD_DIRS+=usr/share/sendmail/cf/hack OLD_FILES+=usr/share/sendmail/cf/m4/cf.m4 OLD_FILES+=usr/share/sendmail/cf/m4/cfhead.m4 OLD_FILES+=usr/share/sendmail/cf/m4/proto.m4 OLD_FILES+=usr/share/sendmail/cf/m4/version.m4 OLD_DIRS+=usr/share/sendmail/cf/m4 OLD_FILES+=usr/share/sendmail/cf/mailer/cyrus.m4 OLD_FILES+=usr/share/sendmail/cf/mailer/cyrusv2.m4 OLD_FILES+=usr/share/sendmail/cf/mailer/fax.m4 OLD_FILES+=usr/share/sendmail/cf/mailer/local.m4 OLD_FILES+=usr/share/sendmail/cf/mailer/mail11.m4 OLD_FILES+=usr/share/sendmail/cf/mailer/phquery.m4 OLD_FILES+=usr/share/sendmail/cf/mailer/pop.m4 OLD_FILES+=usr/share/sendmail/cf/mailer/procmail.m4 OLD_FILES+=usr/share/sendmail/cf/mailer/qpage.m4 OLD_FILES+=usr/share/sendmail/cf/mailer/smtp.m4 OLD_FILES+=usr/share/sendmail/cf/mailer/usenet.m4 OLD_FILES+=usr/share/sendmail/cf/mailer/uucp.m4 OLD_DIRS+=usr/share/sendmail/cf/mailer OLD_FILES+=usr/share/sendmail/cf/ostype/a-ux.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/aix3.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/aix4.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/aix5.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/altos.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/amdahl-uts.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/bsd4.3.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/bsd4.4.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/bsdi.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/bsdi1.0.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/bsdi2.0.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/darwin.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/dgux.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/domainos.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/dragonfly.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/dynix3.2.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/freebsd4.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/freebsd5.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/freebsd6.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/gnu.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/hpux10.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/hpux11.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/hpux9.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/irix4.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/irix5.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/irix6.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/isc4.1.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/linux.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/maxion.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/mklinux.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/mpeix.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/nextstep.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/openbsd.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/osf1.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/powerux.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/ptx2.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/qnx.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/riscos4.5.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/sco-uw-2.1.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/sco3.2.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/sinix.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/solaris11.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/solaris2.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/solaris2.ml.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/solaris2.pre5.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/solaris8.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/sunos3.5.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/sunos4.1.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/svr4.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/ultrix4.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/unicos.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/unicosmk.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/unicosmp.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/unixware7.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/unknown.m4 OLD_FILES+=usr/share/sendmail/cf/ostype/uxpds.m4 OLD_DIRS+=usr/share/sendmail/cf/ostype OLD_FILES+=usr/share/sendmail/cf/sendmail.schema OLD_FILES+=usr/share/sendmail/cf/sh/makeinfo.sh OLD_DIRS+=usr/share/sendmail/cf/sh OLD_FILES+=usr/share/sendmail/cf/siteconfig/uucp.cogsci.m4 OLD_FILES+=usr/share/sendmail/cf/siteconfig/uucp.old.arpa.m4 OLD_FILES+=usr/share/sendmail/cf/siteconfig/uucp.ucbarpa.m4 OLD_FILES+=usr/share/sendmail/cf/siteconfig/uucp.ucbvax.m4 OLD_DIRS+=usr/share/sendmail/cf/siteconfig OLD_DIRS+=usr/share/sendmail/cf OLD_DIRS+=usr/share/sendmail .endif .if ${MK_SHAREDOCS} == no OLD_FILES+=usr/share/doc/pjdfstest/README OLD_DIRS+=usr/share/doc/pjdfstest .endif .if ${MK_SSP} == no OLD_LIBS+=lib/libssp.so.0 OLD_FILES+=usr/include/ssp/ssp.h OLD_FILES+=usr/include/ssp/stdio.h OLD_FILES+=usr/include/ssp/string.h OLD_FILES+=usr/include/ssp/unistd.h OLD_FILES+=usr/lib/libssp.a OLD_FILES+=usr/lib/libssp.so OLD_FILES+=usr/lib/libssp_nonshared.a OLD_FILES+=usr/lib32/libssp.a OLD_FILES+=usr/lib32/libssp.so OLD_LIBS+=usr/lib32/libssp.so.0 OLD_FILES+=usr/lib32/libssp_nonshared.a OLD_FILES+=usr/tests/lib/libc/ssp/Kyuafile OLD_FILES+=usr/tests/lib/libc/ssp/h_fgets OLD_FILES+=usr/tests/lib/libc/ssp/h_getcwd OLD_FILES+=usr/tests/lib/libc/ssp/h_gets OLD_FILES+=usr/tests/lib/libc/ssp/h_memcpy OLD_FILES+=usr/tests/lib/libc/ssp/h_memmove OLD_FILES+=usr/tests/lib/libc/ssp/h_memset OLD_FILES+=usr/tests/lib/libc/ssp/h_read OLD_FILES+=usr/tests/lib/libc/ssp/h_readlink OLD_FILES+=usr/tests/lib/libc/ssp/h_snprintf OLD_FILES+=usr/tests/lib/libc/ssp/h_sprintf OLD_FILES+=usr/tests/lib/libc/ssp/h_stpcpy OLD_FILES+=usr/tests/lib/libc/ssp/h_stpncpy OLD_FILES+=usr/tests/lib/libc/ssp/h_strcat OLD_FILES+=usr/tests/lib/libc/ssp/h_strcpy OLD_FILES+=usr/tests/lib/libc/ssp/h_strncat OLD_FILES+=usr/tests/lib/libc/ssp/h_strncpy OLD_FILES+=usr/tests/lib/libc/ssp/h_vsnprintf OLD_FILES+=usr/tests/lib/libc/ssp/h_vsprintf OLD_FILES+=usr/tests/lib/libc/ssp/ssp_test .endif .if ${MK_SYSCONS} == no OLD_FILES+=usr/share/syscons/fonts/INDEX.fonts OLD_FILES+=usr/share/syscons/fonts/armscii8-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/armscii8-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/armscii8-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp1251-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/cp1251-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp1251-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp437-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/cp437-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp437-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp437-thin-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp437-thin-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp850-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/cp850-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp850-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp850-thin-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp850-thin-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp865-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/cp865-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp865-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp865-thin-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp865-thin-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp866-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/cp866-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp866-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp866b-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp866c-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp866u-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/cp866u-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp866u-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/haik8-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/haik8-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/haik8-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso-thin-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso02-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso02-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso02-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-vga9-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-vga9-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-vga9-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-vga9-wide-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-wide-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso05-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso05-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso05-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso07-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso07-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso07-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso08-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso08-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso08-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso09-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso15-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso15-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso15-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso15-thin-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-r-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-r-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-r-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-rb-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-rc-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-u-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-u-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-u-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/swiss-1131-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/swiss-1251-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/swiss-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/swiss-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/swiss-8x8.fnt OLD_FILES+=usr/share/syscons/keymaps/INDEX.keymaps OLD_FILES+=usr/share/syscons/keymaps/be.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/be.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/bg.bds.ctrlcaps.kbd OLD_FILES+=usr/share/syscons/keymaps/bg.phonetic.ctrlcaps.kbd OLD_FILES+=usr/share/syscons/keymaps/br275.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/br275.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/br275.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/by.cp1131.kbd OLD_FILES+=usr/share/syscons/keymaps/by.cp1251.kbd OLD_FILES+=usr/share/syscons/keymaps/by.iso5.kbd OLD_FILES+=usr/share/syscons/keymaps/ce.iso2.kbd OLD_FILES+=usr/share/syscons/keymaps/colemak.iso15.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/cs.latin2.qwertz.kbd OLD_FILES+=usr/share/syscons/keymaps/cz.iso2.kbd OLD_FILES+=usr/share/syscons/keymaps/danish.cp865.kbd OLD_FILES+=usr/share/syscons/keymaps/danish.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/danish.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/danish.iso.macbook.kbd OLD_FILES+=usr/share/syscons/keymaps/dutch.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/eee_nordic.kbd OLD_FILES+=usr/share/syscons/keymaps/el.iso07.kbd OLD_FILES+=usr/share/syscons/keymaps/estonian.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/estonian.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/estonian.iso15.kbd OLD_FILES+=usr/share/syscons/keymaps/finnish.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/finnish.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/fr.dvorak.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/fr.dvorak.kbd OLD_FILES+=usr/share/syscons/keymaps/fr.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/fr.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/fr.macbook.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/fr_CA.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/german.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/german.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/german.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/gr.elot.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/gr.us101.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/hr.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/hu.iso2.101keys.kbd OLD_FILES+=usr/share/syscons/keymaps/hu.iso2.102keys.kbd OLD_FILES+=usr/share/syscons/keymaps/hy.armscii-8.kbd OLD_FILES+=usr/share/syscons/keymaps/icelandic.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/icelandic.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/it.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/iw.iso8.kbd OLD_FILES+=usr/share/syscons/keymaps/jp.106.kbd OLD_FILES+=usr/share/syscons/keymaps/jp.106x.kbd OLD_FILES+=usr/share/syscons/keymaps/jp.pc98.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/jp.pc98.kbd OLD_FILES+=usr/share/syscons/keymaps/kk.pt154.io.kbd OLD_FILES+=usr/share/syscons/keymaps/kk.pt154.kst.kbd OLD_FILES+=usr/share/syscons/keymaps/latinamerican.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/latinamerican.kbd OLD_FILES+=usr/share/syscons/keymaps/lt.iso4.kbd OLD_FILES+=usr/share/syscons/keymaps/norwegian.dvorak.kbd OLD_FILES+=usr/share/syscons/keymaps/norwegian.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/pl_PL.ISO8859-2.kbd OLD_FILES+=usr/share/syscons/keymaps/pl_PL.dvorak.kbd OLD_FILES+=usr/share/syscons/keymaps/pt.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/pt.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/ru.cp866.kbd OLD_FILES+=usr/share/syscons/keymaps/ru.iso5.kbd OLD_FILES+=usr/share/syscons/keymaps/ru.koi8-r.kbd OLD_FILES+=usr/share/syscons/keymaps/ru.koi8-r.shift.kbd OLD_FILES+=usr/share/syscons/keymaps/ru.koi8-r.win.kbd OLD_FILES+=usr/share/syscons/keymaps/si.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/sk.iso2.kbd OLD_FILES+=usr/share/syscons/keymaps/spanish.dvorak.kbd OLD_FILES+=usr/share/syscons/keymaps/spanish.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/spanish.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/spanish.iso15.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/swedish.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/swedish.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/swissfrench.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/swissfrench.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/swissfrench.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/swissgerman.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/swissgerman.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/swissgerman.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/swissgerman.macbook.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/tr.iso9.q.kbd OLD_FILES+=usr/share/syscons/keymaps/ua.iso5.kbd OLD_FILES+=usr/share/syscons/keymaps/ua.koi8-u.kbd OLD_FILES+=usr/share/syscons/keymaps/ua.koi8-u.shift.alt.kbd OLD_FILES+=usr/share/syscons/keymaps/uk.cp850-ctrl.kbd OLD_FILES+=usr/share/syscons/keymaps/uk.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/uk.dvorak.kbd OLD_FILES+=usr/share/syscons/keymaps/uk.iso-ctrl.kbd OLD_FILES+=usr/share/syscons/keymaps/uk.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/us.dvorak.kbd OLD_FILES+=usr/share/syscons/keymaps/us.dvorakl.kbd OLD_FILES+=usr/share/syscons/keymaps/us.dvorakp.kbd OLD_FILES+=usr/share/syscons/keymaps/us.dvorakr.kbd OLD_FILES+=usr/share/syscons/keymaps/us.dvorakx.kbd OLD_FILES+=usr/share/syscons/keymaps/us.emacs.kbd OLD_FILES+=usr/share/syscons/keymaps/us.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/us.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/us.pc-ctrl.kbd OLD_FILES+=usr/share/syscons/keymaps/us.unix.kbd OLD_FILES+=usr/share/syscons/scrnmaps/armscii8-2haik8.scm OLD_FILES+=usr/share/syscons/scrnmaps/iso-8859-1_to_cp437.scm OLD_FILES+=usr/share/syscons/scrnmaps/iso-8859-4_for_vga9.scm OLD_FILES+=usr/share/syscons/scrnmaps/iso-8859-7_to_cp437.scm OLD_FILES+=usr/share/syscons/scrnmaps/koi8-r2cp866.scm OLD_FILES+=usr/share/syscons/scrnmaps/koi8-u2cp866u.scm OLD_FILES+=usr/share/syscons/scrnmaps/us-ascii_to_cp437.scm .endif .if ${MK_TALK} == no OLD_FILES+=usr/bin/talk OLD_FILES+=usr/libexec/ntalkd OLD_FILES+=usr/share/man/man1/talk.1.gz OLD_FILES+=usr/share/man/man8/talkd.8.gz .endif .if ${MK_TCSH} == no OLD_FILES+=.cshrc OLD_FILES+=etc/csh.cshrc OLD_FILES+=etc/csh.login OLD_FILES+=etc/csh.logout OLD_FILES+=bin/csh OLD_FILES+=bin/tcsh OLD_FILES+=rescue/csh OLD_FILES+=rescue/tcsh OLD_FILES+=root/.cshrc OLD_FILES+=root/.login OLD_FILES+=usr/share/examples/etc/csh.cshrc OLD_FILES+=usr/share/examples/etc/csh.login OLD_FILES+=usr/share/examples/etc/csh.logout OLD_FILES+=usr/share/examples/tcsh/complete.tcsh OLD_FILES+=usr/share/examples/tcsh/csh-mode.el OLD_DIRS+=usr/share/examples/tcsh OLD_FILES+=usr/share/man/man1/csh.1.gz OLD_FILES+=usr/share/man/man1/tcsh.1.gz OLD_FILES+=usr/share/nls/de_AT.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/de_AT.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/de_AT.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/de_CH.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/de_CH.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/de_CH.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/de_DE.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/de_DE.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/el_GR.ISO8859-7/tcsh.cat OLD_FILES+=usr/share/nls/el_GR.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/es_ES.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/es_ES.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/es_ES.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/et_EE.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/et_EE.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fi_FI.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/fi_FI.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/fi_FI.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_BE.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/fr_BE.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/fr_BE.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_CA.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/fr_CA.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/fr_CA.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_CH.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/fr_CH.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/fr_CH.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/fr_FR.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/fr_FR.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/it_CH.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/it_CH.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/it_CH.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/it_IT.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/it_IT.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/it_IT.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/ja_JP.SJIS/tcsh.cat OLD_FILES+=usr/share/nls/ja_JP.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/ja_JP.eucJP/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.CP1251/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.CP866/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.ISO8859-5/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/uk_UA.ISO8859-5/tcsh.cat OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/tcsh.cat OLD_FILES+=usr/share/nls/uk_UA.UTF-8/tcsh.cat .endif .if ${MK_TELNET} == no OLD_FILES+=usr/bin/telnet OLD_FILES+=usr/libexec/telnetd OLD_FILES+=usr/share/man/man1/telnet.1.gz OLD_FILES+=usr/share/man/man8/telnetd.8.gz .endif .if ${MK_TESTS} == yes OLD_FILES+=usr/bin/atf-sh OLD_FILES+=usr/include/atf-c++/config.hpp OLD_FILES+=usr/include/atf-c/config.h OLD_LIBS+=usr/lib/libatf-c++.a OLD_LIBS+=usr/lib/libatf-c++.so OLD_LIBS+=usr/lib/libatf-c++.so.1 OLD_LIBS+=usr/lib/libatf-c++.so.2 OLD_LIBS+=usr/lib/libatf-c++_p.a OLD_LIBS+=usr/lib/libatf-c.a OLD_LIBS+=usr/lib/libatf-c.so OLD_LIBS+=usr/lib/libatf-c.so.1 OLD_LIBS+=usr/lib/libatf-c_p.a OLD_LIBS+=usr/lib/private/libatf-c.so.0 OLD_LIBS+=usr/lib/private/libatf-c++.so.1 .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" OLD_LIBS+=usr/lib32/libatf-c++.a OLD_LIBS+=usr/lib32/libatf-c++.so OLD_LIBS+=usr/lib32/libatf-c++.so.1 OLD_LIBS+=usr/lib32/libatf-c++.so.2 OLD_LIBS+=usr/lib32/libatf-c++_p.a OLD_LIBS+=usr/lib32/libatf-c.a OLD_LIBS+=usr/lib32/libatf-c.so OLD_LIBS+=usr/lib32/libatf-c.so.1 OLD_LIBS+=usr/lib32/libatf-c_p.a OLD_LIBS+=usr/lib32/private/libatf-c.so.0 OLD_LIBS+=usr/lib32/private/libatf-c++.so.1 .endif OLD_FILES+=usr/libdata/pkgconfig/atf-c++.pc OLD_FILES+=usr/libdata/pkgconfig/atf-c.pc OLD_FILES+=usr/libdata/pkgconfig/atf-sh.pc OLD_FILES+=usr/share/aclocal/atf-c++.m4 OLD_FILES+=usr/share/aclocal/atf-c.m4 OLD_FILES+=usr/share/aclocal/atf-common.m4 OLD_FILES+=usr/share/aclocal/atf-sh.m4 OLD_DIRS+=usr/share/aclocal OLD_FILES+=usr/tests/bin/chown/units_basics OLD_FILES+=usr/tests/bin/date/legacy_test OLD_FILES+=usr/tests/bin/sh/legacy_test OLD_FILES+=usr/tests/usr.bin/atf/Kyuafile OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/Kyuafile OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/atf_check_test OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/config_test OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/integration_test OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/misc_helpers OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/normalize_test OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/tc_test OLD_FILES+=usr/tests/usr.bin/atf/atf-sh/tp_test OLD_DIRS+=usr/tests/usr.bin/atf/atf-sh OLD_DIRS+=usr/tests/usr.bin/atf OLD_FILES+=usr/tests/lib/atf/libatf-c/test_helpers_test OLD_FILES+=usr/tests/lib/atf/test-programs/fork_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/application_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/config_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/expand_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/parser_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/sanity_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/ui_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/env_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/exceptions_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/expand_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/fs_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/parser_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/process_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/sanity_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/pkg_config_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/text_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/ui_test OLD_FILES+=usr/tests/lib/atf/libatf-c/config_test OLD_FILES+=usr/tests/lib/atf/libatf-c/dynstr_test OLD_FILES+=usr/tests/lib/atf/libatf-c/env_test OLD_FILES+=usr/tests/lib/atf/libatf-c/fs_test OLD_FILES+=usr/tests/lib/atf/libatf-c/list_test OLD_FILES+=usr/tests/lib/atf/libatf-c/map_test OLD_FILES+=usr/tests/lib/atf/libatf-c/pkg_config_test OLD_FILES+=usr/tests/lib/atf/libatf-c/process_helpers OLD_FILES+=usr/tests/lib/atf/libatf-c/process_test OLD_FILES+=usr/tests/lib/atf/libatf-c/sanity_test OLD_FILES+=usr/tests/lib/atf/libatf-c/text_test OLD_FILES+=usr/tests/lib/atf/libatf-c/user_test .if ${MK_MAKE} == yes OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/legacy_test OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.status.2 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.status.3 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.status.4 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.status.5 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.status.6 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.status.7 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stderr.3 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stderr.4 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stderr.5 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stderr.6 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stderr.7 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stdout.3 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stdout.4 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stdout.5 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stdout.6 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/expected.stdout.7 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd/libtest.a OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/legacy_test OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.status.2 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.status.3 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.status.4 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.status.5 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.status.6 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.status.7 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stderr.3 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stderr.4 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stderr.5 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stderr.6 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stderr.7 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stdout.3 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stdout.4 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stdout.5 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stdout.6 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/expected.stdout.7 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod/libtest.a OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/legacy_test OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.status.2 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.status.3 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.status.4 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.status.5 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.status.6 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.status.7 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stderr.3 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stderr.4 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stderr.5 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stderr.6 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stderr.7 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stdout.3 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stdout.4 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stdout.5 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stdout.6 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/expected.stdout.7 OLD_FILES+=usr/tests/usr.bin/make/archives/fmt_oldbsd/libtest.a OLD_FILES+=usr/tests/usr.bin/make/archives/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/basic/t0/legacy_test OLD_FILES+=usr/tests/usr.bin/make/basic/t0/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/basic/t0/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/basic/t0/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/basic/t0/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/basic/t1/legacy_test OLD_FILES+=usr/tests/usr.bin/make/basic/t1/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/basic/t1/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/basic/t1/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/basic/t1/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/basic/t1/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/basic/t2/legacy_test OLD_FILES+=usr/tests/usr.bin/make/basic/t2/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/basic/t2/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/basic/t2/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/basic/t2/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/basic/t2/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/basic/t3/legacy_test OLD_FILES+=usr/tests/usr.bin/make/basic/t3/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/basic/t3/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/basic/t3/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/basic/t3/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/basic/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/execution/ellipsis/legacy_test OLD_FILES+=usr/tests/usr.bin/make/execution/ellipsis/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/execution/ellipsis/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/execution/ellipsis/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/execution/ellipsis/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/execution/ellipsis/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/execution/empty/legacy_test OLD_FILES+=usr/tests/usr.bin/make/execution/empty/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/execution/empty/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/execution/empty/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/execution/empty/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/execution/empty/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/execution/joberr/legacy_test OLD_FILES+=usr/tests/usr.bin/make/execution/joberr/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/execution/joberr/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/execution/joberr/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/execution/joberr/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/execution/joberr/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/execution/plus/legacy_test OLD_FILES+=usr/tests/usr.bin/make/execution/plus/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/execution/plus/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/execution/plus/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/execution/plus/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/execution/plus/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/execution/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/legacy_test OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/expected.status.2 OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/make/shell/builtin/sh OLD_FILES+=usr/tests/usr.bin/make/shell/meta/legacy_test OLD_FILES+=usr/tests/usr.bin/make/shell/meta/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/shell/meta/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/shell/meta/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/shell/meta/expected.status.2 OLD_FILES+=usr/tests/usr.bin/make/shell/meta/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/shell/meta/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/make/shell/meta/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/shell/meta/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/make/shell/meta/sh OLD_FILES+=usr/tests/usr.bin/make/shell/path/legacy_test OLD_FILES+=usr/tests/usr.bin/make/shell/path/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/shell/path/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/shell/path/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/shell/path/expected.status.2 OLD_FILES+=usr/tests/usr.bin/make/shell/path/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/shell/path/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/make/shell/path/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/shell/path/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/make/shell/path/sh OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/legacy_test OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/expected.status.2 OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/make/shell/path_select/shell OLD_FILES+=usr/tests/usr.bin/make/shell/replace/legacy_test OLD_FILES+=usr/tests/usr.bin/make/shell/replace/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/shell/replace/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/shell/replace/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/shell/replace/expected.status.2 OLD_FILES+=usr/tests/usr.bin/make/shell/replace/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/shell/replace/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/make/shell/replace/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/shell/replace/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/make/shell/replace/shell OLD_FILES+=usr/tests/usr.bin/make/shell/select/legacy_test OLD_FILES+=usr/tests/usr.bin/make/shell/select/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/shell/select/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/shell/select/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/shell/select/expected.status.2 OLD_FILES+=usr/tests/usr.bin/make/shell/select/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/shell/select/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/make/shell/select/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/shell/select/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/make/shell/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/suffixes/basic/legacy_test OLD_FILES+=usr/tests/usr.bin/make/suffixes/basic/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/suffixes/basic/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/suffixes/basic/TEST1.a OLD_FILES+=usr/tests/usr.bin/make/suffixes/basic/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/suffixes/basic/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/suffixes/basic/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/legacy_test OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/TEST1.a OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/TEST2.a OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild1/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/legacy_test OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/TEST1.a OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/TEST2.a OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/suffixes/src_wild2/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/suffixes/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/syntax/directive-t0/legacy_test OLD_FILES+=usr/tests/usr.bin/make/syntax/directive-t0/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/syntax/directive-t0/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/syntax/directive-t0/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/syntax/directive-t0/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/syntax/directive-t0/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/legacy_test OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.status.2 OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.status.3 OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.status.4 OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.status.5 OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stderr.3 OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stderr.4 OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stderr.5 OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stdout.3 OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stdout.4 OLD_FILES+=usr/tests/usr.bin/make/syntax/enl/expected.stdout.5 OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/legacy_test OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/expected.status.2 OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/syntax/funny-targets/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/legacy_test OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/expected.status.2 OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/syntax/semi/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/make/syntax/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/2/1/legacy_test OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/2/1/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/2/1/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/2/1/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/2/1/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/2/1/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/2/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/mk/sys.mk OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/mk/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/sysmk/t0/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/2/1/legacy_test OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/2/1/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/2/1/cleanup OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/2/1/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/2/1/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/2/1/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/2/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/mk/sys.mk OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/mk/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/sysmk/t1/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/2/1/legacy_test OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/2/1/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/2/1/cleanup OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/2/1/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/2/1/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/2/1/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/2/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/mk/sys.mk OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/mk/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/sysmk/t2/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/sysmk/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_M/legacy_test OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_M/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_M/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_M/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_M/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_M/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/legacy_test OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.status.2 OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.status.3 OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.stderr.3 OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/make/variables/modifier_t/expected.stdout.3 OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/legacy_test OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/expected.status.2 OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/variables/opt_V/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/make/variables/t0/legacy_test OLD_FILES+=usr/tests/usr.bin/make/variables/t0/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/variables/t0/Makefile.test OLD_FILES+=usr/tests/usr.bin/make/variables/t0/expected.status.1 OLD_FILES+=usr/tests/usr.bin/make/variables/t0/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/make/variables/t0/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/make/variables/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/Kyuafile OLD_FILES+=usr/tests/usr.bin/make/common.sh OLD_FILES+=usr/tests/usr.bin/make/test-new.mk OLD_DIRS+=usr/tests/usr.bin/make/variables/t0 OLD_DIRS+=usr/tests/usr.bin/make/variables/opt_V OLD_DIRS+=usr/tests/usr.bin/make/variables/modifier_t OLD_DIRS+=usr/tests/usr.bin/make/variables/modifier_M OLD_DIRS+=usr/tests/usr.bin/make/variables OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t2/mk OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t2/2/1 OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t2/2 OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t2 OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t1/mk OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t1/2/1 OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t1/2 OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t1 OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t0/mk OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t0/2/1 OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t0/2 OLD_DIRS+=usr/tests/usr.bin/make/sysmk/t0 OLD_DIRS+=usr/tests/usr.bin/make/sysmk OLD_DIRS+=usr/tests/usr.bin/make/syntax/semi OLD_DIRS+=usr/tests/usr.bin/make/syntax/funny-targets OLD_DIRS+=usr/tests/usr.bin/make/syntax/enl OLD_DIRS+=usr/tests/usr.bin/make/syntax/directive-t0 OLD_DIRS+=usr/tests/usr.bin/make/syntax OLD_DIRS+=usr/tests/usr.bin/make/suffixes/src_wild2 OLD_DIRS+=usr/tests/usr.bin/make/suffixes/src_wild1 OLD_DIRS+=usr/tests/usr.bin/make/suffixes/basic OLD_DIRS+=usr/tests/usr.bin/make/suffixes OLD_DIRS+=usr/tests/usr.bin/make/shell/select OLD_DIRS+=usr/tests/usr.bin/make/shell/replace OLD_DIRS+=usr/tests/usr.bin/make/shell/path_select OLD_DIRS+=usr/tests/usr.bin/make/shell/path OLD_DIRS+=usr/tests/usr.bin/make/shell/meta OLD_DIRS+=usr/tests/usr.bin/make/shell/builtin OLD_DIRS+=usr/tests/usr.bin/make/shell OLD_DIRS+=usr/tests/usr.bin/make/execution/plus OLD_DIRS+=usr/tests/usr.bin/make/execution/joberr OLD_DIRS+=usr/tests/usr.bin/make/execution/empty OLD_DIRS+=usr/tests/usr.bin/make/execution/ellipsis OLD_DIRS+=usr/tests/usr.bin/make/execution OLD_DIRS+=usr/tests/usr.bin/make/basic/t3 OLD_DIRS+=usr/tests/usr.bin/make/basic/t2 OLD_DIRS+=usr/tests/usr.bin/make/basic/t1 OLD_DIRS+=usr/tests/usr.bin/make/basic/t0 OLD_DIRS+=usr/tests/usr.bin/make/basic OLD_DIRS+=usr/tests/usr.bin/make/archives/fmt_oldbsd OLD_DIRS+=usr/tests/usr.bin/make/archives/fmt_44bsd_mod OLD_DIRS+=usr/tests/usr.bin/make/archives/fmt_44bsd OLD_DIRS+=usr/tests/usr.bin/make/archives OLD_DIRS+=usr/tests/usr.bin/make OLD_FILES+=usr/tests/usr.bin/yacc/legacy_test OLD_FILES+=usr/tests/usr.bin/yacc/regress.00.out OLD_FILES+=usr/tests/usr.bin/yacc/regress.01.out OLD_FILES+=usr/tests/usr.bin/yacc/regress.02.out OLD_FILES+=usr/tests/usr.bin/yacc/regress.03.out OLD_FILES+=usr/tests/usr.bin/yacc/regress.04.out OLD_FILES+=usr/tests/usr.bin/yacc/regress.05.out OLD_FILES+=usr/tests/usr.bin/yacc/regress.06.out OLD_FILES+=usr/tests/usr.bin/yacc/regress.07.out OLD_FILES+=usr/tests/usr.bin/yacc/regress.08.out OLD_FILES+=usr/tests/usr.bin/yacc/regress.09.out OLD_FILES+=usr/tests/usr.bin/yacc/regress.10.out OLD_FILES+=usr/tests/usr.bin/yacc/regress.11.out OLD_FILES+=usr/tests/usr.bin/yacc/regress.12.out OLD_FILES+=usr/tests/usr.bin/yacc/regress.13.out OLD_FILES+=usr/tests/usr.bin/yacc/regress.14.out OLD_FILES+=usr/tests/usr.bin/yacc/regress.sh OLD_FILES+=usr/tests/usr.bin/yacc/undefined.y .endif .else # ATF libraries. OLD_FILES+=etc/mtree/BSD.tests.dist OLD_FILES+=usr/bin/atf-sh OLD_DIRS+=usr/include/atf-c OLD_FILES+=usr/include/atf-c/build.h OLD_FILES+=usr/include/atf-c/check.h OLD_FILES+=usr/include/atf-c/config.h OLD_FILES+=usr/include/atf-c/defs.h OLD_FILES+=usr/include/atf-c/error.h OLD_FILES+=usr/include/atf-c/error_fwd.h OLD_FILES+=usr/include/atf-c/macros.h OLD_FILES+=usr/include/atf-c/tc.h OLD_FILES+=usr/include/atf-c/tp.h OLD_FILES+=usr/include/atf-c/utils.h OLD_FILES+=usr/include/atf-c.h OLD_DIRS+=usr/include/atf-c++ OLD_FILES+=usr/include/atf-c++/build.hpp OLD_FILES+=usr/include/atf-c++/check.hpp OLD_FILES+=usr/include/atf-c++/config.hpp OLD_FILES+=usr/include/atf-c++/macros.hpp OLD_FILES+=usr/include/atf-c++/tests.hpp OLD_FILES+=usr/include/atf-c++/utils.hpp OLD_FILES+=usr/include/atf-c++.hpp OLD_FILES+=usr/lib/libatf-c_p.a OLD_FILES+=usr/lib/libatf-c.so.1 OLD_FILES+=usr/lib/libatf-c.so OLD_FILES+=usr/lib/libatf-c++.a OLD_FILES+=usr/lib/libatf-c++_p.a OLD_FILES+=usr/lib/libatf-c++.so.1 OLD_FILES+=usr/lib/libatf-c++.so OLD_FILES+=usr/lib/libatf-c.a OLD_FILES+=usr/libexec/atf-check OLD_FILES+=usr/libexec/atf-sh OLD_DIRS+=usr/share/atf OLD_FILES+=usr/share/atf/libatf-sh.subr OLD_DIRS+=usr/share/doc/atf OLD_FILES+=usr/share/doc/atf/AUTHORS OLD_FILES+=usr/share/doc/atf/COPYING OLD_FILES+=usr/share/doc/atf/NEWS OLD_FILES+=usr/share/doc/atf/README OLD_FILES+=usr/share/doc/pjdfstest/README OLD_FILES+=usr/share/man/man1/atf-check.1.gz OLD_FILES+=usr/share/man/man1/atf-sh.1.gz OLD_FILES+=usr/share/man/man1/atf-test-program.1.gz OLD_FILES+=usr/share/man/man3/atf-c-api.3.gz OLD_FILES+=usr/share/man/man3/atf-c++-api.3.gz OLD_FILES+=usr/share/man/man3/atf-sh-api.3.gz OLD_FILES+=usr/share/man/man3/atf-sh.3.gz OLD_FILES+=usr/share/man/man4/atf-test-case.4.gz OLD_FILES+=usr/share/man/man7/atf.7.gz OLD_FILES+=usr/share/mk/atf.test.mk OLD_FILES+=usr/share/mk/plain.test.mk OLD_FILES+=usr/share/mk/suite.test.mk OLD_FILES+=usr/share/mk/tap.test.mk # Test suite. . if exists(${DESTDIR}${TESTSBASE}) TESTS_DIRS!=find ${DESTDIR}${TESTSBASE} -type d | sed -e 's,^${DESTDIR}/,,'; echo OLD_DIRS+=${TESTS_DIRS} TESTS_FILES!=find ${DESTDIR}${TESTSBASE} \! -type d | sed -e 's,^${DESTDIR}/,,'; echo OLD_FILES+=${TESTS_FILES} . endif .endif # Test suite. .if ${MK_TESTS_SUPPORT} == no OLD_FILES+=usr/include/atf-c++.hpp OLD_FILES+=usr/include/atf-c++/build.hpp OLD_FILES+=usr/include/atf-c++/check.hpp OLD_FILES+=usr/include/atf-c++/macros.hpp OLD_FILES+=usr/include/atf-c++/tests.hpp OLD_FILES+=usr/include/atf-c++/utils.hpp OLD_FILES+=usr/include/atf-c.h OLD_FILES+=usr/include/atf-c/build.h OLD_FILES+=usr/include/atf-c/check.h OLD_FILES+=usr/include/atf-c/defs.h OLD_FILES+=usr/include/atf-c/error.h OLD_FILES+=usr/include/atf-c/error_fwd.h OLD_FILES+=usr/include/atf-c/macros.h OLD_FILES+=usr/include/atf-c/tc.h OLD_FILES+=usr/include/atf-c/tp.h OLD_FILES+=usr/include/atf-c/utils.h OLD_LIBS+=usr/lib/private/libatf-c++.so.2 OLD_LIBS+=usr/lib/private/libatf-c.so.1 OLD_FILES+=usr/share/man/man3/atf-c++.3.gz OLD_FILES+=usr/share/man/man3/atf-c-api++.3.gz OLD_FILES+=usr/share/man/man3/atf-c-api.3.gz OLD_FILES+=usr/share/man/man3/atf-c.3.gz OLD_FILES+=usr/tests/lib/atf/Kyuafile OLD_FILES+=usr/tests/lib/atf/libatf-c++/Kyuafile OLD_FILES+=usr/tests/lib/atf/libatf-c++/atf_c++_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/build_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/check_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/Kyuafile OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/application_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/env_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/exceptions_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/fs_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/process_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/text_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/version_helper OLD_FILES+=usr/tests/lib/atf/libatf-c++/macros_hpp_test.cpp OLD_FILES+=usr/tests/lib/atf/libatf-c++/macros_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/tests_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/unused_test.cpp OLD_FILES+=usr/tests/lib/atf/libatf-c++/utils_test OLD_FILES+=usr/tests/lib/atf/libatf-c/Kyuafile OLD_FILES+=usr/tests/lib/atf/libatf-c/atf_c_test OLD_FILES+=usr/tests/lib/atf/libatf-c/build_test OLD_FILES+=usr/tests/lib/atf/libatf-c/check_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/Kyuafile OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/dynstr_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/env_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/fs_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/list_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/map_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/process_helpers OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/process_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/sanity_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/text_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/user_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/version_helper OLD_FILES+=usr/tests/lib/atf/libatf-c/error_test OLD_FILES+=usr/tests/lib/atf/libatf-c/macros_h_test.c OLD_FILES+=usr/tests/lib/atf/libatf-c/macros_test OLD_FILES+=usr/tests/lib/atf/libatf-c/tc_test OLD_FILES+=usr/tests/lib/atf/libatf-c/tp_test OLD_FILES+=usr/tests/lib/atf/libatf-c/unused_test.c OLD_FILES+=usr/tests/lib/atf/libatf-c/utils_test OLD_FILES+=usr/tests/lib/atf/test-programs/Kyuafile OLD_FILES+=usr/tests/lib/atf/test-programs/c_helpers OLD_FILES+=usr/tests/lib/atf/test-programs/config_test OLD_FILES+=usr/tests/lib/atf/test-programs/cpp_helpers OLD_FILES+=usr/tests/lib/atf/test-programs/expect_test OLD_FILES+=usr/tests/lib/atf/test-programs/meta_data_test OLD_FILES+=usr/tests/lib/atf/test-programs/result_test OLD_FILES+=usr/tests/lib/atf/test-programs/sh_helpers OLD_FILES+=usr/tests/lib/atf/test-programs/srcdir_test .endif .if ${MK_TEXTPROC} == no OLD_FILES+=usr/bin/checknr OLD_FILES+=usr/bin/colcrt OLD_FILES+=usr/bin/ul OLD_FILES+=usr/share/man/man1/checknr.1.gz OLD_FILES+=usr/share/man/man1/colcrt.1.gz OLD_FILES+=usr/share/man/man1/ul.1.gz .endif #.if ${MK_TOOLCHAIN} == no # to be filled in #.endif .if ${MK_UNBOUND} == no OLD_FILES+=etc/rc.d/local_unbound OLD_FILES+=etc/unbound OLD_FILES+=usr/lib/private/libunbound.a OLD_FILES+=usr/lib/private/libunbound.so OLD_LIBS+=usr/lib/private/libunbound.so.5 OLD_FILES+=usr/lib/private/libunbound_p.a .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/lib32/private/libunbound.a OLD_FILES+=usr/lib32/private/libunbound.so OLD_LIBS+=usr/lib32/private/libunbound.so.5 OLD_FILES+=usr/lib32/private/libunbound_p.a .endif OLD_FILES+=usr/sbin/local-unbound-setup OLD_FILES+=usr/sbin/unbound OLD_FILES+=usr/sbin/unbound-anchor OLD_FILES+=usr/sbin/unbound-checkconf OLD_FILES+=usr/sbin/unbound-control OLD_FILES+=usr/sbin/unbound-control-setup OLD_FILES+=usr/share/man/man5/unbound.conf.5.gz OLD_FILES+=usr/share/man/man8/unbound-anchor.8.gz OLD_FILES+=usr/share/man/man8/unbound-checkconf.8.gz OLD_FILES+=usr/share/man/man8/unbound-control.8.gz OLD_FILES+=usr/share/man/man8/unbound.8.gz .endif .if ${MK_USB} == no OLD_FILES+=etc/devd/uath.conf OLD_FILES+=etc/devd/uauth.conf OLD_FILES+=etc/devd/ulpt.conf OLD_FILES+=etc/devd/usb.conf OLD_FILES+=usr/bin/usbhidaction OLD_FILES+=usr/bin/usbhidctl OLD_FILES+=usr/include/libusb.h OLD_FILES+=usr/include/libusb20.h OLD_FILES+=usr/include/libusb20_desc.h OLD_FILES+=usr/include/usb.h OLD_FILES+=usr/include/usbhid.h OLD_FILES+=usr/lib/libusb.a OLD_FILES+=usr/lib/libusb.so OLD_LIBS+=usr/lib/libusb.so.3 OLD_FILES+=usr/lib/libusb_p.a OLD_FILES+=usr/lib/libusbhid.a OLD_FILES+=usr/lib/libusbhid.so OLD_LIBS+=usr/lib/libusbhid.so.4 OLD_FILES+=usr/lib/libusbhid_p.a OLD_FILES+=usr/lib32/libusb.a OLD_FILES+=usr/lib32/libusb.so OLD_LIBS+=usr/lib32/libusb.so.3 OLD_FILES+=usr/lib32/libusb_p.a OLD_FILES+=usr/lib32/libusbhid.a OLD_FILES+=usr/lib32/libusbhid.so OLD_LIBS+=usr/lib32/libusbhid.so.4 OLD_FILES+=usr/lib32/libusbhid_p.a OLD_FILES+=usr/libdata/pkgconfig/libusb-0.1.pc OLD_FILES+=usr/libdata/pkgconfig/libusb-1.0.pc OLD_FILES+=usr/libdata/pkgconfig/libusb-2.0.pc OLD_FILES+=usr/sbin/uathload OLD_FILES+=usr/sbin/uhsoctl OLD_FILES+=usr/sbin/usbconfig OLD_FILES+=usr/sbin/usbdump OLD_FILES+=usr/share/examples/libusb20/Makefile OLD_FILES+=usr/share/examples/libusb20/README OLD_FILES+=usr/share/examples/libusb20/bulk.c OLD_FILES+=usr/share/examples/libusb20/control.c OLD_FILES+=usr/share/examples/libusb20/util.c OLD_FILES+=usr/share/examples/libusb20/util.h OLD_DIRS+=usr/share/examples/libusb20 OLD_FILES+=usr/share/man/man1/uhsoctl.1.gz OLD_FILES+=usr/share/man/man1/usbhidaction.1.gz OLD_FILES+=usr/share/man/man1/usbhidctl.1.gz OLD_FILES+=usr/share/man/man3/hid_dispose_report_desc.3.gz OLD_FILES+=usr/share/man/man3/hid_end_parse.3.gz OLD_FILES+=usr/share/man/man3/hid_get_data.3.gz OLD_FILES+=usr/share/man/man3/hid_get_item.3.gz OLD_FILES+=usr/share/man/man3/hid_get_report_desc.3.gz OLD_FILES+=usr/share/man/man3/hid_init.3.gz OLD_FILES+=usr/share/man/man3/hid_locate.3.gz OLD_FILES+=usr/share/man/man3/hid_report_size.3.gz OLD_FILES+=usr/share/man/man3/hid_set_data.3.gz OLD_FILES+=usr/share/man/man3/hid_start_parse.3.gz OLD_FILES+=usr/share/man/man3/hid_usage_in_page.3.gz OLD_FILES+=usr/share/man/man3/hid_usage_page.3.gz OLD_FILES+=usr/share/man/man3/libusb.3.gz OLD_FILES+=usr/share/man/man3/libusb20.3.gz OLD_FILES+=usr/share/man/man3/libusb20_be_add_dev_quirk.3.gz OLD_FILES+=usr/share/man/man3/libusb20_be_alloc_default.3.gz OLD_FILES+=usr/share/man/man3/libusb20_be_dequeue_device.3.gz OLD_FILES+=usr/share/man/man3/libusb20_be_device_foreach.3.gz OLD_FILES+=usr/share/man/man3/libusb20_be_enqueue_device.3.gz OLD_FILES+=usr/share/man/man3/libusb20_be_free.3.gz OLD_FILES+=usr/share/man/man3/libusb20_be_get_dev_quirk.3.gz OLD_FILES+=usr/share/man/man3/libusb20_be_get_quirk_name.3.gz OLD_FILES+=usr/share/man/man3/libusb20_be_get_template.3.gz OLD_FILES+=usr/share/man/man3/libusb20_be_remove_dev_quirk.3.gz OLD_FILES+=usr/share/man/man3/libusb20_be_set_template.3.gz OLD_FILES+=usr/share/man/man3/libusb20_desc_foreach.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_alloc.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_alloc_config.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_check_connected.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_close.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_detach_kernel_driver.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_free.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_address.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_backend_name.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_bus_number.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_config_index.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_debug.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_desc.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_device_desc.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_fd.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_iface_desc.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_info.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_mode.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_parent_address.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_parent_port.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_port_path.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_power_mode.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_power_usage.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_get_speed.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_kernel_driver_active.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_open.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_process.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_req_string_simple_sync.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_req_string_sync.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_request_sync.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_reset.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_set_alt_index.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_set_config_index.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_set_debug.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_set_power_mode.3.gz OLD_FILES+=usr/share/man/man3/libusb20_dev_wait_process.3.gz OLD_FILES+=usr/share/man/man3/libusb20_error_name.3.gz OLD_FILES+=usr/share/man/man3/libusb20_me_decode.3.gz OLD_FILES+=usr/share/man/man3/libusb20_me_encode.3.gz OLD_FILES+=usr/share/man/man3/libusb20_me_get_1.3.gz OLD_FILES+=usr/share/man/man3/libusb20_me_get_2.3.gz OLD_FILES+=usr/share/man/man3/libusb20_strerror.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_bulk_intr_sync.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_callback_wrapper.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_clear_stall_sync.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_close.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_drain.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_get_actual_frames.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_get_actual_length.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_get_length.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_get_max_frames.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_get_max_packet_length.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_get_max_total_length.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_get_pointer.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_get_priv_sc0.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_get_priv_sc1.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_get_status.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_get_time_complete.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_open.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_pending.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_set_buffer.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_set_callback.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_set_flags.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_set_length.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_set_priv_sc0.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_set_priv_sc1.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_set_timeout.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_set_total_frames.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_setup_bulk.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_setup_control.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_setup_intr.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_setup_isoc.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_start.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_stop.3.gz OLD_FILES+=usr/share/man/man3/libusb20_tr_submit.3.gz OLD_FILES+=usr/share/man/man3/libusb_alloc_transfer.3.gz OLD_FILES+=usr/share/man/man3/libusb_attach_kernel_driver.3.gz OLD_FILES+=usr/share/man/man3/libusb_bulk_transfer.3.gz OLD_FILES+=usr/share/man/man3/libusb_cancel_transfer.3.gz OLD_FILES+=usr/share/man/man3/libusb_check_connected.3.gz OLD_FILES+=usr/share/man/man3/libusb_claim_interface.3.gz OLD_FILES+=usr/share/man/man3/libusb_clear_halt.3.gz OLD_FILES+=usr/share/man/man3/libusb_close.3.gz OLD_FILES+=usr/share/man/man3/libusb_control_transfer.3.gz OLD_FILES+=usr/share/man/man3/libusb_detach_kernel_driver.3.gz OLD_FILES+=usr/share/man/man3/libusb_detach_kernel_driver_np.3.gz OLD_FILES+=usr/share/man/man3/libusb_error_name.3.gz OLD_FILES+=usr/share/man/man3/libusb_event_handler_active.3.gz OLD_FILES+=usr/share/man/man3/libusb_event_handling_ok.3.gz OLD_FILES+=usr/share/man/man3/libusb_exit.3.gz OLD_FILES+=usr/share/man/man3/libusb_free_bos_descriptor.3.gz OLD_FILES+=usr/share/man/man3/libusb_free_config_descriptor.3.gz OLD_FILES+=usr/share/man/man3/libusb_free_device_list.3.gz OLD_FILES+=usr/share/man/man3/libusb_free_ss_endpoint_comp.3.gz OLD_FILES+=usr/share/man/man3/libusb_free_transfer.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_active_config_descriptor.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_bus_number.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_config_descriptor.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_config_descriptor_by_value.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_configuration.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_device.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_device_address.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_device_descriptor.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_device_list.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_device_speed.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_driver.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_driver_np.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_max_iso_packet_size.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_max_packet_size.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_next_timeout.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_pollfds.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_string_descriptor.3.gz OLD_FILES+=usr/share/man/man3/libusb_get_string_descriptor_ascii.3.gz OLD_FILES+=usr/share/man/man3/libusb_handle_events.3.gz OLD_FILES+=usr/share/man/man3/libusb_handle_events_completed.3.gz OLD_FILES+=usr/share/man/man3/libusb_handle_events_locked.3.gz OLD_FILES+=usr/share/man/man3/libusb_handle_events_timeout.3.gz OLD_FILES+=usr/share/man/man3/libusb_handle_events_timeout_completed.3.gz OLD_FILES+=usr/share/man/man3/libusb_init.3.gz OLD_FILES+=usr/share/man/man3/libusb_interrupt_transfer.3.gz OLD_FILES+=usr/share/man/man3/libusb_kernel_driver_active.3.gz OLD_FILES+=usr/share/man/man3/libusb_lock_event_waiters.3.gz OLD_FILES+=usr/share/man/man3/libusb_lock_events.3.gz OLD_FILES+=usr/share/man/man3/libusb_open.3.gz OLD_FILES+=usr/share/man/man3/libusb_open_device_with_vid_pid.3.gz OLD_FILES+=usr/share/man/man3/libusb_parse_bos_descriptor.3.gz OLD_FILES+=usr/share/man/man3/libusb_parse_ss_endpoint_comp.3.gz OLD_FILES+=usr/share/man/man3/libusb_ref_device.3.gz OLD_FILES+=usr/share/man/man3/libusb_release_interface.3.gz OLD_FILES+=usr/share/man/man3/libusb_reset_device.3.gz OLD_FILES+=usr/share/man/man3/libusb_set_configuration.3.gz OLD_FILES+=usr/share/man/man3/libusb_set_debug.3.gz OLD_FILES+=usr/share/man/man3/libusb_set_interface_alt_setting.3.gz OLD_FILES+=usr/share/man/man3/libusb_set_pollfd_notifiers.3.gz OLD_FILES+=usr/share/man/man3/libusb_strerror.3.gz OLD_FILES+=usr/share/man/man3/libusb_submit_transfer.3.gz OLD_FILES+=usr/share/man/man3/libusb_try_lock_events.3.gz OLD_FILES+=usr/share/man/man3/libusb_unlock_event_waiters.3.gz OLD_FILES+=usr/share/man/man3/libusb_unlock_events.3.gz OLD_FILES+=usr/share/man/man3/libusb_unref_device.3.gz OLD_FILES+=usr/share/man/man3/libusb_wait_for_event.3.gz OLD_FILES+=usr/share/man/man3/libusbhid.3.gz OLD_FILES+=usr/share/man/man3/usb.3.gz OLD_FILES+=usr/share/man/man3/usb_bulk_read.3.gz OLD_FILES+=usr/share/man/man3/usb_bulk_write.3.gz OLD_FILES+=usr/share/man/man3/usb_check_connected.3.gz OLD_FILES+=usr/share/man/man3/usb_claim_interface.3.gz OLD_FILES+=usr/share/man/man3/usb_clear_halt.3.gz OLD_FILES+=usr/share/man/man3/usb_close.3.gz OLD_FILES+=usr/share/man/man3/usb_control_msg.3.gz OLD_FILES+=usr/share/man/man3/usb_destroy_configuration.3.gz OLD_FILES+=usr/share/man/man3/usb_device.3.gz OLD_FILES+=usr/share/man/man3/usb_fetch_and_parse_descriptors.3.gz OLD_FILES+=usr/share/man/man3/usb_find_busses.3.gz OLD_FILES+=usr/share/man/man3/usb_find_devices.3.gz OLD_FILES+=usr/share/man/man3/usb_get_busses.3.gz OLD_FILES+=usr/share/man/man3/usb_get_descriptor.3.gz OLD_FILES+=usr/share/man/man3/usb_get_descriptor_by_endpoint.3.gz OLD_FILES+=usr/share/man/man3/usb_get_string.3.gz OLD_FILES+=usr/share/man/man3/usb_get_string_simple.3.gz OLD_FILES+=usr/share/man/man3/usb_init.3.gz OLD_FILES+=usr/share/man/man3/usb_interrupt_read.3.gz OLD_FILES+=usr/share/man/man3/usb_interrupt_write.3.gz OLD_FILES+=usr/share/man/man3/usb_open.3.gz OLD_FILES+=usr/share/man/man3/usb_parse_configuration.3.gz OLD_FILES+=usr/share/man/man3/usb_parse_descriptor.3.gz OLD_FILES+=usr/share/man/man3/usb_release_interface.3.gz OLD_FILES+=usr/share/man/man3/usb_reset.3.gz OLD_FILES+=usr/share/man/man3/usb_resetep.3.gz OLD_FILES+=usr/share/man/man3/usb_set_altinterface.3.gz OLD_FILES+=usr/share/man/man3/usb_set_configuration.3.gz OLD_FILES+=usr/share/man/man3/usb_set_debug.3.gz OLD_FILES+=usr/share/man/man3/usb_strerror.3.gz OLD_FILES+=usr/share/man/man3/usbhid.3.gz OLD_FILES+=usr/share/man/man4/u3g.4.gz OLD_FILES+=usr/share/man/man4/u3gstub.4.gz OLD_FILES+=usr/share/man/man4/uark.4.gz OLD_FILES+=usr/share/man/man4/uart.4.gz OLD_FILES+=usr/share/man/man4/uath.4.gz OLD_FILES+=usr/share/man/man4/ubsa.4.gz OLD_FILES+=usr/share/man/man4/ubsec.4.gz OLD_FILES+=usr/share/man/man4/ubser.4.gz OLD_FILES+=usr/share/man/man4/ubtbcmfw.4.gz OLD_FILES+=usr/share/man/man4/uchcom.4.gz OLD_FILES+=usr/share/man/man4/ucom.4.gz OLD_FILES+=usr/share/man/man4/ucycom.4.gz OLD_FILES+=usr/share/man/man4/udav.4.gz OLD_FILES+=usr/share/man/man4/udbp.4.gz OLD_FILES+=usr/share/man/man4/udp.4.gz OLD_FILES+=usr/share/man/man4/udplite.4.gz OLD_FILES+=usr/share/man/man4/uep.4.gz OLD_FILES+=usr/share/man/man4/ufm.4.gz OLD_FILES+=usr/share/man/man4/ufoma.4.gz OLD_FILES+=usr/share/man/man4/uftdi.4.gz OLD_FILES+=usr/share/man/man4/ugen.4.gz OLD_FILES+=usr/share/man/man4/uhci.4.gz OLD_FILES+=usr/share/man/man4/uhid.4.gz OLD_FILES+=usr/share/man/man4/uhso.4.gz OLD_FILES+=usr/share/man/man4/uipaq.4.gz OLD_FILES+=usr/share/man/man4/ukbd.4.gz OLD_FILES+=usr/share/man/man4/uled.4.gz OLD_FILES+=usr/share/man/man4/ulpt.4.gz OLD_FILES+=usr/share/man/man4/umass.4.gz OLD_FILES+=usr/share/man/man4/umcs.4.gz OLD_FILES+=usr/share/man/man4/umct.4.gz OLD_FILES+=usr/share/man/man4/umodem.4.gz OLD_FILES+=usr/share/man/man4/umoscom.4.gz OLD_FILES+=usr/share/man/man4/ums.4.gz OLD_FILES+=usr/share/man/man4/unix.4.gz OLD_FILES+=usr/share/man/man4/upgt.4.gz OLD_FILES+=usr/share/man/man4/uplcom.4.gz OLD_FILES+=usr/share/man/man4/ural.4.gz OLD_FILES+=usr/share/man/man4/urio.4.gz OLD_FILES+=usr/share/man/man4/urndis.4.gz OLD_FILES+=usr/share/man/man4/urtw.4.gz OLD_FILES+=usr/share/man/man4/urtwn.4.gz OLD_FILES+=usr/share/man/man4/urtwnfw.4.gz OLD_FILES+=usr/share/man/man4/usb.4.gz OLD_FILES+=usr/share/man/man4/usb_quirk.4.gz OLD_FILES+=usr/share/man/man4/usb_template.4.gz OLD_FILES+=usr/share/man/man4/usfs.4.gz OLD_FILES+=usr/share/man/man4/uslcom.4.gz OLD_FILES+=usr/share/man/man4/utopia.4.gz OLD_FILES+=usr/share/man/man4/uvisor.4.gz OLD_FILES+=usr/share/man/man4/uvscom.4.gz OLD_FILES+=usr/share/man/man8/uathload.8.gz OLD_FILES+=usr/share/man/man8/usbconfig.8.gz OLD_FILES+=usr/share/man/man8/usbdump.8.gz OLD_FILES+=usr/share/man/man9/usb_fifo_alloc_buffer.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_attach.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_detach.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_free_buffer.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_get_data.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_get_data_buffer.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_get_data_error.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_get_data_linear.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_put_bytes_max.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_put_data.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_put_data_buffer.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_put_data_error.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_put_data_linear.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_reset.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_softc.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_wakeup.9.gz OLD_FILES+=usr/share/man/man9/usbd_do_request.9.gz OLD_FILES+=usr/share/man/man9/usbd_do_request_flags.9.gz OLD_FILES+=usr/share/man/man9/usbd_errstr.9.gz OLD_FILES+=usr/share/man/man9/usbd_lookup_id_by_info.9.gz OLD_FILES+=usr/share/man/man9/usbd_lookup_id_by_uaa.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_clear_stall.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_drain.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_pending.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_poll.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_setup.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_start.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_stop.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_submit.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_unsetup.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_clr_flag.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_frame_data.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_frame_len.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_get_frame.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_get_priv.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_is_stalled.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_max_framelen.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_max_frames.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_max_len.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_flag.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_frame_data.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_frame_len.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_frame_offset.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_frames.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_interval.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_priv.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_stall.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_timeout.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_softc.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_state.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_status.9.gz OLD_FILES+=usr/share/man/man9/usbdi.9.gz OLD_FILES+=usr/share/misc/usb_hid_usages OLD_FILES+=usr/share/misc/usbdevs .endif .if ${MK_UTMPX} == no OLD_FILES+=etc/periodic/monthly/200.accounting OLD_FILES+=usr/bin/last OLD_FILES+=usr/bin/users OLD_FILES+=usr/bin/who OLD_FILES+=usr/sbin/ac OLD_FILES+=usr/sbin/lastlogin OLD_FILES+=usr/sbin/utx OLD_FILES+=usr/share/man/man1/last.1.gz OLD_FILES+=usr/share/man/man1/users.1.gz OLD_FILES+=usr/share/man/man1/who.1.gz OLD_FILES+=usr/share/man/man8/ac.8.gz OLD_FILES+=usr/share/man/man8/lastlogin.8.gz OLD_FILES+=usr/share/man/man8/utx.8.gz .endif .if ${MK_WIRELESS} == no OLD_FILES+=etc/regdomain.xml OLD_FILES+=etc/rc.d/hostapd OLD_FILES+=etc/rc.d/wpa_supplicant OLD_FILES+=usr/sbin/ancontrol OLD_FILES+=usr/sbin/hostapd OLD_FILES+=usr/sbin/hostapd_cli OLD_FILES+=usr/sbin/ndis_events OLD_FILES+=usr/sbin/wlandebug .if ${TARGET_ARCH} == "i386" OLD_FILES+=usr/sbin/wlconfig .endif OLD_FILES+=usr/sbin/wpa_cli OLD_FILES+=usr/sbin/wpa_passphrase OLD_FILES+=usr/sbin/wpa_supplicant OLD_FILES+=usr/share/examples/etc/regdomain.xml OLD_FILES+=usr/share/examples/etc/wpa_supplicant.conf OLD_FILES+=usr/share/examples/hostapd/hostapd.conf OLD_FILES+=usr/share/examples/hostapd/hostapd.eap_user OLD_FILES+=usr/share/examples/hostapd/hostapd.wpa_psk OLD_DIRS+=usr/share/examples/hostapd OLD_FILES+=usr/share/man/man5/hostapd.conf.5.gz OLD_FILES+=usr/share/man/man5/wpa_supplicant.conf.5.gz OLD_FILES+=usr/share/man/man8/ancontrol.8.gz OLD_FILES+=usr/share/man/man8/hostapd.8.gz OLD_FILES+=usr/share/man/man8/hostapd_cli.8.gz .if ${TARGET_ARCH} == "i386" OLD_FILES+=usr/share/man/man8/i386/wlconfig.8.gz .endif OLD_FILES+=usr/share/man/man8/ndis_events.8.gz OLD_FILES+=usr/share/man/man8/wlandebug.8.gz OLD_FILES+=usr/share/man/man8/wpa_cli.8.gz OLD_FILES+=usr/share/man/man8/wpa_passphrase.8.gz OLD_FILES+=usr/share/man/man8/wpa_supplicant.8.gz .endif .if ${MK_SVNLITE} == no || ${MK_SVN} == yes OLD_FILES+=usr/bin/svnlite OLD_FILES+=usr/bin/svnliteadmin OLD_FILES+=usr/bin/svnlitedumpfilter OLD_FILES+=usr/bin/svnlitelook OLD_FILES+=usr/bin/svnlitemucc OLD_FILES+=usr/bin/svnliterdump OLD_FILES+=usr/bin/svnliteserve OLD_FILES+=usr/bin/svnlitesync OLD_FILES+=usr/bin/svnliteversion OLD_FILES+=usr/share/man/man1/svnlite.1.gz .endif .if ${MK_SVN} == no OLD_FILES+=usr/bin/svn OLD_FILES+=usr/bin/svnadmin OLD_FILES+=usr/bin/svndumpfilter OLD_FILES+=usr/bin/svnlook OLD_FILES+=usr/bin/svnmucc OLD_FILES+=usr/bin/svnrdump OLD_FILES+=usr/bin/svnserve OLD_FILES+=usr/bin/svnsync OLD_FILES+=usr/bin/svnversion .endif .if ${MK_HYPERV} == no OLD_FILES+=etc/devd/hyperv.conf OLD_FILES+=usr/libexec/hyperv/hv_set_ifconfig OLD_FILES+=usr/libexec/hyperv/hv_get_dns_info OLD_FILES+=usr/libexec/hyperv/hv_get_dhcp_info OLD_FILES+=usr/sbin/hv_kvp_daemon OLD_FILES+=usr/share/man/man8/hv_kvp_daemon.8.gz .endif .if ${MK_ZONEINFO} == no OLD_FILES+=usr/share/zoneinfo/Africa/Abidjan OLD_FILES+=usr/share/zoneinfo/Africa/Accra OLD_FILES+=usr/share/zoneinfo/Africa/Addis_Ababa OLD_FILES+=usr/share/zoneinfo/Africa/Algiers OLD_FILES+=usr/share/zoneinfo/Africa/Asmara OLD_FILES+=usr/share/zoneinfo/Africa/Bamako OLD_FILES+=usr/share/zoneinfo/Africa/Bangui OLD_FILES+=usr/share/zoneinfo/Africa/Banjul OLD_FILES+=usr/share/zoneinfo/Africa/Bissau OLD_FILES+=usr/share/zoneinfo/Africa/Blantyre OLD_FILES+=usr/share/zoneinfo/Africa/Brazzaville OLD_FILES+=usr/share/zoneinfo/Africa/Bujumbura OLD_FILES+=usr/share/zoneinfo/Africa/Cairo OLD_FILES+=usr/share/zoneinfo/Africa/Casablanca OLD_FILES+=usr/share/zoneinfo/Africa/Ceuta OLD_FILES+=usr/share/zoneinfo/Africa/Conakry OLD_FILES+=usr/share/zoneinfo/Africa/Dakar OLD_FILES+=usr/share/zoneinfo/Africa/Dar_es_Salaam OLD_FILES+=usr/share/zoneinfo/Africa/Djibouti OLD_FILES+=usr/share/zoneinfo/Africa/Douala OLD_FILES+=usr/share/zoneinfo/Africa/El_Aaiun OLD_FILES+=usr/share/zoneinfo/Africa/Freetown OLD_FILES+=usr/share/zoneinfo/Africa/Gaborone OLD_FILES+=usr/share/zoneinfo/Africa/Harare OLD_FILES+=usr/share/zoneinfo/Africa/Johannesburg OLD_FILES+=usr/share/zoneinfo/Africa/Juba OLD_FILES+=usr/share/zoneinfo/Africa/Kampala OLD_FILES+=usr/share/zoneinfo/Africa/Khartoum OLD_FILES+=usr/share/zoneinfo/Africa/Kigali OLD_FILES+=usr/share/zoneinfo/Africa/Kinshasa OLD_FILES+=usr/share/zoneinfo/Africa/Lagos OLD_FILES+=usr/share/zoneinfo/Africa/Libreville OLD_FILES+=usr/share/zoneinfo/Africa/Lome OLD_FILES+=usr/share/zoneinfo/Africa/Luanda OLD_FILES+=usr/share/zoneinfo/Africa/Lubumbashi OLD_FILES+=usr/share/zoneinfo/Africa/Lusaka OLD_FILES+=usr/share/zoneinfo/Africa/Malabo OLD_FILES+=usr/share/zoneinfo/Africa/Maputo OLD_FILES+=usr/share/zoneinfo/Africa/Maseru OLD_FILES+=usr/share/zoneinfo/Africa/Mbabane OLD_FILES+=usr/share/zoneinfo/Africa/Mogadishu OLD_FILES+=usr/share/zoneinfo/Africa/Monrovia OLD_FILES+=usr/share/zoneinfo/Africa/Nairobi OLD_FILES+=usr/share/zoneinfo/Africa/Ndjamena OLD_FILES+=usr/share/zoneinfo/Africa/Niamey OLD_FILES+=usr/share/zoneinfo/Africa/Nouakchott OLD_FILES+=usr/share/zoneinfo/Africa/Ouagadougou OLD_FILES+=usr/share/zoneinfo/Africa/Porto-Novo OLD_FILES+=usr/share/zoneinfo/Africa/Sao_Tome OLD_FILES+=usr/share/zoneinfo/Africa/Tripoli OLD_FILES+=usr/share/zoneinfo/Africa/Tunis OLD_FILES+=usr/share/zoneinfo/Africa/Windhoek OLD_FILES+=usr/share/zoneinfo/America/Adak OLD_FILES+=usr/share/zoneinfo/America/Anchorage OLD_FILES+=usr/share/zoneinfo/America/Anguilla OLD_FILES+=usr/share/zoneinfo/America/Antigua OLD_FILES+=usr/share/zoneinfo/America/Araguaina OLD_FILES+=usr/share/zoneinfo/America/Argentina/Buenos_Aires OLD_FILES+=usr/share/zoneinfo/America/Argentina/Catamarca OLD_FILES+=usr/share/zoneinfo/America/Argentina/Cordoba OLD_FILES+=usr/share/zoneinfo/America/Argentina/Jujuy OLD_FILES+=usr/share/zoneinfo/America/Argentina/La_Rioja OLD_FILES+=usr/share/zoneinfo/America/Argentina/Mendoza OLD_FILES+=usr/share/zoneinfo/America/Argentina/Rio_Gallegos OLD_FILES+=usr/share/zoneinfo/America/Argentina/Salta OLD_FILES+=usr/share/zoneinfo/America/Argentina/San_Juan OLD_FILES+=usr/share/zoneinfo/America/Argentina/San_Luis OLD_FILES+=usr/share/zoneinfo/America/Argentina/Tucuman OLD_FILES+=usr/share/zoneinfo/America/Argentina/Ushuaia OLD_FILES+=usr/share/zoneinfo/America/Aruba OLD_FILES+=usr/share/zoneinfo/America/Asuncion OLD_FILES+=usr/share/zoneinfo/America/Atikokan OLD_FILES+=usr/share/zoneinfo/America/Bahia OLD_FILES+=usr/share/zoneinfo/America/Bahia_Banderas OLD_FILES+=usr/share/zoneinfo/America/Barbados OLD_FILES+=usr/share/zoneinfo/America/Belem OLD_FILES+=usr/share/zoneinfo/America/Belize OLD_FILES+=usr/share/zoneinfo/America/Blanc-Sablon OLD_FILES+=usr/share/zoneinfo/America/Boa_Vista OLD_FILES+=usr/share/zoneinfo/America/Bogota OLD_FILES+=usr/share/zoneinfo/America/Boise OLD_FILES+=usr/share/zoneinfo/America/Cambridge_Bay OLD_FILES+=usr/share/zoneinfo/America/Campo_Grande OLD_FILES+=usr/share/zoneinfo/America/Cancun OLD_FILES+=usr/share/zoneinfo/America/Caracas OLD_FILES+=usr/share/zoneinfo/America/Cayenne OLD_FILES+=usr/share/zoneinfo/America/Cayman OLD_FILES+=usr/share/zoneinfo/America/Chicago OLD_FILES+=usr/share/zoneinfo/America/Chihuahua OLD_FILES+=usr/share/zoneinfo/America/Costa_Rica OLD_FILES+=usr/share/zoneinfo/America/Creston OLD_FILES+=usr/share/zoneinfo/America/Cuiaba OLD_FILES+=usr/share/zoneinfo/America/Curacao OLD_FILES+=usr/share/zoneinfo/America/Danmarkshavn OLD_FILES+=usr/share/zoneinfo/America/Dawson OLD_FILES+=usr/share/zoneinfo/America/Dawson_Creek OLD_FILES+=usr/share/zoneinfo/America/Denver OLD_FILES+=usr/share/zoneinfo/America/Detroit OLD_FILES+=usr/share/zoneinfo/America/Dominica OLD_FILES+=usr/share/zoneinfo/America/Edmonton OLD_FILES+=usr/share/zoneinfo/America/Eirunepe OLD_FILES+=usr/share/zoneinfo/America/El_Salvador OLD_FILES+=usr/share/zoneinfo/America/Fortaleza OLD_FILES+=usr/share/zoneinfo/America/Glace_Bay OLD_FILES+=usr/share/zoneinfo/America/Godthab OLD_FILES+=usr/share/zoneinfo/America/Goose_Bay OLD_FILES+=usr/share/zoneinfo/America/Grand_Turk OLD_FILES+=usr/share/zoneinfo/America/Grenada OLD_FILES+=usr/share/zoneinfo/America/Guadeloupe OLD_FILES+=usr/share/zoneinfo/America/Guatemala OLD_FILES+=usr/share/zoneinfo/America/Guayaquil OLD_FILES+=usr/share/zoneinfo/America/Guyana OLD_FILES+=usr/share/zoneinfo/America/Halifax OLD_FILES+=usr/share/zoneinfo/America/Havana OLD_FILES+=usr/share/zoneinfo/America/Hermosillo OLD_FILES+=usr/share/zoneinfo/America/Indiana/Indianapolis OLD_FILES+=usr/share/zoneinfo/America/Indiana/Knox OLD_FILES+=usr/share/zoneinfo/America/Indiana/Marengo OLD_FILES+=usr/share/zoneinfo/America/Indiana/Petersburg OLD_FILES+=usr/share/zoneinfo/America/Indiana/Tell_City OLD_FILES+=usr/share/zoneinfo/America/Indiana/Vevay OLD_FILES+=usr/share/zoneinfo/America/Indiana/Vincennes OLD_FILES+=usr/share/zoneinfo/America/Indiana/Winamac OLD_FILES+=usr/share/zoneinfo/America/Inuvik OLD_FILES+=usr/share/zoneinfo/America/Iqaluit OLD_FILES+=usr/share/zoneinfo/America/Jamaica OLD_FILES+=usr/share/zoneinfo/America/Juneau OLD_FILES+=usr/share/zoneinfo/America/Kentucky/Louisville OLD_FILES+=usr/share/zoneinfo/America/Kentucky/Monticello OLD_FILES+=usr/share/zoneinfo/America/Kralendijk OLD_FILES+=usr/share/zoneinfo/America/La_Paz OLD_FILES+=usr/share/zoneinfo/America/Lima OLD_FILES+=usr/share/zoneinfo/America/Los_Angeles OLD_FILES+=usr/share/zoneinfo/America/Lower_Princes OLD_FILES+=usr/share/zoneinfo/America/Maceio OLD_FILES+=usr/share/zoneinfo/America/Managua OLD_FILES+=usr/share/zoneinfo/America/Manaus OLD_FILES+=usr/share/zoneinfo/America/Marigot OLD_FILES+=usr/share/zoneinfo/America/Martinique OLD_FILES+=usr/share/zoneinfo/America/Matamoros OLD_FILES+=usr/share/zoneinfo/America/Mazatlan OLD_FILES+=usr/share/zoneinfo/America/Menominee OLD_FILES+=usr/share/zoneinfo/America/Merida OLD_FILES+=usr/share/zoneinfo/America/Metlakatla OLD_FILES+=usr/share/zoneinfo/America/Mexico_City OLD_FILES+=usr/share/zoneinfo/America/Miquelon OLD_FILES+=usr/share/zoneinfo/America/Moncton OLD_FILES+=usr/share/zoneinfo/America/Monterrey OLD_FILES+=usr/share/zoneinfo/America/Montevideo OLD_FILES+=usr/share/zoneinfo/America/Montreal OLD_FILES+=usr/share/zoneinfo/America/Montserrat OLD_FILES+=usr/share/zoneinfo/America/Nassau OLD_FILES+=usr/share/zoneinfo/America/New_York OLD_FILES+=usr/share/zoneinfo/America/Nipigon OLD_FILES+=usr/share/zoneinfo/America/Nome OLD_FILES+=usr/share/zoneinfo/America/Noronha OLD_FILES+=usr/share/zoneinfo/America/North_Dakota/Beulah OLD_FILES+=usr/share/zoneinfo/America/North_Dakota/Center OLD_FILES+=usr/share/zoneinfo/America/North_Dakota/New_Salem OLD_FILES+=usr/share/zoneinfo/America/Ojinaga OLD_FILES+=usr/share/zoneinfo/America/Panama OLD_FILES+=usr/share/zoneinfo/America/Pangnirtung OLD_FILES+=usr/share/zoneinfo/America/Paramaribo OLD_FILES+=usr/share/zoneinfo/America/Phoenix OLD_FILES+=usr/share/zoneinfo/America/Port-au-Prince OLD_FILES+=usr/share/zoneinfo/America/Port_of_Spain OLD_FILES+=usr/share/zoneinfo/America/Porto_Velho OLD_FILES+=usr/share/zoneinfo/America/Puerto_Rico OLD_FILES+=usr/share/zoneinfo/America/Rainy_River OLD_FILES+=usr/share/zoneinfo/America/Rankin_Inlet OLD_FILES+=usr/share/zoneinfo/America/Recife OLD_FILES+=usr/share/zoneinfo/America/Regina OLD_FILES+=usr/share/zoneinfo/America/Resolute OLD_FILES+=usr/share/zoneinfo/America/Rio_Branco OLD_FILES+=usr/share/zoneinfo/America/Santa_Isabel OLD_FILES+=usr/share/zoneinfo/America/Santarem OLD_FILES+=usr/share/zoneinfo/America/Santiago OLD_FILES+=usr/share/zoneinfo/America/Santo_Domingo OLD_FILES+=usr/share/zoneinfo/America/Sao_Paulo OLD_FILES+=usr/share/zoneinfo/America/Scoresbysund OLD_FILES+=usr/share/zoneinfo/America/Sitka OLD_FILES+=usr/share/zoneinfo/America/St_Barthelemy OLD_FILES+=usr/share/zoneinfo/America/St_Johns OLD_FILES+=usr/share/zoneinfo/America/St_Kitts OLD_FILES+=usr/share/zoneinfo/America/St_Lucia OLD_FILES+=usr/share/zoneinfo/America/St_Thomas OLD_FILES+=usr/share/zoneinfo/America/St_Vincent OLD_FILES+=usr/share/zoneinfo/America/Swift_Current OLD_FILES+=usr/share/zoneinfo/America/Tegucigalpa OLD_FILES+=usr/share/zoneinfo/America/Thule OLD_FILES+=usr/share/zoneinfo/America/Thunder_Bay OLD_FILES+=usr/share/zoneinfo/America/Tijuana OLD_FILES+=usr/share/zoneinfo/America/Toronto OLD_FILES+=usr/share/zoneinfo/America/Tortola OLD_FILES+=usr/share/zoneinfo/America/Vancouver OLD_FILES+=usr/share/zoneinfo/America/Whitehorse OLD_FILES+=usr/share/zoneinfo/America/Winnipeg OLD_FILES+=usr/share/zoneinfo/America/Yakutat OLD_FILES+=usr/share/zoneinfo/America/Yellowknife OLD_FILES+=usr/share/zoneinfo/Antarctica/Casey OLD_FILES+=usr/share/zoneinfo/Antarctica/Davis OLD_FILES+=usr/share/zoneinfo/Antarctica/DumontDUrville OLD_FILES+=usr/share/zoneinfo/Antarctica/Macquarie OLD_FILES+=usr/share/zoneinfo/Antarctica/Mawson OLD_FILES+=usr/share/zoneinfo/Antarctica/McMurdo OLD_FILES+=usr/share/zoneinfo/Antarctica/Palmer OLD_FILES+=usr/share/zoneinfo/Antarctica/Rothera OLD_FILES+=usr/share/zoneinfo/Antarctica/Syowa OLD_FILES+=usr/share/zoneinfo/Antarctica/Troll OLD_FILES+=usr/share/zoneinfo/Antarctica/Vostok OLD_FILES+=usr/share/zoneinfo/Arctic/Longyearbyen OLD_FILES+=usr/share/zoneinfo/Asia/Aden OLD_FILES+=usr/share/zoneinfo/Asia/Almaty OLD_FILES+=usr/share/zoneinfo/Asia/Amman OLD_FILES+=usr/share/zoneinfo/Asia/Anadyr OLD_FILES+=usr/share/zoneinfo/Asia/Aqtau OLD_FILES+=usr/share/zoneinfo/Asia/Aqtobe OLD_FILES+=usr/share/zoneinfo/Asia/Ashgabat OLD_FILES+=usr/share/zoneinfo/Asia/Baghdad OLD_FILES+=usr/share/zoneinfo/Asia/Bahrain OLD_FILES+=usr/share/zoneinfo/Asia/Baku OLD_FILES+=usr/share/zoneinfo/Asia/Bangkok OLD_FILES+=usr/share/zoneinfo/Asia/Beirut OLD_FILES+=usr/share/zoneinfo/Asia/Bishkek OLD_FILES+=usr/share/zoneinfo/Asia/Brunei OLD_FILES+=usr/share/zoneinfo/Asia/Chita OLD_FILES+=usr/share/zoneinfo/Asia/Choibalsan OLD_FILES+=usr/share/zoneinfo/Asia/Colombo OLD_FILES+=usr/share/zoneinfo/Asia/Damascus OLD_FILES+=usr/share/zoneinfo/Asia/Dhaka OLD_FILES+=usr/share/zoneinfo/Asia/Dili OLD_FILES+=usr/share/zoneinfo/Asia/Dubai OLD_FILES+=usr/share/zoneinfo/Asia/Dushanbe OLD_FILES+=usr/share/zoneinfo/Asia/Gaza OLD_FILES+=usr/share/zoneinfo/Asia/Hebron OLD_FILES+=usr/share/zoneinfo/Asia/Ho_Chi_Minh OLD_FILES+=usr/share/zoneinfo/Asia/Hong_Kong OLD_FILES+=usr/share/zoneinfo/Asia/Hovd OLD_FILES+=usr/share/zoneinfo/Asia/Irkutsk OLD_FILES+=usr/share/zoneinfo/Asia/Istanbul OLD_FILES+=usr/share/zoneinfo/Asia/Jakarta OLD_FILES+=usr/share/zoneinfo/Asia/Jayapura OLD_FILES+=usr/share/zoneinfo/Asia/Jerusalem OLD_FILES+=usr/share/zoneinfo/Asia/Kabul OLD_FILES+=usr/share/zoneinfo/Asia/Kamchatka OLD_FILES+=usr/share/zoneinfo/Asia/Karachi OLD_FILES+=usr/share/zoneinfo/Asia/Kathmandu OLD_FILES+=usr/share/zoneinfo/Asia/Khandyga OLD_FILES+=usr/share/zoneinfo/Asia/Kolkata OLD_FILES+=usr/share/zoneinfo/Asia/Krasnoyarsk OLD_FILES+=usr/share/zoneinfo/Asia/Kuala_Lumpur OLD_FILES+=usr/share/zoneinfo/Asia/Kuching OLD_FILES+=usr/share/zoneinfo/Asia/Kuwait OLD_FILES+=usr/share/zoneinfo/Asia/Macau OLD_FILES+=usr/share/zoneinfo/Asia/Magadan OLD_FILES+=usr/share/zoneinfo/Asia/Makassar OLD_FILES+=usr/share/zoneinfo/Asia/Manila OLD_FILES+=usr/share/zoneinfo/Asia/Muscat OLD_FILES+=usr/share/zoneinfo/Asia/Nicosia OLD_FILES+=usr/share/zoneinfo/Asia/Novokuznetsk OLD_FILES+=usr/share/zoneinfo/Asia/Novosibirsk OLD_FILES+=usr/share/zoneinfo/Asia/Omsk OLD_FILES+=usr/share/zoneinfo/Asia/Oral OLD_FILES+=usr/share/zoneinfo/Asia/Phnom_Penh OLD_FILES+=usr/share/zoneinfo/Asia/Pontianak OLD_FILES+=usr/share/zoneinfo/Asia/Pyongyang OLD_FILES+=usr/share/zoneinfo/Asia/Qatar OLD_FILES+=usr/share/zoneinfo/Asia/Qyzylorda OLD_FILES+=usr/share/zoneinfo/Asia/Rangoon OLD_FILES+=usr/share/zoneinfo/Asia/Riyadh OLD_FILES+=usr/share/zoneinfo/Asia/Sakhalin OLD_FILES+=usr/share/zoneinfo/Asia/Samarkand OLD_FILES+=usr/share/zoneinfo/Asia/Seoul OLD_FILES+=usr/share/zoneinfo/Asia/Shanghai OLD_FILES+=usr/share/zoneinfo/Asia/Singapore OLD_FILES+=usr/share/zoneinfo/Asia/Srednekolymsk OLD_FILES+=usr/share/zoneinfo/Asia/Taipei OLD_FILES+=usr/share/zoneinfo/Asia/Tashkent OLD_FILES+=usr/share/zoneinfo/Asia/Tbilisi OLD_FILES+=usr/share/zoneinfo/Asia/Tehran OLD_FILES+=usr/share/zoneinfo/Asia/Thimphu OLD_FILES+=usr/share/zoneinfo/Asia/Tokyo OLD_FILES+=usr/share/zoneinfo/Asia/Ulaanbaatar OLD_FILES+=usr/share/zoneinfo/Asia/Urumqi OLD_FILES+=usr/share/zoneinfo/Asia/Ust-Nera OLD_FILES+=usr/share/zoneinfo/Asia/Vientiane OLD_FILES+=usr/share/zoneinfo/Asia/Vladivostok OLD_FILES+=usr/share/zoneinfo/Asia/Yakutsk OLD_FILES+=usr/share/zoneinfo/Asia/Yekaterinburg OLD_FILES+=usr/share/zoneinfo/Asia/Yerevan OLD_FILES+=usr/share/zoneinfo/Atlantic/Azores OLD_FILES+=usr/share/zoneinfo/Atlantic/Bermuda OLD_FILES+=usr/share/zoneinfo/Atlantic/Canary OLD_FILES+=usr/share/zoneinfo/Atlantic/Cape_Verde OLD_FILES+=usr/share/zoneinfo/Atlantic/Faroe OLD_FILES+=usr/share/zoneinfo/Atlantic/Madeira OLD_FILES+=usr/share/zoneinfo/Atlantic/Reykjavik OLD_FILES+=usr/share/zoneinfo/Atlantic/South_Georgia OLD_FILES+=usr/share/zoneinfo/Atlantic/St_Helena OLD_FILES+=usr/share/zoneinfo/Atlantic/Stanley OLD_FILES+=usr/share/zoneinfo/Australia/Adelaide OLD_FILES+=usr/share/zoneinfo/Australia/Brisbane OLD_FILES+=usr/share/zoneinfo/Australia/Broken_Hill OLD_FILES+=usr/share/zoneinfo/Australia/Currie OLD_FILES+=usr/share/zoneinfo/Australia/Darwin OLD_FILES+=usr/share/zoneinfo/Australia/Eucla OLD_FILES+=usr/share/zoneinfo/Australia/Hobart OLD_FILES+=usr/share/zoneinfo/Australia/Lindeman OLD_FILES+=usr/share/zoneinfo/Australia/Lord_Howe OLD_FILES+=usr/share/zoneinfo/Australia/Melbourne OLD_FILES+=usr/share/zoneinfo/Australia/Perth OLD_FILES+=usr/share/zoneinfo/Australia/Sydney OLD_FILES+=usr/share/zoneinfo/CET OLD_FILES+=usr/share/zoneinfo/CST6CDT OLD_FILES+=usr/share/zoneinfo/EET OLD_FILES+=usr/share/zoneinfo/EST OLD_FILES+=usr/share/zoneinfo/EST5EDT OLD_FILES+=usr/share/zoneinfo/Etc/GMT OLD_FILES+=usr/share/zoneinfo/Etc/GMT+0 OLD_FILES+=usr/share/zoneinfo/Etc/GMT+1 OLD_FILES+=usr/share/zoneinfo/Etc/GMT+10 OLD_FILES+=usr/share/zoneinfo/Etc/GMT+11 OLD_FILES+=usr/share/zoneinfo/Etc/GMT+12 OLD_FILES+=usr/share/zoneinfo/Etc/GMT+2 OLD_FILES+=usr/share/zoneinfo/Etc/GMT+3 OLD_FILES+=usr/share/zoneinfo/Etc/GMT+4 OLD_FILES+=usr/share/zoneinfo/Etc/GMT+5 OLD_FILES+=usr/share/zoneinfo/Etc/GMT+6 OLD_FILES+=usr/share/zoneinfo/Etc/GMT+7 OLD_FILES+=usr/share/zoneinfo/Etc/GMT+8 OLD_FILES+=usr/share/zoneinfo/Etc/GMT+9 OLD_FILES+=usr/share/zoneinfo/Etc/GMT-0 OLD_FILES+=usr/share/zoneinfo/Etc/GMT-1 OLD_FILES+=usr/share/zoneinfo/Etc/GMT-10 OLD_FILES+=usr/share/zoneinfo/Etc/GMT-11 OLD_FILES+=usr/share/zoneinfo/Etc/GMT-12 OLD_FILES+=usr/share/zoneinfo/Etc/GMT-13 OLD_FILES+=usr/share/zoneinfo/Etc/GMT-14 OLD_FILES+=usr/share/zoneinfo/Etc/GMT-2 OLD_FILES+=usr/share/zoneinfo/Etc/GMT-3 OLD_FILES+=usr/share/zoneinfo/Etc/GMT-4 OLD_FILES+=usr/share/zoneinfo/Etc/GMT-5 OLD_FILES+=usr/share/zoneinfo/Etc/GMT-6 OLD_FILES+=usr/share/zoneinfo/Etc/GMT-7 OLD_FILES+=usr/share/zoneinfo/Etc/GMT-8 OLD_FILES+=usr/share/zoneinfo/Etc/GMT-9 OLD_FILES+=usr/share/zoneinfo/Etc/GMT0 OLD_FILES+=usr/share/zoneinfo/Etc/Greenwich OLD_FILES+=usr/share/zoneinfo/Etc/UCT OLD_FILES+=usr/share/zoneinfo/Etc/UTC OLD_FILES+=usr/share/zoneinfo/Etc/Universal OLD_FILES+=usr/share/zoneinfo/Etc/Zulu OLD_FILES+=usr/share/zoneinfo/Europe/Amsterdam OLD_FILES+=usr/share/zoneinfo/Europe/Andorra OLD_FILES+=usr/share/zoneinfo/Europe/Athens OLD_FILES+=usr/share/zoneinfo/Europe/Belgrade OLD_FILES+=usr/share/zoneinfo/Europe/Berlin OLD_FILES+=usr/share/zoneinfo/Europe/Bratislava OLD_FILES+=usr/share/zoneinfo/Europe/Brussels OLD_FILES+=usr/share/zoneinfo/Europe/Bucharest OLD_FILES+=usr/share/zoneinfo/Europe/Budapest OLD_FILES+=usr/share/zoneinfo/Europe/Busingen OLD_FILES+=usr/share/zoneinfo/Europe/Chisinau OLD_FILES+=usr/share/zoneinfo/Europe/Copenhagen OLD_FILES+=usr/share/zoneinfo/Europe/Dublin OLD_FILES+=usr/share/zoneinfo/Europe/Gibraltar OLD_FILES+=usr/share/zoneinfo/Europe/Guernsey OLD_FILES+=usr/share/zoneinfo/Europe/Helsinki OLD_FILES+=usr/share/zoneinfo/Europe/Isle_of_Man OLD_FILES+=usr/share/zoneinfo/Europe/Istanbul OLD_FILES+=usr/share/zoneinfo/Europe/Jersey OLD_FILES+=usr/share/zoneinfo/Europe/Kaliningrad OLD_FILES+=usr/share/zoneinfo/Europe/Kiev OLD_FILES+=usr/share/zoneinfo/Europe/Lisbon OLD_FILES+=usr/share/zoneinfo/Europe/Ljubljana OLD_FILES+=usr/share/zoneinfo/Europe/London OLD_FILES+=usr/share/zoneinfo/Europe/Luxembourg OLD_FILES+=usr/share/zoneinfo/Europe/Madrid OLD_FILES+=usr/share/zoneinfo/Europe/Malta OLD_FILES+=usr/share/zoneinfo/Europe/Mariehamn OLD_FILES+=usr/share/zoneinfo/Europe/Minsk OLD_FILES+=usr/share/zoneinfo/Europe/Monaco OLD_FILES+=usr/share/zoneinfo/Europe/Moscow OLD_FILES+=usr/share/zoneinfo/Europe/Nicosia OLD_FILES+=usr/share/zoneinfo/Europe/Oslo OLD_FILES+=usr/share/zoneinfo/Europe/Paris OLD_FILES+=usr/share/zoneinfo/Europe/Podgorica OLD_FILES+=usr/share/zoneinfo/Europe/Prague OLD_FILES+=usr/share/zoneinfo/Europe/Riga OLD_FILES+=usr/share/zoneinfo/Europe/Rome OLD_FILES+=usr/share/zoneinfo/Europe/Samara OLD_FILES+=usr/share/zoneinfo/Europe/San_Marino OLD_FILES+=usr/share/zoneinfo/Europe/Sarajevo OLD_FILES+=usr/share/zoneinfo/Europe/Simferopol OLD_FILES+=usr/share/zoneinfo/Europe/Skopje OLD_FILES+=usr/share/zoneinfo/Europe/Sofia OLD_FILES+=usr/share/zoneinfo/Europe/Stockholm OLD_FILES+=usr/share/zoneinfo/Europe/Tallinn OLD_FILES+=usr/share/zoneinfo/Europe/Tirane OLD_FILES+=usr/share/zoneinfo/Europe/Uzhgorod OLD_FILES+=usr/share/zoneinfo/Europe/Vaduz OLD_FILES+=usr/share/zoneinfo/Europe/Vatican OLD_FILES+=usr/share/zoneinfo/Europe/Vienna OLD_FILES+=usr/share/zoneinfo/Europe/Vilnius OLD_FILES+=usr/share/zoneinfo/Europe/Volgograd OLD_FILES+=usr/share/zoneinfo/Europe/Warsaw OLD_FILES+=usr/share/zoneinfo/Europe/Zagreb OLD_FILES+=usr/share/zoneinfo/Europe/Zaporozhye OLD_FILES+=usr/share/zoneinfo/Europe/Zurich OLD_FILES+=usr/share/zoneinfo/Factory OLD_FILES+=usr/share/zoneinfo/HST OLD_FILES+=usr/share/zoneinfo/Indian/Antananarivo OLD_FILES+=usr/share/zoneinfo/Indian/Chagos OLD_FILES+=usr/share/zoneinfo/Indian/Christmas OLD_FILES+=usr/share/zoneinfo/Indian/Cocos OLD_FILES+=usr/share/zoneinfo/Indian/Comoro OLD_FILES+=usr/share/zoneinfo/Indian/Kerguelen OLD_FILES+=usr/share/zoneinfo/Indian/Mahe OLD_FILES+=usr/share/zoneinfo/Indian/Maldives OLD_FILES+=usr/share/zoneinfo/Indian/Mauritius OLD_FILES+=usr/share/zoneinfo/Indian/Mayotte OLD_FILES+=usr/share/zoneinfo/Indian/Reunion OLD_FILES+=usr/share/zoneinfo/MET OLD_FILES+=usr/share/zoneinfo/MST OLD_FILES+=usr/share/zoneinfo/MST7MDT OLD_FILES+=usr/share/zoneinfo/PST8PDT OLD_FILES+=usr/share/zoneinfo/Pacific/Apia OLD_FILES+=usr/share/zoneinfo/Pacific/Auckland OLD_FILES+=usr/share/zoneinfo/Pacific/Bougainville OLD_FILES+=usr/share/zoneinfo/Pacific/Chatham OLD_FILES+=usr/share/zoneinfo/Pacific/Chuuk OLD_FILES+=usr/share/zoneinfo/Pacific/Easter OLD_FILES+=usr/share/zoneinfo/Pacific/Efate OLD_FILES+=usr/share/zoneinfo/Pacific/Enderbury OLD_FILES+=usr/share/zoneinfo/Pacific/Fakaofo OLD_FILES+=usr/share/zoneinfo/Pacific/Fiji OLD_FILES+=usr/share/zoneinfo/Pacific/Funafuti OLD_FILES+=usr/share/zoneinfo/Pacific/Galapagos OLD_FILES+=usr/share/zoneinfo/Pacific/Gambier OLD_FILES+=usr/share/zoneinfo/Pacific/Guadalcanal OLD_FILES+=usr/share/zoneinfo/Pacific/Guam OLD_FILES+=usr/share/zoneinfo/Pacific/Honolulu OLD_FILES+=usr/share/zoneinfo/Pacific/Johnston OLD_FILES+=usr/share/zoneinfo/Pacific/Kiritimati OLD_FILES+=usr/share/zoneinfo/Pacific/Kosrae OLD_FILES+=usr/share/zoneinfo/Pacific/Kwajalein OLD_FILES+=usr/share/zoneinfo/Pacific/Majuro OLD_FILES+=usr/share/zoneinfo/Pacific/Marquesas OLD_FILES+=usr/share/zoneinfo/Pacific/Midway OLD_FILES+=usr/share/zoneinfo/Pacific/Nauru OLD_FILES+=usr/share/zoneinfo/Pacific/Niue OLD_FILES+=usr/share/zoneinfo/Pacific/Norfolk OLD_FILES+=usr/share/zoneinfo/Pacific/Noumea OLD_FILES+=usr/share/zoneinfo/Pacific/Pago_Pago OLD_FILES+=usr/share/zoneinfo/Pacific/Palau OLD_FILES+=usr/share/zoneinfo/Pacific/Pitcairn OLD_FILES+=usr/share/zoneinfo/Pacific/Pohnpei OLD_FILES+=usr/share/zoneinfo/Pacific/Port_Moresby OLD_FILES+=usr/share/zoneinfo/Pacific/Rarotonga OLD_FILES+=usr/share/zoneinfo/Pacific/Saipan OLD_FILES+=usr/share/zoneinfo/Pacific/Tahiti OLD_FILES+=usr/share/zoneinfo/Pacific/Tarawa OLD_FILES+=usr/share/zoneinfo/Pacific/Tongatapu OLD_FILES+=usr/share/zoneinfo/Pacific/Wake OLD_FILES+=usr/share/zoneinfo/Pacific/Wallis OLD_FILES+=usr/share/zoneinfo/UTC OLD_FILES+=usr/share/zoneinfo/WET OLD_FILES+=usr/share/zoneinfo/posixrules OLD_FILES+=usr/share/zoneinfo/zone.tab .endif Index: projects/ci20_mips/tools/build/stdlib.h =================================================================== --- projects/ci20_mips/tools/build/stdlib.h (nonexistent) +++ projects/ci20_mips/tools/build/stdlib.h (revision 283031) @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2015 Dimitry Andric + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _LEGACY_STDLIB_H_ +#define _LEGACY_STDLIB_H_ + +#include_next + +__BEGIN_DECLS + +#if __BSD_VISIBLE +void *reallocarray(void *, size_t, size_t); +#endif /* __BSD_VISIBLE */ + +__END_DECLS + +#endif /* !_LEGACY_STDLIB_H_ */ Property changes on: projects/ci20_mips/tools/build/stdlib.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/ci20_mips/tools/regression/p1003_1b/main.c =================================================================== --- projects/ci20_mips/tools/regression/p1003_1b/main.c (revision 283030) +++ projects/ci20_mips/tools/regression/p1003_1b/main.c (revision 283031) @@ -1,78 +1,79 @@ /* $FreeBSD$ */ #include +#include int fifo(int argc, char *argv[]); int memlock(int argc, char *argv[]); int p26(int argc, char *argv[]); int sched(int argc, char *argv[]); int yield(int argc, char *argv[]); static struct { const char *t; int (*f)(int, char *[]); int works; } tab[] = { { "fifo", fifo, 1 }, { "memlock", memlock, 0 }, { "p26", p26, 1 }, { "sched", sched, 1 }, { "yield", yield, 1 }, }; #define N(T) (sizeof (T)/ sizeof(T[0])) static int usage(int argc, char *argv[]) { int i; if (argc > 1) fprintf(stderr, "%s is unknown\n", argv[1]); fprintf(stderr, "usage: %s [-a] or one of [", argv[0]); for (i = 0; i < (sizeof(tab) / sizeof(tab[0])); i++) fprintf(stderr, "%s%s", (i)? " | " : "", tab[i].t); fprintf(stderr, "]\n"); return -1; } int main(int argc, char *argv[]) { int i; if (argc == 2 && strcmp(argv[1], "-a") == 0) { #if 1 fprintf(stderr, "-a should but doesn't really work" " (my notes say \"because things detach\");\n" "meanwhile do these individual tests and look" " for a non-zero exit code:\n"); for (i = 0; i < N(tab); i++) if (tab[i].works) fprintf(stderr, "p1003_1b %s\n", tab[i].t); return -1; #else { int r; for (i = 0; i < N(tab); i++) { if (tab[i].works) { if ( (r = (*tab[i].f)(argc - 1, argv + 1)) ) { fprintf(stderr, "%s failed\n", tab[i].t); return r; } } } return 0; } #endif } if (argc > 1) { for (i = 0; i < N(tab); i++) if (strcmp(tab[i].t, argv[1]) == 0) return (*tab[i].f)(argc - 1, argv + 1); } return usage(argc, argv); } Index: projects/ci20_mips/tools/regression/p1003_1b/prutil.c =================================================================== --- projects/ci20_mips/tools/regression/p1003_1b/prutil.c (revision 283030) +++ projects/ci20_mips/tools/regression/p1003_1b/prutil.c (revision 283031) @@ -1,61 +1,62 @@ +#include #include -#include #include #include - -#include +#include #include +#include + #include "prutil.h" /* * $FreeBSD$ */ void quit(const char *text) { - err(errno, text); + err(errno, "%s", text); } char *sched_text(int scheduler) { switch(scheduler) { case SCHED_FIFO: return "SCHED_FIFO"; case SCHED_RR: return "SCHED_RR"; case SCHED_OTHER: return "SCHED_OTHER"; default: return "Illegal scheduler value"; } } int sched_is(int line, struct sched_param *p, int shouldbe) { int scheduler; struct sched_param param; /* What scheduler are we running now? */ errno = 0; scheduler = sched_getscheduler(0); if (sched_getparam(0, ¶m)) quit("sched_getparam"); if (p) *p = param; if (shouldbe != -1 && scheduler != shouldbe) { fprintf(stderr, "At line %d the scheduler should be %s yet it is %s.\n", line, sched_text(shouldbe), sched_text(scheduler)); exit(-1); } return scheduler; } Index: projects/ci20_mips/tools/tools/ath/athaggrstats/Makefile =================================================================== --- projects/ci20_mips/tools/tools/ath/athaggrstats/Makefile (revision 283030) +++ projects/ci20_mips/tools/tools/ath/athaggrstats/Makefile (revision 283031) @@ -1,28 +1,29 @@ # $FreeBSD$ .PATH: ${.CURDIR}/../../../../sys/dev/ath/ath_hal PROG= athaggrstats SRCS= main.c athaggrstats.c opt_ah.h ah_osdep.h CLEANFILES+= opt_ah.h .include <../Makefile.inc> CFLAGS+=-DATH_SUPPORT_ANI CFLAGS+=-DATH_SUPPORT_TDMA +CFLAGS+=-I${.CURDIR}/../../../../lib/libbsdstat/ LIBADD+= bsdstat opt_ah.h: echo "#define AH_DEBUG 1" > opt_ah.h echo "#define AH_DEBUG_COUNTRY 1" >> opt_ah.h echo "#define AH_SUPPORT_AR5416 1" >> opt_ah.h ah_osdep.h: echo 'typedef void *HAL_SOFTC;' >ah_osdep.h echo 'typedef int HAL_BUS_TAG;' >>ah_osdep.h echo 'typedef void *HAL_BUS_HANDLE;' >>ah_osdep.h echo 'typedef uint32_t HAL_DMA_ADDR;' >>ah_osdep.h .include Index: projects/ci20_mips/tools/tools/ath/athstats/Makefile =================================================================== --- projects/ci20_mips/tools/tools/ath/athstats/Makefile (revision 283030) +++ projects/ci20_mips/tools/tools/ath/athstats/Makefile (revision 283031) @@ -1,39 +1,37 @@ # $FreeBSD$ MAN= .include .PATH: ${.CURDIR}/../../../../sys/dev/ath/ath_hal PROG= athstats -# Because of a clang preprocessor parser limitation causing this -# to not compile, use gcc for now. -#CC= gcc - SRCS= main.c athstats.c opt_ah.h ah_osdep.h CLEANFILES+= opt_ah.h .include <../Makefile.inc> CFLAGS+=-DATH_SUPPORT_ANI CFLAGS+=-DATH_SUPPORT_TDMA + +CFLAGS+=-I${.CURDIR}/../../../../lib/libbsdstat/ CFLAGS.clang+= -fbracket-depth=512 LIBADD= bsdstat opt_ah.h: echo "#define AH_DEBUG 1" > opt_ah.h echo "#define AH_DEBUG_COUNTRY 1" >> opt_ah.h echo "#define AH_SUPPORT_AR5416 1" >> opt_ah.h ah_osdep.h: echo 'typedef void *HAL_SOFTC;' >ah_osdep.h echo 'typedef int HAL_BUS_TAG;' >>ah_osdep.h echo 'typedef void *HAL_BUS_HANDLE;' >>ah_osdep.h echo 'typedef uint32_t HAL_DMA_ADDR;' >>ah_osdep.h .include Index: projects/ci20_mips/tools/tools/mwl/mwlstats/Makefile =================================================================== --- projects/ci20_mips/tools/tools/mwl/mwlstats/Makefile (revision 283030) +++ projects/ci20_mips/tools/tools/mwl/mwlstats/Makefile (revision 283031) @@ -1,12 +1,13 @@ # $FreeBSD$ PROG= mwlstats BINDIR= /usr/local/bin MAN= SRCS= main.c mwlstats.c LIBADD= bsdstat +CFLAGS+=-I${.CURDIR}/../../../../lib/libbsdstat/ .include CFLAGS+= -I. Index: projects/ci20_mips/tools/tools/net80211/wlanstats/Makefile =================================================================== --- projects/ci20_mips/tools/tools/net80211/wlanstats/Makefile (revision 283030) +++ projects/ci20_mips/tools/tools/net80211/wlanstats/Makefile (revision 283031) @@ -1,14 +1,15 @@ # $FreeBSD$ .include PROG= wlanstats BINDIR= /usr/local/bin MAN= LIBADD= bsdstat +CFLAGS+=-I${.CURDIR}/../../../../lib/libbsdstat/ SRCS= wlanstats.c main.c CFLAGS.clang+= -fbracket-depth=512 .include Index: projects/ci20_mips/tools/tools/npe/npestats/Makefile =================================================================== --- projects/ci20_mips/tools/tools/npe/npestats/Makefile (revision 283030) +++ projects/ci20_mips/tools/tools/npe/npestats/Makefile (revision 283031) @@ -1,9 +1,10 @@ # $FreeBSD$ PROG= npestats SRCS= main.c npestats.c BINDIR= /usr/local/bin MAN= LIBADD= bsdstat +CFLAGS+=-I${.CURDIR}/../../../../lib/libbsdstat/ .include Index: projects/ci20_mips/usr.bin/man/man.sh =================================================================== --- projects/ci20_mips/usr.bin/man/man.sh (revision 283030) +++ projects/ci20_mips/usr.bin/man/man.sh (revision 283031) @@ -1,994 +1,997 @@ #! /bin/sh # # Copyright (c) 2010 Gordon Tetlow # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # Usage: add_to_manpath path # Adds a variable to manpath while ensuring we don't have duplicates. # Returns true if we were able to add something. False otherwise. add_to_manpath() { case "$manpath" in *:$1) decho " Skipping duplicate manpath entry $1" 2 ;; $1:*) decho " Skipping duplicate manpath entry $1" 2 ;; *:$1:*) decho " Skipping duplicate manpath entry $1" 2 ;; *) if [ -d "$1" ]; then decho " Adding $1 to manpath" manpath="$manpath:$1" return 0 fi ;; esac return 1 } # Usage: build_manlocales # Builds a correct MANLOCALES variable. build_manlocales() { # If the user has set manlocales, who are we to argue. if [ -n "$MANLOCALES" ]; then return fi parse_configs # Trim leading colon MANLOCALES=${manlocales#:} decho "Available manual locales: $MANLOCALES" } # Usage: build_manpath # Builds a correct MANPATH variable. build_manpath() { local IFS # If the user has set a manpath, who are we to argue. if [ -n "$MANPATH" ]; then return fi search_path decho "Adding default manpath entries" IFS=: for path in $man_default_path; do add_to_manpath "$path" done unset IFS parse_configs # Trim leading colon MANPATH=${manpath#:} decho "Using manual path: $MANPATH" } # Usage: check_cat catglob # Checks to see if a cat glob is available. check_cat() { if exists "$1"; then use_cat=yes catpage=$found setup_cattool $catpage decho " Found catpage $catpage" return 0 else return 1 fi } # Usage: check_man manglob catglob # Given 2 globs, figures out if the manglob is available, if so, check to # see if the catglob is also available and up to date. check_man() { if exists "$1"; then # We have a match, check for a cat page manpage=$found setup_cattool $manpage decho " Found manpage $manpage" if [ -n "${use_width}" ]; then # non-standard width unset use_cat decho " Skipping catpage: non-standard page width" elif exists "$2" && is_newer $found $manpage; then # cat page found and is newer, use that use_cat=yes catpage=$found setup_cattool $catpage decho " Using catpage $catpage" else # no cat page or is older unset use_cat decho " Skipping catpage: not found or old" fi return 0 fi return 1 } # Usage: decho "string" [debuglevel] # Echoes to stderr string prefaced with -- if high enough debuglevel. decho() { if [ $debug -ge ${2:-1} ]; then echo "-- $1" >&2 fi } # Usage: exists glob # Returns true if glob resolves to a real file. exists() { local IFS # Don't accidentally inherit callers IFS (breaks perl manpages) unset IFS # Use some globbing tricks in the shell to determine if a file # exists or not. set +f set -- "$1" $1 set -f if [ "$1" != "$2" -a -r "$2" ]; then found="$2" return 0 fi return 1 } # Usage: find_file path section subdir pagename # Returns: true if something is matched and found. # Search the given path/section combo for a given page. find_file() { local manroot catroot mann man0 catn cat0 manroot="$1/man$2" catroot="$1/cat$2" if [ -n "$3" ]; then manroot="$manroot/$3" catroot="$catroot/$3" fi if [ ! -d "$manroot" ]; then return 1 fi decho " Searching directory $manroot" 2 mann="$manroot/$4.$2*" man0="$manroot/$4.0*" catn="$catroot/$4.$2*" cat0="$catroot/$4.0*" # This is the behavior as seen by the original man utility. # Let's not change that which doesn't seem broken. if check_man "$mann" "$catn"; then return 0 elif check_man "$man0" "$cat0"; then return 0 elif check_cat "$catn"; then return 0 elif check_cat "$cat0"; then return 0 fi return 1 } # Usage: is_newer file1 file2 # Returns true if file1 is newer than file2 as calculated by mtime. is_newer() { if ! [ "$1" -ot "$2" ]; then decho " mtime: $1 not older than $2" 3 return 0 else decho " mtime: $1 older than $2" 3 return 1 fi } # Usage: manpath_parse_args "$@" # Parses commandline options for manpath. manpath_parse_args() { local cmd_arg while getopts 'Ldq' cmd_arg; do case "${cmd_arg}" in L) Lflag=Lflag ;; d) debug=$(( $debug + 1 )) ;; q) qflag=qflag ;; *) manpath_usage ;; esac done >&2 } # Usage: manpath_usage # Display usage for the manpath(1) utility. manpath_usage() { echo 'usage: manpath [-Ldq]' >&2 exit 1 } # Usage: manpath_warnings # Display some warnings to stderr. manpath_warnings() { if [ -z "$Lflag" -a -n "$MANPATH" ]; then echo "(Warning: MANPATH environment variable set)" >&2 fi if [ -n "$Lflag" -a -n "$MANLOCALES" ]; then echo "(Warning: MANLOCALES environment variable set)" >&2 fi } # Usage: man_check_for_so page path # Returns: True if able to resolve the file, false if it ended in tears. # Detects the presence of the .so directive and causes the file to be # redirected to another source file. man_check_for_so() { local IFS line tstr unset IFS # We need to loop to accommodate multiple .so directives. while true do line=$($cattool $manpage | head -1) case "$line" in .so*) trim "${line#.so}" decho "$manpage includes $tstr" # Glob and check for the file. if ! check_man "$path/$tstr*" ""; then decho " Unable to find $tstr" return 1 fi ;; *) break ;; esac done return 0 } # Usage: man_display_page # Display either the manpage or catpage depending on the use_cat variable man_display_page() { local IFS pipeline testline # We are called with IFS set to colon. This causes really weird # things to happen for the variables that have spaces in them. unset IFS # If we are supposed to use a catpage and we aren't using troff(1) # just zcat the catpage and we are done. if [ -z "$tflag" -a -n "$use_cat" ]; then if [ -n "$wflag" ]; then echo "$catpage (source: $manpage)" ret=0 else if [ $debug -gt 0 ]; then decho "Command: $cattool $catpage | $MANPAGER" ret=0 else eval "$cattool $catpage | $MANPAGER" ret=$? fi fi return fi # Okay, we are using the manpage, do we just need to output the # name of the manpage? if [ -n "$wflag" ]; then echo "$manpage" ret=0 return fi + if [ -n "$use_width" ]; then + mandoc_args="-O width=${use_width}" + fi testline="mandoc -Tlint -Wunsupp 2>/dev/null" - pipeline="mandoc | $MANPAGER" + pipeline="mandoc $mandoc_args | $MANPAGER" if ! eval "$cattool $manpage | $testline" ;then if which -s groff; then man_display_page_groff else echo "This manpage needs groff(1) to be rendered" >&2 echo "First install groff(1): " >&2 echo "pkg install groff " >&2 ret=1 fi return fi if [ $debug -gt 0 ]; then decho "Command: $cattool $manpage | $pipeline" ret=0 else eval "$cattool $manpage | $pipeline" ret=$? fi } # Usage: man_display_page_groff # Display the manpage using groff man_display_page_groff() { local EQN NROFF PIC TBL TROFF REFER VGRIND local IFS l nroff_dev pipeline preproc_arg tool # So, we really do need to parse the manpage. First, figure out the # device flag (-T) we have to pass to eqn(1) and groff(1). Then, # setup the pipeline of commands based on the user's request. # If the manpage is from a particular charset, we need to setup nroff # to properly output for the correct device. case "${manpage}" in *.${man_charset}/*) # I don't pretend to know this; I'm just copying from the # previous version of man(1). case "$man_charset" in KOI8-R) nroff_dev="koi8-r" ;; ISO8859-1) nroff_dev="latin1" ;; ISO8859-15) nroff_dev="latin1" ;; UTF-8) nroff_dev="utf8" ;; *) nroff_dev="ascii" ;; esac NROFF="$NROFF -T$nroff_dev" EQN="$EQN -T$nroff_dev" # Iff the manpage is from the locale and not just the charset, # then we need to define the locale string. case "${manpage}" in */${man_lang}_${man_country}.${man_charset}/*) NROFF="$NROFF -dlocale=$man_lang.$man_charset" ;; */${man_lang}.${man_charset}/*) NROFF="$NROFF -dlocale=$man_lang.$man_charset" ;; esac # Allow language specific calls to override the default # set of utilities. l=$(echo $man_lang | tr [:lower:] [:upper:]) for tool in EQN NROFF PIC TBL TROFF REFER VGRIND; do eval "$tool=\${${tool}_$l:-\$$tool}" done ;; *) NROFF="$NROFF -Tascii" EQN="$EQN -Tascii" ;; esac if [ -z "$MANCOLOR" ]; then NROFF="$NROFF -P-c" fi if [ -n "${use_width}" ]; then NROFF="$NROFF -rLL=${use_width}n -rLT=${use_width}n" fi if [ -n "$MANROFFSEQ" ]; then set -- -$MANROFFSEQ while getopts 'egprtv' preproc_arg; do case "${preproc_arg}" in e) pipeline="$pipeline | $EQN" ;; g) ;; # Ignore for compatibility. p) pipeline="$pipeline | $PIC" ;; r) pipeline="$pipeline | $REFER" ;; t) pipeline="$pipeline | $TBL" ;; v) pipeline="$pipeline | $VGRIND" ;; *) usage ;; esac done # Strip the leading " | " from the resulting pipeline. pipeline="${pipeline#" | "}" else pipeline="$TBL" fi if [ -n "$tflag" ]; then pipeline="$pipeline | $TROFF" else pipeline="$pipeline | $NROFF | $MANPAGER" fi if [ $debug -gt 0 ]; then decho "Command: $cattool $manpage | $pipeline" ret=0 else eval "$cattool $manpage | $pipeline" ret=$? fi } # Usage: man_find_and_display page # Search through the manpaths looking for the given page. man_find_and_display() { local found_page locpath p path sect # Check to see if it's a file. But only if it has a '/' in # the filename. case "$1" in */*) if [ -f "$1" -a -r "$1" ]; then decho "Found a usable page, displaying that" unset use_cat manpage="$1" setup_cattool $manpage if man_check_for_so $manpage $(dirname $manpage); then found_page=yes man_display_page fi return fi ;; esac IFS=: for sect in $MANSECT; do decho "Searching section $sect" 2 for path in $MANPATH; do for locpath in $locpaths; do p=$path/$locpath p=${p%/.} # Rid ourselves of the trailing /. # Check if there is a MACHINE specific manpath. if find_file $p $sect $MACHINE "$1"; then if man_check_for_so $manpage $p; then found_page=yes man_display_page if [ -n "$aflag" ]; then continue 2 else return fi fi fi # Check if there is a MACHINE_ARCH # specific manpath. if find_file $p $sect $MACHINE_ARCH "$1"; then if man_check_for_so $manpage $p; then found_page=yes man_display_page if [ -n "$aflag" ]; then continue 2 else return fi fi fi # Check plain old manpath. if find_file $p $sect '' "$1"; then if man_check_for_so $manpage $p; then found_page=yes man_display_page if [ -n "$aflag" ]; then continue 2 else return fi fi fi done done done unset IFS # Nothing? Well, we are done then. if [ -z "$found_page" ]; then echo "No manual entry for $1" >&2 ret=1 return fi } # Usage: man_parse_args "$@" # Parses commandline options for man. man_parse_args() { local IFS cmd_arg while getopts 'M:P:S:adfhkm:op:tw' cmd_arg; do case "${cmd_arg}" in M) MANPATH=$OPTARG ;; P) MANPAGER=$OPTARG ;; S) MANSECT=$OPTARG ;; a) aflag=aflag ;; d) debug=$(( $debug + 1 )) ;; f) fflag=fflag ;; h) man_usage 0 ;; k) kflag=kflag ;; m) mflag=$OPTARG ;; o) oflag=oflag ;; p) MANROFFSEQ=$OPTARG ;; t) tflag=tflag ;; w) wflag=wflag ;; *) man_usage ;; esac done >&2 shift $(( $OPTIND - 1 )) # Check the args for incompatible options. case "${fflag}${kflag}${tflag}${wflag}" in fflagkflag*) echo "Incompatible options: -f and -k"; man_usage ;; fflag*tflag*) echo "Incompatible options: -f and -t"; man_usage ;; fflag*wflag) echo "Incompatible options: -f and -w"; man_usage ;; *kflagtflag*) echo "Incompatible options: -k and -t"; man_usage ;; *kflag*wflag) echo "Incompatible options: -k and -w"; man_usage ;; *tflagwflag) echo "Incompatible options: -t and -w"; man_usage ;; esac # Short circuit for whatis(1) and apropos(1) if [ -n "$fflag" ]; then do_whatis "$@" exit fi if [ -n "$kflag" ]; then do_apropos "$@" exit fi IFS=: for sect in $man_default_sections; do if [ "$sect" = "$1" ]; then decho "Detected manual section as first arg: $1" MANSECT="$1" shift break fi done unset IFS pages="$*" } # Usage: man_setup # Setup various trivial but essential variables. man_setup() { # Setup machine and architecture variables. if [ -n "$mflag" ]; then MACHINE_ARCH=${mflag%%:*} MACHINE=${mflag##*:} fi if [ -z "$MACHINE_ARCH" ]; then MACHINE_ARCH=$($SYSCTL -n hw.machine_arch) fi if [ -z "$MACHINE" ]; then MACHINE=$($SYSCTL -n hw.machine) fi decho "Using architecture: $MACHINE_ARCH:$MACHINE" setup_pager # Setup manual sections to search. if [ -z "$MANSECT" ]; then MANSECT=$man_default_sections fi decho "Using manual sections: $MANSECT" build_manpath man_setup_locale man_setup_width } # Usage: man_setup_width # Set up page width. man_setup_width() { local sizes unset use_width case "$MANWIDTH" in [0-9]*) if [ "$MANWIDTH" -gt 0 2>/dev/null ]; then use_width=$MANWIDTH fi ;; [Tt][Tt][Yy]) if { sizes=$($STTY size 0>&3 2>/dev/null); } 3>&1; then set -- $sizes if [ $2 -gt 80 ]; then use_width=$(($2-2)) fi fi ;; esac if [ -n "$use_width" ]; then decho "Using non-standard page width: ${use_width}" else decho 'Using standard page width' fi } # Usage: man_setup_locale # Setup necessary locale variables. man_setup_locale() { local lang_cc locpaths='.' man_charset='US-ASCII' # Setup locale information. if [ -n "$oflag" ]; then decho 'Using non-localized manpages' else # Use the locale tool to give us the proper LC_CTYPE eval $( $LOCALE ) case "$LC_CTYPE" in C) ;; POSIX) ;; [a-z][a-z]_[A-Z][A-Z]\.*) lang_cc="${LC_CTYPE%.*}" man_lang="${LC_CTYPE%_*}" man_country="${lang_cc#*_}" man_charset="${LC_CTYPE#*.}" locpaths="$LC_CTYPE" locpaths="$locpaths:$man_lang.$man_charset" if [ "$man_lang" != "en" ]; then locpaths="$locpaths:en.$man_charset" fi locpaths="$locpaths:." ;; *) echo 'Unknown locale, assuming C' >&2 ;; esac fi decho "Using locale paths: $locpaths" } # Usage: man_usage [exitcode] # Display usage for the man utility. man_usage() { echo 'Usage:' echo ' man [-adho] [-t | -w] [-M manpath] [-P pager] [-S mansect]' echo ' [-m arch[:machine]] [-p [eprtv]] [mansect] page [...]' echo ' man -f page [...] -- Emulates whatis(1)' echo ' man -k page [...] -- Emulates apropos(1)' # When exit'ing with -h, it's not an error. exit ${1:-1} } # Usage: parse_configs # Reads the end-user adjustable config files. parse_configs() { local IFS file files if [ -n "$parsed_configs" ]; then return fi unset IFS # Read the global config first in case the user wants # to override config_local. if [ -r "$config_global" ]; then parse_file "$config_global" fi # Glob the list of files to parse. set +f files=$(echo $config_local) set -f for file in $files; do if [ -r "$file" ]; then parse_file "$file" fi done parsed_configs='yes' } # Usage: parse_file file # Reads the specified config files. parse_file() { local file line tstr var file="$1" decho "Parsing config file: $file" while read line; do decho " $line" 2 case "$line" in \#*) decho " Comment" 3 ;; MANPATH*) decho " MANPATH" 3 trim "${line#MANPATH}" add_to_manpath "$tstr" ;; MANLOCALE*) decho " MANLOCALE" 3 trim "${line#MANLOCALE}" manlocales="$manlocales:$tstr" ;; MANCONFIG*) decho " MANCONFIG" 3 trim "${line#MANCONFIG}" config_local="$tstr" ;; # Set variables in the form of FOO_BAR *_*[\ \ ]*) var="${line%%[\ \ ]*}" trim "${line#$var}" eval "$var=\"$tstr\"" decho " Parsed $var" 3 ;; esac done < "$file" } # Usage: search_path # Traverse $PATH looking for manpaths. search_path() { local IFS p path decho "Searching PATH for man directories" IFS=: for path in $PATH; do # Do a little special casing since the base manpages # are in /usr/share/man instead of /usr/man or /man. case "$path" in /bin|/usr/bin) add_to_manpath "/usr/share/man" ;; *) if add_to_manpath "$path/man"; then : elif add_to_manpath "$path/MAN"; then : else case "$path" in */bin) p="${path%/bin}/man" add_to_manpath "$p" ;; *) ;; esac fi ;; esac done unset IFS if [ -z "$manpath" ]; then decho ' Unable to find any manpaths, using default' manpath=$man_default_path fi } # Usage: search_whatis cmd [arglist] # Do the heavy lifting for apropos/whatis search_whatis() { local IFS bad cmd f good key keywords loc opt out path rval wlist cmd="$1" shift whatis_parse_args "$@" build_manpath build_manlocales setup_pager if [ "$cmd" = "whatis" ]; then opt="-w" fi f='whatis' IFS=: for path in $MANPATH; do if [ \! -d "$path" ]; then decho "Skipping non-existent path: $path" 2 continue fi if [ -f "$path/$f" -a -r "$path/$f" ]; then decho "Found whatis: $path/$f" wlist="$wlist $path/$f" fi for loc in $MANLOCALES; do if [ -f "$path/$loc/$f" -a -r "$path/$loc/$f" ]; then decho "Found whatis: $path/$loc/$f" wlist="$wlist $path/$loc/$f" fi done done unset IFS if [ -z "$wlist" ]; then echo "$cmd: no whatis databases in $MANPATH" >&2 exit 1 fi rval=0 for key in $keywords; do out=$(grep -Ehi $opt -- "$key" $wlist) if [ -n "$out" ]; then good="$good\\n$out" else bad="$bad\\n$key: nothing appropriate" rval=1 fi done # Strip leading carriage return. good=${good#\\n} bad=${bad#\\n} if [ -n "$good" ]; then echo -e "$good" | $MANPAGER fi if [ -n "$bad" ]; then echo -e "$bad" >&2 fi exit $rval } # Usage: setup_cattool page # Finds an appropriate decompressor based on extension setup_cattool() { case "$1" in *.bz) cattool='/usr/bin/bzcat' ;; *.bz2) cattool='/usr/bin/bzcat' ;; *.gz) cattool='/usr/bin/zcat' ;; *.lzma) cattool='/usr/bin/lzcat' ;; *.xz) cattool='/usr/bin/xzcat' ;; *) cattool='/usr/bin/zcat -f' ;; esac } # Usage: setup_pager # Correctly sets $MANPAGER setup_pager() { # Setup pager. if [ -z "$MANPAGER" ]; then if [ -n "$MANCOLOR" ]; then MANPAGER="less -sR" else if [ -n "$PAGER" ]; then MANPAGER="$PAGER" else MANPAGER="more -s" fi fi fi decho "Using pager: $MANPAGER" } # Usage: trim string # Trims whitespace from beginning and end of a variable trim() { tstr=$1 while true; do case "$tstr" in [\ \ ]*) tstr="${tstr##[\ \ ]}" ;; *[\ \ ]) tstr="${tstr%%[\ \ ]}" ;; *) break ;; esac done } # Usage: whatis_parse_args "$@" # Parse commandline args for whatis and apropos. whatis_parse_args() { local cmd_arg while getopts 'd' cmd_arg; do case "${cmd_arg}" in d) debug=$(( $debug + 1 )) ;; *) whatis_usage ;; esac done >&2 shift $(( $OPTIND - 1 )) keywords="$*" } # Usage: whatis_usage # Display usage for the whatis/apropos utility. whatis_usage() { echo "usage: $cmd [-d] keyword [...]" exit 1 } # Supported commands do_apropos() { search_whatis apropos "$@" } do_man() { man_parse_args "$@" if [ -z "$pages" ]; then echo 'What manual page do you want?' >&2 exit 1 fi man_setup for page in $pages; do decho "Searching for $page" man_find_and_display "$page" done exit ${ret:-0} } do_manpath() { manpath_parse_args "$@" if [ -z "$qflag" ]; then manpath_warnings fi if [ -n "$Lflag" ]; then build_manlocales echo $MANLOCALES else build_manpath echo $MANPATH fi exit 0 } do_whatis() { search_whatis whatis "$@" } # User's PATH setting decides on the groff-suite to pick up. EQN=eqn NROFF='groff -S -P-h -Wall -mtty-char -man' PIC=pic REFER=refer TBL=tbl TROFF='groff -S -man' VGRIND=vgrind LOCALE=/usr/bin/locale STTY=/bin/stty SYSCTL=/sbin/sysctl debug=0 man_default_sections='1:8:2:3:n:4:5:6:7:9:l' man_default_path='/usr/share/man:/usr/share/openssl/man:/usr/local/man' cattool='/usr/bin/zcat -f' config_global='/etc/man.conf' # This can be overridden via a setting in /etc/man.conf. config_local='/usr/local/etc/man.d/*.conf' # Set noglobbing for now. I don't want spurious globbing. set -f case "$0" in *apropos) do_apropos "$@" ;; *manpath) do_manpath "$@" ;; *whatis) do_whatis "$@" ;; *) do_man "$@" ;; esac Index: projects/ci20_mips/usr.bin/netstat/route.c =================================================================== --- projects/ci20_mips/usr.bin/netstat/route.c (revision 283030) +++ projects/ci20_mips/usr.bin/netstat/route.c (revision 283031) @@ -1,829 +1,829 @@ /*- * Copyright (c) 1983, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char sccsid[] = "From: @(#)route.c 8.6 (Berkeley) 4/28/95"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "netstat.h" /* * Definitions for showing gateway flags. */ struct bits { u_long b_mask; char b_val; const char *b_name; } bits[] = { { RTF_UP, 'U', "up" }, { RTF_GATEWAY, 'G', "gateway" }, { RTF_HOST, 'H', "host" }, { RTF_REJECT, 'R', "reject" }, { RTF_DYNAMIC, 'D', "dynamic" }, { RTF_MODIFIED, 'M', "modified" }, { RTF_DONE, 'd', "done" }, /* Completed -- for routing msgs only */ { RTF_XRESOLVE, 'X', "xresolve" }, { RTF_STATIC, 'S', "static" }, { RTF_PROTO1, '1', "proto1" }, { RTF_PROTO2, '2', "proto2" }, { RTF_PROTO3, '3', "proto3" }, { RTF_BLACKHOLE,'B', "blackhole" }, { RTF_BROADCAST,'b', "broadcast" }, #ifdef RTF_LLINFO { RTF_LLINFO, 'L', "llinfo" }, #endif { 0 , 0, NULL } }; /* * kvm(3) bindings for every needed symbol */ static struct nlist rl[] = { #define N_RTSTAT 0 { .n_name = "_rtstat" }, #define N_RTTRASH 1 { .n_name = "_rttrash" }, { .n_name = NULL }, }; typedef union { long dummy; /* Helps align structure. */ struct sockaddr u_sa; u_short u_data[128]; } sa_u; struct ifmap_entry { char ifname[IFNAMSIZ]; }; static struct ifmap_entry *ifmap; static int ifmap_size; struct timespec uptime; static void p_rtable_sysctl(int, int); static void p_rtentry_sysctl(const char *name, struct rt_msghdr *); static void p_sockaddr(const char *name, struct sockaddr *, struct sockaddr *, int, int); static const char *fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags); static void p_flags(int, const char *); static const char *fmt_flags(int f); static void domask(char *, in_addr_t, u_long); /* * Print routing tables. */ void routepr(int fibnum, int af) { size_t intsize; int numfibs; if (live == 0) return; intsize = sizeof(int); if (fibnum == -1 && sysctlbyname("net.my_fibnum", &fibnum, &intsize, NULL, 0) == -1) fibnum = 0; if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1) numfibs = 1; if (fibnum < 0 || fibnum > numfibs - 1) errx(EX_USAGE, "%d: invalid fib", fibnum); /* * Since kernel & userland use different timebase * (time_uptime vs time_second) and we are reading kernel memory * directly we should do rt_expire --> expire_time conversion. */ if (clock_gettime(CLOCK_UPTIME, &uptime) < 0) err(EX_OSERR, "clock_gettime() failed"); xo_open_container("route-information"); xo_emit("{T:Routing tables}"); if (fibnum) xo_emit(" ({L:fib}: {:fib/%d})", fibnum); xo_emit("\n"); p_rtable_sysctl(fibnum, af); xo_close_container("route-information"); } /* * Print address family header before a section of the routing table. */ void pr_family(int af1) { const char *afname; switch (af1) { case AF_INET: afname = "Internet"; break; #ifdef INET6 case AF_INET6: afname = "Internet6"; break; #endif /*INET6*/ case AF_ISO: afname = "ISO"; break; case AF_CCITT: afname = "X.25"; break; case AF_NETGRAPH: afname = "Netgraph"; break; default: afname = NULL; break; } if (afname) xo_emit("\n{k:address-family/%s}:\n", afname); else xo_emit("\n{L:Protocol Family} {k:address-family/%d}:\n", af1); } /* column widths; each followed by one space */ #ifndef INET6 #define WID_DST_DEFAULT(af) 18 /* width of destination column */ #define WID_GW_DEFAULT(af) 18 /* width of gateway column */ #define WID_IF_DEFAULT(af) (Wflag ? 10 : 8) /* width of netif column */ #else #define WID_DST_DEFAULT(af) \ ((af) == AF_INET6 ? (numeric_addr ? 33: 18) : 18) #define WID_GW_DEFAULT(af) \ ((af) == AF_INET6 ? (numeric_addr ? 29 : 18) : 18) #define WID_IF_DEFAULT(af) ((af) == AF_INET6 ? 8 : (Wflag ? 10 : 8)) #endif /*INET6*/ static int wid_dst; static int wid_gw; static int wid_flags; static int wid_pksent; static int wid_mtu; static int wid_if; static int wid_expire; /* * Print header for routing table columns. */ void pr_rthdr(int af1) { if (Aflag) xo_emit("{T:/%-8.8s} ","Address"); if (Wflag) { xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%*.*s} " - "{T:/%*.*s} {T:/%*.*s} {T:/%*.*s} {T:/%*s}\n", + "{T:/%*.*s} {T:/%*.*s} {T:/%*s}\n", wid_dst, wid_dst, "Destination", wid_gw, wid_gw, "Gateway", wid_flags, wid_flags, "Flags", wid_pksent, wid_pksent, "Use", wid_mtu, wid_mtu, "Mtu", wid_if, wid_if, "Netif", wid_expire, "Expire"); } else { xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%*.*s} " "{T:/%*s}\n", wid_dst, wid_dst, "Destination", wid_gw, wid_gw, "Gateway", wid_flags, wid_flags, "Flags", wid_if, wid_if, "Netif", wid_expire, "Expire"); } } static void p_rtable_sysctl(int fibnum, int af) { size_t needed; int mib[7]; char *buf, *next, *lim; struct rt_msghdr *rtm; struct sockaddr *sa; int fam = AF_UNSPEC, ifindex = 0, size; int need_table_close = false; struct ifaddrs *ifap, *ifa; struct sockaddr_dl *sdl; /* * Retrieve interface list at first * since we need #ifindex -> if_xname match */ if (getifaddrs(&ifap) != 0) err(EX_OSERR, "getifaddrs"); for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != AF_LINK) continue; sdl = (struct sockaddr_dl *)ifa->ifa_addr; ifindex = sdl->sdl_index; if (ifindex >= ifmap_size) { size = roundup(ifindex + 1, 32) * sizeof(struct ifmap_entry); if ((ifmap = realloc(ifmap, size)) == NULL) errx(2, "realloc(%d) failed", size); memset(&ifmap[ifmap_size], 0, size - ifmap_size * sizeof(struct ifmap_entry)); ifmap_size = roundup(ifindex + 1, 32); } if (*ifmap[ifindex].ifname != '\0') continue; strlcpy(ifmap[ifindex].ifname, ifa->ifa_name, IFNAMSIZ); } freeifaddrs(ifap); mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = af; mib[4] = NET_RT_DUMP; mib[5] = 0; mib[6] = fibnum; if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) err(EX_OSERR, "sysctl: net.route.0.%d.dump.%d estimate", af, fibnum); if ((buf = malloc(needed)) == NULL) errx(2, "malloc(%lu)", (unsigned long)needed); if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) err(1, "sysctl: net.route.0.%d.dump.%d", af, fibnum); lim = buf + needed; xo_open_container("route-table"); xo_open_list("rt-family"); for (next = buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; if (rtm->rtm_version != RTM_VERSION) continue; /* * Peek inside header to determine AF */ sa = (struct sockaddr *)(rtm + 1); /* Only print family first time. */ if (fam != sa->sa_family) { if (need_table_close) { xo_close_list("rt-entry"); xo_close_instance("rt-family"); } need_table_close = true; fam = sa->sa_family; wid_dst = WID_DST_DEFAULT(fam); wid_gw = WID_GW_DEFAULT(fam); wid_flags = 6; wid_pksent = 8; wid_mtu = 6; wid_if = WID_IF_DEFAULT(fam); wid_expire = 6; xo_open_instance("rt-family"); pr_family(fam); xo_open_list("rt-entry"); pr_rthdr(fam); } p_rtentry_sysctl("rt-entry", rtm); } if (need_table_close) { xo_close_list("rt-entry"); xo_close_instance("rt-family"); } xo_close_list("rt-family"); xo_close_container("route-table"); free(buf); } static void p_rtentry_sysctl(const char *name, struct rt_msghdr *rtm) { struct sockaddr *sa = (struct sockaddr *)(rtm + 1); char buffer[128]; char prettyname[128]; sa_u addr, mask, gw; unsigned int l; xo_open_instance(name); #define GETSA(_s, _f) { \ bzero(&(_s), sizeof(_s)); \ if (rtm->rtm_addrs & _f) { \ l = roundup(sa->sa_len, sizeof(long)); \ memcpy(&(_s), sa, (l > sizeof(_s)) ? sizeof(_s) : l); \ sa = (struct sockaddr *)((char *)sa + l); \ } \ } GETSA(addr, RTA_DST); GETSA(gw, RTA_GATEWAY); GETSA(mask, RTA_NETMASK); p_sockaddr("destination", &addr.u_sa, &mask.u_sa, rtm->rtm_flags, wid_dst); p_sockaddr("gateway", &gw.u_sa, NULL, RTF_HOST, wid_gw); snprintf(buffer, sizeof(buffer), "{[:-%d}{:flags/%%s}{]:}", wid_flags); p_flags(rtm->rtm_flags, buffer); if (Wflag) { xo_emit("{t:use/%*lu} ", wid_pksent, rtm->rtm_rmx.rmx_pksent); if (rtm->rtm_rmx.rmx_mtu != 0) xo_emit("{t:mtu/%*lu} ", wid_mtu, rtm->rtm_rmx.rmx_mtu); else xo_emit("{P:/%*s} ", wid_mtu, ""); } memset(prettyname, 0, sizeof(prettyname)); if (rtm->rtm_index < ifmap_size) { strlcpy(prettyname, ifmap[rtm->rtm_index].ifname, sizeof(prettyname)); if (*prettyname == '\0') strlcpy(prettyname, "---", sizeof(prettyname)); } xo_emit("{t:interface-name/%*.*s}", wid_if, wid_if, prettyname); if (rtm->rtm_rmx.rmx_expire) { time_t expire_time; if ((expire_time = rtm->rtm_rmx.rmx_expire - uptime.tv_sec) > 0) xo_emit(" {:expire-time/%*d}", wid_expire, (int)expire_time); } xo_emit("\n"); xo_close_instance(name); } static void p_sockaddr(const char *name, struct sockaddr *sa, struct sockaddr *mask, int flags, int width) { const char *cp; char buf[128]; cp = fmt_sockaddr(sa, mask, flags); if (width < 0) { snprintf(buf, sizeof(buf), "{:%s/%%s} ", name); xo_emit(buf, cp); } else { if (numeric_addr) { snprintf(buf, sizeof(buf), "{[:%d}{:%s/%%s}{]:} ", -width, name); xo_emit(buf, cp); } else { snprintf(buf, sizeof(buf), "{[:%d}{:%s/%%-.*s}{]:} ", -width, name); xo_emit(buf, width, cp); } } } static const char * fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags) { static char workbuf[128]; const char *cp; if (sa == NULL) return ("null"); switch(sa->sa_family) { case AF_INET: { struct sockaddr_in *sockin = (struct sockaddr_in *)sa; if ((sockin->sin_addr.s_addr == INADDR_ANY) && mask && ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr) ==0L) cp = "default" ; else if (flags & RTF_HOST) cp = routename(sockin->sin_addr.s_addr); else if (mask) cp = netname(sockin->sin_addr.s_addr, ((struct sockaddr_in *)mask)->sin_addr.s_addr); else cp = netname(sockin->sin_addr.s_addr, INADDR_ANY); break; } #ifdef INET6 case AF_INET6: { struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; /* * The sa6->sin6_scope_id must be filled here because * this sockaddr is extracted from kmem(4) directly * and has KAME-specific embedded scope id in * sa6->sin6_addr.s6_addr[2]. */ in6_fillscopeid(sa6); if (flags & RTF_HOST) cp = routename6(sa6); else if (mask) cp = netname6(sa6, &((struct sockaddr_in6 *)mask)->sin6_addr); else { cp = netname6(sa6, NULL); } break; } #endif /*INET6*/ case AF_NETGRAPH: { strlcpy(workbuf, ((struct sockaddr_ng *)sa)->sg_data, sizeof(workbuf)); cp = workbuf; break; } case AF_LINK: { struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && sdl->sdl_slen == 0) { (void) sprintf(workbuf, "link#%d", sdl->sdl_index); cp = workbuf; } else switch (sdl->sdl_type) { case IFT_ETHER: case IFT_L2VLAN: case IFT_BRIDGE: if (sdl->sdl_alen == ETHER_ADDR_LEN) { cp = ether_ntoa((struct ether_addr *) (sdl->sdl_data + sdl->sdl_nlen)); break; } /* FALLTHROUGH */ default: cp = link_ntoa(sdl); break; } break; } default: { u_char *s = (u_char *)sa->sa_data, *slim; char *cq, *cqlim; cq = workbuf; slim = sa->sa_len + (u_char *) sa; cqlim = cq + sizeof(workbuf) - 6; cq += sprintf(cq, "(%d)", sa->sa_family); while (s < slim && cq < cqlim) { cq += sprintf(cq, " %02x", *s++); if (s < slim) cq += sprintf(cq, "%02x", *s++); } cp = workbuf; } } return (cp); } static void p_flags(int f, const char *format) { struct bits *p; xo_emit(format, fmt_flags(f)); xo_open_list("flags_pretty"); for (p = bits; p->b_mask; p++) if (p->b_mask & f) xo_emit("{le:flags_pretty/%s}", p->b_name); xo_close_list("flags_pretty"); } static const char * fmt_flags(int f) { static char name[33]; char *flags; struct bits *p = bits; for (flags = name; p->b_mask; p++) if (p->b_mask & f) *flags++ = p->b_val; *flags = '\0'; return (name); } char * routename(in_addr_t in) { char *cp; static char line[MAXHOSTNAMELEN]; struct hostent *hp; cp = 0; if (!numeric_addr) { hp = gethostbyaddr(&in, sizeof (struct in_addr), AF_INET); if (hp) { cp = hp->h_name; trimdomain(cp, strlen(cp)); } } if (cp) { strlcpy(line, cp, sizeof(line)); } else { #define C(x) ((x) & 0xff) in = ntohl(in); sprintf(line, "%u.%u.%u.%u", C(in >> 24), C(in >> 16), C(in >> 8), C(in)); } return (line); } #define NSHIFT(m) ( \ (m) == IN_CLASSA_NET ? IN_CLASSA_NSHIFT : \ (m) == IN_CLASSB_NET ? IN_CLASSB_NSHIFT : \ (m) == IN_CLASSC_NET ? IN_CLASSC_NSHIFT : \ 0) static void domask(char *dst, in_addr_t addr __unused, u_long mask) { int b, i; if (mask == 0 || (!numeric_addr && NSHIFT(mask) != 0)) { *dst = '\0'; return; } i = 0; for (b = 0; b < 32; b++) if (mask & (1 << b)) { int bb; i = b; for (bb = b+1; bb < 32; bb++) if (!(mask & (1 << bb))) { i = -1; /* noncontig */ break; } break; } if (i == -1) sprintf(dst, "&0x%lx", mask); else sprintf(dst, "/%d", 32-i); } /* * Return the name of the network whose address is given. */ char * netname(in_addr_t in, in_addr_t mask) { char *cp = 0; static char line[MAXHOSTNAMELEN]; struct netent *np = 0; in_addr_t i; /* It is ok to supply host address. */ in &= mask; i = ntohl(in); if (!numeric_addr && i) { np = getnetbyaddr(i >> NSHIFT(ntohl(mask)), AF_INET); if (np != NULL) { cp = np->n_name; trimdomain(cp, strlen(cp)); } } if (cp != NULL) { strlcpy(line, cp, sizeof(line)); } else { inet_ntop(AF_INET, &in, line, sizeof(line) - 1); } domask(line + strlen(line), i, ntohl(mask)); return (line); } #undef NSHIFT #ifdef INET6 void in6_fillscopeid(struct sockaddr_in6 *sa6) { #if defined(__KAME__) /* * XXX: This is a special workaround for KAME kernels. * sin6_scope_id field of SA should be set in the future. */ if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) || IN6_IS_ADDR_MC_NODELOCAL(&sa6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) { if (sa6->sin6_scope_id == 0) sa6->sin6_scope_id = ntohs(*(u_int16_t *)&sa6->sin6_addr.s6_addr[2]); sa6->sin6_addr.s6_addr[2] = sa6->sin6_addr.s6_addr[3] = 0; } #endif } const char * netname6(struct sockaddr_in6 *sa6, struct in6_addr *mask) { static char line[MAXHOSTNAMELEN]; u_char *p = (u_char *)mask; u_char *lim; int masklen, illegal = 0, flag = 0; if (mask) { for (masklen = 0, lim = p + 16; p < lim; p++) { switch (*p) { case 0xff: masklen += 8; break; case 0xfe: masklen += 7; break; case 0xfc: masklen += 6; break; case 0xf8: masklen += 5; break; case 0xf0: masklen += 4; break; case 0xe0: masklen += 3; break; case 0xc0: masklen += 2; break; case 0x80: masklen += 1; break; case 0x00: break; default: illegal ++; break; } } if (illegal) xo_error("illegal prefixlen\n"); } else masklen = 128; if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr)) return("default"); if (numeric_addr) flag |= NI_NUMERICHOST; getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line), NULL, 0, flag); if (numeric_addr) sprintf(&line[strlen(line)], "/%d", masklen); return line; } char * routename6(struct sockaddr_in6 *sa6) { static char line[MAXHOSTNAMELEN]; int flag = 0; /* use local variable for safety */ struct sockaddr_in6 sa6_local; sa6_local.sin6_family = AF_INET6; sa6_local.sin6_len = sizeof(sa6_local); sa6_local.sin6_addr = sa6->sin6_addr; sa6_local.sin6_scope_id = sa6->sin6_scope_id; if (numeric_addr) flag |= NI_NUMERICHOST; getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len, line, sizeof(line), NULL, 0, flag); return line; } #endif /*INET6*/ /* * Print routing statistics */ void rt_stats(void) { struct rtstat rtstat; u_long rtsaddr, rttaddr; int rttrash; kresolve_list(rl); if ((rtsaddr = rl[N_RTSTAT].n_value) == 0) { xo_emit("{W:rtstat: symbol not in namelist}\n"); return; } if ((rttaddr = rl[N_RTTRASH].n_value) == 0) { xo_emit("{W:rttrash: symbol not in namelist}\n"); return; } kread(rtsaddr, (char *)&rtstat, sizeof (rtstat)); kread(rttaddr, (char *)&rttrash, sizeof (rttrash)); xo_emit("{T:routing}:\n"); #define p(f, m) if (rtstat.f || sflag <= 1) \ xo_emit(m, rtstat.f, plural(rtstat.f)) p(rts_badredirect, "\t{:bad-redirects/%hu} " "{N:/bad routing redirect%s}\n"); p(rts_dynamic, "\t{:dynamically-created/%hu} " "{N:/dynamically created route%s}\n"); p(rts_newgateway, "\t{:new-gateways/%hu} " "{N:/new gateway%s due to redirects}\n"); p(rts_unreach, "\t{:unreachable-destination/%hu} " "{N:/destination%s found unreachable}\n"); p(rts_wildcard, "\t{:wildcard-uses/%hu} " "{N:/use%s of a wildcard route}\n"); #undef p if (rttrash || sflag <= 1) xo_emit("\t{:unused-but-not-freed/%u} " "{N:/route%s not in table but not freed}\n", rttrash, plural(rttrash)); } Index: projects/ci20_mips/usr.bin/ssh-copy-id/ssh-copy-id.sh =================================================================== --- projects/ci20_mips/usr.bin/ssh-copy-id/ssh-copy-id.sh (revision 283030) +++ projects/ci20_mips/usr.bin/ssh-copy-id/ssh-copy-id.sh (revision 283031) @@ -1,117 +1,117 @@ #!/bin/sh #- # Copyright (c) 2012 Eitan Adler # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer # in this position and unchanged. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ usage() { echo "usage: ssh-copy-id [-lv] [-i keyfile] [-o option] [-p port] [user@]hostname" >&2 exit 1 } sendkey() { local h="$1" local k="$2" printf "%s\n" "$k" | ssh $port -S none $options "$user$h" /bin/sh -c \'' \ set -e; \ umask 077; \ keyfile=$HOME/.ssh/authorized_keys ; \ mkdir -p -- "$HOME/.ssh/" ; \ while read alg key comment ; do \ [ -n "$key" ] || continue; \ if ! grep -sqwF "$key" "$keyfile"; then \ printf "$alg $key $comment\n" >> "$keyfile" ; \ fi ; \ done ; \ if [ -x /sbin/restorecon ]; then \ /sbin/restorecon -F "$HOME/.ssh/" "$keyfile" >/dev/null 2>&1 || true ; \ - fi + fi \ '\' } agentKeys() { keys="$(ssh-add -L | grep -v 'The agent has no identities.')$nl$keys" } keys="" host="" hasarg="" user="" port="" nl=" " options="" IFS=$nl while getopts 'i:lo:p:v' arg; do case $arg in i) hasarg="x" if [ -r "${OPTARG}.pub" ]; then keys="$(cat -- "${OPTARG}.pub")$nl$keys" elif [ -r "$OPTARG" ]; then keys="$(cat -- "$OPTARG")$nl$keys" else echo "File $OPTARG not found" >&2 exit 1 fi ;; l) hasarg="x" agentKeys ;; p) port=-p$nl$OPTARG ;; o) options=$options$nl-o$nl$OPTARG ;; v) options="$options$nl-v" ;; *) usage ;; esac done >&2 shift $((OPTIND-1)) if [ -z "$hasarg" ]; then agentKeys fi if [ -z "$keys" ] || [ "$keys" = "$nl" ]; then echo "no keys found" >&2 exit 1 fi if [ "$#" -eq 0 ]; then usage fi for host in "$@"; do sendkey "$host" "$keys" done Index: projects/ci20_mips/usr.sbin/bsdinstall/scripts/zfsboot =================================================================== --- projects/ci20_mips/usr.sbin/bsdinstall/scripts/zfsboot (revision 283030) +++ projects/ci20_mips/usr.sbin/bsdinstall/scripts/zfsboot (revision 283031) @@ -1,1606 +1,1610 @@ #!/bin/sh #- # Copyright (c) 2013-2014 Allan Jude # Copyright (c) 2013-2015 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # ############################################################ INCLUDES BSDCFG_SHARE="/usr/share/bsdconfig" . $BSDCFG_SHARE/common.subr || exit 1 f_dprintf "%s: loading includes..." "$0" f_include $BSDCFG_SHARE/device.subr f_include $BSDCFG_SHARE/dialog.subr f_include $BSDCFG_SHARE/password/password.subr f_include $BSDCFG_SHARE/variable.subr ############################################################ CONFIGURATION # # Default name of the boot-pool # : ${ZFSBOOT_POOL_NAME:=zroot} # # Default options to use when creating zroot pool # : ${ZFSBOOT_POOL_CREATE_OPTIONS:=-O compress=lz4 -O atime=off} # # Default name for the boot environment parent dataset # : ${ZFSBOOT_BEROOT_NAME:=ROOT} # # Default name for the primany boot environment # : ${ZFSBOOT_BOOTFS_NAME:=default} # # Default Virtual Device (vdev) type to create # : ${ZFSBOOT_VDEV_TYPE:=stripe} # # Should we use sysctl(8) vfs.zfs.min_auto_ashift=12 to force 4K sectors? # : ${ZFSBOOT_FORCE_4K_SECTORS:=1} # # Should we use geli(8) to encrypt the drives? # NB: Automatically enables ZFSBOOT_BOOT_POOL # : ${ZFSBOOT_GELI_ENCRYPTION=} # # Default path to the geli(8) keyfile used in drive encryption # : ${ZFSBOOT_GELI_KEY_FILE:=/boot/encryption.key} # # Create a separate boot pool? # NB: Automatically set when using geli(8) or MBR # : ${ZFSBOOT_BOOT_POOL=} # # Options to use when creating separate boot pool (if any) # : ${ZFSBOOT_BOOT_POOL_CREATE_OPTIONS:=} # # Default name for boot pool when enabled (e.g., geli(8) or MBR) # : ${ZFSBOOT_BOOT_POOL_NAME:=bootpool} # # Default size for boot pool when enabled (e.g., geli(8) or MBR) # : ${ZFSBOOT_BOOT_POOL_SIZE:=2g} # # Default disks to use (always empty unless being scripted) # : ${ZFSBOOT_DISKS:=} # # Default partitioning scheme to use on disks # : ${ZFSBOOT_PARTITION_SCHEME:=GPT} # # How much swap to put on each block device in the boot zpool # NOTE: Value passed to gpart(8); which supports SI unit suffixes. # : ${ZFSBOOT_SWAP_SIZE:=2g} # # Should we use geli(8) to encrypt the swap? # : ${ZFSBOOT_SWAP_ENCRYPTION=} # # Should we use gmirror(8) to mirror the swap? # : ${ZFSBOOT_SWAP_MIRROR=} # # Default ZFS datasets for root zpool # # NOTE: Requires /tmp, /var/tmp, /$ZFSBOOT_BOOTFS_NAME/$ZFSBOOT_BOOTFS_NAME # NOTE: Anything after pound/hash character [#] is ignored as a comment. # f_isset ZFSBOOT_DATASETS || ZFSBOOT_DATASETS=" # DATASET OPTIONS (comma or space separated; or both) # Boot Environment [BE] root and default boot dataset /$ZFSBOOT_BEROOT_NAME mountpoint=none /$ZFSBOOT_BEROOT_NAME/$ZFSBOOT_BOOTFS_NAME mountpoint=/ # Compress /tmp, allow exec but not setuid /tmp mountpoint=/tmp,exec=on,setuid=off # Don't mount /usr so that 'base' files go to the BEROOT /usr mountpoint=/usr,canmount=off # Home directories separated so they are common to all BEs /usr/home # NB: /home is a symlink to /usr/home # Ports tree /usr/ports setuid=off # Source tree (compressed) /usr/src # Create /var and friends /var mountpoint=/var,canmount=off /var/crash exec=off,setuid=off /var/log exec=off,setuid=off /var/mail atime=on /var/tmp setuid=off " # END-QUOTE # # If interactive and the user has not explicitly chosen a vdev type or disks, # make the user confirm scripted/default choices when proceeding to install. # : ${ZFSBOOT_CONFIRM_LAYOUT:=1} ############################################################ GLOBALS # # Format of a line in printf(1) syntax to add to fstab(5) # FSTAB_FMT="%s\t\t%s\t%s\t%s\t\t%s\t%s\n" # # Command strings for various tasks # CHMOD_MODE='chmod %s "%s"' DD_WITH_OPTIONS='dd if="%s" of="%s" %s' ECHO_APPEND='echo "%s" >> "%s"' GELI_ATTACH='geli attach -j - -k "%s" "%s"' GELI_DETACH_F='geli detach -f "%s"' GELI_PASSWORD_INIT='geli init -b -B "%s" -e %s -J - -K "%s" -l 256 -s 4096 "%s"' GPART_ADD='gpart add -t %s "%s"' GPART_ADD_INDEX='gpart add -i %s -t %s "%s"' GPART_ADD_INDEX_WITH_SIZE='gpart add -i %s -t %s -s %s "%s"' GPART_ADD_LABEL='gpart add -l %s -t %s "%s"' GPART_ADD_LABEL_WITH_SIZE='gpart add -l %s -t %s -s %s "%s"' GPART_BOOTCODE='gpart bootcode -b "%s" "%s"' GPART_BOOTCODE_PART='gpart bootcode -b "%s" -p "%s" -i %s "%s"' GPART_CREATE='gpart create -s %s "%s"' GPART_DESTROY_F='gpart destroy -F "%s"' GPART_SET_ACTIVE='gpart set -a active -i %s "%s"' GRAID_DELETE='graid delete "%s"' LN_SF='ln -sf "%s" "%s"' MKDIR_P='mkdir -p "%s"' MOUNT_TYPE='mount -t %s "%s" "%s"' PRINTF_CONF="printf '%s=\"%%s\"\\\n' %s >> \"%s\"" PRINTF_FSTAB='printf "$FSTAB_FMT" "%s" "%s" "%s" "%s" "%s" "%s" >> "%s"' SHELL_TRUNCATE=':> "%s"' SWAP_GMIRROR_LABEL='gmirror label swap %s' SYSCTL_ZFS_MIN_ASHIFT_12='sysctl vfs.zfs.min_auto_ashift=12' UMOUNT='umount "%s"' ZFS_CREATE_WITH_OPTIONS='zfs create %s "%s"' ZFS_SET='zfs set "%s" "%s"' ZFS_UNMOUNT='zfs unmount "%s"' ZPOOL_CREATE_WITH_OPTIONS='zpool create %s "%s" %s %s' ZPOOL_DESTROY='zpool destroy "%s"' ZPOOL_EXPORT='zpool export "%s"' ZPOOL_IMPORT_WITH_OPTIONS='zpool import %s "%s"' ZPOOL_LABELCLEAR_F='zpool labelclear -f "%s"' ZPOOL_SET='zpool set %s "%s"' # # Strings that should be moved to an i18n file and loaded with f_include_lang() # hline_alnum_arrows_punc_tab_enter="Use alnum, arrows, punctuation, TAB or ENTER" hline_arrows_space_tab_enter="Use arrows, SPACE, TAB or ENTER" hline_arrows_tab_enter="Press arrows, TAB or ENTER" msg_an_unknown_error_occurred="An unknown error occurred" msg_back="Back" msg_cancel="Cancel" msg_change_selection="Change Selection" msg_configure_options="Configure Options:" msg_detailed_disk_info="gpart(8) show %s:\n%s\n\ncamcontrol(8) inquiry %s:\n%s\n\n\ncamcontrol(8) identify %s:\n%s\n" msg_disk_info="Disk Info" msg_disk_info_help="Get detailed information on disk device(s)" msg_disk_singular="disk" msg_disk_plural="disks" msg_encrypt_disks="Encrypt Disks?" msg_encrypt_disks_help="Use geli(8) to encrypt all data partitions" msg_error="Error" msg_force_4k_sectors="Force 4K Sectors?" msg_force_4k_sectors_help="Use sysctl(8) vfs.zfs.min_auto_ashift=12 to force 4K sectors" msg_freebsd_installer="FreeBSD Installer" msg_geli_password="Enter a strong passphrase, used to protect your encryption keys. You will be required to enter this passphrase each time the system is booted" msg_geli_setup="Initializing encryption on selected disks,\n this will take several seconds per disk" msg_install="Install" msg_install_desc="Proceed with Installation" msg_install_help="Create ZFS boot pool with displayed options" msg_invalid_boot_pool_size="Invalid boot pool size \`%s'" msg_invalid_disk_argument="Invalid disk argument \`%s'" msg_invalid_index_argument="Invalid index argument \`%s'" msg_invalid_swap_size="Invalid swap size \`%s'" msg_invalid_virtual_device_type="Invalid Virtual Device type \`%s'" msg_last_chance_are_you_sure="Last Chance! Are you sure you want to destroy\nthe current contents of the following disks:\n\n %s" msg_last_chance_are_you_sure_color='\\ZrLast Chance!\\ZR Are you \\Z1sure\\Zn you want to \\Zr\\Z1destroy\\Zn\nthe current contents of the following disks:\n\n %s' msg_mirror_desc="Mirror - n-Way Mirroring" msg_mirror_help="[2+ Disks] Mirroring provides the best performance, but the least storage" msg_missing_disk_arguments="missing disk arguments" msg_missing_one_or_more_scripted_disks="Missing one or more scripted disks!" msg_no="NO" msg_no_disks_present_to_configure="No disk(s) present to configure" msg_no_disks_selected="No disks selected." msg_not_enough_disks_selected="Not enough disks selected. (%u < %u minimum)" msg_null_disk_argument="NULL disk argument" msg_null_index_argument="NULL index argument" msg_null_poolname="NULL poolname" msg_ok="OK" msg_partition_scheme="Partition Scheme" msg_partition_scheme_help="Toggle between GPT and MBR partitioning schemes" msg_please_enter_a_name_for_your_zpool="Please enter a name for your zpool:" msg_please_enter_amount_of_swap_space="Please enter amount of swap space (SI-Unit suffixes\nrecommended; e.g., \`2g' for 2 Gigabytes):" msg_please_select_one_or_more_disks="Please select one or more disks to create a zpool:" msg_pool_name="Pool Name" msg_pool_name_cannot_be_empty="Pool name cannot be empty." msg_pool_name_help="Customize the name of the zpool to be created (Required)" msg_pool_type_disks="Pool Type/Disks:" msg_pool_type_disks_help="Choose type of ZFS Virtual Device and disks to use (Required)" msg_processing_selection="Processing selection..." msg_raidz1_desc="RAID-Z1 - Single Redundant RAID" msg_raidz1_help="[3+ Disks] Withstand failure of 1 disk. Recommended for: 3, 5 or 9 disks" msg_raidz2_desc="RAID-Z2 - Double Redundant RAID" msg_raidz2_help="[4+ Disks] Withstand failure of 2 disks. Recommended for: 4, 6 or 10 disks" msg_raidz3_desc="RAID-Z3 - Triple Redundant RAID" msg_raidz3_help="[5+ Disks] Withstand failure of 3 disks. Recommended for: 5, 7 or 11 disks" msg_rescan_devices="Rescan Devices" msg_rescan_devices_help="Scan for device changes" msg_select="Select" msg_select_a_disk_device="Select a disk device" msg_select_virtual_device_type="Select Virtual Device type:" msg_stripe_desc="Stripe - No Redundancy" msg_stripe_help="[1+ Disks] Striping provides maximum storage but no redundancy" msg_swap_encrypt="Encrypt Swap?" msg_swap_encrypt_help="Encrypt swap partitions with temporary keys, discarded on reboot" msg_swap_invalid="The selected swap size (%s) is invalid. Enter a number optionally followed by units. Example: 2G" msg_swap_mirror="Mirror Swap?" msg_swap_mirror_help="Mirror swap partitions for redundancy, breaks crash dumps" msg_swap_size="Swap Size" msg_swap_size_help="Customize how much swap space is allocated to each selected disk" msg_swap_toosmall="The selected swap size (%s) is to small. Please enter a value greater than 100MB or enter 0 for no swap" msg_these_disks_are_too_small="These disks are too small given the amount of requested\nswap (%s) and/or geli(8) (%s) partitions, which would\ntake 50%% or more of each of the following selected disk\ndevices (not recommended):\n\n %s\n\nRecommend changing partition size(s) and/or selecting a\ndifferent set of devices." msg_uefi_not_supported="The FreeBSD UEFI loader does not currently support booting root-on-ZFS. Your system will need to boot in legacy (CSM) mode.\nDo you want to continue?" msg_unable_to_get_disk_capacity="Unable to get disk capacity of \`%s'" msg_unsupported_partition_scheme="%s is an unsupported partition scheme" msg_user_cancelled="User Cancelled." msg_yes="YES" msg_zfs_configuration="ZFS Configuration" ############################################################ FUNCTIONS # dialog_menu_main # # Display the dialog(1)-based application main menu. # dialog_menu_main() { local title="$DIALOG_TITLE" local btitle="$DIALOG_BACKTITLE" local prompt="$msg_configure_options" local force4k="$msg_no" local usegeli="$msg_no" local swapgeli="$msg_no" local swapmirror="$msg_no" [ "$ZFSBOOT_FORCE_4K_SECTORS" ] && force4k="$msg_yes" [ "$ZFSBOOT_GELI_ENCRYPTION" ] && usegeli="$msg_yes" [ "$ZFSBOOT_SWAP_ENCRYPTION" ] && swapgeli="$msg_yes" [ "$ZFSBOOT_SWAP_MIRROR" ] && swapmirror="$msg_yes" local disks n disks_grammar f_count n $ZFSBOOT_DISKS { [ $n -eq 1 ] && disks_grammar=$msg_disk_singular; } || disks_grammar=$msg_disk_plural # grammar local menu_list=" '>>> $msg_install' '$msg_install_desc' '$msg_install_help' 'T $msg_pool_type_disks' '$ZFSBOOT_VDEV_TYPE: $n $disks_grammar' '$msg_pool_type_disks_help' '- $msg_rescan_devices' '*' '$msg_rescan_devices_help' '- $msg_disk_info' '*' '$msg_disk_info_help' 'N $msg_pool_name' '$ZFSBOOT_POOL_NAME' '$msg_pool_name_help' '4 $msg_force_4k_sectors' '$force4k' '$msg_force_4k_sectors_help' 'E $msg_encrypt_disks' '$usegeli' '$msg_encrypt_disks_help' 'P $msg_partition_scheme' '$ZFSBOOT_PARTITION_SCHEME' '$msg_partition_scheme_help' 'S $msg_swap_size' '$ZFSBOOT_SWAP_SIZE' '$msg_swap_size_help' 'M $msg_swap_mirror' '$swapmirror' '$msg_swap_mirror_help' 'W $msg_swap_encrypt' '$swapgeli' '$msg_swap_encrypt_help' " # END-QUOTE local defaultitem= # Calculated below local hline="$hline_alnum_arrows_punc_tab_enter" local height width rows eval f_dialog_menu_with_help_size height width rows \ \"\$title\" \"\$btitle\" \"\$prompt\" \"\$hline\" $menu_list # Obtain default-item from previously stored selection f_dialog_default_fetch defaultitem local menu_choice menu_choice=$( eval $DIALOG \ --title \"\$title\" \ --backtitle \"\$btitle\" \ --hline \"\$hline\" \ --item-help \ --ok-label \"\$msg_select\" \ --cancel-label \"\$msg_cancel\" \ --default-item \"\$defaultitem\" \ --menu \"\$prompt\" \ $height $width $rows \ $menu_list \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) local retval=$? f_dialog_data_sanitize menu_choice f_dialog_menutag_store "$menu_choice" # Only update default-item on success [ $retval -eq $DIALOG_OK ] && f_dialog_default_store "$menu_choice" return $retval } # dialog_last_chance $disks ... # # Display a list of the disks that the user is about to destroy. The default # action is to return error status unless the user explicitly (non-default) # selects "Yes" from the noyes dialog. # dialog_last_chance() { local title="$DIALOG_TITLE" local btitle="$DIALOG_BACKTITLE" local prompt # Calculated below local hline="$hline_arrows_tab_enter" local height=8 width=50 prefix=" " local plen=${#prefix} list= line= local max_width=$(( $width - 3 - $plen )) local yes no defaultno extra_args format if [ "$USE_XDIALOG" ]; then yes=ok no=cancel defaultno=default-no extra_args="--wrap --left" format="$msg_last_chance_are_you_sure" else yes=yes no=no defaultno=defaultno extra_args="--colors --cr-wrap" format="$msg_last_chance_are_you_sure_color" fi local disk line_width for disk in $*; do if [ "$line" ]; then line_width=${#line} else line_width=$plen fi line_width=$(( $line_width + 1 + ${#disk} )) # Add newline before disk if it would exceed max_width if [ $line_width -gt $max_width ]; then list="$list$line\n" line="$prefix" height=$(( $height + 1 )) fi # Add the disk to the list line="$line $disk" done # Append the left-overs if [ "${line#$prefix}" ]; then list="$list$line" height=$(( $height + 1 )) fi # Add height for Xdialog(1) [ "$USE_XDIALOG" ] && height=$(( $height + $height / 5 + 3 )) prompt=$( printf "$format" "$list" ) f_dprintf "%s: Last Chance!" "$0" $DIALOG \ --title "$title" \ --backtitle "$btitle" \ --hline "$hline" \ --$defaultno \ --$yes-label "$msg_yes" \ --$no-label "$msg_no" \ $extra_args \ --yesno "$prompt" $height $width } # dialog_menu_layout # # Configure Virtual Device type and disks to use for the ZFS boot pool. User # must select enough disks to satisfy the chosen vdev type. # dialog_menu_layout() { local funcname=dialog_menu_layout local title="$DIALOG_TITLE" local btitle="$DIALOG_BACKTITLE" local vdev_prompt="$msg_select_virtual_device_type" local disk_prompt="$msg_please_select_one_or_more_disks" local vdev_menu_list=" 'stripe' '$msg_stripe_desc' '$msg_stripe_help' 'mirror' '$msg_mirror_desc' '$msg_mirror_help' 'raidz1' '$msg_raidz1_desc' '$msg_raidz1_help' 'raidz2' '$msg_raidz2_desc' '$msg_raidz2_help' 'raidz3' '$msg_raidz3_desc' '$msg_raidz3_help' " # END-QUOTE local disk_check_list= # Calculated below local vdev_hline="$hline_arrows_tab_enter" local disk_hline="$hline_arrows_space_tab_enter" # Warn the user if vdev type is not valid case "$ZFSBOOT_VDEV_TYPE" in stripe|mirror|raidz1|raidz2|raidz3) : known good ;; *) f_dprintf "%s: Invalid virtual device type \`%s'" \ $funcname "$ZFSBOOT_VDEV_TYPE" f_show_err "$msg_invalid_virtual_device_type" \ "$ZFSBOOT_VDEV_TYPE" f_interactive || return $FAILURE esac # Calculate size of vdev menu once only local vheight vwidth vrows eval f_dialog_menu_with_help_size vheight vwidth vrows \ \"\$title\" \"\$btitle\" \"\$vdev_prompt\" \"\$vdev_hline\" \ $vdev_menu_list # Get a list of probed disk devices local disks= debug= f_device_find "" $DEVICE_TYPE_DISK disks # Prune out mounted md(4) devices that may be part of the boot process local disk name new_list= for disk in $disks; do debug= $disk get name name case "$name" in md[0-9]*) f_mounted -b "/dev/$name" && continue ;; esac new_list="$new_list $disk" done disks="${new_list# }" # Debugging if [ "$debug" ]; then local disk_names= for disk in $disks; do debug= $disk get name name disk_names="$disk_names $name" done f_dprintf "$funcname: disks=[%s]" "${disk_names# }" fi if [ ! "$disks" ]; then f_dprintf "No disk(s) present to configure" f_show_err "$msg_no_disks_present_to_configure" return $FAILURE fi # Lets sort the disks array to be more user friendly f_device_sort_by name disks disks # # Operate in a loop so we can (if interactive) repeat if not enough # disks are selected to satisfy the chosen vdev type or user wants to # back-up to the previous menu. # local vardisk ndisks onoff selections vdev_choice breakout device local valid_disks all_valid want_disks desc height width rows while :; do # # Confirm the vdev type that was selected # if f_interactive && [ "$ZFSBOOT_CONFIRM_LAYOUT" ]; then vdev_choice=$( eval $DIALOG \ --title \"\$title\" \ --backtitle \"\$btitle\" \ --hline \"\$vdev_hline\" \ --ok-label \"\$msg_ok\" \ --cancel-label \"\$msg_cancel\" \ --item-help \ --default-item \"\$ZFSBOOT_VDEV_TYPE\" \ --menu \"\$vdev_prompt\" \ $vheight $vwidth $vrows \ $vdev_menu_list \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) || return $? # Exit if user pressed ESC or chose Cancel/No f_dialog_data_sanitize vdev_choice ZFSBOOT_VDEV_TYPE="$vdev_choice" f_dprintf "$funcname: ZFSBOOT_VDEV_TYPE=[%s]" \ "$ZFSBOOT_VDEV_TYPE" fi # Determine the number of disks needed for this vdev type want_disks=0 case "$ZFSBOOT_VDEV_TYPE" in stripe) want_disks=1 ;; mirror) want_disks=2 ;; raidz1) want_disks=3 ;; raidz2) want_disks=4 ;; raidz3) want_disks=5 ;; esac # # Warn the user if any scripted disks are invalid # valid_disks= all_valid=${ZFSBOOT_DISKS:+1} # optimism for disk in $ZFSBOOT_DISKS; do if debug= f_device_find -1 \ $disk $DEVICE_TYPE_DISK device then valid_disks="$valid_disks $disk" continue fi f_dprintf "$funcname: \`%s' is not a real disk" "$disk" all_valid= done if [ ! "$all_valid" ]; then if [ "$ZFSBOOT_DISKS" ]; then f_show_err \ "$msg_missing_one_or_more_scripted_disks" else f_dprintf "No disks selected." f_interactive || f_show_err "$msg_no_disks_selected" fi f_interactive || return $FAILURE fi ZFSBOOT_DISKS="${valid_disks# }" # # Short-circuit if we're running non-interactively # if ! f_interactive || [ ! "$ZFSBOOT_CONFIRM_LAYOUT" ]; then f_count ndisks $ZFSBOOT_DISKS [ $ndisks -ge $want_disks ] && break # to success # Not enough disks selected f_dprintf "$funcname: %s: %s (%u < %u minimum)" \ "$ZFSBOOT_VDEV_TYPE" \ "Not enough disks selected." \ $ndisks $want_disks f_interactive || return $FAILURE msg_yes="$msg_change_selection" msg_no="$msg_cancel" \ f_yesno "%s: $msg_not_enough_disks_selected" \ "$ZFSBOOT_VDEV_TYPE" $ndisks $want_disks || return $FAILURE fi # # Confirm the disks that were selected # Loop until the user cancels or selects enough disks # breakout= while :; do # Loop over list of available disks, resetting state for disk in $disks; do f_isset _${disk}_status && _${disk}_status= done # Loop over list of selected disks and create temporary # locals to map statuses onto up-to-date list of disks for disk in $ZFSBOOT_DISKS; do debug= f_device_find -1 \ $disk $DEVICE_TYPE_DISK disk f_isset _${disk}_status || local _${disk}_status _${disk}_status=on done # Create the checklist menu of discovered disk devices disk_check_list= for disk in $disks; do desc= $disk get name name $disk get desc desc f_shell_escape "$desc" desc f_getvar _${disk}_status:-off onoff disk_check_list="$disk_check_list $name '$desc' $onoff" done eval f_dialog_checklist_size height width rows \ \"\$title\" \"\$btitle\" \"\$prompt\" \ \"\$hline\" $disk_check_list selections=$( eval $DIALOG \ --title \"\$DIALOG_TITLE\" \ --backtitle \"\$DIALOG_BACKTITLE\" \ --separate-output \ --hline \"\$hline\" \ --ok-label \"\$msg_ok\" \ --cancel-label \"\$msg_back\" \ --checklist \"\$prompt\" \ $height $width $rows \ $disk_check_list \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) || break # Loop if user pressed ESC or chose Cancel/No f_dialog_data_sanitize selections ZFSBOOT_DISKS="$selections" f_dprintf "$funcname: ZFSBOOT_DISKS=[%s]" \ "$ZFSBOOT_DISKS" f_count ndisks $ZFSBOOT_DISKS [ $ndisks -ge $want_disks ] && breakout=break && break # Not enough disks selected f_dprintf "$funcname: %s: %s (%u < %u minimum)" \ "$ZFSBOOT_VDEV_TYPE" \ "Not enough disks selected." \ $ndisks $want_disks msg_yes="$msg_change_selection" msg_no="$msg_cancel" \ f_yesno "%s: $msg_not_enough_disks_selected" \ "$ZFSBOOT_VDEV_TYPE" $ndisks $want_disks || break done [ "$breakout" = "break" ] && break [ "$ZFSBOOT_CONFIRM_LAYOUT" ] || return $FAILURE done return $DIALOG_OK } # dialog_uefi_prompt # # Confirm that the user wants to continue with the installation on a BIOS # system when they have booted with UEFI # dialog_uefi_prompt() { local title="$DIALOG_TITLE" local btitle="$DIALOG_BACKTITLE" local prompt # Calculated below local hline="$hline_arrows_tab_enter" local height=8 width=50 prefix=" " local plen=${#prefix} list= line= local max_width=$(( $width - 3 - $plen )) local yes no defaultno extra_args format if [ "$USE_XDIALOG" ]; then yes=ok no=cancel defaultno=default-no extra_args="--wrap --left" format="$msg_uefi_not_supported" else yes=yes no=no defaultno=defaultno extra_args="--cr-wrap" format="$msg_uefi_not_supported" fi # Add height for Xdialog(1) [ "$USE_XDIALOG" ] && height=$(( $height + $height / 5 + 3 )) prompt=$( printf "$format" ) f_dprintf "%s: UEFI prompt" "$0" $DIALOG \ --title "$title" \ --backtitle "$btitle" \ --hline "$hline" \ --$yes-label "$msg_yes" \ --$no-label "$msg_no" \ $extra_args \ --yesno "$prompt" $height $width } # zfs_create_diskpart $disk $index # # For each block device to be used in the zpool, rather than just create the # zpool with the raw block devices (e.g., da0, da1, etc.) we create partitions # so we can have some real swap. This also provides wiggle room incase your # replacement drivers do not have the exact same sector counts. # # NOTE: $swapsize and $bootsize should be defined by the calling function. # NOTE: Sets $bootpart and $targetpart for the calling function. # zfs_create_diskpart() { local funcname=zfs_create_diskpart local disk="$1" index="$2" # Check arguments if [ ! "$disk" ]; then f_dprintf "$funcname: NULL disk argument" msg_error="$msg_error: $funcname" \ f_show_err "$msg_null_disk_argument" return $FAILURE fi if [ "${disk#*[$IFS]}" != "$disk" ]; then f_dprintf "$funcname: Invalid disk argument \`%s'" "$disk" msg_error="$msg_error: $funcname" \ f_show_err "$msg_invalid_disk_argument" "$disk" return $FAILURE fi if [ ! "$index" ]; then f_dprintf "$funcname: NULL index argument" msg_error="$msg_error: $funcname" \ f_show_err "$msg_null_index_argument" return $FAILURE fi if ! f_isinteger "$index"; then f_dprintf "$funcname: Invalid index argument \`%s'" "$index" msg_error="$msg_error: $funcname" \ f_show_err "$msg_invalid_index_argument" "$index" return $FAILURE fi f_dprintf "$funcname: disk=[%s] index=[%s]" "$disk" "$index" # Check for unknown partition scheme before proceeding further case "$ZFSBOOT_PARTITION_SCHEME" in ""|MBR|GPT) : known good ;; *) f_dprintf "$funcname: %s is an unsupported partition scheme" \ "$ZFSBOOT_PARTITION_SCHEME" msg_error="$msg_error: $funcname" f_show_err \ "$msg_unsupported_partition_scheme" \ "$ZFSBOOT_PARTITION_SCHEME" return $FAILURE esac # # Destroy whatever partition layout is currently on disk. # NOTE: `-F' required to destroy if partitions still exist. # NOTE: Failure is ok here, blank disk will have nothing to destroy. # f_dprintf "$funcname: Destroying all data/layouts on \`%s'..." "$disk" f_eval_catch -d $funcname gpart "$GPART_DESTROY_F" $disk f_eval_catch -d $funcname graid "$GRAID_DELETE" $disk f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" /dev/$disk # Make doubly-sure backup GPT is destroyed f_eval_catch -d $funcname gpart "$GPART_CREATE" gpt $disk f_eval_catch -d $funcname gpart "$GPART_DESTROY_F" $disk # # Enable boot pool if encryption is desired # [ "$ZFSBOOT_GELI_ENCRYPTION" ] && ZFSBOOT_BOOT_POOL=1 # # Lay down the desired type of partition scheme # local setsize mbrindex case "$ZFSBOOT_PARTITION_SCHEME" in ""|GPT) f_dprintf "$funcname: Creating GPT layout..." # # 1. Create GPT layout using labels # f_eval_catch $funcname gpart "$GPART_CREATE" gpt $disk || return $FAILURE # # 2. Add small freebsd-boot partition labeled `boot#' # f_eval_catch $funcname gpart "$GPART_ADD_LABEL_WITH_SIZE" \ gptboot$index freebsd-boot 512k $disk || return $FAILURE f_eval_catch $funcname gpart "$GPART_BOOTCODE_PART" \ /boot/pmbr /boot/gptzfsboot 1 $disk || return $FAILURE # NB: zpool will use the `zfs#' GPT labels bootpart=p2 swappart=p2 targetpart=p2 [ ${swapsize:-0} -gt 0 ] && targetpart=p3 # # Prepare boot pool if enabled (e.g., for geli(8)) # if [ "$ZFSBOOT_BOOT_POOL" ]; then bootpart=p2 swappart=p3 targetpart=p3 [ ${swapsize:-0} -gt 0 ] && targetpart=p4 f_eval_catch $funcname gpart \ "$GPART_ADD_LABEL_WITH_SIZE" boot$index \ freebsd-zfs ${bootsize}b $disk || return $FAILURE # Pedantically nuke any old labels f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \ /dev/$disk$bootpart if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then # Pedantically detach targetpart for later f_eval_catch -d $funcname geli \ "$GELI_DETACH_F" \ /dev/$disk$targetpart fi fi # # 3. Add freebsd-swap partition labeled `swap#' # if [ ${swapsize:-0} -gt 0 ]; then f_eval_catch $funcname gpart \ "$GPART_ADD_LABEL_WITH_SIZE" swap$index \ freebsd-swap ${swapsize}b $disk || return $FAILURE # Pedantically nuke any old labels on the swap f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \ /dev/$disk$swappart fi # # 4. Add freebsd-zfs partition labeled `zfs#' for zroot # f_eval_catch $funcname gpart "$GPART_ADD_LABEL" \ zfs$index freebsd-zfs $disk || return $FAILURE f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \ /dev/$disk$targetpart ;; MBR) f_dprintf "$funcname: Creating MBR layout..." # # 1. Create MBR layout (no labels) # f_eval_catch $funcname gpart "$GPART_CREATE" mbr $disk || return $FAILURE f_eval_catch $funcname gpart "$GPART_BOOTCODE" /boot/mbr \ $disk || return $FAILURE # # 2. Add freebsd slice with all available space # f_eval_catch $funcname gpart "$GPART_ADD" freebsd $disk || return $FAILURE f_eval_catch $funcname gpart "$GPART_SET_ACTIVE" 1 $disk || return $FAILURE # Pedantically nuke any old labels f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \ /dev/${disk}s1 # Pedantically nuke any old scheme f_eval_catch -d $funcname gpart "$GPART_DESTROY_F" ${disk}s1 # # 3. Write BSD scheme to the freebsd slice # f_eval_catch $funcname gpart "$GPART_CREATE" BSD ${disk}s1 || return $FAILURE # NB: zpool will use s1a (no labels) bootpart=s1a swappart=s1b targetpart=s1d mbrindex=4 # # Always prepare a boot pool on MBR # ZFSBOOT_BOOT_POOL=1 f_eval_catch $funcname gpart \ "$GPART_ADD_INDEX_WITH_SIZE" \ 1 freebsd-zfs ${bootsize}b ${disk}s1 || return $FAILURE # Pedantically nuke any old labels f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \ /dev/$disk$bootpart if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then # Pedantically detach targetpart for later f_eval_catch -d $funcname geli \ "$GELI_DETACH_F" \ /dev/$disk$targetpart fi # # 4. Add freebsd-swap partition # if [ ${swapsize:-0} -gt 0 ]; then f_eval_catch $funcname gpart \ "$GPART_ADD_INDEX_WITH_SIZE" 2 \ freebsd-swap ${swapsize}b ${disk}s1 || return $FAILURE # Pedantically nuke any old labels on the swap f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \ /dev/${disk}s1b fi # # 5. Add freebsd-zfs partition for zroot # f_eval_catch $funcname gpart "$GPART_ADD_INDEX" \ $mbrindex freebsd-zfs ${disk}s1 || return $FAILURE f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \ /dev/$disk$targetpart # Pedantic f_eval_catch $funcname dd "$DD_WITH_OPTIONS" \ /boot/zfsboot /dev/${disk}s1 count=1 || return $FAILURE ;; esac # $ZFSBOOT_PARTITION_SCHEME # Update fstab(5) + local swapsize + f_expand_number "$ZFSBOOT_SWAP_SIZE" swapsize if [ "$isswapmirror" ]; then # This is not the first disk in the mirror, do nothing elif [ "$ZFSBOOT_SWAP_ENCRYPTION" -a "$ZFSBOOT_SWAP_MIRROR" ]; then f_eval_catch $funcname printf "$PRINTF_FSTAB" \ /dev/mirror/swap.eli none swap sw 0 0 \ $BSDINSTALL_TMPETC/fstab || return $FAILURE isswapmirror=1 elif [ "$ZFSBOOT_SWAP_MIRROR" ]; then f_eval_catch $funcname printf "$PRINTF_FSTAB" \ /dev/mirror/swap none swap sw 0 0 \ $BSDINSTALL_TMPETC/fstab || return $FAILURE isswapmirror=1 elif [ "$ZFSBOOT_SWAP_ENCRYPTION" ]; then f_eval_catch $funcname printf "$PRINTF_FSTAB" \ /dev/$disk${swappart}.eli none swap sw 0 0 \ $BSDINSTALL_TMPETC/fstab || return $FAILURE + elif [ ${swapsize:-0} -eq 0 ] + # If swap is 0 sized, don't add it to fstab else f_eval_catch $funcname printf "$PRINTF_FSTAB" \ /dev/$disk$swappart none swap sw 0 0 \ $BSDINSTALL_TMPETC/fstab || return $FAILURE fi return $SUCCESS } # zfs_create_boot $poolname $vdev_type $disks ... # # Creates boot pool and dataset layout. Returns error if something goes wrong. # Errors are printed to stderr for collection and display. # zfs_create_boot() { local funcname=zfs_create_boot local zroot_name="$1" local zroot_vdevtype="$2" local zroot_vdevs= # Calculated below local swap_devs= # Calculated below local boot_vdevs= # Used for geli(8) and/or MBR layouts shift 2 # poolname vdev_type local disks="$*" disk local isswapmirror local bootpart targetpart swappart # Set by zfs_create_diskpart() below local create_options # # Pedantic checks; should never be seen # if [ ! "$zroot_name" ]; then f_dprintf "$funcname: NULL poolname" msg_error="$msg_error: $funcname" \ f_show_err "$msg_null_poolname" return $FAILURE fi if [ $# -lt 1 ]; then f_dprintf "$funcname: missing disk arguments" msg_error="$msg_error: $funcname" \ f_show_err "$msg_missing_disk_arguments" return $FAILURE fi f_dprintf "$funcname: poolname=[%s] vdev_type=[%s]" \ "$zroot_name" "$zroot_vdevtype" # # Initialize fstab(5) # f_dprintf "$funcname: Initializing temporary fstab(5) file..." f_eval_catch $funcname sh "$SHELL_TRUNCATE" $BSDINSTALL_TMPETC/fstab || return $FAILURE f_eval_catch $funcname printf "$PRINTF_FSTAB" \ "# Device" Mountpoint FStype Options Dump "Pass#" \ $BSDINSTALL_TMPETC/fstab || return $FAILURE # # Expand SI units in desired sizes # f_dprintf "$funcname: Expanding supplied size values..." local swapsize bootsize if ! f_expand_number "$ZFSBOOT_SWAP_SIZE" swapsize; then f_dprintf "$funcname: Invalid swap size \`%s'" \ "$ZFSBOOT_SWAP_SIZE" f_show_err "$msg_invalid_swap_size" "$ZFSBOOT_SWAP_SIZE" return $FAILURE fi if ! f_expand_number "$ZFSBOOT_BOOT_POOL_SIZE" bootsize; then f_dprintf "$funcname: Invalid boot pool size \`%s'" \ "$ZFSBOOT_BOOT_POOL_SIZE" f_show_err "$msg_invalid_boot_pool_size" \ "$ZFSBOOT_BOOT_POOL_SIZE" return $FAILURE fi f_dprintf "$funcname: ZFSBOOT_SWAP_SIZE=[%s] swapsize=[%s]" \ "$ZFSBOOT_SWAP_SIZE" "$swapsize" f_dprintf "$funcname: ZFSBOOT_BOOT_POOL_SIZE=[%s] bootsize=[%s]" \ "$ZFSBOOT_BOOT_POOL_SIZE" "$bootsize" # # Destroy the pool in-case this is our second time 'round (case of # failure and installer presented ``Retry'' option to come back). # # NB: If we don't destroy the pool, later gpart(8) destroy commands # that try to clear existing partitions (see zfs_create_diskpart()) # will fail with a `Device Busy' error, leading to `GEOM exists'. # f_eval_catch -d $funcname zpool "$ZPOOL_DESTROY" "$zroot_name" # # Prepare the disks and build pool device list(s) # f_dprintf "$funcname: Preparing disk partitions for ZFS pool..." # Force 4K sectors using vfs.zfs.min_auto_ashift=12 if [ "$ZFSBOOT_FORCE_4K_SECTORS" ]; then f_dprintf "$funcname: With 4K sectors..." f_eval_catch $funcname sysctl "$SYSCTL_ZFS_MIN_ASHIFT_12" \ || return $FAILURE fi local n=0 for disk in $disks; do zfs_create_diskpart $disk $n || return $FAILURE # Now $bootpart, $targetpart, and $swappart are set (suffix # for $disk) if [ "$ZFSBOOT_BOOT_POOL" ]; then boot_vdevs="$boot_vdevs $disk$bootpart" fi zroot_vdevs="$zroot_vdevs $disk$targetpart" if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then zroot_vdevs="$zroot_vdevs.eli" fi n=$(( $n + 1 )) done # disks # # If we need/want a boot pool, create it # if [ "$ZFSBOOT_BOOT_POOL" ]; then local bootpool_vdevtype= # Calculated below local bootpool_options= # Calculated below local bootpool_name="$ZFSBOOT_BOOT_POOL_NAME" local bootpool="$BSDINSTALL_CHROOT/$bootpool_name" local zroot_key="${ZFSBOOT_GELI_KEY_FILE#/}" f_dprintf "$funcname: Setting up boot pool..." [ "$ZFSBOOT_GELI_ENCRYPTION" ] && f_dprintf "$funcname: For encrypted root disk..." # Create parent directory for boot pool f_eval_catch -d $funcname umount "$UMOUNT" /mnt f_eval_catch $funcname mount "$MOUNT_TYPE" tmpfs none \ $BSDINSTALL_CHROOT || return $FAILURE # Create mirror across the boot partition on all disks local nvdevs f_count nvdevs $boot_vdevs [ $nvdevs -gt 1 ] && bootpool_vdevtype=mirror create_options="$ZFSBOOT_BOOT_POOL_CREATE_OPTIONS" bootpool_options="-o altroot=$BSDINSTALL_CHROOT" bootpool_options="$bootpool_options $create_options" bootpool_options="$bootpool_options -m \"/$bootpool_name\" -f" f_eval_catch $funcname zpool "$ZPOOL_CREATE_WITH_OPTIONS" \ "$bootpool_options" "$bootpool_name" \ "$bootpool_vdevtype" "$boot_vdevs" || return $FAILURE f_eval_catch $funcname mkdir "$MKDIR_P" "$bootpool/boot" || return $FAILURE if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then # Generate an encryption key using random(4) f_eval_catch $funcname dd "$DD_WITH_OPTIONS" \ /dev/random "$bootpool/$zroot_key" \ "bs=4096 count=1" || return $FAILURE f_eval_catch $funcname chmod "$CHMOD_MODE" \ go-wrx "$bootpool/$zroot_key" || return $FAILURE else # Clean up f_eval_catch $funcname zfs "$ZFS_UNMOUNT" \ "$bootpool_name" || return $FAILURE f_eval_catch -d $funcname umount "$UMOUNT" /mnt # tmpfs fi fi # # Create the geli(8) GEOMS # if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then # Prompt user for password (twice) if ! msg_enter_new_password="$msg_geli_password" \ f_dialog_input_password then f_dprintf "$funcname: User cancelled" f_show_err "$msg_user_cancelled" return $FAILURE fi # Initialize geli(8) on each of the target partitions for disk in $disks; do f_dialog_info "$msg_geli_setup" \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD if ! echo "$pw_password" | f_eval_catch \ $funcname geli "$GELI_PASSWORD_INIT" \ "$bootpool/boot/$disk$targetpart.eli" \ AES-XTS "$bootpool/$zroot_key" \ $disk$targetpart then f_interactive || f_die unset pw_password # Sensitive info return $FAILURE fi if ! echo "$pw_password" | f_eval_catch \ $funcname geli "$GELI_ATTACH" \ "$bootpool/$zroot_key" $disk$targetpart then f_interactive || f_die unset pw_password # Sensitive info return $FAILURE fi done unset pw_password # Sensitive info # Clean up f_eval_catch $funcname zfs "$ZFS_UNMOUNT" "$bootpool_name" || return $FAILURE f_eval_catch -d $funcname umount "$UMOUNT" /mnt # tmpfs fi # # Create the gmirror(8) GEOMS for swap # if [ "$ZFSBOOT_SWAP_MIRROR" ]; then for disk in $disks; do swap_devs="$swap_devs $disk$swappart" done f_eval_catch $funcname gmirror "$SWAP_GMIRROR_LABEL" \ "$swap_devs" || return $FAILURE fi # # Create the ZFS root pool with desired type and disk devices # f_dprintf "$funcname: Creating root pool..." create_options="$ZFSBOOT_POOL_CREATE_OPTIONS" f_eval_catch $funcname zpool "$ZPOOL_CREATE_WITH_OPTIONS" \ "-o altroot=$BSDINSTALL_CHROOT $create_options -m none -f" \ "$zroot_name" "$zroot_vdevtype" "$zroot_vdevs" || return $FAILURE # # Create ZFS dataset layout within the new root pool # f_dprintf "$funcname: Creating ZFS datasets..." echo "$ZFSBOOT_DATASETS" | while read dataset options; do # Skip blank lines and comments case "$dataset" in "#"*|"") continue; esac # Remove potential inline comments in options options="${options%%#*}" # Replace tabs with spaces f_replaceall "$options" " " " " options # Reduce contiguous runs of space to one single space oldoptions= while [ "$oldoptions" != "$options" ]; do oldoptions="$options" f_replaceall "$options" " " " " options done # Replace both commas and spaces with ` -o ' f_replaceall "$options" "[ ,]" " -o " options # Create the dataset with desired options f_eval_catch $funcname zfs "$ZFS_CREATE_WITH_OPTIONS" \ "${options:+-o $options}" "$zroot_name$dataset" || return $FAILURE done # Touch up permissions on the tmp directories f_dprintf "$funcname: Modifying directory permissions..." local dir for dir in /tmp /var/tmp; do f_eval_catch $funcname chmod "$CHMOD_MODE" 1777 \ $BSDINSTALL_CHROOTDIR$dir || return $FAILURE done # Create symlink(s) if [ "$ZFSBOOT_BOOT_POOL" ]; then f_dprintf "$funcname: Creating /boot symlink for boot pool..." f_eval_catch $funcname ln "$LN_SF" "$bootpool_name/boot" \ $BSDINSTALL_CHROOT/boot || return $FAILURE fi # Set bootfs property local zroot_bootfs="$ZFSBOOT_BEROOT_NAME/$ZFSBOOT_BOOTFS_NAME" f_dprintf "$funcname: Setting bootfs property..." f_eval_catch $funcname zpool "$ZPOOL_SET" \ "bootfs=\"$zroot_name/$zroot_bootfs\"" "$zroot_name" || return $FAILURE # Export the pool(s) f_dprintf "$funcname: Temporarily exporting ZFS pool(s)..." f_eval_catch $funcname zpool "$ZPOOL_EXPORT" "$zroot_name" || return $FAILURE if [ "$ZFSBOOT_BOOT_POOL" ]; then f_eval_catch $funcname zpool "$ZPOOL_EXPORT" \ "$bootpool_name" || return $FAILURE fi # MBR boot loader touch-up if [ "$ZFSBOOT_PARTITION_SCHEME" = "MBR" ]; then f_dprintf "$funcname: Updating MBR boot loader on disks..." # Stick the ZFS boot loader in the "convienient hole" after # the ZFS internal metadata for disk in $disks; do f_eval_catch $funcname dd "$DD_WITH_OPTIONS" \ /boot/zfsboot /dev/$disk$bootpart \ "skip=1 seek=1024" || return $FAILURE done fi # Re-import the ZFS pool(s) f_dprintf "$funcname: Re-importing ZFS pool(s)..." f_eval_catch $funcname zpool "$ZPOOL_IMPORT_WITH_OPTIONS" \ "-o altroot=\"$BSDINSTALL_CHROOT\"" "$zroot_name" || return $FAILURE if [ "$ZFSBOOT_BOOT_POOL" ]; then f_eval_catch $funcname zpool "$ZPOOL_IMPORT_WITH_OPTIONS" \ "-o altroot=\"$BSDINSTALL_CHROOT\"" \ "$bootpool_name" || return $FAILURE fi # While this is apparently not needed, it seems to help MBR f_dprintf "$funcname: Configuring zpool.cache for zroot..." f_eval_catch $funcname mkdir "$MKDIR_P" $BSDINSTALL_CHROOT/boot/zfs || return $FAILURE f_eval_catch $funcname zpool "$ZPOOL_SET" \ "cachefile=\"$BSDINSTALL_CHROOT/boot/zfs/zpool.cache\"" \ "$zroot_name" || return $FAILURE # Last, but not least... required lines for rc.conf(5)/loader.conf(5) # NOTE: We later concatenate these into their destination f_dprintf "%s: Configuring rc.conf(5)/loader.conf(5) additions..." \ "$funcname" f_eval_catch $funcname echo "$ECHO_APPEND" 'zfs_enable=\"YES\"' \ $BSDINSTALL_TMPETC/rc.conf.zfs || return $FAILURE f_eval_catch $funcname echo "$ECHO_APPEND" \ 'kern.geom.label.disk_ident.enable=\"0\"' \ $BSDINSTALL_TMPBOOT/loader.conf.zfs || return $FAILURE f_eval_catch $funcname echo "$ECHO_APPEND" \ 'kern.geom.label.gptid.enable=\"0\"' \ $BSDINSTALL_TMPBOOT/loader.conf.zfs || return $FAILURE if [ "$ZFSBOOT_SWAP_MIRROR" ]; then f_eval_catch $funcname echo "$ECHO_APPEND" \ 'geom_mirror_load=\"YES\"' \ $BSDINSTALL_TMPBOOT/loader.conf.gmirror || return $FAILURE fi # We're all done unless we should go on for boot pool [ "$ZFSBOOT_BOOT_POOL" ] || return $SUCCESS # Set cachefile for boot pool so it auto-imports at system start f_dprintf "$funcname: Configuring zpool.cache for boot pool..." f_eval_catch $funcname zpool "$ZPOOL_SET" \ "cachefile=\"$BSDINSTALL_CHROOT/boot/zfs/zpool.cache\"" \ "$bootpool_name" || return $FAILURE # Some additional geli(8) requirements for loader.conf(5) for option in \ 'zpool_cache_load=\"YES\"' \ 'zpool_cache_type=\"/boot/zfs/zpool.cache\"' \ 'zpool_cache_name=\"/boot/zfs/zpool.cache\"' \ ; do f_eval_catch $funcname echo "$ECHO_APPEND" "$option" \ $BSDINSTALL_TMPBOOT/loader.conf.zfs || return $FAILURE done f_eval_catch $funcname printf "$PRINTF_CONF" vfs.root.mountfrom \ "\"zfs:$zroot_name/$zroot_bootfs\"" \ $BSDINSTALL_TMPBOOT/loader.conf.root || return $FAILURE # We're all done unless we should go on to do encryption [ "$ZFSBOOT_GELI_ENCRYPTION" ] || return $SUCCESS # # Configure geli(8)-based encryption # f_dprintf "$funcname: Configuring disk encryption..." f_eval_catch $funcname echo "$ECHO_APPEND" 'aesni_load=\"YES\"' \ $BSDINSTALL_TMPBOOT/loader.conf.aesni || return $FAILURE f_eval_catch $funcname echo "$ECHO_APPEND" 'geom_eli_load=\"YES\"' \ $BSDINSTALL_TMPBOOT/loader.conf.geli || return $FAILURE f_eval_catch $funcname echo "$ECHO_APPEND" \ 'geom_eli_passphrase_prompt=\"YES\"' \ $BSDINSTALL_TMPBOOT/loader.conf.geli || return $FAILURE for disk in $disks; do f_eval_catch $funcname printf "$PRINTF_CONF" \ geli_%s_keyfile0_load "$disk$targetpart YES" \ $BSDINSTALL_TMPBOOT/loader.conf.$disk$targetpart || return $FAILURE f_eval_catch $funcname printf "$PRINTF_CONF" \ geli_%s_keyfile0_type \ "$disk$targetpart $disk$targetpart:geli_keyfile0" \ $BSDINSTALL_TMPBOOT/loader.conf.$disk$targetpart || return $FAILURE f_eval_catch $funcname printf "$PRINTF_CONF" \ geli_%s_keyfile0_name \ "$disk$targetpart \"$ZFSBOOT_GELI_KEY_FILE\"" \ $BSDINSTALL_TMPBOOT/loader.conf.$disk$targetpart || return $FAILURE done return $SUCCESS } # dialog_menu_diskinfo # # Prompt the user to select a disk and then provide detailed info on it. # dialog_menu_diskinfo() { local device disk # # Break from loop when user cancels disk selection # while :; do device=$( msg_cancel="$msg_back" f_device_menu \ "$DIALOG_TITLE" "$msg_select_a_disk_device" "" \ $DEVICE_TYPE_DISK 2>&1 ) || break $device get name disk # Show gpart(8) `show' and camcontrol(8) `inquiry' data f_show_msg "$msg_detailed_disk_info" \ "$disk" "$( gpart show $disk 2> /dev/null )" \ "$disk" "$( camcontrol inquiry $disk 2> /dev/null )" \ "$disk" "$( camcontrol identify $disk 2> /dev/null )" done return $SUCCESS } ############################################################ MAIN # # Initialize # f_dialog_title "$msg_zfs_configuration" f_dialog_backtitle "$msg_freebsd_installer" # User may have specifically requested ZFS-related operations be interactive ! f_interactive && f_zfsinteractive && unset $VAR_NONINTERACTIVE # # Debugging # f_dprintf "BSDINSTALL_CHROOT=[%s]" "$BSDINSTALL_CHROOT" f_dprintf "BSDINSTALL_TMPETC=[%s]" "$BSDINSTALL_TMPETC" f_dprintf "FSTAB_FMT=[%s]" "$FSTAB_FMT" # # If the system was booted with UEFI, warn the user that FreeBSD can't do # ZFS with UEFI yet # if f_interactive; then bootmethod=$( sysctl -n machdep.bootmethod ) f_dprintf "machdep.bootmethod=[%s]" "$bootmethod" if [ "$bootmethod" != "BIOS" ]; then dialog_uefi_prompt retval=$? f_dprintf "uefi_prompt=[%s]" "$retval" [ $retval -eq $DIALOG_OK ] || f_die fi fi # # Loop over the main menu until we've accomplished what we came here to do # while :; do if ! f_interactive; then retval=$DIALOG_OK mtag=">>> $msg_install" else dialog_menu_main retval=$? f_dialog_menutag_fetch mtag fi f_dprintf "retval=%u mtag=[%s]" $retval "$mtag" [ $retval -eq $DIALOG_OK ] || f_die case "$mtag" in ">>> $msg_install") # # First, validate the user's selections # # Make sure they gave us a name for the pool if [ ! "$ZFSBOOT_POOL_NAME" ]; then f_dprintf "Pool name cannot be empty." f_show_err "$msg_pool_name_cannot_be_empty" continue fi # Validate vdev type against number of disks selected/scripted # (also validates that ZFSBOOT_DISKS are real [probed] disks) # NB: dialog_menu_layout supports running non-interactively dialog_menu_layout || continue # Make sure each disk will be at least 50% ZFS if f_expand_number "$ZFSBOOT_SWAP_SIZE" swapsize && f_expand_number "$ZFSBOOT_BOOT_POOL_SIZE" bootsize then minsize=$swapsize teeny_disks= [ "$ZFSBOOT_BOOT_POOL" ] && minsize=$(( $minsize + $bootsize )) for disk in $ZFSBOOT_DISKS; do debug= f_device_find -1 \ $disk $DEVICE_TYPE_DISK device $device get capacity disksize || continue [ ${disksize:-0} -ge 0 ] || disksize=0 disksize=$(( $disksize - $minsize )) [ $disksize -lt $minsize ] && teeny_disks="$teeny_disks $disk" done if [ "$teeny_disks" ]; then f_dprintf "swapsize=[%s] bootsize[%s] %s" \ "$ZFSBOOT_SWAP_SIZE" \ "$ZFSBOOT_BOOT_POOL_SIZE" \ "minsize=[$minsize]" f_dprintf "These disks are too small: %s" \ "$teeny_disks" f_show_err "$msg_these_disks_are_too_small" \ "$ZFSBOOT_SWAP_SIZE" \ "$ZFSBOOT_BOOT_POOL_SIZE" \ "$teeny_disks" continue fi fi # # Last Chance! # if f_interactive; then dialog_last_chance $ZFSBOOT_DISKS || continue fi # # Let's do this # vdev_type="$ZFSBOOT_VDEV_TYPE" # Blank the vdev type for the default layout [ "$vdev_type" = "stripe" ] && vdev_type= zfs_create_boot "$ZFSBOOT_POOL_NAME" \ "$vdev_type" $ZFSBOOT_DISKS || continue break # to success ;; ?" $msg_pool_type_disks") ZFSBOOT_CONFIRM_LAYOUT=1 dialog_menu_layout # User has poked settings, disable later confirmation ZFSBOOT_CONFIRM_LAYOUT= ;; "- $msg_rescan_devices") f_device_rescan ;; "- $msg_disk_info") dialog_menu_diskinfo ;; ?" $msg_pool_name") # Prompt the user to input/change the name for the new pool f_dialog_input input \ "$msg_please_enter_a_name_for_your_zpool" \ "$ZFSBOOT_POOL_NAME" && ZFSBOOT_POOL_NAME="$input" ;; ?" $msg_force_4k_sectors") # Toggle the variable referenced both by the menu and later if [ "$ZFSBOOT_FORCE_4K_SECTORS" ]; then ZFSBOOT_FORCE_4K_SECTORS= else ZFSBOOT_FORCE_4K_SECTORS=1 fi ;; ?" $msg_encrypt_disks") # Toggle the variable referenced both by the menu and later if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then ZFSBOOT_GELI_ENCRYPTION= else ZFSBOOT_FORCE_4K_SECTORS=1 ZFSBOOT_GELI_ENCRYPTION=1 fi ;; ?" $msg_partition_scheme") # Toggle between GPT and MBR if [ "$ZFSBOOT_PARTITION_SCHEME" = GPT ]; then ZFSBOOT_PARTITION_SCHEME=MBR else ZFSBOOT_PARTITION_SCHEME=GPT fi ;; ?" $msg_swap_size") # Prompt the user to input/change the swap size for each disk while :; do f_dialog_input input \ "$msg_please_enter_amount_of_swap_space" \ "$ZFSBOOT_SWAP_SIZE" && ZFSBOOT_SWAP_SIZE="${input:-0}" if f_expand_number "$ZFSBOOT_SWAP_SIZE" swapsize then if [ $swapsize -ne 0 -a $swapsize -lt 104857600 ]; then f_show_err "$msg_swap_toosmall" \ "$ZFSBOOT_SWAP_SIZE" continue; else break; fi else f_show_err "$msg_swap_invalid" \ "$ZFSBOOT_SWAP_SIZE" continue; fi done ;; ?" $msg_swap_mirror") # Toggle the variable referenced both by the menu and later if [ "$ZFSBOOT_SWAP_MIRROR" ]; then ZFSBOOT_SWAP_MIRROR= else ZFSBOOT_SWAP_MIRROR=1 fi ;; ?" $msg_swap_encrypt") # Toggle the variable referenced both by the menu and later if [ "$ZFSBOOT_SWAP_ENCRYPTION" ]; then ZFSBOOT_SWAP_ENCRYPTION= else ZFSBOOT_SWAP_ENCRYPTION=1 fi ;; esac done return $SUCCESS ################################################################################ # END ################################################################################ Index: projects/ci20_mips/usr.sbin/mountd/mountd.c =================================================================== --- projects/ci20_mips/usr.sbin/mountd/mountd.c (revision 283030) +++ projects/ci20_mips/usr.sbin/mountd/mountd.c (revision 283031) @@ -1,3216 +1,3219 @@ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Herb Hasler and Rick Macklem at The University of Guelph. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /*not lint*/ #if 0 #ifndef lint static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; #endif /*not lint*/ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pathnames.h" #include "mntopts.h" #ifdef DEBUG #include #endif /* * Structures for keeping the mount list and export list */ struct mountlist { struct mountlist *ml_next; char ml_host[MNTNAMLEN+1]; char ml_dirp[MNTPATHLEN+1]; }; struct dirlist { struct dirlist *dp_left; struct dirlist *dp_right; int dp_flag; struct hostlist *dp_hosts; /* List of hosts this dir exported to */ char dp_dirp[1]; /* Actually malloc'd to size of dir */ }; /* dp_flag bits */ #define DP_DEFSET 0x1 #define DP_HOSTSET 0x2 struct exportlist { struct exportlist *ex_next; struct dirlist *ex_dirl; struct dirlist *ex_defdir; int ex_flag; fsid_t ex_fs; char *ex_fsdir; char *ex_indexfile; int ex_numsecflavors; int ex_secflavors[MAXSECFLAVORS]; int ex_defnumsecflavors; int ex_defsecflavors[MAXSECFLAVORS]; }; /* ex_flag bits */ #define EX_LINKED 0x1 struct netmsk { struct sockaddr_storage nt_net; struct sockaddr_storage nt_mask; char *nt_name; }; union grouptypes { struct addrinfo *gt_addrinfo; struct netmsk gt_net; }; struct grouplist { int gr_type; union grouptypes gr_ptr; struct grouplist *gr_next; int gr_numsecflavors; int gr_secflavors[MAXSECFLAVORS]; }; /* Group types */ #define GT_NULL 0x0 #define GT_HOST 0x1 #define GT_NET 0x2 #define GT_DEFAULT 0x3 #define GT_IGNORE 0x5 struct hostlist { int ht_flag; /* Uses DP_xx bits */ struct grouplist *ht_grp; struct hostlist *ht_next; }; struct fhreturn { int fhr_flag; int fhr_vers; nfsfh_t fhr_fh; int fhr_numsecflavors; int *fhr_secflavors; }; #define GETPORT_MAXTRY 20 /* Max tries to get a port # */ /* Global defs */ char *add_expdir(struct dirlist **, char *, int); void add_dlist(struct dirlist **, struct dirlist *, struct grouplist *, int, struct exportlist *); void add_mlist(char *, char *); int check_dirpath(char *); int check_options(struct dirlist *); int checkmask(struct sockaddr *sa); int chk_host(struct dirlist *, struct sockaddr *, int *, int *, int *, int **); static int create_service(struct netconfig *nconf); static void complete_service(struct netconfig *nconf, char *port_str); static void clearout_service(void); void del_mlist(char *hostp, char *dirp); struct dirlist *dirp_search(struct dirlist *, char *); int do_mount(struct exportlist *, struct grouplist *, int, struct xucred *, char *, int, struct statfs *); int do_opt(char **, char **, struct exportlist *, struct grouplist *, int *, int *, struct xucred *); struct exportlist *ex_search(fsid_t *); struct exportlist *get_exp(void); void free_dir(struct dirlist *); void free_exp(struct exportlist *); void free_grp(struct grouplist *); void free_host(struct hostlist *); void get_exportlist(void); int get_host(char *, struct grouplist *, struct grouplist *); struct hostlist *get_ht(void); int get_line(void); void get_mountlist(void); int get_net(char *, struct netmsk *, int); void getexp_err(struct exportlist *, struct grouplist *); struct grouplist *get_grp(void); void hang_dirp(struct dirlist *, struct grouplist *, struct exportlist *, int); void huphandler(int sig); int makemask(struct sockaddr_storage *ssp, int bitlen); void mntsrv(struct svc_req *, SVCXPRT *); void nextfield(char **, char **); void out_of_mem(void); void parsecred(char *, struct xucred *); int parsesec(char *, struct exportlist *); int put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); void *sa_rawaddr(struct sockaddr *sa, int *nbytes); int sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask); int scan_tree(struct dirlist *, struct sockaddr *); static void usage(void); int xdr_dir(XDR *, char *); int xdr_explist(XDR *, caddr_t); int xdr_explist_brief(XDR *, caddr_t); int xdr_explist_common(XDR *, caddr_t, int); int xdr_fhs(XDR *, caddr_t); int xdr_mlist(XDR *, caddr_t); void terminate(int); struct exportlist *exphead; struct mountlist *mlhead; struct grouplist *grphead; char *exnames_default[2] = { _PATH_EXPORTS, NULL }; char **exnames; char **hosts = NULL; struct xucred def_anon = { XUCRED_VERSION, (uid_t)-2, 1, { (gid_t)-2 }, NULL }; int force_v2 = 0; int resvport_only = 1; int nhosts = 0; int dir_only = 1; int dolog = 0; int got_sighup = 0; int xcreated = 0; char *svcport_str = NULL; static int mallocd_svcport = 0; static int *sock_fd; static int sock_fdcnt; static int sock_fdpos; static int suspend_nfsd = 0; int opt_flags; static int have_v6 = 1; int v4root_phase = 0; char v4root_dirpath[PATH_MAX + 1]; int has_publicfh = 0; struct pidfh *pfh = NULL; /* Bits for opt_flags above */ #define OP_MAPROOT 0x01 #define OP_MAPALL 0x02 /* 0x4 free */ #define OP_MASK 0x08 #define OP_NET 0x10 #define OP_ALLDIRS 0x40 #define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ #define OP_QUIET 0x100 #define OP_MASKLEN 0x200 #define OP_SEC 0x400 #ifdef DEBUG int debug = 1; void SYSLOG(int, const char *, ...) __printflike(2, 3); #define syslog SYSLOG #else int debug = 0; #endif /* * Mountd server for NFS mount protocol as described in: * NFS: Network File System Protocol Specification, RFC1094, Appendix A * The optional arguments are the exports file name * default: _PATH_EXPORTS * and "-n" to allow nonroot mount. */ int main(int argc, char **argv) { fd_set readfds; struct netconfig *nconf; char *endptr, **hosts_bak; void *nc_handle; pid_t otherpid; in_port_t svcport; int c, k, s; int maxrec = RPC_MAXDATASIZE; int attempt_cnt, port_len, port_pos, ret; char **port_list; /* Check that another mountd isn't already running. */ pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); if (pfh == NULL) { if (errno == EEXIST) errx(1, "mountd already running, pid: %d.", otherpid); warn("cannot open or create pidfile"); } s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (s < 0) have_v6 = 0; else close(s); while ((c = getopt(argc, argv, "2deh:lnp:rS")) != -1) switch (c) { case '2': force_v2 = 1; break; case 'e': /* now a no-op, since this is the default */ break; case 'n': resvport_only = 0; break; case 'r': dir_only = 0; break; case 'd': debug = debug ? 0 : 1; break; case 'l': dolog = 1; break; case 'p': endptr = NULL; svcport = (in_port_t)strtoul(optarg, &endptr, 10); if (endptr == NULL || *endptr != '\0' || svcport == 0 || svcport >= IPPORT_MAX) usage(); svcport_str = strdup(optarg); break; case 'h': ++nhosts; hosts_bak = hosts; hosts_bak = realloc(hosts, nhosts * sizeof(char *)); if (hosts_bak == NULL) { if (hosts != NULL) { for (k = 0; k < nhosts; k++) free(hosts[k]); free(hosts); out_of_mem(); } } hosts = hosts_bak; hosts[nhosts - 1] = strdup(optarg); if (hosts[nhosts - 1] == NULL) { for (k = 0; k < (nhosts - 1); k++) free(hosts[k]); free(hosts); out_of_mem(); } break; case 'S': suspend_nfsd = 1; break; default: usage(); }; if (modfind("nfsd") < 0) { /* Not present in kernel, try loading it */ if (kldload("nfsd") < 0 || modfind("nfsd") < 0) errx(1, "NFS server is not available"); } argc -= optind; argv += optind; grphead = (struct grouplist *)NULL; exphead = (struct exportlist *)NULL; mlhead = (struct mountlist *)NULL; if (argc > 0) exnames = argv; else exnames = exnames_default; openlog("mountd", LOG_PID, LOG_DAEMON); if (debug) warnx("getting export list"); get_exportlist(); if (debug) warnx("getting mount list"); get_mountlist(); if (debug) warnx("here we go"); if (debug == 0) { daemon(0, 0); signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); } signal(SIGHUP, huphandler); signal(SIGTERM, terminate); signal(SIGPIPE, SIG_IGN); pidfile_write(pfh); rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); if (!resvport_only) { if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, &resvport_only, sizeof(resvport_only)) != 0 && errno != ENOENT) { syslog(LOG_ERR, "sysctl: %m"); exit(1); } } /* * If no hosts were specified, add a wildcard entry to bind to * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the * list. */ if (nhosts == 0) { hosts = malloc(sizeof(char**)); if (hosts == NULL) out_of_mem(); hosts[0] = "*"; nhosts = 1; } else { hosts_bak = hosts; if (have_v6) { hosts_bak = realloc(hosts, (nhosts + 2) * sizeof(char *)); if (hosts_bak == NULL) { for (k = 0; k < nhosts; k++) free(hosts[k]); free(hosts); out_of_mem(); } else hosts = hosts_bak; nhosts += 2; hosts[nhosts - 2] = "::1"; } else { hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); if (hosts_bak == NULL) { for (k = 0; k < nhosts; k++) free(hosts[k]); free(hosts); out_of_mem(); } else { nhosts += 1; hosts = hosts_bak; } } hosts[nhosts - 1] = "127.0.0.1"; } attempt_cnt = 1; sock_fdcnt = 0; sock_fd = NULL; port_list = NULL; port_len = 0; nc_handle = setnetconfig(); while ((nconf = getnetconfig(nc_handle))) { if (nconf->nc_flag & NC_VISIBLE) { if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { /* DO NOTHING */ } else { ret = create_service(nconf); if (ret == 1) /* Ignore this call */ continue; if (ret < 0) { /* * Failed to bind port, so close off * all sockets created and try again * if the port# was dynamically * assigned via bind(2). */ clearout_service(); if (mallocd_svcport != 0 && attempt_cnt < GETPORT_MAXTRY) { free(svcport_str); svcport_str = NULL; mallocd_svcport = 0; } else { errno = EADDRINUSE; syslog(LOG_ERR, "bindresvport_sa: %m"); exit(1); } /* Start over at the first service. */ free(sock_fd); sock_fdcnt = 0; sock_fd = NULL; nc_handle = setnetconfig(); attempt_cnt++; } else if (mallocd_svcport != 0 && attempt_cnt == GETPORT_MAXTRY) { /* * For the last attempt, allow * different port #s for each nconf * by saving the svcport_str and * setting it back to NULL. */ port_list = realloc(port_list, (port_len + 1) * sizeof(char *)); if (port_list == NULL) out_of_mem(); port_list[port_len++] = svcport_str; svcport_str = NULL; mallocd_svcport = 0; } } } } /* * Successfully bound the ports, so call complete_service() to * do the rest of the setup on the service(s). */ sock_fdpos = 0; port_pos = 0; nc_handle = setnetconfig(); while ((nconf = getnetconfig(nc_handle))) { if (nconf->nc_flag & NC_VISIBLE) { if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { /* DO NOTHING */ } else if (port_list != NULL) { if (port_pos >= port_len) { syslog(LOG_ERR, "too many port#s"); exit(1); } complete_service(nconf, port_list[port_pos++]); } else complete_service(nconf, svcport_str); } } endnetconfig(nc_handle); free(sock_fd); if (port_list != NULL) { for (port_pos = 0; port_pos < port_len; port_pos++) free(port_list[port_pos]); free(port_list); } if (xcreated == 0) { syslog(LOG_ERR, "could not create any services"); exit(1); } /* Expand svc_run() here so that we can call get_exportlist(). */ for (;;) { if (got_sighup) { get_exportlist(); got_sighup = 0; } readfds = svc_fdset; switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { case -1: if (errno == EINTR) continue; syslog(LOG_ERR, "mountd died: select: %m"); exit(1); case 0: continue; default: svc_getreqset(&readfds); } } } /* * This routine creates and binds sockets on the appropriate * addresses. It gets called one time for each transport. * It returns 0 upon success, 1 for ingore the call and -1 to indicate * bind failed with EADDRINUSE. * Any file descriptors that have been created are stored in sock_fd and * the total count of them is maintained in sock_fdcnt. */ static int create_service(struct netconfig *nconf) { struct addrinfo hints, *res = NULL; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; struct __rpc_sockinfo si; int aicode; int fd; int nhostsbak; int one = 1; int r; u_int32_t host_addr[4]; /* IPv4 or IPv6 */ int mallocd_res; if ((nconf->nc_semantics != NC_TPI_CLTS) && (nconf->nc_semantics != NC_TPI_COTS) && (nconf->nc_semantics != NC_TPI_COTS_ORD)) return (1); /* not my type */ /* * XXX - using RPC library internal functions. */ if (!__rpc_nconf2sockinfo(nconf, &si)) { syslog(LOG_ERR, "cannot get information for %s", nconf->nc_netid); return (1); } /* Get mountd's address on this transport */ memset(&hints, 0, sizeof hints); hints.ai_family = si.si_af; hints.ai_socktype = si.si_socktype; hints.ai_protocol = si.si_proto; /* * Bind to specific IPs if asked to */ nhostsbak = nhosts; while (nhostsbak > 0) { --nhostsbak; sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); if (sock_fd == NULL) out_of_mem(); sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ mallocd_res = 0; hints.ai_flags = AI_PASSIVE; /* * XXX - using RPC library internal functions. */ if ((fd = __rpc_nconf2fd(nconf)) < 0) { int non_fatal = 0; if (errno == EAFNOSUPPORT && nconf->nc_semantics != NC_TPI_CLTS) non_fatal = 1; syslog(non_fatal ? LOG_DEBUG : LOG_ERR, "cannot create socket for %s", nconf->nc_netid); if (non_fatal != 0) continue; exit(1); } switch (hints.ai_family) { case AF_INET: if (inet_pton(AF_INET, hosts[nhostsbak], host_addr) == 1) { hints.ai_flags |= AI_NUMERICHOST; } else { /* * Skip if we have an AF_INET6 address. */ if (inet_pton(AF_INET6, hosts[nhostsbak], host_addr) == 1) { close(fd); continue; } } break; case AF_INET6: if (inet_pton(AF_INET6, hosts[nhostsbak], host_addr) == 1) { hints.ai_flags |= AI_NUMERICHOST; } else { /* * Skip if we have an AF_INET address. */ if (inet_pton(AF_INET, hosts[nhostsbak], host_addr) == 1) { close(fd); continue; } } /* * We're doing host-based access checks here, so don't * allow v4-in-v6 to confuse things. The kernel will * disable it by default on NFS sockets too. */ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof one) < 0) { syslog(LOG_ERR, "can't disable v4-in-v6 on IPv6 socket"); exit(1); } break; default: break; } /* * If no hosts were specified, just bind to INADDR_ANY */ if (strcmp("*", hosts[nhostsbak]) == 0) { if (svcport_str == NULL) { res = malloc(sizeof(struct addrinfo)); if (res == NULL) out_of_mem(); mallocd_res = 1; res->ai_flags = hints.ai_flags; res->ai_family = hints.ai_family; res->ai_protocol = hints.ai_protocol; switch (res->ai_family) { case AF_INET: sin = malloc(sizeof(struct sockaddr_in)); if (sin == NULL) out_of_mem(); sin->sin_family = AF_INET; sin->sin_port = htons(0); sin->sin_addr.s_addr = htonl(INADDR_ANY); res->ai_addr = (struct sockaddr*) sin; res->ai_addrlen = (socklen_t) sizeof(struct sockaddr_in); break; case AF_INET6: sin6 = malloc(sizeof(struct sockaddr_in6)); if (sin6 == NULL) out_of_mem(); sin6->sin6_family = AF_INET6; sin6->sin6_port = htons(0); sin6->sin6_addr = in6addr_any; res->ai_addr = (struct sockaddr*) sin6; res->ai_addrlen = (socklen_t) sizeof(struct sockaddr_in6); break; default: syslog(LOG_ERR, "bad addr fam %d", res->ai_family); exit(1); } } else { if ((aicode = getaddrinfo(NULL, svcport_str, &hints, &res)) != 0) { syslog(LOG_ERR, "cannot get local address for %s: %s", nconf->nc_netid, gai_strerror(aicode)); close(fd); continue; } } } else { if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, &hints, &res)) != 0) { syslog(LOG_ERR, "cannot get local address for %s: %s", nconf->nc_netid, gai_strerror(aicode)); close(fd); continue; } } /* Store the fd. */ sock_fd[sock_fdcnt - 1] = fd; /* Now, attempt the bind. */ r = bindresvport_sa(fd, res->ai_addr); if (r != 0) { if (errno == EADDRINUSE && mallocd_svcport != 0) { if (mallocd_res != 0) { free(res->ai_addr); free(res); } else freeaddrinfo(res); return (-1); } syslog(LOG_ERR, "bindresvport_sa: %m"); exit(1); } if (svcport_str == NULL) { svcport_str = malloc(NI_MAXSERV * sizeof(char)); if (svcport_str == NULL) out_of_mem(); mallocd_svcport = 1; if (getnameinfo(res->ai_addr, res->ai_addr->sa_len, NULL, NI_MAXHOST, svcport_str, NI_MAXSERV * sizeof(char), NI_NUMERICHOST | NI_NUMERICSERV)) errx(1, "Cannot get port number"); } if (mallocd_res != 0) { free(res->ai_addr); free(res); } else freeaddrinfo(res); res = NULL; } return (0); } /* * Called after all the create_service() calls have succeeded, to complete * the setup and registration. */ static void complete_service(struct netconfig *nconf, char *port_str) { struct addrinfo hints, *res = NULL; struct __rpc_sockinfo si; struct netbuf servaddr; SVCXPRT *transp = NULL; int aicode, fd, nhostsbak; int registered = 0; if ((nconf->nc_semantics != NC_TPI_CLTS) && (nconf->nc_semantics != NC_TPI_COTS) && (nconf->nc_semantics != NC_TPI_COTS_ORD)) return; /* not my type */ /* * XXX - using RPC library internal functions. */ if (!__rpc_nconf2sockinfo(nconf, &si)) { syslog(LOG_ERR, "cannot get information for %s", nconf->nc_netid); return; } nhostsbak = nhosts; while (nhostsbak > 0) { --nhostsbak; if (sock_fdpos >= sock_fdcnt) { /* Should never happen. */ syslog(LOG_ERR, "Ran out of socket fd's"); return; } fd = sock_fd[sock_fdpos++]; if (fd < 0) continue; if (nconf->nc_semantics != NC_TPI_CLTS) listen(fd, SOMAXCONN); if (nconf->nc_semantics == NC_TPI_CLTS ) transp = svc_dg_create(fd, 0, 0); else transp = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE); if (transp != (SVCXPRT *) NULL) { if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv, NULL)) syslog(LOG_ERR, "can't register %s MOUNTVERS service", nconf->nc_netid); if (!force_v2) { if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3, mntsrv, NULL)) syslog(LOG_ERR, "can't register %s MOUNTVERS3 service", nconf->nc_netid); } } else syslog(LOG_WARNING, "can't create %s services", nconf->nc_netid); if (registered == 0) { registered = 1; memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; hints.ai_family = si.si_af; hints.ai_socktype = si.si_socktype; hints.ai_protocol = si.si_proto; if ((aicode = getaddrinfo(NULL, port_str, &hints, &res)) != 0) { syslog(LOG_ERR, "cannot get local address: %s", gai_strerror(aicode)); exit(1); } servaddr.buf = malloc(res->ai_addrlen); memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); servaddr.len = res->ai_addrlen; rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr); rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr); xcreated++; freeaddrinfo(res); } } /* end while */ } /* * Clear out sockets after a failure to bind one of them, so that the * cycle of socket creation/binding can start anew. */ static void clearout_service(void) { int i; for (i = 0; i < sock_fdcnt; i++) { if (sock_fd[i] >= 0) { shutdown(sock_fd[i], SHUT_RDWR); close(sock_fd[i]); } } } static void usage(void) { fprintf(stderr, "usage: mountd [-2] [-d] [-e] [-l] [-n] [-p ] [-r] " "[-S] [-h ] [export_file ...]\n"); exit(1); } /* * The mount rpc service */ void mntsrv(struct svc_req *rqstp, SVCXPRT *transp) { struct exportlist *ep; struct dirlist *dp; struct fhreturn fhr; struct stat stb; struct statfs fsb; char host[NI_MAXHOST], numerichost[NI_MAXHOST]; int lookup_failed = 1; struct sockaddr *saddr; u_short sport; char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN]; int bad = 0, defset, hostset; sigset_t sighup_mask; int numsecflavors, *secflavorsp; sigemptyset(&sighup_mask); sigaddset(&sighup_mask, SIGHUP); saddr = svc_getrpccaller(transp)->buf; switch (saddr->sa_family) { case AF_INET6: sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); break; case AF_INET: sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); break; default: syslog(LOG_ERR, "request from unknown address family"); return; } lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, NULL, 0, 0); getnameinfo(saddr, saddr->sa_len, numerichost, sizeof numerichost, NULL, 0, NI_NUMERICHOST); switch (rqstp->rq_proc) { case NULLPROC: if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) syslog(LOG_ERR, "can't send reply"); return; case MOUNTPROC_MNT: if (sport >= IPPORT_RESERVED && resvport_only) { syslog(LOG_NOTICE, "mount request from %s from unprivileged port", numerichost); svcerr_weakauth(transp); return; } if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { syslog(LOG_NOTICE, "undecodable mount request from %s", numerichost); svcerr_decode(transp); return; } /* * Get the real pathname and make sure it is a directory * or a regular file if the -r option was specified * and it exists. */ if (realpath(rpcpath, dirpath) == NULL || stat(dirpath, &stb) < 0 || (!S_ISDIR(stb.st_mode) && (dir_only || !S_ISREG(stb.st_mode))) || statfs(dirpath, &fsb) < 0) { chdir("/"); /* Just in case realpath doesn't */ syslog(LOG_NOTICE, "mount request from %s for non existent path %s", numerichost, dirpath); if (debug) warnx("stat failed on %s", dirpath); bad = ENOENT; /* We will send error reply later */ } /* Check in the exports list */ sigprocmask(SIG_BLOCK, &sighup_mask, NULL); ep = ex_search(&fsb.f_fsid); hostset = defset = 0; if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset, &numsecflavors, &secflavorsp) || ((dp = dirp_search(ep->ex_dirl, dirpath)) && chk_host(dp, saddr, &defset, &hostset, &numsecflavors, &secflavorsp)) || (defset && scan_tree(ep->ex_defdir, saddr) == 0 && scan_tree(ep->ex_dirl, saddr) == 0))) { if (bad) { if (!svc_sendreply(transp, (xdrproc_t)xdr_long, (caddr_t)&bad)) syslog(LOG_ERR, "can't send reply"); sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); return; } if (hostset & DP_HOSTSET) { fhr.fhr_flag = hostset; fhr.fhr_numsecflavors = numsecflavors; fhr.fhr_secflavors = secflavorsp; } else { fhr.fhr_flag = defset; fhr.fhr_numsecflavors = ep->ex_defnumsecflavors; fhr.fhr_secflavors = ep->ex_defsecflavors; } fhr.fhr_vers = rqstp->rq_vers; /* Get the file handle */ memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { bad = errno; syslog(LOG_ERR, "can't get fh for %s", dirpath); if (!svc_sendreply(transp, (xdrproc_t)xdr_long, (caddr_t)&bad)) syslog(LOG_ERR, "can't send reply"); sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); return; } if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, (caddr_t)&fhr)) syslog(LOG_ERR, "can't send reply"); if (!lookup_failed) add_mlist(host, dirpath); else add_mlist(numerichost, dirpath); if (debug) warnx("mount successful"); if (dolog) syslog(LOG_NOTICE, "mount request succeeded from %s for %s", numerichost, dirpath); } else { bad = EACCES; syslog(LOG_NOTICE, "mount request denied from %s for %s", numerichost, dirpath); } if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, (caddr_t)&bad)) syslog(LOG_ERR, "can't send reply"); sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); return; case MOUNTPROC_DUMP: if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) syslog(LOG_ERR, "can't send reply"); else if (dolog) syslog(LOG_NOTICE, "dump request succeeded from %s", numerichost); return; case MOUNTPROC_UMNT: if (sport >= IPPORT_RESERVED && resvport_only) { syslog(LOG_NOTICE, "umount request from %s from unprivileged port", numerichost); svcerr_weakauth(transp); return; } if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { syslog(LOG_NOTICE, "undecodable umount request from %s", numerichost); svcerr_decode(transp); return; } if (realpath(rpcpath, dirpath) == NULL) { syslog(LOG_NOTICE, "umount request from %s " "for non existent path %s", numerichost, dirpath); } if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) syslog(LOG_ERR, "can't send reply"); if (!lookup_failed) del_mlist(host, dirpath); del_mlist(numerichost, dirpath); if (dolog) syslog(LOG_NOTICE, "umount request succeeded from %s for %s", numerichost, dirpath); return; case MOUNTPROC_UMNTALL: if (sport >= IPPORT_RESERVED && resvport_only) { syslog(LOG_NOTICE, "umountall request from %s from unprivileged port", numerichost); svcerr_weakauth(transp); return; } if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) syslog(LOG_ERR, "can't send reply"); if (!lookup_failed) del_mlist(host, NULL); del_mlist(numerichost, NULL); if (dolog) syslog(LOG_NOTICE, "umountall request succeeded from %s", numerichost); return; case MOUNTPROC_EXPORT: if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, (caddr_t)NULL)) syslog(LOG_ERR, "can't send reply"); if (dolog) syslog(LOG_NOTICE, "export request succeeded from %s", numerichost); return; default: svcerr_noproc(transp); return; } } /* * Xdr conversion for a dirpath string */ int xdr_dir(XDR *xdrsp, char *dirp) { return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); } /* * Xdr routine to generate file handle reply */ int xdr_fhs(XDR *xdrsp, caddr_t cp) { struct fhreturn *fhrp = (struct fhreturn *)cp; u_long ok = 0, len, auth; int i; if (!xdr_long(xdrsp, &ok)) return (0); switch (fhrp->fhr_vers) { case 1: return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); case 3: len = NFSX_V3FH; if (!xdr_long(xdrsp, &len)) return (0); if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) return (0); if (fhrp->fhr_numsecflavors) { if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors)) return (0); for (i = 0; i < fhrp->fhr_numsecflavors; i++) if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i])) return (0); return (1); } else { auth = AUTH_SYS; len = 1; if (!xdr_long(xdrsp, &len)) return (0); return (xdr_long(xdrsp, &auth)); } }; return (0); } int xdr_mlist(XDR *xdrsp, caddr_t cp __unused) { struct mountlist *mlp; int true = 1; int false = 0; char *strp; mlp = mlhead; while (mlp) { if (!xdr_bool(xdrsp, &true)) return (0); strp = &mlp->ml_host[0]; if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) return (0); strp = &mlp->ml_dirp[0]; if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) return (0); mlp = mlp->ml_next; } if (!xdr_bool(xdrsp, &false)) return (0); return (1); } /* * Xdr conversion for export list */ int xdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief) { struct exportlist *ep; int false = 0; int putdef; sigset_t sighup_mask; sigemptyset(&sighup_mask); sigaddset(&sighup_mask, SIGHUP); sigprocmask(SIG_BLOCK, &sighup_mask, NULL); ep = exphead; while (ep) { putdef = 0; if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef, brief)) goto errout; if (ep->ex_defdir && putdef == 0 && put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, &putdef, brief)) goto errout; ep = ep->ex_next; } sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); if (!xdr_bool(xdrsp, &false)) return (0); return (1); errout: sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); return (0); } /* * Called from xdr_explist() to traverse the tree and export the * directory paths. */ int put_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp, int brief) { struct grouplist *grp; struct hostlist *hp; int true = 1; int false = 0; int gotalldir = 0; char *strp; if (dp) { if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) return (1); if (!xdr_bool(xdrsp, &true)) return (1); strp = dp->dp_dirp; if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) return (1); if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { gotalldir = 1; *putdefp = 1; } if (brief) { if (!xdr_bool(xdrsp, &true)) return (1); strp = "(...)"; if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) return (1); } else if ((dp->dp_flag & DP_DEFSET) == 0 && (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { hp = dp->dp_hosts; while (hp) { grp = hp->ht_grp; if (grp->gr_type == GT_HOST) { if (!xdr_bool(xdrsp, &true)) return (1); strp = grp->gr_ptr.gt_addrinfo->ai_canonname; if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) return (1); } else if (grp->gr_type == GT_NET) { if (!xdr_bool(xdrsp, &true)) return (1); strp = grp->gr_ptr.gt_net.nt_name; if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) return (1); } hp = hp->ht_next; if (gotalldir && hp == (struct hostlist *)NULL) { hp = adp->dp_hosts; gotalldir = 0; } } } if (!xdr_bool(xdrsp, &false)) return (1); if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) return (1); } return (0); } int xdr_explist(XDR *xdrsp, caddr_t cp) { return xdr_explist_common(xdrsp, cp, 0); } int xdr_explist_brief(XDR *xdrsp, caddr_t cp) { return xdr_explist_common(xdrsp, cp, 1); } char *line; int linesize; FILE *exp_file; /* * Get the export list from one, currently open file */ static void get_exportlist_one(void) { struct exportlist *ep, *ep2; struct grouplist *grp, *tgrp; struct exportlist **epp; struct dirlist *dirhead; struct statfs fsb; struct xucred anon; char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; int len, has_host, exflags, got_nondir, dirplen, netgrp; v4root_phase = 0; dirhead = (struct dirlist *)NULL; while (get_line()) { if (debug) warnx("got line %s", line); cp = line; nextfield(&cp, &endcp); if (*cp == '#') goto nextline; /* * Set defaults. */ has_host = FALSE; anon = def_anon; exflags = MNT_EXPORTED; got_nondir = 0; opt_flags = 0; ep = (struct exportlist *)NULL; dirp = NULL; /* * Handle the V4 root dir. */ if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') { /* * V4: just indicates that it is the v4 root point, * so skip over that and set v4root_phase. */ if (v4root_phase > 0) { syslog(LOG_ERR, "V4:duplicate line, ignored"); goto nextline; } v4root_phase = 1; cp += 3; nextfield(&cp, &endcp); } /* * Create new exports list entry */ len = endcp-cp; tgrp = grp = get_grp(); while (len > 0) { if (len > MNTNAMLEN) { getexp_err(ep, tgrp); goto nextline; } if (*cp == '-') { if (ep == (struct exportlist *)NULL) { getexp_err(ep, tgrp); goto nextline; } if (debug) warnx("doing opt %s", cp); got_nondir = 1; if (do_opt(&cp, &endcp, ep, grp, &has_host, &exflags, &anon)) { getexp_err(ep, tgrp); goto nextline; } } else if (*cp == '/') { savedc = *endcp; *endcp = '\0'; if (v4root_phase > 1) { if (dirp != NULL) { syslog(LOG_ERR, "Multiple V4 dirs"); getexp_err(ep, tgrp); goto nextline; } } if (check_dirpath(cp) && statfs(cp, &fsb) >= 0) { + if ((fsb.f_flags & MNT_AUTOMOUNTED) != 0) + syslog(LOG_ERR, "Warning: exporting of " + "automounted fs %s not supported", cp); if (got_nondir) { syslog(LOG_ERR, "dirs must be first"); getexp_err(ep, tgrp); goto nextline; } if (v4root_phase == 1) { if (dirp != NULL) { syslog(LOG_ERR, "Multiple V4 dirs"); getexp_err(ep, tgrp); goto nextline; } if (strlen(v4root_dirpath) == 0) { strlcpy(v4root_dirpath, cp, sizeof (v4root_dirpath)); } else if (strcmp(v4root_dirpath, cp) != 0) { syslog(LOG_ERR, "different V4 dirpath %s", cp); getexp_err(ep, tgrp); goto nextline; } dirp = cp; v4root_phase = 2; got_nondir = 1; ep = get_exp(); } else { if (ep) { if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { getexp_err(ep, tgrp); goto nextline; } } else { /* * See if this directory is already * in the list. */ ep = ex_search(&fsb.f_fsid); if (ep == (struct exportlist *)NULL) { ep = get_exp(); ep->ex_fs = fsb.f_fsid; ep->ex_fsdir = (char *)malloc (strlen(fsb.f_mntonname) + 1); if (ep->ex_fsdir) strcpy(ep->ex_fsdir, fsb.f_mntonname); else out_of_mem(); if (debug) warnx( "making new ep fs=0x%x,0x%x", fsb.f_fsid.val[0], fsb.f_fsid.val[1]); } else if (debug) warnx("found ep fs=0x%x,0x%x", fsb.f_fsid.val[0], fsb.f_fsid.val[1]); } /* * Add dirpath to export mount point. */ dirp = add_expdir(&dirhead, cp, len); dirplen = len; } } else { getexp_err(ep, tgrp); goto nextline; } *endcp = savedc; } else { savedc = *endcp; *endcp = '\0'; got_nondir = 1; if (ep == (struct exportlist *)NULL) { getexp_err(ep, tgrp); goto nextline; } /* * Get the host or netgroup. */ setnetgrent(cp); netgrp = getnetgrent(&hst, &usr, &dom); do { if (has_host) { grp->gr_next = get_grp(); grp = grp->gr_next; } if (netgrp) { if (hst == 0) { syslog(LOG_ERR, "null hostname in netgroup %s, skipping", cp); grp->gr_type = GT_IGNORE; } else if (get_host(hst, grp, tgrp)) { syslog(LOG_ERR, "bad host %s in netgroup %s, skipping", hst, cp); grp->gr_type = GT_IGNORE; } } else if (get_host(cp, grp, tgrp)) { syslog(LOG_ERR, "bad host %s, skipping", cp); grp->gr_type = GT_IGNORE; } has_host = TRUE; } while (netgrp && getnetgrent(&hst, &usr, &dom)); endnetgrent(); *endcp = savedc; } cp = endcp; nextfield(&cp, &endcp); len = endcp - cp; } if (check_options(dirhead)) { getexp_err(ep, tgrp); goto nextline; } if (!has_host) { grp->gr_type = GT_DEFAULT; if (debug) warnx("adding a default entry"); /* * Don't allow a network export coincide with a list of * host(s) on the same line. */ } else if ((opt_flags & OP_NET) && tgrp->gr_next) { syslog(LOG_ERR, "network/host conflict"); getexp_err(ep, tgrp); goto nextline; /* * If an export list was specified on this line, make sure * that we have at least one valid entry, otherwise skip it. */ } else { grp = tgrp; while (grp && grp->gr_type == GT_IGNORE) grp = grp->gr_next; if (! grp) { getexp_err(ep, tgrp); goto nextline; } } if (v4root_phase == 1) { syslog(LOG_ERR, "V4:root, no dirp, ignored"); getexp_err(ep, tgrp); goto nextline; } /* * Loop through hosts, pushing the exports into the kernel. * After loop, tgrp points to the start of the list and * grp points to the last entry in the list. */ grp = tgrp; do { if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, &fsb)) { getexp_err(ep, tgrp); goto nextline; } } while (grp->gr_next && (grp = grp->gr_next)); /* * For V4: don't enter in mount lists. */ if (v4root_phase > 0 && v4root_phase <= 2) { /* * Since these structures aren't used by mountd, * free them up now. */ if (ep != NULL) free_exp(ep); while (tgrp != NULL) { grp = tgrp; tgrp = tgrp->gr_next; free_grp(grp); } goto nextline; } /* * Success. Update the data structures. */ if (has_host) { hang_dirp(dirhead, tgrp, ep, opt_flags); grp->gr_next = grphead; grphead = tgrp; } else { hang_dirp(dirhead, (struct grouplist *)NULL, ep, opt_flags); free_grp(grp); } dirhead = (struct dirlist *)NULL; if ((ep->ex_flag & EX_LINKED) == 0) { ep2 = exphead; epp = &exphead; /* * Insert in the list in alphabetical order. */ while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { epp = &ep2->ex_next; ep2 = ep2->ex_next; } if (ep2) ep->ex_next = ep2; *epp = ep; ep->ex_flag |= EX_LINKED; } nextline: v4root_phase = 0; if (dirhead) { free_dir(dirhead); dirhead = (struct dirlist *)NULL; } } } /* * Get the export list from all specified files */ void get_exportlist(void) { struct exportlist *ep, *ep2; struct grouplist *grp, *tgrp; struct export_args export; struct iovec *iov; struct statfs *fsp, *mntbufp; struct xvfsconf vfc; char errmsg[255]; int num, i; int iovlen; int done; struct nfsex_args eargs; if (suspend_nfsd != 0) (void)nfssvc(NFSSVC_SUSPENDNFSD, NULL); v4root_dirpath[0] = '\0'; bzero(&export, sizeof(export)); export.ex_flags = MNT_DELEXPORT; iov = NULL; iovlen = 0; bzero(errmsg, sizeof(errmsg)); /* * First, get rid of the old list */ ep = exphead; while (ep) { ep2 = ep; ep = ep->ex_next; free_exp(ep2); } exphead = (struct exportlist *)NULL; grp = grphead; while (grp) { tgrp = grp; grp = grp->gr_next; free_grp(tgrp); } grphead = (struct grouplist *)NULL; /* * and the old V4 root dir. */ bzero(&eargs, sizeof (eargs)); eargs.export.ex_flags = MNT_DELEXPORT; if (nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && errno != ENOENT) syslog(LOG_ERR, "Can't delete exports for V4:"); /* * and clear flag that notes if a public fh has been exported. */ has_publicfh = 0; /* * And delete exports that are in the kernel for all local * filesystems. * XXX: Should know how to handle all local exportable filesystems. */ num = getmntinfo(&mntbufp, MNT_NOWAIT); if (num > 0) { build_iovec(&iov, &iovlen, "fstype", NULL, 0); build_iovec(&iov, &iovlen, "fspath", NULL, 0); build_iovec(&iov, &iovlen, "from", NULL, 0); build_iovec(&iov, &iovlen, "update", NULL, 0); build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); } for (i = 0; i < num; i++) { fsp = &mntbufp[i]; if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { syslog(LOG_ERR, "getvfsbyname() failed for %s", fsp->f_fstypename); continue; } /* * We do not need to delete "export" flag from * filesystems that do not have it set. */ if (!(fsp->f_flags & MNT_EXPORTED)) continue; /* * Do not delete export for network filesystem by * passing "export" arg to nmount(). * It only makes sense to do this for local filesystems. */ if (vfc.vfc_flags & VFCF_NETWORK) continue; iov[1].iov_base = fsp->f_fstypename; iov[1].iov_len = strlen(fsp->f_fstypename) + 1; iov[3].iov_base = fsp->f_mntonname; iov[3].iov_len = strlen(fsp->f_mntonname) + 1; iov[5].iov_base = fsp->f_mntfromname; iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; errmsg[0] = '\0'; /* * EXDEV is returned when path exists but is not a * mount point. May happens if raced with unmount. */ if (nmount(iov, iovlen, fsp->f_flags) < 0 && errno != ENOENT && errno != ENOTSUP && errno != EXDEV) { syslog(LOG_ERR, "can't delete exports for %s: %m %s", fsp->f_mntonname, errmsg); } } if (iov != NULL) { /* Free strings allocated by strdup() in getmntopts.c */ free(iov[0].iov_base); /* fstype */ free(iov[2].iov_base); /* fspath */ free(iov[4].iov_base); /* from */ free(iov[6].iov_base); /* update */ free(iov[8].iov_base); /* export */ free(iov[10].iov_base); /* errmsg */ /* free iov, allocated by realloc() */ free(iov); iovlen = 0; } /* * Read in the exports file and build the list, calling * nmount() as we go along to push the export rules into the kernel. */ done = 0; for (i = 0; exnames[i] != NULL; i++) { if (debug) warnx("reading exports from %s", exnames[i]); if ((exp_file = fopen(exnames[i], "r")) == NULL) { syslog(LOG_WARNING, "can't open %s", exnames[i]); continue; } get_exportlist_one(); fclose(exp_file); done++; } if (done == 0) { syslog(LOG_ERR, "can't open any exports file"); exit(2); } /* * If there was no public fh, clear any previous one set. */ if (has_publicfh == 0) (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); /* Resume the nfsd. If they weren't suspended, this is harmless. */ (void)nfssvc(NFSSVC_RESUMENFSD, NULL); } /* * Allocate an export list element */ struct exportlist * get_exp(void) { struct exportlist *ep; ep = (struct exportlist *)calloc(1, sizeof (struct exportlist)); if (ep == (struct exportlist *)NULL) out_of_mem(); return (ep); } /* * Allocate a group list element */ struct grouplist * get_grp(void) { struct grouplist *gp; gp = (struct grouplist *)calloc(1, sizeof (struct grouplist)); if (gp == (struct grouplist *)NULL) out_of_mem(); return (gp); } /* * Clean up upon an error in get_exportlist(). */ void getexp_err(struct exportlist *ep, struct grouplist *grp) { struct grouplist *tgrp; if (!(opt_flags & OP_QUIET)) syslog(LOG_ERR, "bad exports list line %s", line); if (ep && (ep->ex_flag & EX_LINKED) == 0) free_exp(ep); while (grp) { tgrp = grp; grp = grp->gr_next; free_grp(tgrp); } } /* * Search the export list for a matching fs. */ struct exportlist * ex_search(fsid_t *fsid) { struct exportlist *ep; ep = exphead; while (ep) { if (ep->ex_fs.val[0] == fsid->val[0] && ep->ex_fs.val[1] == fsid->val[1]) return (ep); ep = ep->ex_next; } return (ep); } /* * Add a directory path to the list. */ char * add_expdir(struct dirlist **dpp, char *cp, int len) { struct dirlist *dp; dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); if (dp == (struct dirlist *)NULL) out_of_mem(); dp->dp_left = *dpp; dp->dp_right = (struct dirlist *)NULL; dp->dp_flag = 0; dp->dp_hosts = (struct hostlist *)NULL; strcpy(dp->dp_dirp, cp); *dpp = dp; return (dp->dp_dirp); } /* * Hang the dir list element off the dirpath binary tree as required * and update the entry for host. */ void hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, int flags) { struct hostlist *hp; struct dirlist *dp2; if (flags & OP_ALLDIRS) { if (ep->ex_defdir) free((caddr_t)dp); else ep->ex_defdir = dp; if (grp == (struct grouplist *)NULL) { ep->ex_defdir->dp_flag |= DP_DEFSET; /* Save the default security flavors list. */ ep->ex_defnumsecflavors = ep->ex_numsecflavors; if (ep->ex_numsecflavors > 0) memcpy(ep->ex_defsecflavors, ep->ex_secflavors, sizeof(ep->ex_secflavors)); } else while (grp) { hp = get_ht(); hp->ht_grp = grp; hp->ht_next = ep->ex_defdir->dp_hosts; ep->ex_defdir->dp_hosts = hp; /* Save the security flavors list for this host set. */ grp->gr_numsecflavors = ep->ex_numsecflavors; if (ep->ex_numsecflavors > 0) memcpy(grp->gr_secflavors, ep->ex_secflavors, sizeof(ep->ex_secflavors)); grp = grp->gr_next; } } else { /* * Loop through the directories adding them to the tree. */ while (dp) { dp2 = dp->dp_left; add_dlist(&ep->ex_dirl, dp, grp, flags, ep); dp = dp2; } } } /* * Traverse the binary tree either updating a node that is already there * for the new directory or adding the new node. */ void add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, int flags, struct exportlist *ep) { struct dirlist *dp; struct hostlist *hp; int cmp; dp = *dpp; if (dp) { cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); if (cmp > 0) { add_dlist(&dp->dp_left, newdp, grp, flags, ep); return; } else if (cmp < 0) { add_dlist(&dp->dp_right, newdp, grp, flags, ep); return; } else free((caddr_t)newdp); } else { dp = newdp; dp->dp_left = (struct dirlist *)NULL; *dpp = dp; } if (grp) { /* * Hang all of the host(s) off of the directory point. */ do { hp = get_ht(); hp->ht_grp = grp; hp->ht_next = dp->dp_hosts; dp->dp_hosts = hp; /* Save the security flavors list for this host set. */ grp->gr_numsecflavors = ep->ex_numsecflavors; if (ep->ex_numsecflavors > 0) memcpy(grp->gr_secflavors, ep->ex_secflavors, sizeof(ep->ex_secflavors)); grp = grp->gr_next; } while (grp); } else { dp->dp_flag |= DP_DEFSET; /* Save the default security flavors list. */ ep->ex_defnumsecflavors = ep->ex_numsecflavors; if (ep->ex_numsecflavors > 0) memcpy(ep->ex_defsecflavors, ep->ex_secflavors, sizeof(ep->ex_secflavors)); } } /* * Search for a dirpath on the export point. */ struct dirlist * dirp_search(struct dirlist *dp, char *dirp) { int cmp; if (dp) { cmp = strcmp(dp->dp_dirp, dirp); if (cmp > 0) return (dirp_search(dp->dp_left, dirp)); else if (cmp < 0) return (dirp_search(dp->dp_right, dirp)); else return (dp); } return (dp); } /* * Scan for a host match in a directory tree. */ int chk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp, int *hostsetp, int *numsecflavors, int **secflavorsp) { struct hostlist *hp; struct grouplist *grp; struct addrinfo *ai; if (dp) { if (dp->dp_flag & DP_DEFSET) *defsetp = dp->dp_flag; hp = dp->dp_hosts; while (hp) { grp = hp->ht_grp; switch (grp->gr_type) { case GT_HOST: ai = grp->gr_ptr.gt_addrinfo; for (; ai; ai = ai->ai_next) { if (!sacmp(ai->ai_addr, saddr, NULL)) { *hostsetp = (hp->ht_flag | DP_HOSTSET); if (numsecflavors != NULL) { *numsecflavors = grp->gr_numsecflavors; *secflavorsp = grp->gr_secflavors; } return (1); } } break; case GT_NET: if (!sacmp(saddr, (struct sockaddr *) &grp->gr_ptr.gt_net.nt_net, (struct sockaddr *) &grp->gr_ptr.gt_net.nt_mask)) { *hostsetp = (hp->ht_flag | DP_HOSTSET); if (numsecflavors != NULL) { *numsecflavors = grp->gr_numsecflavors; *secflavorsp = grp->gr_secflavors; } return (1); } break; } hp = hp->ht_next; } } return (0); } /* * Scan tree for a host that matches the address. */ int scan_tree(struct dirlist *dp, struct sockaddr *saddr) { int defset, hostset; if (dp) { if (scan_tree(dp->dp_left, saddr)) return (1); if (chk_host(dp, saddr, &defset, &hostset, NULL, NULL)) return (1); if (scan_tree(dp->dp_right, saddr)) return (1); } return (0); } /* * Traverse the dirlist tree and free it up. */ void free_dir(struct dirlist *dp) { if (dp) { free_dir(dp->dp_left); free_dir(dp->dp_right); free_host(dp->dp_hosts); free((caddr_t)dp); } } /* * Parse a colon separated list of security flavors */ int parsesec(char *seclist, struct exportlist *ep) { char *cp, savedc; int flavor; ep->ex_numsecflavors = 0; for (;;) { cp = strchr(seclist, ':'); if (cp) { savedc = *cp; *cp = '\0'; } if (!strcmp(seclist, "sys")) flavor = AUTH_SYS; else if (!strcmp(seclist, "krb5")) flavor = RPCSEC_GSS_KRB5; else if (!strcmp(seclist, "krb5i")) flavor = RPCSEC_GSS_KRB5I; else if (!strcmp(seclist, "krb5p")) flavor = RPCSEC_GSS_KRB5P; else { if (cp) *cp = savedc; syslog(LOG_ERR, "bad sec flavor: %s", seclist); return (1); } if (ep->ex_numsecflavors == MAXSECFLAVORS) { if (cp) *cp = savedc; syslog(LOG_ERR, "too many sec flavors: %s", seclist); return (1); } ep->ex_secflavors[ep->ex_numsecflavors] = flavor; ep->ex_numsecflavors++; if (cp) { *cp = savedc; seclist = cp + 1; } else { break; } } return (0); } /* * Parse the option string and update fields. * Option arguments may either be -