From f9e868fc8fde318d34d00831429d727f20f03042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Mon, 31 Jan 2022 18:42:19 +0100 Subject: [PATCH] sdhci: accomodate 64-bit PCI BARs * init works better with this. it doesn't work yet, but at least the boot isn't completely borked. * also fix the infinite loop in SoftwareReset() to timeout after 100ms. Change-Id: I76dac8360eaf3575adf7d0b3bf3e2b72daeedb21 Reviewed-on: https://review.haiku-os.org/c/haiku/+/4923 Reviewed-by: waddlesplash --- src/add-ons/kernel/busses/mmc/sdhci_pci.cpp | 50 ++++++++++++++------- src/add-ons/kernel/busses/mmc/sdhci_pci.h | 14 +++--- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp b/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp index 796a20ae94..b6d78c813d 100644 --- a/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp +++ b/src/add-ons/kernel/busses/mmc/sdhci_pci.cpp @@ -104,7 +104,9 @@ SdhciBus::SdhciBus(struct registers* registers, uint8_t irq) } fSemaphore = create_sem(0, "SDHCI interrupts"); - + + DisableInterrupts(); + fStatus = install_io_interrupt_handler(fIrq, sdhci_generic_interrupt, this, 0); @@ -200,7 +202,7 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response) uint32_t replyType; - switch(command) { + switch (command) { case SD_GO_IDLE_STATE: replyType = Command::kNoReplyType; break; @@ -338,7 +340,8 @@ SdhciBus::InitCheck() void SdhciBus::Reset() { - fRegisters->software_reset.ResetAll(); + if (!fRegisters->software_reset.ResetAll()) + ERROR("SdhciBus::Reset: SoftwareReset timeout\n"); } @@ -392,7 +395,7 @@ SdhciBus::DoIO(uint8_t command, IOOperation* operation, bool offsetAsSectors) off_t offset = operation->Offset(); generic_size_t length = operation->Length(); - TRACE("%s %"B_PRIu64 " bytes at %" B_PRIdOFF "\n", + TRACE("%s %" B_PRIu64 " bytes at %" B_PRIdOFF "\n", isWrite ? "Write" : "Read", length, offset); // Check that the IO scheduler did its job in following our DMA restrictions @@ -675,14 +678,29 @@ init_bus(device_node* node, void** bus_cookie) pci_info pciInfo; pci->get_pci_info(device, &pciInfo); - if (pciInfo.u.h0.base_register_sizes[bar] == 0) { + for (; bar < 6 && slot > 0; bar++, slot--) { + if ((pciInfo.u.h0.base_register_flags[bar] & PCI_address_type) + == PCI_address_type_64) { + bar++; + } + } + + phys_addr_t physicalAddress = pciInfo.u.h0.base_registers[bar]; + uint64 barSize = pciInfo.u.h0.base_register_sizes[bar]; + if ((pciInfo.u.h0.base_register_flags[bar] & PCI_address_type) + == PCI_address_type_64) { + physicalAddress |= (uint64)pciInfo.u.h0.base_registers[bar + 1] << 32; + barSize |= (uint64)pciInfo.u.h0.base_register_sizes[bar + 1] << 32; + } + + if (physicalAddress == 0 || barSize == 0) { ERROR("No registers to map\n"); return B_IO_ERROR; } int msiCount = sPCIx86Module->get_msi_count(pciInfo.bus, pciInfo.device, pciInfo.function); - TRACE("interrupts count: %d\n",msiCount); + TRACE("interrupts count: %d\n", msiCount); // FIXME if available, use MSI rather than good old IRQ... // enable bus master and io @@ -695,8 +713,7 @@ init_bus(device_node* node, void** bus_cookie) area_id regs_area; struct registers* _regs; regs_area = map_physical_memory("sdhc_regs_map", - pciInfo.u.h0.base_registers[bar], - pciInfo.u.h0.base_register_sizes[bar], B_ANY_KERNEL_BLOCK_ADDRESS, + physicalAddress, barSize, B_ANY_KERNEL_BLOCK_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&_regs); if (regs_area < B_OK) { @@ -763,22 +780,23 @@ register_child_devices(void* cookie) device_node* parent = gDeviceManager->get_parent_node(context->fNode); pci_device_module_info* pci; pci_device* device; - uint8 slots_count, bar, slotsInfo; gDeviceManager->get_driver(parent, (driver_module_info**)&pci, (void**)&device); - slotsInfo = pci->read_pci_config(device, SDHCI_PCI_SLOT_INFO, 1); - bar = SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(slotsInfo); - slots_count = SDHCI_PCI_SLOTS(slotsInfo); + uint8 slotsInfo = pci->read_pci_config(device, SDHCI_PCI_SLOT_INFO, 1); + uint8 bar = SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(slotsInfo); + uint8 slotsCount = SDHCI_PCI_SLOTS(slotsInfo); + + TRACE("register_child_devices: %u, %u\n", bar, slotsCount); char prettyName[25]; - if (slots_count > 6 || bar > 5) { - ERROR("Invalid slots count: %d or BAR count: %d \n", slots_count, bar); + if (slotsCount > 6 || bar > 5) { + ERROR("Invalid slots count: %d or BAR count: %d \n", slotsCount, bar); return B_BAD_VALUE; } - for (uint8_t slot = 0; slot <= slots_count; slot++) { + for (uint8_t slot = 0; slot < slotsCount; slot++) { sprintf(prettyName, "SDHC bus %" B_PRIu8, slot); device_attr attrs[] = { // properties of this controller for mmc bus manager @@ -799,7 +817,7 @@ register_child_devices(void* cookie) // private data to identify device { SLOT_NUMBER, B_UINT8_TYPE, { ui8: slot} }, - { BAR_INDEX, B_UINT8_TYPE, { ui8: bar + slot} }, + { BAR_INDEX, B_UINT8_TYPE, { ui8: bar} }, { NULL } }; device_node* node; diff --git a/src/add-ons/kernel/busses/mmc/sdhci_pci.h b/src/add-ons/kernel/busses/mmc/sdhci_pci.h index 418f2ed931..76285922b6 100644 --- a/src/add-ons/kernel/busses/mmc/sdhci_pci.h +++ b/src/add-ons/kernel/busses/mmc/sdhci_pci.h @@ -14,8 +14,8 @@ #define SDHCI_PCI_SLOT_INFO 0x40 -#define SDHCI_PCI_SLOTS(x) ((( x >> 4) & 7)) -#define SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(x) (( x ) & 7) +#define SDHCI_PCI_SLOTS(x) ((((x) >> 4) & 0x7) + 1) +#define SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(x) ((x) & 0x7) // Ricoh specific PCI registers // Ricoh devices start in a vendor-specific mode but can be switched @@ -159,9 +159,13 @@ class SoftwareReset { public: uint8_t Bits() { return fBits; } - void ResetAll() { - fBits |= 1; - while(fBits & 1); + bool ResetAll() { + fBits = 1; + int i = 0; + // wait up to 100ms + while ((fBits & 1) != 0 && i++ < 10) + snooze(10000); + return i < 10; } void ResetCommandLine() {