source: mainline/uspace/drv/intctl/apic/apic.c@ c8ea6eca

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

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 6.4 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/irc.h>
39#include <loc.h>
40#include <sysinfo.h>
41#include <as.h>
42#include <ddf/driver.h>
43#include <ddf/log.h>
44#include <ddi.h>
45#include <stdbool.h>
46#include <errno.h>
47#include <str_error.h>
48#include <async.h>
49#include <stdio.h>
50
51#include "apic.h"
52
53#define NAME "apic"
54
55#define APIC_MAX_IRQ 15
56
57#define IOREGSEL (0x00U / sizeof(uint32_t))
58#define IOWIN (0x10U / sizeof(uint32_t))
59
60#define IOREDTBL 0x10U
61
62/** I/O Register Select Register. */
63typedef union {
64 uint32_t value;
65 struct {
66 uint8_t reg_addr; /**< APIC Register Address. */
67 unsigned int : 24; /**< Reserved. */
68 } __attribute__((packed));
69} io_regsel_t;
70
71/** I/O Redirection Register. */
72typedef struct io_redirection_reg {
73 union {
74 uint32_t lo;
75 struct {
76 uint8_t intvec; /**< Interrupt Vector. */
77 unsigned int delmod : 3; /**< Delivery Mode. */
78 unsigned int destmod : 1; /**< Destination mode. */
79 unsigned int delivs : 1; /**< Delivery status (RO). */
80 unsigned int intpol : 1; /**< Interrupt Input Pin Polarity. */
81 unsigned int irr : 1; /**< Remote IRR (RO). */
82 unsigned int trigger_mode : 1; /**< Trigger Mode. */
83 unsigned int masked : 1; /**< Interrupt Mask. */
84 unsigned int : 15; /**< Reserved. */
85 } __attribute__((packed));
86 };
87 union {
88 uint32_t hi;
89 struct {
90 unsigned int : 24; /**< Reserved. */
91 uint8_t dest : 8; /**< Destination Field. */
92 } __attribute__((packed));
93 };
94} __attribute__((packed)) io_redirection_reg_t;
95
96#define IO_APIC_SIZE 20
97
98/** Read from IO APIC register.
99 *
100 * @param apic APIC
101 * @param address IO APIC register address.
102 *
103 * @return Content of the addressed IO APIC register.
104 *
105 */
106static uint32_t io_apic_read(apic_t *apic, uint8_t address)
107{
108 io_regsel_t regsel;
109
110 regsel.value = pio_read_32(&apic->regs[IOREGSEL]);
111 regsel.reg_addr = address;
112 pio_write_32(&apic->regs[IOREGSEL], regsel.value);
113 return pio_read_32(&apic->regs[IOWIN]);
114}
115
116/** Write to IO APIC register.
117 *
118 * @param apic APIC
119 * @param address IO APIC register address.
120 * @param val Content to be written to the addressed IO APIC register.
121 *
122 */
123static void io_apic_write(apic_t *apic, uint8_t address, uint32_t val)
124{
125 io_regsel_t regsel;
126
127 regsel.value = pio_read_32(&apic->regs[IOREGSEL]);
128 regsel.reg_addr = address;
129 pio_write_32(&apic->regs[IOREGSEL], regsel.value);
130 pio_write_32(&apic->regs[IOWIN], val);
131}
132
133static int irq_to_pin(int irq)
134{
135 // FIXME: get the map from the kernel, even though this may work
136 // for simple cases
137 if (irq == 0)
138 return 2;
139 return irq;
140}
141
142static errno_t apic_enable_irq(apic_t *apic, sysarg_t irq)
143{
144 io_redirection_reg_t reg;
145
146 if (irq > APIC_MAX_IRQ)
147 return ELIMIT;
148
149 int pin = irq_to_pin(irq);
150 if (pin == -1)
151 return ENOENT;
152
153 reg.lo = io_apic_read(apic, (uint8_t) (IOREDTBL + pin * 2));
154 reg.masked = false;
155 io_apic_write(apic, (uint8_t) (IOREDTBL + pin * 2), reg.lo);
156
157 return EOK;
158}
159
160/** Handle one connection to APIC.
161 *
162 * @param icall Call data of the request that opened the connection.
163 * @param arg Local argument.
164 *
165 */
166static void apic_connection(ipc_call_t *icall, void *arg)
167{
168 ipc_call_t call;
169 apic_t *apic;
170
171 /*
172 * Answer the first IPC_M_CONNECT_ME_TO call.
173 */
174 async_answer_0(icall, EOK);
175
176 apic = (apic_t *) ddf_dev_data_get(ddf_fun_get_dev((ddf_fun_t *) arg));
177
178 while (true) {
179 async_get_call(&call);
180
181 if (!IPC_GET_IMETHOD(call)) {
182 /* The other side has hung up. */
183 async_answer_0(&call, EOK);
184 return;
185 }
186
187 switch (IPC_GET_IMETHOD(call)) {
188 case IRC_ENABLE_INTERRUPT:
189 async_answer_0(&call, apic_enable_irq(apic,
190 IPC_GET_ARG1(call)));
191 break;
192 case IRC_DISABLE_INTERRUPT:
193 /* XXX TODO */
194 async_answer_0(&call, EOK);
195 break;
196 case IRC_CLEAR_INTERRUPT:
197 /* Noop */
198 async_answer_0(&call, EOK);
199 break;
200 default:
201 async_answer_0(&call, EINVAL);
202 break;
203 }
204 }
205}
206
207/** Add APIC device. */
208errno_t apic_add(apic_t *apic, apic_res_t *res)
209{
210 sysarg_t have_apic;
211 ddf_fun_t *fun_a = NULL;
212 void *regs;
213 errno_t rc;
214
215 if ((sysinfo_get_value("apic", &have_apic) != EOK) || (!have_apic)) {
216 printf("%s: No APIC found\n", NAME);
217 return ENOTSUP;
218 }
219
220 rc = pio_enable((void *) res->base, IO_APIC_SIZE, &regs);
221 if (rc != EOK) {
222 printf("%s: Failed to enable PIO for APIC: %s\n", NAME, str_error(rc));
223 return EIO;
224 }
225
226 apic->regs = (ioport32_t *)regs;
227
228 fun_a = ddf_fun_create(apic->dev, fun_exposed, "a");
229 if (fun_a == NULL) {
230 ddf_msg(LVL_ERROR, "Failed creating function 'a'.");
231 rc = ENOMEM;
232 goto error;
233 }
234
235 ddf_fun_set_conn_handler(fun_a, apic_connection);
236
237 rc = ddf_fun_bind(fun_a);
238 if (rc != EOK) {
239 ddf_msg(LVL_ERROR, "Failed binding function 'a': %s", str_error(rc));
240 goto error;
241 }
242
243 rc = ddf_fun_add_to_category(fun_a, "irc");
244 if (rc != EOK)
245 goto error;
246
247 return EOK;
248error:
249 if (fun_a != NULL)
250 ddf_fun_destroy(fun_a);
251 return rc;
252}
253
254/** Remove APIC device */
255errno_t apic_remove(apic_t *apic)
256{
257 return ENOTSUP;
258}
259
260/** APIC device gone */
261errno_t apic_gone(apic_t *apic)
262{
263 return ENOTSUP;
264}
265
266/**
267 * @}
268 */
Note: See TracBrowser for help on using the repository browser.