The Pedigree Project  0.1
Heathrow.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 "Heathrow.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 #include "pedigree/kernel/processor/Processor.h"
27 
28 // TODO: Needs locking
29 
31 
32 irq_id_t Heathrow::registerIsaIrqHandler(uint8_t irq, IrqHandler *handler)
33 {
34  // Save the IrqHandler
35  m_Handler[irq] = handler;
36 
37  // Enable/Unmask the IRQ
38  enable(irq, true);
39 
40  return irq;
41 }
42 irq_id_t Heathrow::registerPciIrqHandler(IrqHandler *handler)
43 {
44  // TODO
45  return 0;
46 }
47 void Heathrow::acknowledgeIrq(irq_id_t Id)
48 {
49  uint8_t irq = Id;
50 
51  // Enable the irq again (the interrupt reason got removed)
52  enable(irq, true);
53  eoi(irq);
54 }
55 void Heathrow::unregisterHandler(irq_id_t Id, IrqHandler *handler)
56 {
57  uint8_t irq = Id;
58 
59  // Disable the IRQ
60  enable(irq, false);
61 
62  // Remove the handler
63  m_Handler[irq] = 0;
64 }
65 
66 void Heathrow::searchNode(Device *pDev)
67 {
68  for (unsigned int i = 0; i < pDev->getNumChildren(); i++)
69  {
70  Device *pChild = pDev->getChild(i);
71  OFDevice ofDev(pChild->getOFHandle());
72  NormalStaticString type;
73  ofDev.getProperty("device_type", type);
74  if (type == "interrupt-controller")
75  {
76  // Found it - double check that it's the right compatibility.
77  NormalStaticString comp;
78  ofDev.getProperty("compatible", comp);
79  if (!(comp == "heathrow"))
80  {
81  return;
82  }
83 
84  uint32_t reg[2];
85  ofDev.getProperty("reg", reg, 8);
86 
87  // Look for the parent's BAR0.
88  for (unsigned int j = 0; j < pDev->addresses().count(); j++)
89  {
90  if (!StringCompare(pDev->addresses()[j]->m_Name, "bar0"))
91  {
92  uintptr_t regAddr = static_cast<uintptr_t>(reg[0]) +
93  pDev->addresses()[j]->m_Address;
94  size_t regSize = 0x40; // static_cast<size_t>(reg[1]);
95  pChild->addresses().pushBack(new Device::Address(
96  String("reg"), regAddr, regSize,
97  false /* Always memory for PPC */));
98  m_pPort = pChild->addresses()[j]->m_Io;
99  return;
100  }
101  }
102  }
103  // Recurse.
104  if (m_pPort)
105  return;
106  searchNode(pChild);
107  }
108 }
109 
111 {
112  // Allocate the I/O ports - run through the device tree until we find a
113  // device with a property "interrupt-controller".
114  Device *dev = &Device::root();
115  searchNode(dev);
116 
117  // Did the search return anything?
118  if (!m_pPort)
119  {
120  ERROR("Heathrow: Device not found!");
121  return false;
122  }
123 
124  // Register the interrupts
126  if (IntManager.registerInterruptHandler(4, this) == false)
127  return false;
128 
129  m_nIrqs = 64;
130 
131  // Disable all IRQ's
132  enableAll(false);
133 
134  return true;
135 }
136 
137 Heathrow::Heathrow() : m_pPort(0), m_nIrqs(0), m_LowMask(0), m_HighMask(0)
138 {
139  for (size_t i = 0; i < 16; i++)
140  m_Handler[i] = 0;
141 }
142 
143 void Heathrow::interrupt(size_t interruptNumber, InterruptState &state)
144 {
145  uint32_t low = LITTLE_TO_HOST32(m_pPort->read32(0x10)) & m_LowMask;
146  uint32_t high = LITTLE_TO_HOST32(m_pPort->read32(0x00)) & m_HighMask;
147 
148  int32_t irq = -1;
149  for (int i = 0; i < 32; i++)
150  {
151  if (low & (1 << i))
152  {
153  irq = i;
154  break;
155  }
156  }
157  if (irq == -1)
158  for (int i = 0; i < 32; i++)
159  {
160  if (high & (1 << i))
161  {
162  irq = i + 32;
163  break;
164  }
165  }
166 
167  if (irq == -1)
168  return;
169 
170  // size_t irq = (interruptNumber - BASE_INTERRUPT_VECTOR);
171 
172  // // Is Spurios IRQ7?
173  // if (irq == 7)
174  // {
175  // m_MasterPort.write8(0x03, 3);
176  // if (UNLIKELY((m_MasterPort.read8(0) & 0x80) == 0))
177  // {
178  // NOTICE("PIC: spurious IRQ7");
179  // eoi(irq);
180  // return;
181  // }
182  // }
183  // /// \todo Logic faulty here, reporting spurious interrupts for disk
184  // accesses!
185  // // Is spurious IRQ15?
186  // else if (irq == 15)
187  // {
188  // m_SlavePort.write8(0x03, 3);
189  // if (UNLIKELY((m_SlavePort.read8(0) & 0x80) == 0))
190  // {
191  // NOTICE("PIC: spurious IRQ15");
192  // eoi(irq);
193  // return;
194  // }
195  // }
196 
197  // Call the irq handler, if any
198  if (LIKELY(m_Handler[irq] != 0))
199  {
200  if (m_Handler[irq]->irq(irq, state) == false)
201  {
202  // Disable/Mask the IRQ line (the handler did not remove
203  // the interrupt reason, yet)
204  enable(irq, false);
205  }
206  }
207  else
208  {
209  NOTICE("PIC: unhandled irq #" << irq << " occurred");
210 
211  // #ifdef DEBUGGER
212  // LargeStaticString str;
213  // str += "Unhandled IRQ: #";
214  // str += irq;
215  // str += " occurred.";
216  // Debugger::instance().start(state, str);
217  // #endif
218  enable(irq, false);
219  }
220 
221  eoi(irq);
222 }
223 
224 void Heathrow::eoi(uint8_t irq)
225 {
226  uintptr_t reg = 0x18;
227  if (irq > 31)
228  {
229  reg = 0x08;
230  irq -= 32;
231  }
232 
233  uint32_t shift = 1 << irq;
234  m_pPort->write32(LITTLE_TO_HOST32(shift), reg);
235 }
236 void Heathrow::enable(uint8_t irq, bool enable)
237 {
238  uintptr_t reg = 0x14;
239  if (irq > 31)
240  {
241  reg = 0x04;
242  irq -= 32;
243  }
244 
245  uint32_t value = LITTLE_TO_HOST32(m_pPort->read32(reg));
246  uint32_t shift = 1 << irq;
247  if (enable)
248  value |= shift;
249  else
250  value &= ~shift;
251 
252  if (reg == 0x14)
253  m_LowMask = value;
254  else
255  m_HighMask = value;
256 
257  m_pPort->write32(LITTLE_TO_HOST32(value), reg);
258 }
259 void Heathrow::enableAll(bool enable)
260 {
261  if (enable)
262  {
263  m_pPort->write32(0xFFFFFFFF, 0x04);
264  m_pPort->write32(0xFFFFFFFF, 0x14);
265  m_LowMask = 0xFFFFFFFF;
266  m_HighMask = 0xFFFFFFFF;
267  }
268  else
269  {
270  m_pPort->write32(0x00000000, 0x04);
271  m_pPort->write32(0x00000000, 0x14);
272  m_LowMask = 0;
273  m_HighMask = 0;
274  }
275 }
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)=0
Heathrow() INITIALISATION_ONLY
Definition: Heathrow.cc:137
Device * getChild(size_t n)
Definition: Device.cc:132
size_t getNumChildren()
Definition: Device.cc:137
virtual void interrupt(size_t interruptNumber, InterruptState &state)
Definition: Heathrow.cc:143
virtual Vector< Address * > & addresses()
Definition: Device.h:256
Handles interrupts and interrupt registrations from kernel components.
Definition: String.h:49
Definition: Device.h:43
virtual void unregisterHandler(irq_id_t Id, IrqHandler *handler)
Definition: Heathrow.cc:55
virtual void acknowledgeIrq(irq_id_t Id)
Definition: Heathrow.cc:47
virtual uint32_t read32(size_t offset=0)=0
#define NOTICE(text)
Definition: Log.h:74
static Device & root()
Definition: Device.h:356
IoBase * m_pPort
Definition: Heathrow.h:80
IrqHandler * m_Handler[64]
Definition: Heathrow.h:83
#define ERROR(text)
Definition: Log.h:82
size_t m_nIrqs
Definition: Heathrow.h:86
static InterruptManager & instance()
virtual void write32(uint32_t value, size_t offset=0)=0
bool initialise() INITIALISATION_ONLY
Definition: Heathrow.cc:110
static Heathrow m_Instance
Definition: Heathrow.h:89