summaryrefslogtreecommitdiffstats
path: root/arch/ia64/kernel/sal.c
blob: f4b8ce9ddb4d959cb3d8c8b5abc069f15348a803 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*
 * System Abstraction Layer (SAL) interface routines.
 *
 * Copyright (C) 1998, 1999 Hewlett-Packard Co
 * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
 * Copyright (C) 1999 VA Linux Systems
 * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
 */
#include <linux/config.h>

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/spinlock.h>
#include <linux/string.h>

#include <asm/page.h>
#include <asm/sal.h>
#include <asm/pal.h>

#define SAL_DEBUG

spinlock_t sal_lock = SPIN_LOCK_UNLOCKED;

static struct {
	void *addr;	/* function entry point */
	void *gpval;	/* gp value to use */
} pdesc;

static long
default_handler (void)
{
	return -1;
}

ia64_sal_handler ia64_sal = (ia64_sal_handler) default_handler;

const char *
ia64_sal_strerror (long status)
{
	const char *str;
	switch (status) {
	      case 0: str = "Call completed without error"; break;
	      case 1: str = "Effect a warm boot of the system to complete "
			      "the update"; break;
	      case -1: str = "Not implemented"; break;
	      case -2: str = "Invalid argument"; break;
	      case -3: str = "Call completed with error"; break;
	      case -4: str = "Virtual address not registered"; break;
	      case -5: str = "No information available"; break;
	      case -6: str = "Insufficient space to add the entry"; break;
	      case -7: str = "Invalid entry_addr value"; break;
	      case -8: str = "Invalid interrupt vector"; break;
	      case -9: str = "Requested memory not available"; break;
	      case -10: str = "Unable to write to the NVM device"; break;
	      case -11: str = "Invalid partition type specified"; break;
	      case -12: str = "Invalid NVM_Object id specified"; break;
	      case -13: str = "NVM_Object already has the maximum number "
				"of partitions"; break;
	      case -14: str = "Insufficient space in partition for the "
				"requested write sub-function"; break;
	      case -15: str = "Insufficient data buffer space for the "
				"requested read record sub-function"; break;
	      case -16: str = "Scratch buffer required for the write/delete "
				"sub-function"; break;
	      case -17: str = "Insufficient space in the NVM_Object for the "
				"requested create sub-function"; break;
	      case -18: str = "Invalid value specified in the partition_rec "
				"argument"; break;
	      case -19: str = "Record oriented I/O not supported for this "
				"partition"; break;
	      case -20: str = "Bad format of record to be written or "
				"required keyword variable not "
				"specified"; break;
	      default: str = "Unknown SAL status code"; break;
	}
	return str;
}

static void __init 
ia64_sal_handler_init (void *entry_point, void *gpval)
{
	/* fill in the SAL procedure descriptor and point ia64_sal to it: */
	pdesc.addr = entry_point;
	pdesc.gpval = gpval;
	ia64_sal = (ia64_sal_handler) &pdesc;
}


void __init
ia64_sal_init (struct ia64_sal_systab *systab)
{
	unsigned long min, max;
	char *p;
	struct ia64_sal_desc_entry_point *ep;
	int i;

	if (!systab) {
		printk("Hmm, no SAL System Table.\n");
		return;
	}

	if (strncmp(systab->signature, "SST_", 4) != 0)
		printk("bad signature in system table!");

	printk("SAL v%u.%02u: ia32bios=%s, oem=%.32s, product=%.32s\n",
	       systab->sal_rev_major, systab->sal_rev_minor,
	       systab->ia32_bios_present ? "present" : "absent",
	       systab->oem_id, systab->product_id);

	min = ~0UL;
	max = 0;

	p = (char *) (systab + 1);
	for (i = 0; i < systab->entry_count; i++) {
		/*
		 * The first byte of each entry type contains the type desciptor.
		 */
		switch (*p) {
		      case SAL_DESC_ENTRY_POINT:
			ep = (struct ia64_sal_desc_entry_point *) p;
#ifdef SAL_DEBUG
			printk("sal[%d] - entry: pal_proc=0x%lx, sal_proc=0x%lx\n",
			       i, ep->pal_proc, ep->sal_proc);
#endif
			ia64_pal_handler_init(__va(ep->pal_proc));
			ia64_sal_handler_init(__va(ep->sal_proc), __va(ep->gp));
			break;

		      case SAL_DESC_AP_WAKEUP:
#ifdef CONFIG_SMP
		      {
			      struct ia64_sal_desc_ap_wakeup *ap = (void *) p;
# ifdef SAL_DEBUG
			      printk("sal[%d] - wakeup type %x, 0x%lx\n",
				     i, ap->mechanism, ap->vector);
# endif
			      switch (ap->mechanism) {
				    case IA64_SAL_AP_EXTERNAL_INT:
				      ap_wakeup_vector = ap->vector;
# ifdef SAL_DEBUG
				      printk("SAL: AP wakeup using external interrupt "
					     "vector 0x%lx\n", ap_wakeup_vector);
# endif
				      break;

				    default:
				      printk("SAL: AP wakeup mechanism unsupported!\n");
				      break;
			      }
			      break;
		      }
#endif
		      case SAL_DESC_PLATFORM_FEATURE:
		      {
			      struct ia64_sal_desc_platform_feature *pf = (void *) p;
			      printk("SAL: Platform features ");

			      if (pf->feature_mask & (1 << 0))
				      printk("BusLock ");

			      if (pf->feature_mask & (1 << 1)) {
				      printk("IRQ_Redirection ");
#ifdef CONFIG_SMP
				      if (no_int_routing) 
					      smp_int_redirect &= ~SMP_IRQ_REDIRECTION;
				      else
					      smp_int_redirect |= SMP_IRQ_REDIRECTION;
#endif
			      }
			      if (pf->feature_mask & (1 << 2)) {
				      printk("IPI_Redirection ");
#ifdef CONFIG_SMP
				      if (no_int_routing) 
					      smp_int_redirect &= ~SMP_IPI_REDIRECTION;
				      else
					      smp_int_redirect |= SMP_IPI_REDIRECTION;
#endif
			      }
			      printk("\n");
			      break;
 		      }

		}
		p += SAL_DESC_SIZE(*p);
	}
}