The Pedigree Project  0.1
Ehci.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 "Ehci.h"
21 #include "modules/system/usb/Usb.h"
22 #include "modules/system/usb/UsbHub.h"
23 #include "pedigree/kernel/LockGuard.h"
24 #include "pedigree/kernel/Log.h"
25 #include "pedigree/kernel/Spinlock.h"
26 #include "pedigree/kernel/machine/Device.h"
27 #include "pedigree/kernel/machine/IrqManager.h"
28 #include "pedigree/kernel/machine/Machine.h"
29 #include "pedigree/kernel/machine/Pci.h"
30 #include "pedigree/kernel/machine/types.h"
31 #include "pedigree/kernel/process/Mutex.h"
32 #include "pedigree/kernel/process/Thread.h"
33 #include "pedigree/kernel/processor/IoBase.h"
34 #include "pedigree/kernel/processor/MemoryRegion.h"
35 #include "pedigree/kernel/processor/PhysicalMemoryManager.h"
36 #include "pedigree/kernel/processor/Processor.h"
37 #include "pedigree/kernel/processor/ProcessorInformation.h"
38 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
39 #include "pedigree/kernel/processor/state_forward.h"
40 #include "pedigree/kernel/processor/types.h"
41 #include "pedigree/kernel/time/Time.h"
42 #include "pedigree/kernel/utilities/ExtensibleBitmap.h"
43 #include "pedigree/kernel/utilities/RequestQueue.h"
44 #include "pedigree/kernel/utilities/String.h"
45 #include "pedigree/kernel/utilities/Vector.h"
46 #include "pedigree/kernel/utilities/utility.h"
47 
48 #define INDEX_FROM_QTD(ptr) \
49  (((reinterpret_cast<uintptr_t>((ptr)) & 0xFFF) / sizeof(qTD)))
50 #define PHYS_QTD(idx) (m_pqTDListPhys + ((idx) * sizeof(qTD)))
51 
52 #define GET_PAGE(param, page, qhIndex) \
53  do \
54  { \
55  if ((nBufferPageOffset + nBytes) > ((page) *0x1000)) \
56  { \
57  if (va.isMapped(reinterpret_cast<void *>( \
58  pBufferPageStart + (page) *0x1000))) \
59  { \
60  physical_uintptr_t phys = 0; \
61  size_t flags = 0; \
62  va.getMapping( \
63  reinterpret_cast<void *>( \
64  pBufferPageStart + (page) *0x1000), \
65  phys, flags); \
66  (param) = phys >> 12; \
67  } \
68  else \
69  { \
70  ERROR( \
71  "EHCI: addTransferToTransaction: Buffer (page " \
72  << Dec << (page) << Hex << ") isn't mapped!"); \
73  m_QHBitmap.clear((qhIndex)); \
74  return; \
75  } \
76  } \
77  } while (0)
78 
79 Ehci::Ehci(Device *pDev)
80  : UsbHub(pDev), RequestQueue("EHCI"), m_pCurrentQueueTail(0),
81  m_pCurrentQueueHead(0), m_EhciMR("Ehci-MR")
82 {
83  setSpecificType(String("EHCI"));
84 }
85 
87 {
88  // Allocate the pages we need
89  if (!PhysicalMemoryManager::instance().allocateRegion(
92  {
93  ERROR("USB: EHCI: Couldn't allocate Memory Region!");
94  return false;
95  }
96 
97  uintptr_t virtualBase =
98  reinterpret_cast<uintptr_t>(m_EhciMR.virtualAddress());
99  uintptr_t physicalBase = m_EhciMR.physicalAddress();
100  m_pQHList = reinterpret_cast<QH *>(virtualBase);
101  m_pFrameList = reinterpret_cast<uint32_t *>(virtualBase + 0x2000);
102  m_pqTDList = reinterpret_cast<qTD *>(virtualBase + 0x3000);
103  m_pQHListPhys = physicalBase;
104  m_pFrameListPhys = physicalBase + 0x2000;
105  m_pqTDListPhys = physicalBase + 0x3000;
106 
107  DoubleWordSet(m_pFrameList, 1, 0x400);
108 
109 #ifdef X86_COMMON
110  uint32_t nPciCmdSts = PciBus::instance().readConfigSpace(this, 1);
111 #ifdef USB_VERBOSE_DEBUG
112  DEBUG_LOG("USB: EHCI: PCI command register: " << (nPciCmdSts & 0xffff));
113  DEBUG_LOG(
114  "USB: EHCI: PCI status register: "
115  << ((nPciCmdSts & 0xffff0000) >> 16));
116 #endif
117  PciBus::instance().writeConfigSpace(this, 1, nPciCmdSts | 0x4);
118 #endif
119 
120  // Grab the ports
121  m_pBase = m_Addresses[0]->m_Io;
122  NOTICE(
123  "EHCI: Working off: " << (m_Addresses[0]->m_IsIoSpace ? "P" : "MM")
124  << "IO");
125  m_Addresses[0]->map();
126 
127  uint32_t hccapbase = m_pBase->read32(EHCI_CAPLENGTH);
128  uint16_t version = hccapbase >> 16;
129 
130  m_nOpRegsOffset = hccapbase & 0xF;
131 #ifdef USB_VERBOSE_DEBUG
132  NOTICE("EHCI operation registers are at offset " << m_nOpRegsOffset);
133 #endif
134  if (m_nOpRegsOffset == 0)
135  {
136  // No offset for operational base: this is almost certainly not really
137  // a controller.
138  return false;
139  }
140 
141  NOTICE(
142  "EHCI controller version " << ((version & 0xFF) >> 8) << "."
143  << (version & 0xFF));
144 
145  // Get structural capabilities to determine the number of physical ports
146  // we have available to us.
147  uint32_t hcsparams = m_pBase->read32(EHCI_HCSPARAMS);
148  m_nPorts = hcsparams & 0xF;
149 #ifdef USB_VERBOSE_DEBUG
150  NOTICE(
151  "EHCI controller has " << Dec << m_nPorts << Hex << " physical ports.");
152 #endif
153 
154  uint32_t hccparams = m_pBase->read32(EHCI_HCCPARAMS);
155  uint8_t eecp = (hccparams >> 8) & 0xFF;
156  if (eecp && (eecp < 0x40))
157  {
158  ERROR("EHCI: EECP pointer is invalid");
159  eecp = 0;
160  }
161 
162 #ifdef USB_VERBOSE_DEBUG
163  DEBUG_LOG(
164  "EHCI: Host controller " << (hccparams & 1 ? "does" : "does not")
165  << " require 64-bit data structures.");
166  DEBUG_LOG(
167  " Host controller " << (hccparams & 2 ? "does" : "does not")
168  << " allow us to use frame lists with "
169  "anything other than 1024 items in them.");
170  DEBUG_LOG(
171  " Host controller "
172  << (hccparams & 4 ? "does" : "does not")
173  << " support the asynchronous schedule park capability.");
174  DEBUG_LOG(" HCCAPBASE is " << hccapbase);
175  DEBUG_LOG(" HCCPARAMS is " << hccparams);
176  DEBUG_LOG(" HCSPARAMS is " << hcsparams);
177  DEBUG_LOG(" EECP is " << eecp);
178 #endif
179 
180 #ifdef X86_COMMON
181  // Pre-OS to OS handoff
182  while (eecp)
183  {
184 #ifdef USB_VERBOSE_DEBUG
185  DEBUG_LOG(
186  "EHCI: Reading LEGSUP register and checking for BIOS ownership.");
187 #endif
188  uint32_t legsup = 0;
190  uint32_t dwordOffset = eecp / sizeof(uint32_t);
191  legsup = PciBus::instance().readConfigSpace(this, dwordOffset);
192 
193  if (legsup & 1)
194  {
195  // Perform handoff if necessary
196  bool bBiosOwned = legsup & (1 << 16);
197  if (bBiosOwned)
198  {
199 #ifdef USB_VERBOSE_DEBUG
200  DEBUG_LOG("EHCI: Performing handoff from BIOS to the OS...");
201 #endif
202 
203  // Take ownership of the controller
204  legsup |= (1 << 24);
205  PciBus::instance().writeConfigSpace(this, dwordOffset, legsup);
206 
207  // Wait for the BIOS to relinquish control
208  while (legsup & (1 << 16))
209  {
210  legsup =
211  PciBus::instance().readConfigSpace(this, dwordOffset);
212  Time::delay(5 * Time::Multiplier::Millisecond);
213  }
214  }
215 
216  eecp = (legsup >> 8) & 0xFF; // Zero = "end of list"
217  }
218  else
219  eecp = 0;
220  }
221 #endif
222 
223 #ifdef USB_VERBOSE_DEBUG
224  DEBUG_LOG("USB: EHCI: disabling running schedules");
225 #endif
226  // Disable any running schedules gracefully before halting the controller
227  m_pBase->write32(
228  m_pBase->read32(m_nOpRegsOffset + EHCI_CMD) &
229  ~(EHCI_CMD_ASYNCLE | EHCI_CMD_PERIODICLE),
230  m_nOpRegsOffset + EHCI_CMD);
231  while (m_pBase->read32(m_nOpRegsOffset + EHCI_STS) & 0xC000)
232  Time::delay(5 * Time::Multiplier::Millisecond);
233 
234  uint32_t status = m_pBase->read32(m_nOpRegsOffset + EHCI_STS);
235  if (!(status & EHCI_STS_HALTED))
236  {
237 #ifdef USB_VERBOSE_DEBUG
238  DEBUG_LOG("USB: EHCI: pausing controller");
239 #endif
240  // Must halt the controller, it's not yet halted.
241  m_pBase->write32(
242  m_pBase->read32(m_nOpRegsOffset + EHCI_CMD) & ~EHCI_CMD_RUN,
243  m_nOpRegsOffset + EHCI_CMD);
244  while (!(m_pBase->read32(m_nOpRegsOffset + EHCI_STS) & EHCI_STS_HALTED))
245  Time::delay(5 * Time::Multiplier::Millisecond);
246  }
247 
248 #ifdef USB_VERBOSE_DEBUG
249  DEBUG_LOG("USB: EHCI: resetting controller");
250 #endif
251  // Write host controller reset command and wait for it to complete
252  m_pBase->write32(EHCI_CMD_HCRES, m_nOpRegsOffset + EHCI_CMD);
253  while (m_pBase->read32(m_nOpRegsOffset + EHCI_CMD) & EHCI_CMD_HCRES)
254  Time::delay(5 * Time::Multiplier::Millisecond);
255 #ifdef USB_VERBOSE_DEBUG
256  DEBUG_LOG(
257  "USB: EHCI: Reset complete, status: "
258  << m_pBase->read32(m_nOpRegsOffset + EHCI_STS) << ".");
259 #endif
260 
261 // Install the IRQ handler
262 #ifdef X86_COMMON
263  Machine::instance().getIrqManager()->registerPciIrqHandler(this, this);
264 #else
266  getInterruptNumber(), this);
267 #endif
268  Machine::instance().getIrqManager()->control(
269  getInterruptNumber(), IrqManager::MitigationThreshold,
270  7500000 / 64); // 58 MB/s (480Mbps) in bytes/s, divided by 64 bytes
271  // maximum per control transfer/IRQ
272 
273  // Zero the top 64 bits for addresses of EHCI data structures
274  m_pBase->write32(0, m_nOpRegsOffset + EHCI_CTRLDSEG);
275 
276  // Enable interrupts
277  m_pBase->write32(0x3b, m_nOpRegsOffset + EHCI_INTR);
278 
279  // Write the base address of the periodic frame list - all T-bits are set to
280  // one
281  m_pBase->write32(m_pFrameListPhys, m_nOpRegsOffset + EHCI_PERIODICLP);
282 
283  Time::delay(5 * Time::Multiplier::Millisecond);
284 
285  // Create a dummy QH and qTD
286  m_QHBitmap.set(0);
287  m_qTDBitmap.set(0);
288  QH *pDummyQH = &m_pQHList[0];
289  qTD *pDummyTD = &m_pqTDList[0];
290  ByteSet(pDummyQH, 0, sizeof(QH));
291  ByteSet(pDummyTD, 0, sizeof(qTD));
292 
293  // Configure the dummy TD
294  pDummyTD->bNextInvalid = pDummyTD->bAltNextInvalid = 1;
295 
296  // Configure the dummy QH
297  pDummyQH->pNext = m_pQHListPhys >> 5;
298  pDummyQH->nNextType = 1;
299 
300  pDummyQH->pQTD = m_pqTDListPhys >> 5;
301  pDummyQH->mult = 1;
302  pDummyQH->hrcl = 1;
303 
304  pDummyQH->pMetaData = new QH::MetaData;
305  ByteSet(pDummyQH->pMetaData, 0, sizeof(QH::MetaData));
306  pDummyQH->pMetaData->pFirstQTD = 0;
307  pDummyQH->pMetaData->pLastQTD = pDummyTD;
308  pDummyQH->pMetaData->pNext = pDummyQH;
309  pDummyQH->pMetaData->pPrev = pDummyQH;
310 
311  MemoryCopy(&pDummyQH->overlay, pDummyTD, sizeof(qTD));
312 
313  m_pCurrentQueueHead = m_pCurrentQueueTail = pDummyQH;
314 
315  // Disable the asynchronous schedule, and wait for it to become disabled
316  m_pBase->write32(
317  m_pBase->read32(m_nOpRegsOffset + EHCI_CMD) & ~EHCI_CMD_ASYNCLE,
318  m_nOpRegsOffset + EHCI_CMD);
319  while (m_pBase->read32(m_nOpRegsOffset + EHCI_STS) & 0x8000)
320  ;
321 
322  // Write the async list head pointer
323  m_pBase->write32(m_pQHListPhys, m_nOpRegsOffset + EHCI_ASYNCLP);
324 
325  // Set the desired interrupt threshold (frame list size = 4096 bytes)
326  m_pBase->write32(
327  (m_pBase->read32(m_nOpRegsOffset + EHCI_CMD) & ~0xFF0000) | 0x80000,
328  m_nOpRegsOffset + EHCI_CMD);
329 
330  // Turn on the controller
331  m_pBase->write32(
332  m_pBase->read32(m_nOpRegsOffset + EHCI_CMD) | EHCI_CMD_RUN,
333  m_nOpRegsOffset + EHCI_CMD);
334  while (m_pBase->read32(m_nOpRegsOffset + EHCI_STS) & EHCI_STS_HALTED)
335  Time::delay(5 * Time::Multiplier::Millisecond);
336 
337  // Set up the RequestQueue
338  initialise();
339 
340  // Take over the ports
341  m_pBase->write32(1, m_nOpRegsOffset + EHCI_CFGFLAG);
342 
343  // If it's supported, enable the asynchronous park mode with only one
344  // transaction before advancing through the queue.
345  if (hccparams & 4)
346  {
347  m_pBase->write32(
348  m_pBase->read32(m_nOpRegsOffset + EHCI_CMD) | 0x900,
349  m_nOpRegsOffset + EHCI_CMD);
350  }
351 
352  // Enable the asynchronous schedule, and wait for it to become enabled
353  m_pBase->write32(
354  m_pBase->read32(m_nOpRegsOffset + EHCI_CMD) | EHCI_CMD_ASYNCLE,
355  m_nOpRegsOffset + EHCI_CMD);
356  while (!(m_pBase->read32(m_nOpRegsOffset + EHCI_STS) & 0x8000))
357  Time::delay(5 * Time::Multiplier::Millisecond);
358 
359  // Search for ports with devices and initialise them
360  for (size_t i = 0; i < m_nPorts; i++)
361  {
362 #ifdef USB_VERBOSE_DEBUG
363  DEBUG_LOG(
364  "USB: EHCI: Port "
365  << Dec << i << Hex << " - status initially: "
366  << m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + i * 4));
367 #endif
368  // Check for port power
369  if (!(m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + i * 4) &
370  EHCI_PORTSC_PPOW))
371  {
372  m_pBase->write32(
373  EHCI_PORTSC_PPOW, m_nOpRegsOffset + EHCI_PORTSC + i * 4);
374  Time::delay(20 * Time::Multiplier::Millisecond);
375 #ifdef USB_VERBOSE_DEBUG
376  DEBUG_LOG(
377  "USB: EHCI: Port "
378  << Dec << i << Hex << " - status after power-up: "
379  << m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + i * 4));
380 #endif
381  }
382 
383  // Check for an existing reset on the port and request termination
384  m_pBase->write32(
385  m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + (i * 4)) &
386  ~EHCI_PORTSC_PRES,
387  m_nOpRegsOffset + EHCI_PORTSC + (i * 4));
388  while (m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + (i * 4)) &
389  EHCI_PORTSC_PRES)
390  Time::delay(5 * Time::Multiplier::Millisecond);
391 
392  executeRequest(i);
393  }
394 
395  // Enable port status change interrupt and clear it from status
396  m_pBase->write32(EHCI_STS_PORTCH, m_nOpRegsOffset + EHCI_STS);
397  m_pBase->write32(0x3f, m_nOpRegsOffset + EHCI_INTR);
398 
399  return true;
400 }
401 
402 Ehci::~Ehci()
403 {
404 }
405 
406 static int threadStub(void *p)
407 {
408  Ehci *pEhci = reinterpret_cast<Ehci *>(p);
409  pEhci->doDequeue();
410  return 0;
411 }
412 
413 void Ehci::doDequeue()
414 {
415  // Absolutely cannot have queue insetions during a dequeue
416  LockGuard<Mutex> guard(m_Mutex);
417 
418  for (size_t i = 1; i < 0x2000 / sizeof(QH); i++)
419  {
420  if (!m_QHBitmap.test(i))
421  continue;
422 
423  QH *pQH = &m_pQHList[i];
424 
425  // Is this QH valid?
426  if (!pQH->pMetaData)
427  {
428 #ifdef USB_VERBOSE_DEBUG
429  DEBUG_LOG(
430  "Not performing dequeue on QH #"
431  << Dec << i << Hex << " as it's not even initialised.");
432 #endif
433  continue;
434  }
435 
436  // Is this QH even linked!?
437  if (!pQH->pMetaData->bIgnore)
438  {
439 #ifdef USB_VERBOSE_DEBUG
440  DEBUG_LOG(
441  "Not performing dequeue on QH #" << Dec << i << Hex
442  << " as it's still active.");
443 #endif
444  continue;
445  }
446 
447  // Remove all qTDs
448  size_t nQTDIndex = INDEX_FROM_QTD(pQH->pMetaData->pFirstQTD);
449  while (true)
450  {
451  m_qTDBitmap.clear(nQTDIndex);
452 
453  qTD *pqTD = &m_pqTDList[nQTDIndex];
454  bool shouldBreak = pqTD->bNextInvalid;
455  if (!shouldBreak)
456  nQTDIndex = ((pqTD->pNext << 5) & 0xFFF) / sizeof(qTD);
457 
458  ByteSet(pqTD, 0, sizeof(qTD));
459 
460  if (shouldBreak)
461  break;
462  }
463 
464  // Completely invalidate the QH
465  delete pQH->pMetaData;
466  ByteSet(pQH, 0, sizeof(QH));
467 
468 #ifdef USB_VERBOSE_DEBUG
469  DEBUG_LOG("Dequeue for QH #" << Dec << i << Hex << ".");
470 #endif
471 
472  // This QH is done
473  m_QHBitmap.clear(i);
474  }
475 }
476 
477 #ifdef X86_COMMON
478 bool Ehci::irq(irq_id_t number, InterruptState &state)
479 #else
480 void Ehci::interrupt(size_t number, InterruptState &state)
481 #endif
482 {
483  /*
484  uint32_t pciStatus = PciBus::instance().readConfigSpace(this, 1) >> 16;
485  if(!(pciStatus & 8))
486  {
487  NOTICE_NOLOCK("EHCI: IRQ fired, but not for us [" << pciStatus << "]");
488  return
489 #ifdef X86_COMMON
490  false
491 #endif
492  ;
493  }
494  */
495 
496  uint32_t nStatus = m_pBase->read32(m_nOpRegsOffset + EHCI_STS) &
497  m_pBase->read32(m_nOpRegsOffset + EHCI_INTR);
498 
499  if (!nStatus)
500  {
501  WARNING_NOLOCK("EHCI: unwanted IRQ?");
502  return
503 #ifdef X86_COMMON
504  false // Shared IRQ: this IRQ is for another device
505 #endif
506  ;
507  }
508 
509  // ACK the cause of the interrupt early.
510  m_pBase->write32(nStatus, m_nOpRegsOffset + EHCI_STS);
511 
512  if (nStatus & 0x16)
513  {
514  NOTICE_NOLOCK("EHCI: Unusual IRQ, status is " << nStatus);
515  }
516 
517 #ifdef USB_VERBOSE_DEBUG
518  DEBUG_LOG_NOLOCK("EHCI IRQ " << nStatus);
519 #endif
520  if (nStatus & EHCI_STS_PORTCH)
521  {
522  for (size_t i = 0; i < m_nPorts; i++)
523  {
524  if (m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + i * 4) &
525  EHCI_PORTSC_CSCH)
526  {
527  m_pBase->write32(
528  m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + i * 4),
529  m_nOpRegsOffset + EHCI_PORTSC + i * 4);
530 
531  if (!m_IgnoredPorts.test(i))
532  addAsyncRequest(0, i);
533  }
534  }
535  }
536 
537  // Because there's no IOC for *every* transfer, we need to handle errors
538  // that occur before the last transfer. These will create an error status
539  // only.
540  if (nStatus & (EHCI_STS_INT | EHCI_STS_ERR))
541  {
542  for (size_t i = 1; i < 128; i++)
543  {
544  if (!m_QHBitmap.test(i))
545  continue;
546 
547  QH *pQH = &m_pQHList[i];
548  if (!pQH->pMetaData) // This QH isn't actually ready to be handled
549  // yet.
550  continue;
551  if (!(pQH->pMetaData->pPrev &&
552  pQH->pMetaData->pNext)) // This QH isn't actually linked yet
553  continue;
554  if (pQH->pMetaData->bIgnore)
555  continue;
556  if (!(pQH->pMetaData->pFirstQTD && pQH->pMetaData->pLastQTD))
557  continue;
558 
559  bool bPeriodic = pQH->pMetaData->bPeriodic;
560 
561  size_t nQTDIndex = INDEX_FROM_QTD(pQH->pMetaData->pFirstQTD);
562  while (true)
563  {
564  qTD *pqTD = &m_pqTDList[nQTDIndex];
565 
566  if (pqTD->nStatus != 0x80)
567  {
568  ssize_t nResult;
569  if ((pqTD->nStatus & 0x7c) || (nStatus & EHCI_STS_ERR))
570  {
571 #ifdef USB_VERBOSE_DEBUG
572  ERROR_NOLOCK(
573  ((nStatus & EHCI_STS_ERR) ? "USB" : "qTD")
574  << " ERROR!");
575  ERROR_NOLOCK(
576  "qTD Status: " << pqTD->nStatus
577  << " [overlay status="
578  << pQH->overlay.nStatus << "]");
579  ERROR_NOLOCK(
580  "qTD Error Counter: " << pqTD->nErr
581  << " [overlay counter="
582  << pQH->overlay.nErr << "]");
583  ERROR_NOLOCK(
584  "QH NAK counter: " << pqTD->res1
585  << " [overlay count="
586  << pQH->overlay.res1 << "]");
587  ERROR_NOLOCK("qTD PID: " << pqTD->nPid << ".");
588 #endif
589  nResult = -pqTD->getError();
590  }
591  else
592  {
593  nResult = pqTD->nBufferSize - pqTD->nBytes;
594  pQH->pMetaData->nTotalBytes += nResult;
595  }
596 #ifdef USB_VERBOSE_DEBUG
597  DEBUG_LOG_NOLOCK(
598  "qTD #" << Dec << nQTDIndex << Hex << " [from QH #"
599  << Dec << i << Hex << "] DONE: " << Dec
600  << pQH->nAddress << ":" << pQH->nEndpoint << " "
601  << (pqTD->nPid == 0 ?
602  "OUT" :
603  (pqTD->nPid == 1 ?
604  "IN" :
605  (pqTD->nPid == 2 ? "SETUP" : "")))
606  << " " << nResult << Hex);
607 #endif
608 
609  // Last qTD or error condition?
610  if ((nResult < 0) || (pqTD == pQH->pMetaData->pLastQTD))
611  {
612  // Valid callback?
613  if (pQH->pMetaData->pCallback)
614  pQH->pMetaData->pCallback(
615  pQH->pMetaData->pParam,
616  nResult < 0 ? nResult :
617  pQH->pMetaData->nTotalBytes);
618 
619  if (!bPeriodic)
620  {
621  // Ensure the list doesn't change as we modify it
622  m_QueueListChangeLock
623  .acquire(); // Atomic operation
624 
625  // Was the reclaim head bit set?
626  if (pQH->hrcl)
627  pQH->pMetaData->pNext->hrcl =
628  1; // Make sure there's always a reclaim
629  // head
630 
631  // This queue head is done, dequeue.
632  QH *pPrev = pQH->pMetaData->pPrev;
633  QH *pNext = pQH->pMetaData->pNext;
634 
635  // Main non-hardware linked list update
636  pPrev->pMetaData->pNext = pNext;
637  pNext->pMetaData->pPrev = pPrev;
638 
639  // Hardware linked list update
640  pPrev->pNext = pQH->pNext;
641 
642  // Update the tail pointer if we need to
643  if (pQH == m_pCurrentQueueTail)
644  {
645  m_pCurrentQueueTail = pPrev;
646  }
647 
648  // Interrupt on Async Advance Doorbell - will run
649  // the dequeue thread to clear bits in the QH and
650  // qTD bitmaps
651  size_t cmdReg =
652  m_pBase->read32(m_nOpRegsOffset + EHCI_CMD);
653  m_pBase->write32(
654  cmdReg | (1 << 6), m_nOpRegsOffset + EHCI_CMD);
655 
656  // Now ready for dequeue.
657  pQH->pMetaData->bIgnore = true;
658 
659  m_QueueListChangeLock.release();
660  }
661  }
662  // Interrupt qTDs need constant refresh
663  if (bPeriodic)
664  {
665  pqTD->nStatus = 0x80;
666  pqTD->nBytes = pqTD->nBufferSize;
667  pqTD->nPage = 0;
668  // pqTD->nOffset = pQH->pMetaData->nBufferOffset%0x1000;
669  pqTD->nErr = 0;
670  // pqTD->pPage0 = m_pTransferPagesPhys>>12;
671  // pqTD->pPage1 = (m_pTransferPagesPhys + 0x1000)>>12;
672  // pqTD->pPage2 = (m_pTransferPagesPhys + 0x2000)>>12;
673  // pqTD->pPage3 = (m_pTransferPagesPhys + 0x3000)>>12;
674  // pqTD->pPage4 = (m_pTransferPagesPhys + 0x4000)>>12;
675  MemoryCopy(&pQH->overlay, pqTD, sizeof(qTD));
676  }
677  }
678 
679  size_t oldIndex = nQTDIndex;
680 
681  if (pqTD->bNextInvalid)
682  break;
683  else
684  nQTDIndex = ((pqTD->pNext << 5) & 0xFFF) / sizeof(qTD);
685 
686  if (nQTDIndex == oldIndex)
687  {
688  ERROR_NOLOCK(
689  "EHCI: QH #"
690  << Dec << i << Hex
691  << "'s qTD list is invalid - circular reference!");
692  break;
693  }
694  else if (pqTD->pNext == 0)
695  {
696  ERROR_NOLOCK(
697  "EHCI: QH #" << Dec << i << Hex
698  << "'s qTD list is invalid - null pNext "
699  "pointer (and T bit not set)!");
700  break;
701  }
702  }
703  }
704  }
705 
706  if (nStatus & EHCI_STS_ASYNCADVANCE)
707  {
708  Thread *pThread = new Thread(
709  Processor::information().getCurrentThread()->getParent(),
710  threadStub, reinterpret_cast<void *>(this));
711  pThread->detach();
712  }
713 
714 #ifdef X86_COMMON
715  return true;
716 #endif
717 }
718 
720  uintptr_t nTransaction, bool bToggle, UsbPid pid, uintptr_t pBuffer,
721  size_t nBytes)
722 {
723  // Atomic operation: find clear bit, set it
724  size_t nIndex = 0;
725  {
726  LockGuard<Mutex> guard(m_Mutex);
727  nIndex = m_qTDBitmap.getFirstClear();
728  if (nIndex >= (0x1000 / sizeof(qTD)))
729  {
730  ERROR("USB: EHCI: qTD space full");
731  return;
732  }
733  m_qTDBitmap.set(nIndex);
734  }
735 
736  // Grab the qTD pointer we're going to set up now
737  qTD *pqTD = &m_pqTDList[nIndex];
738  ByteSet(pqTD, 0, sizeof(qTD));
739 
740  // There's nothing after us for now
741  pqTD->bNextInvalid = 1;
742  pqTD->bAltNextInvalid = 1;
743 
744  // PID for the transfer
745  switch (pid)
746  {
747  case UsbPidOut:
748  pqTD->nPid = 0;
749  break;
750  case UsbPidIn:
751  pqTD->nPid = 1;
752  break;
753  case UsbPidSetup:
754  pqTD->nPid = 2;
755  break;
756  default:
757  pqTD->nPid = 3;
758  };
759 
760  // Active, we want an interrupt on completion, and reset the error counter
761  pqTD->nStatus = 0x80;
762  pqTD->bIoc = 0; // Interrupt only on last TD
763  pqTD->nErr = 3; // Up to 3 retries of this transaction
764 
765  // Set up the transfer
766  pqTD->nBytes = nBytes;
767  pqTD->nBufferSize = nBytes;
768  pqTD->bDataToggle = bToggle;
769 
770  if (nBytes)
771  {
772  // Configure transfer pages
773  uintptr_t nBufferPageOffset = pBuffer & 0xFFF,
774  pBufferPageStart = pBuffer & ~0xFFF;
775  pqTD->nOffset = nBufferPageOffset;
776 
777  if (nBufferPageOffset + nBytes >= 0x5000)
778  {
779  ERROR("EHCI: addTransferToTransaction: Too many bytes for a single "
780  "transaction!");
781  return;
782  }
783 
784  VirtualAddressSpace &va =
785  Processor::information().getVirtualAddressSpace();
786  GET_PAGE(pqTD->pPage0, 0, nIndex);
787  GET_PAGE(pqTD->pPage1, 1, nIndex);
788  GET_PAGE(pqTD->pPage2, 2, nIndex);
789  GET_PAGE(pqTD->pPage3, 3, nIndex);
790  GET_PAGE(pqTD->pPage4, 4, nIndex);
791  }
792 
793  // Grab transaction's QH and add our qTD to it
794  QH *pQH = &m_pQHList[nTransaction];
795  if (pQH->pMetaData->pLastQTD)
796  {
797  pQH->pMetaData->pLastQTD->pNext = PHYS_QTD(nIndex) >> 5;
798  pQH->pMetaData->pLastQTD->bNextInvalid = 0;
799 
800  if (pQH->pMetaData->pLastQTD == pQH->pMetaData->pFirstQTD)
801  {
802  pQH->overlay.pNext = pQH->pMetaData->pLastQTD->pNext;
803  pQH->overlay.bNextInvalid = pQH->pMetaData->pLastQTD->bNextInvalid;
804  }
805  }
806  else
807  {
808  pQH->pMetaData->pFirstQTD = pqTD;
809  pQH->pQTD = PHYS_QTD(nIndex) >> 5;
810  MemoryCopy(&pQH->overlay, pqTD, sizeof(qTD));
811  }
812  pQH->pMetaData->pLastQTD = pqTD;
813 }
814 
815 uintptr_t Ehci::createTransaction(UsbEndpoint endpointInfo)
816 {
817  // Atomic operation: find clear bit, set it
818  size_t nIndex = 0;
819  {
820  LockGuard<Mutex> guard(m_Mutex);
821  nIndex = m_QHBitmap.getFirstClear();
822  if (nIndex >= (0x2000 / sizeof(QH)))
823  {
824  ERROR("USB: EHCI: QH space full");
825  return static_cast<uintptr_t>(-1);
826  }
827  m_QHBitmap.set(nIndex);
828  }
829 
830  QH *pQH = &m_pQHList[nIndex];
831  ByteSet(pQH, 0, sizeof(QH));
832 
833  // The pointer to the next QH gets set in doAsync
834  pQH->nNextType = 1;
835 
836  // NAK counter reload = 15
837  pQH->nNakReload = 15;
838 
839  // Head of the reclaim list
840  pQH->hrcl = true;
841 
842  // LS/FS handling
843  pQH->nHubAddress =
844  endpointInfo.speed != HighSpeed ? endpointInfo.nHubAddress : 0;
845  pQH->nHubPort = endpointInfo.speed != HighSpeed ? endpointInfo.nHubPort : 0;
846  pQH->bControlEndpoint =
847  (endpointInfo.speed != HighSpeed) && !endpointInfo.nEndpoint;
848 
849  // Data toggle controlled by qTD
850  pQH->bDataToggleSrc = 1;
851 
852  // Device address and speed
853  pQH->nAddress = endpointInfo.nAddress;
854  pQH->nSpeed = endpointInfo.speed;
855 
856  // Endpoint number and maximum packet size
857  pQH->nEndpoint = endpointInfo.nEndpoint;
858  pQH->nMaxPacketSize = endpointInfo.nMaxPacketSize;
859 
860  // Bandwidth multiplier - number of transactions that can be performed in a
861  // microframe
862  pQH->mult = 1;
863 
864  // Setup the metadata
865  QH::MetaData *pMetaData = new QH::MetaData();
866  pMetaData->bPeriodic = false;
867  pMetaData->pFirstQTD = 0;
868  pMetaData->pLastQTD = 0;
869  pMetaData->pNext = 0;
870  pMetaData->pPrev = 0;
871  pMetaData->bIgnore = false;
872  pMetaData->nTotalBytes = 0;
873 
874  pQH->pMetaData = pMetaData;
875 
876  // Complete
877  return nIndex;
878 }
879 
881  uintptr_t nTransaction, void (*pCallback)(uintptr_t, ssize_t),
882  uintptr_t pParam)
883 {
884  LockGuard<Mutex> guard(m_Mutex);
885  if ((nTransaction == static_cast<uintptr_t>(-1)) ||
886  !m_QHBitmap.test(nTransaction))
887  {
888  ERROR(
889  "EHCI: doAsync: didn't get a valid transaction id [" << nTransaction
890  << "].");
891  return;
892  }
893 
894  QH *pQH = &m_pQHList[nTransaction];
895  pQH->pMetaData->pCallback = pCallback;
896  pQH->pMetaData->pParam = pParam;
897  pQH->pMetaData->pLastQTD->bIoc = 1;
898 
899  // Only one transaction on this QH?
900  if (pQH->pMetaData->pFirstQTD == pQH->pMetaData->pLastQTD)
901  {
902  // Update IOC bit in Transfer Overlay as well (as we have just changed)
903  pQH->overlay.bIoc = 1;
904  }
905 
906 #ifdef USB_VERBOSE_DEBUG
907  DEBUG_LOG(
908  "START #" << Dec << nTransaction << Hex << " " << Dec << pQH->nAddress
909  << ":" << pQH->nEndpoint << Hex);
910 #endif
911 
912  // Link in to the asynchronous schedule
913  if (m_pCurrentQueueTail)
914  {
915  // This QH is NOT the queue head. If we leave this set to one, and the
916  // reclaim bit is set, the controller will think it's executed a full
917  // circle, when in fact it's only partway there.
918  pQH->hrcl = 0;
919 
920  // Current QH needs to point to the schedule's head
921  size_t queueHeadIndex =
922  (reinterpret_cast<uintptr_t>(m_pCurrentQueueHead) & 0xFFF) /
923  sizeof(QH);
924  pQH->pNext = (m_pQHListPhys + (queueHeadIndex * sizeof(QH))) >> 5;
925 
926  // Enter the information for correct dequeue
927  pQH->pMetaData->pNext = m_pCurrentQueueHead;
928  pQH->pMetaData->pPrev = m_pCurrentQueueTail;
929 
930  QH *pOldTail = m_pCurrentQueueTail;
931 
932  {
933  // Atomic operation - modifying both the housekeeping and the
934  // hardware linked lists
935  LockGuard<Spinlock> queueGuard(m_QueueListChangeLock);
936 
937  // Update the tail pointer
938  m_pCurrentQueueTail = pQH;
939 
940  // The current tail needs to point to this QH
941  pOldTail->pNext =
942  (m_pQHListPhys + (nTransaction * sizeof(QH))) >> 5;
943  pOldTail->nNextType = 1; // QH
944 
945  // Finally, fix the linked list
946  pOldTail->pMetaData->pNext = pQH;
947  }
948 
949  // No longer reclaiming
950  m_pCurrentQueueHead->hrcl = 1;
951  }
952  else
953  {
954  ERROR("EHCI: Queue tail is null!");
955  }
956 }
957 
959  UsbEndpoint endpointInfo, uintptr_t pBuffer, uint16_t nBytes,
960  void (*pCallback)(uintptr_t, ssize_t), uintptr_t pParam)
961 {
962  LockGuard<Mutex> guard(m_Mutex);
963 
964  // Find an empty frame entry
965  size_t nFrameIndex = m_FrameBitmap.getFirstClear();
966  if (nFrameIndex >= 1024)
967  {
968  ERROR("USB: EHCI: Frame list full");
969  return;
970  }
971  m_FrameBitmap.set(nFrameIndex);
972 
973  // Create a new transaction
974  uintptr_t nTransaction = createTransaction(endpointInfo);
975 
976  // Get the QH and set the periodic flag
977  QH *pQH = &m_pQHList[nTransaction];
978  pQH->pMetaData->bPeriodic = true;
979 
980  // Add a single transfer to the transaction
981  addTransferToTransaction(nTransaction, false, UsbPidIn, pBuffer, nBytes);
982  if (!pQH->pMetaData->pLastQTD)
983  {
984  ERROR("USB: EHCI: Couldn't add transfer to transaction!");
985  return;
986  }
987 
988  // Get the qTD and set the error counter to "unlimited retries"
989  qTD *pqTD = pQH->pMetaData->pLastQTD;
990  pqTD->nErr = 0;
991 
992  // Add the QH to the frame list
993  m_pFrameList[nFrameIndex] = (m_pQHListPhys + nTransaction * sizeof(QH)) | 2;
994 }
995 
996 bool Ehci::portReset(uint8_t nPort, bool bErrorResponse)
997 {
998  int retry;
999  for (retry = 0; retry < 3; retry++)
1000  {
1001 #ifdef USB_VERBOSE_DEBUG
1002  DEBUG_LOG(
1003  "USB: EHCI: Port "
1004  << Dec << nPort << Hex << " - status before reset: "
1005  << m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + (nPort * 4)));
1006 #endif
1007 
1008  // Set the reset bit
1009  m_pBase->write32(
1010  m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + (nPort * 4)) |
1011  EHCI_PORTSC_PRES,
1012  m_nOpRegsOffset + EHCI_PORTSC + (nPort * 4));
1013 
1014  Time::delay(50 * Time::Multiplier::Millisecond);
1015 
1016  // Unset the reset bit
1017  m_pBase->write32(
1018  m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + (nPort * 4)) &
1019  ~EHCI_PORTSC_PRES,
1020  m_nOpRegsOffset + EHCI_PORTSC + (nPort * 4));
1021 
1022  // Wait for the reset to complete
1023  while (m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + (nPort * 4)) &
1024  EHCI_PORTSC_PRES)
1025  Time::delay(5 * Time::Multiplier::Millisecond);
1026 
1027 #ifdef USB_VERBOSE_DEBUG
1028  DEBUG_LOG(
1029  "USB: EHCI: Port "
1030  << Dec << nPort << Hex << " - status after reset: "
1031  << m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + (nPort * 4)));
1032 #endif
1033 
1034  if ((m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + (nPort * 4)) &
1035  EHCI_PORTSC_EN) &&
1036  (m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + (nPort * 4)) &
1037  EHCI_PORTSC_CONN))
1038  {
1039  DEBUG_LOG(
1040  "USB: EHCI: Port " << Dec << nPort << Hex << " is connected");
1041  return true;
1042  }
1043  else
1044  {
1045  DEBUG_LOG(
1046  "USB: EHCI: Port " << Dec << nPort << Hex
1047  << " seems to be not HighSpeed. Returning "
1048  "to companion controllers.");
1049  m_pBase->write32(
1050  m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + (nPort * 4)) |
1051  0x2000,
1052  m_nOpRegsOffset + EHCI_PORTSC + (nPort * 4));
1053  }
1054  }
1055 
1056  WARNING("EHCI: Port " << Dec << nPort << Hex << " could not be connected");
1057 
1058  return false;
1059 }
1060 
1062  uint64_t p1, uint64_t p2, uint64_t p3, uint64_t p4, uint64_t p5,
1063  uint64_t p6, uint64_t p7, uint64_t p8)
1064 {
1065  // See if there's any device attached on the port
1066  if (m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + p1 * 4) &
1067  EHCI_PORTSC_CONN)
1068  {
1069  if (portReset(p1))
1070  if (!deviceConnected(p1, HighSpeed))
1071  WARNING(
1072  "EHCI: Port "
1073  << Dec << p1 << Hex
1074  << " appeared to be connected but could not be set up");
1075  }
1076  else
1077  {
1078  DEBUG_LOG("USB: EHCI: Port " << Dec << p1 << Hex << " is disconnected");
1079 
1080  deviceDisconnected(p1);
1081 
1082  // Clean any bits that would remain
1083  m_pBase->write32(
1084  m_pBase->read32(m_nOpRegsOffset + EHCI_PORTSC + p1 * 4),
1085  m_nOpRegsOffset + EHCI_PORTSC + p1 * 4);
1086  }
1087  return 0;
1088 }
virtual bool registerInterruptHandler(size_t nInterruptNumber, InterruptHandler *pHandler)=0
virtual void doAsync(uintptr_t pTransaction, void(*pCallback)(uintptr_t, ssize_t)=0, uintptr_t pParam=0)
Definition: Ehci.cc:880
static PhysicalMemoryManager & instance()
Definition: Ehci.h:41
virtual void addTransferToTransaction(uintptr_t pTransaction, bool bToggle, UsbPid pid, uintptr_t pBuffer, size_t nBytes)
Adds a new transfer to an existent transaction.
Definition: Ehci.cc:719
Definition: String.h:49
static ProcessorInformation & information()
Definition: Processor.cc:45
Definition: Device.h:43
virtual bool portReset(uint8_t nPort, bool bErrorResponse=false)
Gets a UsbDevice from a given vendor:product pair.
Definition: Ehci.cc:996
#define WARNING(text)
Definition: Log.h:78
virtual void addInterruptInHandler(UsbEndpoint endpointInfo, uintptr_t pBuffer, uint16_t nBytes, void(*pCallback)(uintptr_t, ssize_t), uintptr_t pParam=0)
Adds a new handler for an interrupt IN transaction.
Definition: Ehci.cc:958
#define NOTICE(text)
Definition: Log.h:74
uint32_t readConfigSpace(Device *pDev, uint8_t offset)
Definition: Pci.cc:75
Definition: Log.h:136
Definition: Ehci.h:105
Definition: Ehci.h:55
Definition: UsbHub.h:30
virtual uintptr_t createTransaction(UsbEndpoint endpointInfo)
Creates a new transaction with the given endpoint data.
Definition: Ehci.cc:815
bool initialiseController()
Definition: Ehci.cc:86
Definition: Thread.h:54
virtual irq_id_t registerPciIrqHandler(IrqHandler *handler, Device *pDevice)=0
#define ERROR(text)
Definition: Log.h:82
bool detach()
Definition: Thread.cc:885
Definition: Log.h:138
virtual bool control(uint8_t irq, ControlCode code, size_t argument)
Definition: IrqManager.cc:29
#define DEBUG_LOG(text)
Definition: Log.h:69
static InterruptManager & instance()
virtual bool irq(irq_id_t number, InterruptState &state)
IRQ handler.
Definition: Ehci.cc:478
virtual uint64_t executeRequest(uint64_t p1=0, uint64_t p2=0, uint64_t p3=0, uint64_t p4=0, uint64_t p5=0, uint64_t p6=0, uint64_t p7=0, uint64_t p8=0)
Definition: Ehci.cc:1061
void writeConfigSpace(Device *pDev, uint8_t offset, uint32_t data)
Definition: Pci.cc:104