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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6769005 was 6769005, checked in by Jakub Jermar <jakub@…>, 7 years ago

Use user-defined labels instead of phone hashes

This commit changes the way how the async framework maps incomming calls
to connections. Instead of abusing the kernel addresses of attached
phones as identifiers, the IPC_M_CONNECT_TO_ME and IPC_M_CONNECT_ME_TO
messages allow the server to specify an arbitrary label which is
remembered in the connected phone and consequently imprinted on each
call which is routed through this phone.

The async framework uses the address of the connection structure as the
label. This removes the need for a connection hash table because each
incoming call already remembers the connection in its label.

To disambiguate this new label and the other user-defined label used for
answers, the call structure now has the request_label member for the
former and answer_label member for the latter.

This commit also moves the kernel definition of ipc_data_t to abi/ and
removes the uspace redefinition thereof. Finally, when forwarding the
IPC_M_CONNECT_TO_ME call, the phone capability and the kernel object
allocated in request_process are now correctly disposed of.

  • 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 uspace_drv_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_5(icall, EOK, 0, 0, 0, 0, async_get_label());
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.