5d2bc782f171008a32f4bf2a1088f3cec6773642
[platform/upstream/openblas.git] / driver / others / dynamic.c
1 /*********************************************************************/
2 /* Copyright 2009, 2010 The University of Texas at Austin.           */
3 /* All rights reserved.                                              */
4 /*                                                                   */
5 /* Redistribution and use in source and binary forms, with or        */
6 /* without modification, are permitted provided that the following   */
7 /* conditions are met:                                               */
8 /*                                                                   */
9 /*   1. Redistributions of source code must retain the above         */
10 /*      copyright notice, this list of conditions and the following  */
11 /*      disclaimer.                                                  */
12 /*                                                                   */
13 /*   2. Redistributions in binary form must reproduce the above      */
14 /*      copyright notice, this list of conditions and the following  */
15 /*      disclaimer in the documentation and/or other materials       */
16 /*      provided with the distribution.                              */
17 /*                                                                   */
18 /*    THIS  SOFTWARE IS PROVIDED  BY THE  UNIVERSITY OF  TEXAS AT    */
19 /*    AUSTIN  ``AS IS''  AND ANY  EXPRESS OR  IMPLIED WARRANTIES,    */
20 /*    INCLUDING, BUT  NOT LIMITED  TO, THE IMPLIED  WARRANTIES OF    */
21 /*    MERCHANTABILITY  AND FITNESS FOR  A PARTICULAR  PURPOSE ARE    */
22 /*    DISCLAIMED.  IN  NO EVENT SHALL THE UNIVERSITY  OF TEXAS AT    */
23 /*    AUSTIN OR CONTRIBUTORS BE  LIABLE FOR ANY DIRECT, INDIRECT,    */
24 /*    INCIDENTAL,  SPECIAL, EXEMPLARY,  OR  CONSEQUENTIAL DAMAGES    */
25 /*    (INCLUDING, BUT  NOT LIMITED TO,  PROCUREMENT OF SUBSTITUTE    */
26 /*    GOODS  OR  SERVICES; LOSS  OF  USE,  DATA,  OR PROFITS;  OR    */
27 /*    BUSINESS INTERRUPTION) HOWEVER CAUSED  AND ON ANY THEORY OF    */
28 /*    LIABILITY, WHETHER  IN CONTRACT, STRICT  LIABILITY, OR TORT    */
29 /*    (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY WAY OUT    */
30 /*    OF  THE  USE OF  THIS  SOFTWARE,  EVEN  IF ADVISED  OF  THE    */
31 /*    POSSIBILITY OF SUCH DAMAGE.                                    */
32 /*                                                                   */
33 /* The views and conclusions contained in the software and           */
34 /* documentation are those of the authors and should not be          */
35 /* interpreted as representing official policies, either expressed   */
36 /* or implied, of The University of Texas at Austin.                 */
37 /*********************************************************************/
38
39 #include "common.h"
40
41 #ifdef ARCH_X86
42 #define EXTERN extern
43 #else
44 #define EXTERN
45 #endif
46
47 EXTERN gotoblas_t  gotoblas_KATMAI;
48 EXTERN gotoblas_t  gotoblas_COPPERMINE;
49 EXTERN gotoblas_t  gotoblas_NORTHWOOD;
50 EXTERN gotoblas_t  gotoblas_BANIAS;
51 EXTERN gotoblas_t  gotoblas_ATHLON;
52
53 extern gotoblas_t  gotoblas_PRESCOTT;
54 extern gotoblas_t  gotoblas_ATOM;
55 extern gotoblas_t  gotoblas_NANO;
56 extern gotoblas_t  gotoblas_CORE2;
57 extern gotoblas_t  gotoblas_PENRYN;
58 extern gotoblas_t  gotoblas_DUNNINGTON;
59 extern gotoblas_t  gotoblas_NEHALEM;
60 extern gotoblas_t  gotoblas_OPTERON;
61 extern gotoblas_t  gotoblas_OPTERON_SSE3;
62 extern gotoblas_t  gotoblas_BARCELONA;
63 extern gotoblas_t  gotoblas_BOBCAT;
64 #ifndef NO_AVX
65 extern gotoblas_t  gotoblas_SANDYBRIDGE;
66 #else
67 //Use NEHALEM kernels for sandy bridge
68 #define gotoblas_SANDYBRIDGE gotoblas_NEHALEM
69 #endif
70
71
72 #define VENDOR_INTEL      1
73 #define VENDOR_AMD        2
74 #define VENDOR_CENTAUR    3
75 #define VENDOR_UNKNOWN   99
76
77 #define BITMASK(a, b, c) ((((a) >> (b)) & (c)))
78
79 #ifndef NO_AVX
80 static inline void xgetbv(int op, int * eax, int * edx){
81   __asm__ __volatile__
82     ("xgetbv": "=a" (*eax), "=d" (*edx) : "c" (op) : "cc");
83 }
84 #endif
85
86 int support_avx(){
87 #ifndef NO_AVX
88   int eax, ebx, ecx, edx;
89   int ret=0;
90   
91   cpuid(1, &eax, &ebx, &ecx, &edx);
92   if ((ecx & (1 << 28)) != 0 && (ecx & (1 << 27)) != 0){
93     xgetbv(0, &eax, &edx);
94     if((eax & 6) == 6){
95       ret=1;  //OS support AVX
96     }
97   }
98   return ret;
99 #else
100   return 0;
101 #endif
102 }
103
104 static int get_vendor(void){
105   int eax, ebx, ecx, edx;
106   char vendor[13];
107
108   cpuid(0, &eax, &ebx, &ecx, &edx);
109   
110   *(int *)(&vendor[0]) = ebx;
111   *(int *)(&vendor[4]) = edx;
112   *(int *)(&vendor[8]) = ecx;
113   vendor[12] = (char)0;
114
115   if (!strcmp(vendor, "GenuineIntel")) return VENDOR_INTEL;
116   if (!strcmp(vendor, "AuthenticAMD")) return VENDOR_AMD;
117   if (!strcmp(vendor, "CentaurHauls")) return VENDOR_CENTAUR;
118
119   if ((eax == 0) || ((eax & 0x500) != 0)) return VENDOR_INTEL;
120
121   return VENDOR_UNKNOWN;
122 }
123
124 static gotoblas_t *get_coretype(void){
125
126   int eax, ebx, ecx, edx;
127   int family, exfamily, model, vendor, exmodel;
128
129   cpuid(1, &eax, &ebx, &ecx, &edx);
130
131   family   = BITMASK(eax,  8, 0x0f);
132   exfamily = BITMASK(eax, 20, 0xff);
133   model    = BITMASK(eax,  4, 0x0f);
134   exmodel  = BITMASK(eax, 16, 0x0f);
135
136   vendor = get_vendor();
137
138   if (vendor == VENDOR_INTEL){
139     switch (family) {
140     case 0x6:
141       switch (exmodel) {
142       case 0:
143         if (model <= 0x7) return &gotoblas_KATMAI;
144         if ((model == 0x8) || (model == 0xa) || (model == 0xb)) return &gotoblas_COPPERMINE;
145         if ((model == 0x9) || (model == 0xd)) return &gotoblas_BANIAS;
146         if (model == 14) return &gotoblas_BANIAS;
147         if (model == 15) return &gotoblas_CORE2;
148         return NULL;
149
150       case 1:
151         if (model == 6) return &gotoblas_CORE2;
152         if (model == 7) return &gotoblas_PENRYN;
153         if (model == 13) return &gotoblas_DUNNINGTON;
154         if ((model == 10) || (model == 11) || (model == 14) || (model == 15)) return &gotoblas_NEHALEM;
155         if (model == 12) return &gotoblas_ATOM;
156         return NULL;
157
158       case 2:
159         //Intel Core (Clarkdale) / Core (Arrandale)
160         // Pentium (Clarkdale) / Pentium Mobile (Arrandale)
161         // Xeon (Clarkdale), 32nm
162         if (model ==  5) return &gotoblas_NEHALEM;
163                   
164         //Intel Xeon Processor 5600 (Westmere-EP)
165         //Xeon Processor E7 (Westmere-EX)
166         if (model == 12 || model == 15) return &gotoblas_NEHALEM;
167
168         //Intel Core i5-2000 /i7-2000 (Sandy Bridge)
169         //Intel Core i7-3000 / Xeon E5
170         if (model == 10 || model == 13) {
171           if(support_avx())
172             return &gotoblas_SANDYBRIDGE;
173           else{
174             fprintf(stderr, "OpenBLAS : Your OS doesn't support AVX. Use Nehalem kernels.\n");
175             return &gotoblas_NEHALEM; //OS doesn't support AVX. Use old kernels.
176           }
177         }
178         return NULL;
179       case 3:
180         //Intel Sandy Bridge 22nm (Ivy Bridge?)
181         if (model == 10) {
182           if(support_avx())
183             return &gotoblas_SANDYBRIDGE;
184           else{
185             fprintf(stderr, "OpenBLAS : Your OS doesn't support AVX. Use Nehalem kernels.\n");
186             return &gotoblas_NEHALEM; //OS doesn't support AVX. Use old kernels.
187           }
188         }
189         return NULL;
190       }
191       case 0xf:
192       if (model <= 0x2) return &gotoblas_NORTHWOOD;
193       return &gotoblas_PRESCOTT;
194     }
195   }
196
197   if (vendor == VENDOR_AMD){
198     if (family <= 0xe) return &gotoblas_ATHLON;
199     if (family == 0xf){
200       if ((exfamily == 0) || (exfamily == 2)) {
201         if (ecx & (1 <<  0)) return &gotoblas_OPTERON_SSE3; 
202         else return &gotoblas_OPTERON;
203       }  else if (exfamily == 5) {
204         return &gotoblas_BOBCAT;
205       } else {
206         return &gotoblas_BARCELONA;
207       }
208     }
209   }
210
211   if (vendor == VENDOR_CENTAUR) {
212     switch (family) {
213     case 0x6:
214       return &gotoblas_NANO;
215       break;
216     }
217   }
218   
219   return NULL;
220 }
221
222 static char *corename[] = {
223     "Unknown",
224     "Katmai",
225     "Coppermine",
226     "Northwood",
227     "Prescott",
228     "Banias",
229     "Atom",
230     "Core2",
231     "Penryn",
232     "Dunnington",
233     "Nehalem",
234     "Athlon",
235     "Opteron",
236     "Opteron(SSE3)",
237     "Barcelona",
238     "Nano",
239     "Sandybridge",
240     "Bobcat",
241 };
242
243 char *gotoblas_corename(void) {
244
245   if (gotoblas == &gotoblas_KATMAI)       return corename[ 1];
246   if (gotoblas == &gotoblas_COPPERMINE)   return corename[ 2];
247   if (gotoblas == &gotoblas_NORTHWOOD)    return corename[ 3];
248   if (gotoblas == &gotoblas_PRESCOTT)     return corename[ 4];
249   if (gotoblas == &gotoblas_BANIAS)       return corename[ 5];
250   if (gotoblas == &gotoblas_ATOM)         return corename[ 6];
251   if (gotoblas == &gotoblas_CORE2)        return corename[ 7];
252   if (gotoblas == &gotoblas_PENRYN)       return corename[ 8];
253   if (gotoblas == &gotoblas_DUNNINGTON)   return corename[ 9];
254   if (gotoblas == &gotoblas_NEHALEM)      return corename[10];
255   if (gotoblas == &gotoblas_ATHLON)       return corename[11];
256   if (gotoblas == &gotoblas_OPTERON_SSE3) return corename[12]; 
257   if (gotoblas == &gotoblas_OPTERON)      return corename[13];
258   if (gotoblas == &gotoblas_BARCELONA)    return corename[14];
259   if (gotoblas == &gotoblas_NANO)         return corename[15];
260   if (gotoblas == &gotoblas_SANDYBRIDGE)  return corename[16];
261   if (gotoblas == &gotoblas_BOBCAT)       return corename[17];
262
263   return corename[0];
264 }
265
266 void gotoblas_dynamic_init(void) {
267   
268   if (gotoblas) return;
269
270   gotoblas = get_coretype();
271   
272 #ifdef ARCH_X86
273   if (gotoblas == NULL) gotoblas = &gotoblas_KATMAI;
274 #else
275   if (gotoblas == NULL) gotoblas = &gotoblas_PRESCOTT;
276 #endif
277   
278   if (gotoblas && gotoblas -> init) {
279     gotoblas -> init();
280   } else {
281     fprintf(stderr, "OpenBLAS : Architecture Initialization failed. No initialization function found.\n");
282     exit(1);
283   }
284   
285 }
286
287 void gotoblas_dynamic_quit(void) {
288   
289   gotoblas = NULL;
290
291 }