Init AMD Bulldozer codebase.
[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 extern gotoblas_t  gotoblas_BULLDOZER;
67 #else
68 //Use NEHALEM kernels for sandy bridge
69 #define gotoblas_SANDYBRIDGE gotoblas_NEHALEM
70 #define gotoblas_BULLDOZER gotoblas_BARCELONA
71 #endif
72
73
74 #define VENDOR_INTEL      1
75 #define VENDOR_AMD        2
76 #define VENDOR_CENTAUR    3
77 #define VENDOR_UNKNOWN   99
78
79 #define BITMASK(a, b, c) ((((a) >> (b)) & (c)))
80
81 #ifndef NO_AVX
82 static inline void xgetbv(int op, int * eax, int * edx){
83   __asm__ __volatile__
84     ("xgetbv": "=a" (*eax), "=d" (*edx) : "c" (op) : "cc");
85 }
86 #endif
87
88 int support_avx(){
89 #ifndef NO_AVX
90   int eax, ebx, ecx, edx;
91   int ret=0;
92   
93   cpuid(1, &eax, &ebx, &ecx, &edx);
94   if ((ecx & (1 << 28)) != 0 && (ecx & (1 << 27)) != 0){
95     xgetbv(0, &eax, &edx);
96     if((eax & 6) == 6){
97       ret=1;  //OS support AVX
98     }
99   }
100   return ret;
101 #else
102   return 0;
103 #endif
104 }
105
106 static int get_vendor(void){
107   int eax, ebx, ecx, edx;
108   char vendor[13];
109
110   cpuid(0, &eax, &ebx, &ecx, &edx);
111   
112   *(int *)(&vendor[0]) = ebx;
113   *(int *)(&vendor[4]) = edx;
114   *(int *)(&vendor[8]) = ecx;
115   vendor[12] = (char)0;
116
117   if (!strcmp(vendor, "GenuineIntel")) return VENDOR_INTEL;
118   if (!strcmp(vendor, "AuthenticAMD")) return VENDOR_AMD;
119   if (!strcmp(vendor, "CentaurHauls")) return VENDOR_CENTAUR;
120
121   if ((eax == 0) || ((eax & 0x500) != 0)) return VENDOR_INTEL;
122
123   return VENDOR_UNKNOWN;
124 }
125
126 static gotoblas_t *get_coretype(void){
127
128   int eax, ebx, ecx, edx;
129   int family, exfamily, model, vendor, exmodel;
130
131   cpuid(1, &eax, &ebx, &ecx, &edx);
132
133   family   = BITMASK(eax,  8, 0x0f);
134   exfamily = BITMASK(eax, 20, 0xff);
135   model    = BITMASK(eax,  4, 0x0f);
136   exmodel  = BITMASK(eax, 16, 0x0f);
137
138   vendor = get_vendor();
139
140   if (vendor == VENDOR_INTEL){
141     switch (family) {
142     case 0x6:
143       switch (exmodel) {
144       case 0:
145         if (model <= 0x7) return &gotoblas_KATMAI;
146         if ((model == 0x8) || (model == 0xa) || (model == 0xb)) return &gotoblas_COPPERMINE;
147         if ((model == 0x9) || (model == 0xd)) return &gotoblas_BANIAS;
148         if (model == 14) return &gotoblas_BANIAS;
149         if (model == 15) return &gotoblas_CORE2;
150         return NULL;
151
152       case 1:
153         if (model == 6) return &gotoblas_CORE2;
154         if (model == 7) return &gotoblas_PENRYN;
155         if (model == 13) return &gotoblas_DUNNINGTON;
156         if ((model == 10) || (model == 11) || (model == 14) || (model == 15)) return &gotoblas_NEHALEM;
157         if (model == 12) return &gotoblas_ATOM;
158         return NULL;
159
160       case 2:
161         //Intel Core (Clarkdale) / Core (Arrandale)
162         // Pentium (Clarkdale) / Pentium Mobile (Arrandale)
163         // Xeon (Clarkdale), 32nm
164         if (model ==  5) return &gotoblas_NEHALEM;
165                   
166         //Intel Xeon Processor 5600 (Westmere-EP)
167         //Xeon Processor E7 (Westmere-EX)
168         if (model == 12 || model == 15) return &gotoblas_NEHALEM;
169
170         //Intel Core i5-2000 /i7-2000 (Sandy Bridge)
171         //Intel Core i7-3000 / Xeon E5
172         if (model == 10 || model == 13) {
173           if(support_avx())
174             return &gotoblas_SANDYBRIDGE;
175           else{
176             fprintf(stderr, "OpenBLAS : Your OS doesn't support AVX. Use Nehalem kernels.\n");
177             return &gotoblas_NEHALEM; //OS doesn't support AVX. Use old kernels.
178           }
179         }
180         return NULL;
181       case 3:
182         //Intel Sandy Bridge 22nm (Ivy Bridge?)
183         if (model == 10) {
184           if(support_avx())
185             return &gotoblas_SANDYBRIDGE;
186           else{
187             fprintf(stderr, "OpenBLAS : Your OS doesn't support AVX. Use Nehalem kernels.\n");
188             return &gotoblas_NEHALEM; //OS doesn't support AVX. Use old kernels.
189           }
190         }
191         return NULL;
192       }
193       case 0xf:
194       if (model <= 0x2) return &gotoblas_NORTHWOOD;
195       return &gotoblas_PRESCOTT;
196     }
197   }
198
199   if (vendor == VENDOR_AMD){
200     if (family <= 0xe) return &gotoblas_ATHLON;
201     if (family == 0xf){
202       if ((exfamily == 0) || (exfamily == 2)) {
203         if (ecx & (1 <<  0)) return &gotoblas_OPTERON_SSE3; 
204         else return &gotoblas_OPTERON;
205       }  else if (exfamily == 5) {
206         return &gotoblas_BOBCAT;
207       } else if (exfamily == 6) {
208         //AMD Bulldozer Opteron 6200 / Opteron 4200 / AMD FX-Series
209           if(support_avx())
210             return &gotoblas_BULLDOZER;
211           else{
212             fprintf(stderr, "OpenBLAS : Your OS doesn't support AVX. Use Barcelona kernels.\n");
213             return &gotoblas_BARCELONA; //OS doesn't support AVX. Use old kernels.
214           }     
215       } else {
216         return &gotoblas_BARCELONA;
217       }
218     }
219   }
220
221   if (vendor == VENDOR_CENTAUR) {
222     switch (family) {
223     case 0x6:
224       return &gotoblas_NANO;
225       break;
226     }
227   }
228   
229   return NULL;
230 }
231
232 static char *corename[] = {
233     "Unknown",
234     "Katmai",
235     "Coppermine",
236     "Northwood",
237     "Prescott",
238     "Banias",
239     "Atom",
240     "Core2",
241     "Penryn",
242     "Dunnington",
243     "Nehalem",
244     "Athlon",
245     "Opteron",
246     "Opteron(SSE3)",
247     "Barcelona",
248     "Nano",
249     "Sandybridge",
250     "Bobcat",
251     "Bulldozer",
252 };
253
254 char *gotoblas_corename(void) {
255
256   if (gotoblas == &gotoblas_KATMAI)       return corename[ 1];
257   if (gotoblas == &gotoblas_COPPERMINE)   return corename[ 2];
258   if (gotoblas == &gotoblas_NORTHWOOD)    return corename[ 3];
259   if (gotoblas == &gotoblas_PRESCOTT)     return corename[ 4];
260   if (gotoblas == &gotoblas_BANIAS)       return corename[ 5];
261   if (gotoblas == &gotoblas_ATOM)         return corename[ 6];
262   if (gotoblas == &gotoblas_CORE2)        return corename[ 7];
263   if (gotoblas == &gotoblas_PENRYN)       return corename[ 8];
264   if (gotoblas == &gotoblas_DUNNINGTON)   return corename[ 9];
265   if (gotoblas == &gotoblas_NEHALEM)      return corename[10];
266   if (gotoblas == &gotoblas_ATHLON)       return corename[11];
267   if (gotoblas == &gotoblas_OPTERON_SSE3) return corename[12]; 
268   if (gotoblas == &gotoblas_OPTERON)      return corename[13];
269   if (gotoblas == &gotoblas_BARCELONA)    return corename[14];
270   if (gotoblas == &gotoblas_NANO)         return corename[15];
271   if (gotoblas == &gotoblas_SANDYBRIDGE)  return corename[16];
272   if (gotoblas == &gotoblas_BOBCAT)       return corename[17];
273   if (gotoblas == &gotoblas_BULLDOZER)    return corename[18];
274
275   return corename[0];
276 }
277
278 void gotoblas_dynamic_init(void) {
279   
280   if (gotoblas) return;
281
282   gotoblas = get_coretype();
283   
284 #ifdef ARCH_X86
285   if (gotoblas == NULL) gotoblas = &gotoblas_KATMAI;
286 #else
287   if (gotoblas == NULL) gotoblas = &gotoblas_PRESCOTT;
288 #endif
289   
290   if (gotoblas && gotoblas -> init) {
291     gotoblas -> init();
292   } else {
293     fprintf(stderr, "OpenBLAS : Architecture Initialization failed. No initialization function found.\n");
294     exit(1);
295   }
296   
297 }
298
299 void gotoblas_dynamic_quit(void) {
300   
301   gotoblas = NULL;
302
303 }