EHCI: Try to use physical buffers directly when possible.
EHCI has more DMA restrictions than XHCI, so if we can't use them, we just fall back to copying the buffers as before. Tested in QEMU, system booted successfully. However, it seems that quite a lot of disk I/O can't use physical buffers here, probably due to packagefs' use of uncached reads. Change-Id: I4d35642ee1a8f5ba2531f6658f8cbbef5a7785ac Reviewed-on: https://review.haiku-os.org/c/haiku/+/9613 Tested-by: Commit checker robot <[email protected]> Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
f65a156bf8
commit
779ae8bcd3
@@ -2006,7 +2006,8 @@ EHCI::FinishTransfers()
|
||||
|
||||
if (callbackStatus == B_OK) {
|
||||
bool nextDataToggle = false;
|
||||
if (transfer->data_descriptor && transfer->incoming) {
|
||||
if (transfer->data_descriptor && transfer->incoming
|
||||
&& transfer->data_descriptor->buffer_log != NULL) {
|
||||
// data to read out
|
||||
generic_io_vec *vector = transfer->transfer->Vector();
|
||||
size_t vectorCount = transfer->transfer->VectorCount();
|
||||
@@ -2017,7 +2018,7 @@ EHCI::FinishTransfers()
|
||||
vector, vectorCount, transfer->transfer->IsPhysical(),
|
||||
&nextDataToggle);
|
||||
}
|
||||
} else if (transfer->data_descriptor) {
|
||||
} else if (transfer->data_descriptor != NULL) {
|
||||
// calculate transfered length
|
||||
actualLength = ReadActualLength(
|
||||
transfer->data_descriptor, &nextDataToggle);
|
||||
@@ -2461,8 +2462,9 @@ EHCI::FillQueueWithRequest(Transfer *transfer, ehci_qh *queueHead,
|
||||
if (transfer->VectorCount() > 0) {
|
||||
ehci_qtd *lastDescriptor = NULL;
|
||||
status_t result = CreateDescriptorChain(pipe, &dataDescriptor,
|
||||
&lastDescriptor, statusDescriptor, transfer->FragmentLength(),
|
||||
directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT);
|
||||
&lastDescriptor, statusDescriptor,
|
||||
directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT,
|
||||
transfer->FragmentLength());
|
||||
|
||||
if (result != B_OK) {
|
||||
FreeDescriptor(setupDescriptor);
|
||||
@@ -2504,6 +2506,14 @@ status_t
|
||||
EHCI::FillQueueWithData(Transfer *transfer, ehci_qh *queueHead,
|
||||
ehci_qtd **_dataDescriptor, bool *_directionIn, bool prepareKernelAccess)
|
||||
{
|
||||
if (transfer->IsPhysical()) {
|
||||
// Try to use the physical buffer directly, first.
|
||||
status_t result = _FillQueueWithPhysicalData(transfer, queueHead,
|
||||
_dataDescriptor, _directionIn);
|
||||
if (result != B_NOT_SUPPORTED)
|
||||
return result;
|
||||
}
|
||||
|
||||
Pipe *pipe = transfer->TransferPipe();
|
||||
bool directionIn = (pipe->Direction() == Pipe::In);
|
||||
|
||||
@@ -2511,13 +2521,13 @@ EHCI::FillQueueWithData(Transfer *transfer, ehci_qh *queueHead,
|
||||
ehci_qtd *lastDescriptor = NULL;
|
||||
ehci_qtd *strayDescriptor = queueHead->stray_log;
|
||||
status_t result = CreateDescriptorChain(pipe, &firstDescriptor,
|
||||
&lastDescriptor, strayDescriptor, transfer->FragmentLength(),
|
||||
directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT);
|
||||
&lastDescriptor, strayDescriptor,
|
||||
directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT,
|
||||
transfer->FragmentLength());
|
||||
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
lastDescriptor->token |= EHCI_QTD_IOC;
|
||||
if (!directionIn) {
|
||||
if (prepareKernelAccess) {
|
||||
result = transfer->PrepareKernelAccess();
|
||||
@@ -2533,6 +2543,96 @@ EHCI::FillQueueWithData(Transfer *transfer, ehci_qh *queueHead,
|
||||
queueHead->element_log = firstDescriptor;
|
||||
queueHead->overlay.next_phy = firstDescriptor->this_phy;
|
||||
queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
|
||||
lastDescriptor->token |= EHCI_QTD_IOC;
|
||||
|
||||
*_dataDescriptor = firstDescriptor;
|
||||
if (_directionIn)
|
||||
*_directionIn = directionIn;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
EHCI::_FillQueueWithPhysicalData(Transfer *transfer, ehci_qh *queueHead,
|
||||
ehci_qtd **_dataDescriptor, bool *_directionIn)
|
||||
{
|
||||
generic_io_vec* transferVec = transfer->Vector();
|
||||
size_t vecI;
|
||||
int32 pagesCount = 0;
|
||||
bool canUseBuffer = true;
|
||||
|
||||
for (vecI = 0; vecI < transfer->VectorCount(); vecI++) {
|
||||
canUseBuffer = canUseBuffer
|
||||
&& (transferVec[vecI].base + transferVec[vecI].length) < UINT32_MAX;
|
||||
pagesCount += (transferVec[vecI].length + B_PAGE_SIZE - 1) / B_PAGE_SIZE;
|
||||
}
|
||||
|
||||
if (transfer->VectorCount() > 1) {
|
||||
canUseBuffer = canUseBuffer
|
||||
&& ((transferVec[0].base + transferVec[0].length) % B_PAGE_SIZE) == 0;
|
||||
}
|
||||
for (vecI = 1; vecI < (transfer->VectorCount() - 1); vecI++) {
|
||||
canUseBuffer = canUseBuffer
|
||||
&& (transferVec[vecI].base % B_PAGE_SIZE) == 0
|
||||
&& (transferVec[vecI].length % B_PAGE_SIZE) == 0;
|
||||
}
|
||||
if (vecI != 1) {
|
||||
canUseBuffer = canUseBuffer
|
||||
&& ((transferVec[vecI - 1].base) % B_PAGE_SIZE) == 0;
|
||||
}
|
||||
|
||||
if (!canUseBuffer)
|
||||
return B_NOT_SUPPORTED;
|
||||
|
||||
Pipe *pipe = transfer->TransferPipe();
|
||||
bool directionIn = (pipe->Direction() == Pipe::In);
|
||||
|
||||
ehci_qtd *firstDescriptor = NULL;
|
||||
ehci_qtd *lastDescriptor = NULL;
|
||||
ehci_qtd *strayDescriptor = queueHead->stray_log;
|
||||
status_t result = CreateDescriptorChain(pipe, &firstDescriptor,
|
||||
&lastDescriptor, strayDescriptor,
|
||||
directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT,
|
||||
0, (pagesCount + 5 - 1) / 5);
|
||||
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ehci_qtd *current = firstDescriptor;
|
||||
uint32 transferVecOffset = 0;
|
||||
size_t remaining = transfer->FragmentLength();
|
||||
while (remaining != 0) {
|
||||
uint32 qtdLength = 0;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
current->buffer_phy[i] = (uint32)transferVec->base + transferVecOffset;
|
||||
|
||||
// Special cases for the first and last buffers.
|
||||
uint32 bufferLength = B_PAGE_SIZE;
|
||||
if ((current->buffer_phy[i] % B_PAGE_SIZE) != 0)
|
||||
bufferLength -= (current->buffer_phy[i] % B_PAGE_SIZE);
|
||||
if (bufferLength > remaining)
|
||||
bufferLength = remaining;
|
||||
|
||||
qtdLength += bufferLength;
|
||||
transferVecOffset += bufferLength;
|
||||
remaining -= bufferLength;
|
||||
if (transferVec->length == transferVecOffset) {
|
||||
transferVec++;
|
||||
transferVecOffset = 0;
|
||||
}
|
||||
if (remaining == 0)
|
||||
break;
|
||||
}
|
||||
current->buffer_size = qtdLength;
|
||||
current->token |= qtdLength << EHCI_QTD_BYTES_SHIFT;
|
||||
|
||||
current = current->next_log;
|
||||
}
|
||||
|
||||
queueHead->element_log = firstDescriptor;
|
||||
queueHead->overlay.next_phy = firstDescriptor->this_phy;
|
||||
queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
|
||||
lastDescriptor->token |= EHCI_QTD_IOC;
|
||||
|
||||
*_dataDescriptor = firstDescriptor;
|
||||
if (_directionIn)
|
||||
@@ -2595,17 +2695,18 @@ EHCI::CreateDescriptor(size_t bufferSize, uint8 pid)
|
||||
|
||||
status_t
|
||||
EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor,
|
||||
ehci_qtd **_lastDescriptor, ehci_qtd *strayDescriptor, size_t bufferSize,
|
||||
uint8 pid)
|
||||
ehci_qtd **_lastDescriptor, ehci_qtd *strayDescriptor, uint8 pid,
|
||||
size_t buffersLength, int32 descriptorCount)
|
||||
{
|
||||
size_t packetSize = B_PAGE_SIZE * 4;
|
||||
int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
|
||||
if (descriptorCount < 0)
|
||||
descriptorCount = (buffersLength + packetSize - 1) / packetSize;
|
||||
|
||||
bool dataToggle = pipe->DataToggle();
|
||||
ehci_qtd *firstDescriptor = NULL;
|
||||
ehci_qtd *lastDescriptor = *_firstDescriptor;
|
||||
for (int32 i = 0; i < descriptorCount; i++) {
|
||||
ehci_qtd *descriptor = CreateDescriptor(min_c(packetSize, bufferSize),
|
||||
ehci_qtd *descriptor = CreateDescriptor(min_c(packetSize, buffersLength),
|
||||
pid);
|
||||
|
||||
if (!descriptor) {
|
||||
@@ -2619,7 +2720,8 @@ EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor,
|
||||
if (lastDescriptor)
|
||||
LinkDescriptors(lastDescriptor, descriptor, strayDescriptor);
|
||||
|
||||
bufferSize -= packetSize;
|
||||
if (buffersLength != 0)
|
||||
buffersLength -= packetSize;
|
||||
lastDescriptor = descriptor;
|
||||
if (!firstDescriptor)
|
||||
firstDescriptor = descriptor;
|
||||
|
||||
@@ -149,6 +149,10 @@ static int32 FinishIsochronousThread(void *data);
|
||||
ehci_qtd **dataDescriptor,
|
||||
bool *directionIn,
|
||||
bool prepareKernelAccess);
|
||||
status_t _FillQueueWithPhysicalData(Transfer *transfer,
|
||||
ehci_qh *queueHead,
|
||||
ehci_qtd **dataDescriptor,
|
||||
bool *directionIn);
|
||||
|
||||
bool LockIsochronous();
|
||||
void UnlockIsochronous();
|
||||
@@ -161,8 +165,9 @@ static int32 FinishIsochronousThread(void *data);
|
||||
ehci_qtd **firstDescriptor,
|
||||
ehci_qtd **lastDescriptor,
|
||||
ehci_qtd *strayDescriptor,
|
||||
size_t bufferSizeToAllocate,
|
||||
uint8 pid);
|
||||
uint8 pid,
|
||||
size_t buffersLength,
|
||||
int32 descriptorsCount = -1);
|
||||
ehci_itd* CreateItdDescriptor();
|
||||
ehci_sitd* CreateSitdDescriptor();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user