The Pedigree Project  0.1
OpenPic.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "OpenPic.h"
21 #include "pedigree/kernel/Log.h"
22 #include "pedigree/kernel/compiler.h"
23 #include "pedigree/kernel/debugger/Debugger.h"
24 #include "pedigree/kernel/machine/Device.h"
25 #include "pedigree/kernel/machine/openfirmware/Device.h"
26 
27 // TODO: Needs locking
28 
30 
31 irq_id_t OpenPic::registerIsaIrqHandler(uint8_t irq, IrqHandler *handler)
32 {
33  if (UNLIKELY(irq >= 64))
34  return 0;
35 
36  // Save the IrqHandler
37  m_Handler[irq] = handler;
38 
39  // Enable/Unmask the IRQ
40  enable(irq, true);
41 
42  return irq;
43 }
44 irq_id_t OpenPic::registerPciIrqHandler(IrqHandler *handler)
45 {
46  // TODO
47  return 0;
48 }
49 void OpenPic::acknowledgeIrq(irq_id_t Id)
50 {
51  uint8_t irq = Id;
52 
53  // Enable the irq again (the interrupt reason got removed)
54  enable(irq, true);
55  eoi(irq);
56 }
57 void OpenPic::unregisterHandler(irq_id_t Id, IrqHandler *handler)
58 {
59  uint8_t irq = Id;
60 
61  // Disable the IRQ
62  enable(irq, false);
63 
64  // Remove the handler
65  m_Handler[irq] = 0;
66 }
67 
68 void OpenPic::searchNode(Device *pDev)
69 {
70  for (unsigned int i = 0; i < pDev->getNumChildren(); i++)
71  {
72  Device *pChild = pDev->getChild(i);
73  OFDevice ofDev(pChild->getOFHandle());
74  NormalStaticString type;
75  ofDev.getProperty("device_type", type);
76  if (type == "open-pic")
77  {
78  uint32_t reg[2];
79  ofDev.getProperty("reg", reg, 8);
80 
81  // Look for the parent's BAR0.
82  for (unsigned int j = 0; j < pDev->addresses().count(); j++)
83  {
84  if (!StringCompare(pDev->addresses()[j]->m_Name, "bar0"))
85  {
86  uintptr_t regAddr = static_cast<uintptr_t>(reg[0]) +
87  pDev->addresses()[j]->m_Address;
88  size_t regSize = static_cast<size_t>(reg[1]);
89 
90  pChild->addresses().pushBack(new Device::Address(
91  String("reg"), regAddr, regSize,
92  false /* Always memory for PPC */));
93  m_pPort = pChild->addresses()[j]->m_Io;
94  return;
95  }
96  }
97  }
98  // Recurse.
99  if (m_pPort)
100  return;
101  searchNode(pChild);
102  }
103 }
104 
106 {
107  // Allocate the I/O ports - run through the device tree until we find a
108  // device with a property "interrupt-controller".
109  Device *dev = &Device::root();
110  searchNode(dev);
111 
112  // Did the search return anything?
113  if (!m_pPort)
114  {
115  ERROR("OpenPic: Device not found!");
116  return false;
117  }
118 
119  // Disable 8259 passthrough mode.
120  m_pPort->write32(HOST_TO_LITTLE32(OPENPIC_FLAG_CONF0_P), OPENPIC_REG_CONF0);
121 
122  // Register the interrupts
124  if (IntManager.registerInterruptHandler(4, this) == false)
125  return false;
126 
127  // Grab the feature reporting register.
128  uint32_t feature = LITTLE_TO_HOST32(m_pPort->read32(OPENPIC_REG_FEATURE));
129  Feature f = *reinterpret_cast<Feature *>(&feature);
130 
131  // Save the number of valid IRQ sources, and check the version.
132  m_nIrqs = f.num_irq + 1;
133  if (f.version > 0x2)
134  {
135  ERROR("OpenPIC: invalid version returned: " << Hex << f.version);
136  return false;
137  }
138 
140 
141  // Set up all IRQ sources.
142  for (int i = 0; i < m_nIrqs; i++)
143  {
144  uintptr_t reg = i * 0x20 + OPENPIC_SOURCE_START;
145 
146  // Set up interrupt sources.
147  m_pPort->write32(
148  HOST_TO_LITTLE32(OPENPIC_SOURCE_MASK | OPENPIC_SOURCE_PRIORITY | i),
149  reg);
150 // Ensure that IRQs are sent to this processor (the first one).
151 #ifdef MULTIPROCESSOR
152 #error Problems here.
153 #endif
154  m_pPort->write32(HOST_TO_LITTLE32(0x1), reg + 0x10);
155  }
156 
157  asm volatile("sync");
158 
159  // Set the task priority to 0, so all interrupts with priority >0 can be
160  // received.
161  m_pPort->write32(0x0, OPENPIC_REG_TASK_PRIORITY);
162 
163  return true;
164 }
165 
167 {
168  for (size_t i = 0; i < 64; i++)
169  m_Handler[i] = 0;
170 }
171 
172 void OpenPic::interrupt(size_t interruptNumber, InterruptState &state)
173 {
174  uint32_t irq = LITTLE_TO_HOST32(m_pPort->read32(OPENPIC_REG_ACK));
175 
176  // Is Spurious IRQ255?
177  if (irq == 0xff)
178  {
179  NOTICE("PIC: spurious IRQ255");
180  eoi(irq);
181  return;
182  }
183 
184  // Call the irq handler, if any
185  if (LIKELY(m_Handler[irq] != 0))
186  {
187  if (m_Handler[irq]->irq(irq, state) == false)
188  {
189  // Disable/Mask the IRQ line (the handler did not remove
190  // the interrupt reason, yet)
191  enable(irq, false);
192  }
193  }
194  else
195  {
196  NOTICE("PIC: unhandled irq #" << irq << " occurred");
197 
198 #ifdef DEBUGGER
199  LargeStaticString str;
200  str += "Unhandled IRQ: #";
201  str += irq;
202  str += " occurred.";
203  Debugger::instance().start(state, str);
204 #endif
205  }
206 
207  eoi(irq);
208 }
209 
210 void OpenPic::eoi(uint8_t irq)
211 {
212  m_pPort->write32(0, OPENPIC_REG_EOI);
213 }
214 void OpenPic::enable(uint8_t irq, bool enable)
215 {
216  uintptr_t reg = irq * 0x20 + OPENPIC_SOURCE_START;
217 
218  uintptr_t receivedReg = LITTLE_TO_HOST32(m_pPort->read32(reg));
219 
220  if (enable)
221  m_pPort->write32(
222  HOST_TO_LITTLE32(receivedReg & ~OPENPIC_SOURCE_MASK), reg);
223  else
224  m_pPort->write32(
225  HOST_TO_LITTLE32(receivedReg | OPENPIC_SOURCE_MASK), reg);
226 
227  asm volatile("sync; isync");
228 }
229 void OpenPic::enableAll(bool enable)
230 {
231  for (int i = 0; i < m_nIrqs; i++)
232  this->enable(i, enable);
233 }
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)=0
Device * getChild(size_t n)
Definition: Device.cc:132
OpenPic() INITIALISATION_ONLY
Definition: OpenPic.cc:166
static OpenPic m_Instance
Definition: OpenPic.h:114
size_t getNumChildren()
Definition: Device.cc:137
static Debugger & instance()
Definition: Debugger.h:48
virtual Vector< Address * > & addresses()
Definition: Device.h:256
Handles interrupts and interrupt registrations from kernel components.
Definition: String.h:49
virtual void acknowledgeIrq(irq_id_t Id)
Definition: OpenPic.cc:49
Definition: Device.h:43
bool initialise() INITIALISATION_ONLY
Definition: OpenPic.cc:105
virtual void interrupt(size_t interruptNumber, InterruptState &state)
Definition: OpenPic.cc:172
void start(InterruptState &state, LargeStaticString &description)
Definition: Debugger.cc:121
IrqHandler * m_Handler[64]
Definition: OpenPic.h:108
virtual uint32_t read32(size_t offset=0)=0
#define NOTICE(text)
Definition: Log.h:74
Definition: Log.h:136
static Device & root()
Definition: Device.h:356
IoBase * m_pPort
Definition: OpenPic.h:105
#define ERROR(text)
Definition: Log.h:82
size_t m_nIrqs
Definition: OpenPic.h:111
virtual void unregisterHandler(irq_id_t Id, IrqHandler *handler)
Definition: OpenPic.cc:57
static InterruptManager & instance()
virtual void write32(uint32_t value, size_t offset=0)=0