source: mainline/uspace/srv/hw/irc/apic/apic.c@ b688fd8

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b688fd8 was b688fd8, checked in by Martin Decky <martin@…>, 10 years ago

gradually introduce async ports, initial phase

The initial phase is to reimplement the traditional async client connections as an untyped fallback port. This creates the possibility to introduce ports typed by interface type gradually in later changesets.

  • Property mode set to 100644
File size: 5.7 KB
Line 
1/*
2 * Copyright (c) 2011 Martin Decky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup apic
30 * @{
31 */
32
33/**
34 * @file apic.c
35 * @brief APIC driver.
36 */
37
38#include <ipc/services.h>
39#include <ipc/irc.h>
40#include <ns.h>
41#include <sysinfo.h>
42#include <as.h>
43#include <ddi.h>
44#include <stdbool.h>
45#include <errno.h>
46#include <async.h>
47#include <stdio.h>
48
49#define NAME "apic"
50
51#define APIC_MAX_IRQ 15
52
53#define IOREGSEL (0x00U / sizeof(uint32_t))
54#define IOWIN (0x10U / sizeof(uint32_t))
55
56#define IOREDTBL 0x10U
57
58/** I/O Register Select Register. */
59typedef union {
60 uint32_t value;
61 struct {
62 uint8_t reg_addr; /**< APIC Register Address. */
63 unsigned int : 24; /**< Reserved. */
64 } __attribute__ ((packed));
65} io_regsel_t;
66
67/** I/O Redirection Register. */
68typedef struct io_redirection_reg {
69 union {
70 uint32_t lo;
71 struct {
72 uint8_t intvec; /**< Interrupt Vector. */
73 unsigned int delmod : 3; /**< Delivery Mode. */
74 unsigned int destmod : 1; /**< Destination mode. */
75 unsigned int delivs : 1; /**< Delivery status (RO). */
76 unsigned int intpol : 1; /**< Interrupt Input Pin Polarity. */
77 unsigned int irr : 1; /**< Remote IRR (RO). */
78 unsigned int trigger_mode : 1; /**< Trigger Mode. */
79 unsigned int masked : 1; /**< Interrupt Mask. */
80 unsigned int : 15; /**< Reserved. */
81 } __attribute__ ((packed));
82 };
83 union {
84 uint32_t hi;
85 struct {
86 unsigned int : 24; /**< Reserved. */
87 uint8_t dest : 8; /**< Destination Field. */
88 } __attribute__ ((packed));
89 };
90} __attribute__ ((packed)) io_redirection_reg_t;
91
92// FIXME: get the address from the kernel
93#define IO_APIC_BASE 0xfec00000UL
94#define IO_APIC_SIZE 20
95
96ioport32_t *io_apic = NULL;
97
98/** Read from IO APIC register.
99 *
100 * @param address IO APIC register address.
101 *
102 * @return Content of the addressed IO APIC register.
103 *
104 */
105static uint32_t io_apic_read(uint8_t address)
106{
107 io_regsel_t regsel;
108
109 regsel.value = io_apic[IOREGSEL];
110 regsel.reg_addr = address;
111 io_apic[IOREGSEL] = regsel.value;
112 return io_apic[IOWIN];
113}
114
115/** Write to IO APIC register.
116 *
117 * @param address IO APIC register address.
118 * @param val Content to be written to the addressed IO APIC register.
119 *
120 */
121static void io_apic_write(uint8_t address, uint32_t val)
122{
123 io_regsel_t regsel;
124
125 regsel.value = io_apic[IOREGSEL];
126 regsel.reg_addr = address;
127 io_apic[IOREGSEL] = regsel.value;
128 io_apic[IOWIN] = val;
129}
130
131static int irq_to_pin(int irq)
132{
133 // FIXME: get the map from the kernel, even though this may work
134 // for simple cases
135 if (irq == 0)
136 return 2;
137 return irq;
138}
139
140static int apic_enable_irq(sysarg_t irq)
141{
142 io_redirection_reg_t reg;
143
144 if (irq > APIC_MAX_IRQ)
145 return ELIMIT;
146
147 int pin = irq_to_pin(irq);
148 if (pin == -1)
149 return ENOENT;
150
151 reg.lo = io_apic_read((uint8_t) (IOREDTBL + pin * 2));
152 reg.masked = false;
153 io_apic_write((uint8_t) (IOREDTBL + pin * 2), reg.lo);
154
155 return EOK;
156}
157
158/** Handle one connection to APIC.
159 *
160 * @param iid Hash of the request that opened the connection.
161 * @param icall Call data of the request that opened the connection.
162 * @param arg Local argument.
163 */
164static void apic_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
165{
166 ipc_callid_t callid;
167 ipc_call_t call;
168
169 /*
170 * Answer the first IPC_M_CONNECT_ME_TO call.
171 */
172 async_answer_0(iid, EOK);
173
174 while (true) {
175 callid = async_get_call(&call);
176
177 if (!IPC_GET_IMETHOD(call)) {
178 /* The other side has hung up. */
179 async_answer_0(callid, EOK);
180 return;
181 }
182
183 switch (IPC_GET_IMETHOD(call)) {
184 case IRC_ENABLE_INTERRUPT:
185 async_answer_0(callid, apic_enable_irq(IPC_GET_ARG1(call)));
186 break;
187 case IRC_CLEAR_INTERRUPT:
188 /* Noop */
189 async_answer_0(callid, EOK);
190 break;
191 default:
192 async_answer_0(callid, EINVAL);
193 break;
194 }
195 }
196}
197
198/** Initialize the APIC driver.
199 *
200 */
201static bool apic_init(void)
202{
203 sysarg_t apic;
204
205 if ((sysinfo_get_value("apic", &apic) != EOK) || (!apic)) {
206 printf("%s: No APIC found\n", NAME);
207 return false;
208 }
209
210 int rc = pio_enable((void *) IO_APIC_BASE, IO_APIC_SIZE,
211 (void **) &io_apic);
212 if (rc != EOK) {
213 printf("%s: Failed to enable PIO for APIC: %d\n", NAME, rc);
214 return false;
215 }
216
217 async_set_fallback_port_handler(apic_connection, NULL);
218 service_register(SERVICE_IRC);
219
220 return true;
221}
222
223int main(int argc, char **argv)
224{
225 printf("%s: HelenOS APIC driver\n", NAME);
226
227 if (!apic_init())
228 return -1;
229
230 printf("%s: Accepting connections\n", NAME);
231 task_retval(0);
232 async_manager();
233
234 /* Never reached */
235 return 0;
236}
237
238/**
239 * @}
240 */
Note: See TracBrowser for help on using the repository browser.