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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 6.5 KB
RevLine 
[3e5a814]1/*
[acc7ce4]2 * Copyright (c) 2011 Martin Decky
[3e5a814]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
[acc7ce4]29/** @addtogroup apic
[3e5a814]30 * @{
[acc7ce4]31 */
[3e5a814]32
33/**
[acc7ce4]34 * @file apic.c
35 * @brief APIC driver.
[3e5a814]36 */
37
[acc7ce4]38#include <ipc/irc.h>
[9a2eb14]39#include <loc.h>
[3e5a814]40#include <sysinfo.h>
41#include <as.h>
[b446b02]42#include <ddf/driver.h>
43#include <ddf/log.h>
[3e5a814]44#include <ddi.h>
[3e6a98c5]45#include <stdbool.h>
[3e5a814]46#include <errno.h>
[c1694b6b]47#include <str_error.h>
[3e5a814]48#include <async.h>
[df02460]49#include <stdio.h>
[3e5a814]50
[b446b02]51#include "apic.h"
52
[acc7ce4]53#define NAME "apic"
[3e5a814]54
[f5d51de]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 *
[b446b02]100 * @param apic APIC
[f5d51de]101 * @param address IO APIC register address.
102 *
103 * @return Content of the addressed IO APIC register.
104 *
105 */
[b446b02]106static uint32_t io_apic_read(apic_t *apic, uint8_t address)
[f5d51de]107{
108 io_regsel_t regsel;
109
[b446b02]110 regsel.value = pio_read_32(&apic->regs[IOREGSEL]);
[f5d51de]111 regsel.reg_addr = address;
[b446b02]112 pio_write_32(&apic->regs[IOREGSEL], regsel.value);
113 return pio_read_32(&apic->regs[IOWIN]);
[f5d51de]114}
115
116/** Write to IO APIC register.
117 *
[b446b02]118 * @param apic APIC
[f5d51de]119 * @param address IO APIC register address.
120 * @param val Content to be written to the addressed IO APIC register.
121 *
122 */
[b446b02]123static void io_apic_write(apic_t *apic, uint8_t address, uint32_t val)
[f5d51de]124{
125 io_regsel_t regsel;
126
[b446b02]127 regsel.value = pio_read_32(&apic->regs[IOREGSEL]);
[f5d51de]128 regsel.reg_addr = address;
[b446b02]129 pio_write_32(&apic->regs[IOREGSEL], regsel.value);
130 pio_write_32(&apic->regs[IOWIN], val);
[f5d51de]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
[b50bf6c2]137 if (irq == 0)
138 return 2;
[f5d51de]139 return irq;
140}
141
[b7fd2a0]142static errno_t apic_enable_irq(apic_t *apic, sysarg_t irq)
[acc7ce4]143{
[f5d51de]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
[b446b02]153 reg.lo = io_apic_read(apic, (uint8_t) (IOREDTBL + pin * 2));
[f5d51de]154 reg.masked = false;
[b446b02]155 io_apic_write(apic, (uint8_t) (IOREDTBL + pin * 2), reg.lo);
[f5d51de]156
157 return EOK;
[acc7ce4]158}
[3e5a814]159
[acc7ce4]160/** Handle one connection to APIC.
161 *
162 * @param iid Hash of the request that opened the connection.
163 * @param icall Call data of the request that opened the connection.
[9934f7d]164 * @param arg Local argument.
[3e5a814]165 */
[9934f7d]166static void apic_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[3e5a814]167{
168 ipc_callid_t callid;
169 ipc_call_t call;
[b446b02]170 apic_t *apic;
[a35b458]171
[3e5a814]172 /*
173 * Answer the first IPC_M_CONNECT_ME_TO call.
174 */
[ffa2c8ef]175 async_answer_0(iid, EOK);
[a35b458]176
[b446b02]177 apic = (apic_t *)ddf_dev_data_get(ddf_fun_get_dev((ddf_fun_t *)arg));
[a35b458]178
[acc7ce4]179 while (true) {
[3e5a814]180 callid = async_get_call(&call);
[a35b458]181
[79ae36dd]182 if (!IPC_GET_IMETHOD(call)) {
183 /* The other side has hung up. */
184 async_answer_0(callid, EOK);
185 return;
186 }
[a35b458]187
[228e490]188 switch (IPC_GET_IMETHOD(call)) {
[acc7ce4]189 case IRC_ENABLE_INTERRUPT:
[b446b02]190 async_answer_0(callid, apic_enable_irq(apic,
191 IPC_GET_ARG1(call)));
[acc7ce4]192 break;
[07cb0108]193 case IRC_DISABLE_INTERRUPT:
194 /* XXX TODO */
195 async_answer_0(callid, EOK);
196 break;
[acc7ce4]197 case IRC_CLEAR_INTERRUPT:
198 /* Noop */
[ffa2c8ef]199 async_answer_0(callid, EOK);
[3e5a814]200 break;
201 default:
[ffa2c8ef]202 async_answer_0(callid, EINVAL);
[3e5a814]203 break;
204 }
205 }
206}
207
[b446b02]208/** Add APIC device. */
[b7fd2a0]209errno_t apic_add(apic_t *apic, apic_res_t *res)
[3e5a814]210{
[b446b02]211 sysarg_t have_apic;
212 ddf_fun_t *fun_a = NULL;
213 void *regs;
[b7fd2a0]214 errno_t rc;
[a35b458]215
[b446b02]216 if ((sysinfo_get_value("apic", &have_apic) != EOK) || (!have_apic)) {
[79ae36dd]217 printf("%s: No APIC found\n", NAME);
[b446b02]218 return ENOTSUP;
[9a2eb14]219 }
[a35b458]220
[b446b02]221 rc = pio_enable((void *) res->base, IO_APIC_SIZE, &regs);
[9a2eb14]222 if (rc != EOK) {
[dd8ab1c]223 printf("%s: Failed to enable PIO for APIC: %s\n", NAME, str_error(rc));
[b446b02]224 return EIO;
[9a2eb14]225 }
[b446b02]226
227 apic->regs = (ioport32_t *)regs;
228
229 fun_a = ddf_fun_create(apic->dev, fun_exposed, "a");
230 if (fun_a == NULL) {
231 ddf_msg(LVL_ERROR, "Failed creating function 'a'.");
232 rc = ENOMEM;
233 goto error;
[9a2eb14]234 }
[b446b02]235
236 ddf_fun_set_conn_handler(fun_a, apic_connection);
237
238 rc = ddf_fun_bind(fun_a);
[9a2eb14]239 if (rc != EOK) {
[c1694b6b]240 ddf_msg(LVL_ERROR, "Failed binding function 'a': %s", str_error(rc));
[b446b02]241 goto error;
[9a2eb14]242 }
[b446b02]243
244 rc = ddf_fun_add_to_category(fun_a, "irc");
245 if (rc != EOK)
246 goto error;
247
248 return EOK;
249error:
250 if (fun_a != NULL)
251 ddf_fun_destroy(fun_a);
252 return rc;
[3e5a814]253}
254
[b446b02]255/** Remove APIC device */
[b7fd2a0]256errno_t apic_remove(apic_t *apic)
[3e5a814]257{
[b446b02]258 return ENOTSUP;
259}
260
261/** APIC device gone */
[b7fd2a0]262errno_t apic_gone(apic_t *apic)
[b446b02]263{
264 return ENOTSUP;
[3e5a814]265}
266
267/**
268 * @}
[acc7ce4]269 */
Note: See TracBrowser for help on using the repository browser.