2 * System Abstraction Layer (SAL) interface routines.
4 * Copyright (C) 1998, 1999, 2001, 2003 Hewlett-Packard Co
5 * David Mosberger-Tang <davidm@hpl.hp.com>
6 * Copyright (C) 1999 VA Linux Systems
7 * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
9 #include <linux/config.h>
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/spinlock.h>
14 #include <linux/string.h>
20 spinlock_t sal_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
21 unsigned long sal_platform_features;
23 unsigned short sal_revision;
24 unsigned short sal_version;
26 #define SAL_MAJOR(x) ((x) >> 8)
27 #define SAL_MINOR(x) ((x) & 0xff)
30 void *addr; /* function entry point */
31 void *gpval; /* gp value to use */
35 default_handler (void)
40 ia64_sal_handler ia64_sal = (ia64_sal_handler) default_handler;
41 ia64_sal_desc_ptc_t *ia64_ptc_domain_info;
44 ia64_sal_strerror (long status)
48 case 0: str = "Call completed without error"; break;
49 case 1: str = "Effect a warm boot of the system to complete "
51 case -1: str = "Not implemented"; break;
52 case -2: str = "Invalid argument"; break;
53 case -3: str = "Call completed with error"; break;
54 case -4: str = "Virtual address not registered"; break;
55 case -5: str = "No information available"; break;
56 case -6: str = "Insufficient space to add the entry"; break;
57 case -7: str = "Invalid entry_addr value"; break;
58 case -8: str = "Invalid interrupt vector"; break;
59 case -9: str = "Requested memory not available"; break;
60 case -10: str = "Unable to write to the NVM device"; break;
61 case -11: str = "Invalid partition type specified"; break;
62 case -12: str = "Invalid NVM_Object id specified"; break;
63 case -13: str = "NVM_Object already has the maximum number "
64 "of partitions"; break;
65 case -14: str = "Insufficient space in partition for the "
66 "requested write sub-function"; break;
67 case -15: str = "Insufficient data buffer space for the "
68 "requested read record sub-function"; break;
69 case -16: str = "Scratch buffer required for the write/delete "
70 "sub-function"; break;
71 case -17: str = "Insufficient space in the NVM_Object for the "
72 "requested create sub-function"; break;
73 case -18: str = "Invalid value specified in the partition_rec "
75 case -19: str = "Record oriented I/O not supported for this "
77 case -20: str = "Bad format of record to be written or "
78 "required keyword variable not "
80 default: str = "Unknown SAL status code"; break;
86 ia64_sal_handler_init (void *entry_point, void *gpval)
88 /* fill in the SAL procedure descriptor and point ia64_sal to it: */
89 pdesc.addr = entry_point;
91 ia64_sal = (ia64_sal_handler) &pdesc;
95 check_versions (struct ia64_sal_systab *systab)
97 sal_revision = (systab->sal_rev_major << 8) | systab->sal_rev_minor;
98 sal_version = (systab->sal_b_rev_major << 8) | systab->sal_b_rev_minor;
100 /* Check for broken firmware */
101 if ((sal_revision == SAL_VERSION_CODE(49, 29))
102 && (sal_version == SAL_VERSION_CODE(49, 29)))
105 * Old firmware for zx2000 prototypes have this weird version number,
106 * reset it to something sane.
108 sal_revision = SAL_VERSION_CODE(2, 8);
109 sal_version = SAL_VERSION_CODE(0, 0);
114 sal_desc_entry_point (void *p)
116 struct ia64_sal_desc_entry_point *ep = p;
117 ia64_pal_handler_init(__va(ep->pal_proc));
118 ia64_sal_handler_init(__va(ep->sal_proc), __va(ep->gp));
123 set_smp_redirect (int flag)
126 smp_int_redirect &= ~flag;
128 smp_int_redirect |= flag;
131 #define set_smp_redirect(flag) do { } while (0)
135 sal_desc_platform_feature (void *p)
137 struct ia64_sal_desc_platform_feature *pf = p;
138 sal_platform_features = pf->feature_mask;
140 printk(KERN_INFO "SAL Platform features:");
141 if (!sal_platform_features) {
146 if (sal_platform_features & IA64_SAL_PLATFORM_FEATURE_BUS_LOCK)
148 if (sal_platform_features & IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT) {
149 printk(" IRQ_Redirection");
150 set_smp_redirect(SMP_IRQ_REDIRECTION);
152 if (sal_platform_features & IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT) {
153 printk(" IPI_Redirection");
154 set_smp_redirect(SMP_IPI_REDIRECTION);
156 if (sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)
157 printk(" ITC_Drift");
163 sal_desc_ap_wakeup (void *p)
165 struct ia64_sal_desc_ap_wakeup *ap = p;
167 switch (ap->mechanism) {
168 case IA64_SAL_AP_EXTERNAL_INT:
169 ap_wakeup_vector = ap->vector;
170 printk(KERN_INFO "SAL: AP wakeup using external interrupt "
171 "vector 0x%lx\n", ap_wakeup_vector);
174 printk(KERN_ERR "SAL: AP wakeup mechanism unsupported!\n");
179 static void __init sal_desc_ap_wakeup(void *p) { }
183 ia64_sal_init (struct ia64_sal_systab *systab)
189 printk(KERN_WARNING "Hmm, no SAL System Table.\n");
193 if (strncmp(systab->signature, "SST_", 4) != 0)
194 printk(KERN_ERR "bad signature in system table!");
196 check_versions(systab);
198 /* revisions are coded in BCD, so %x does the job for us */
199 printk(KERN_INFO "SAL %x.%x: %.32s %.32s%sversion %x.%x\n",
200 SAL_MAJOR(sal_revision), SAL_MINOR(sal_revision),
201 systab->oem_id, systab->product_id,
202 systab->product_id[0] ? " " : "",
203 SAL_MAJOR(sal_version), SAL_MINOR(sal_version));
205 p = (char *) (systab + 1);
206 for (i = 0; i < systab->entry_count; i++) {
208 * The first byte of each entry type contains the type
212 case SAL_DESC_ENTRY_POINT:
213 sal_desc_entry_point(p);
215 case SAL_DESC_PLATFORM_FEATURE:
216 sal_desc_platform_feature(p);
219 ia64_ptc_domain_info = (ia64_sal_desc_ptc_t *)p;
221 case SAL_DESC_AP_WAKEUP:
222 sal_desc_ap_wakeup(p);
225 p += SAL_DESC_SIZE(*p);