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 <waddlesplash@gmail.com>
This commit is contained in:
Jérôme Duval 2022-01-31 18:42:19 +01:00 committed by waddlesplash
parent 50ea01e93d
commit f9e868fc8f
2 changed files with 43 additions and 21 deletions

View File

@ -104,7 +104,9 @@ SdhciBus::SdhciBus(struct registers* registers, uint8_t irq)
} }
fSemaphore = create_sem(0, "SDHCI interrupts"); fSemaphore = create_sem(0, "SDHCI interrupts");
DisableInterrupts();
fStatus = install_io_interrupt_handler(fIrq, fStatus = install_io_interrupt_handler(fIrq,
sdhci_generic_interrupt, this, 0); sdhci_generic_interrupt, this, 0);
@ -200,7 +202,7 @@ SdhciBus::ExecuteCommand(uint8_t command, uint32_t argument, uint32_t* response)
uint32_t replyType; uint32_t replyType;
switch(command) { switch (command) {
case SD_GO_IDLE_STATE: case SD_GO_IDLE_STATE:
replyType = Command::kNoReplyType; replyType = Command::kNoReplyType;
break; break;
@ -338,7 +340,8 @@ SdhciBus::InitCheck()
void void
SdhciBus::Reset() 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(); off_t offset = operation->Offset();
generic_size_t length = operation->Length(); 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); isWrite ? "Write" : "Read", length, offset);
// Check that the IO scheduler did its job in following our DMA restrictions // 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_info pciInfo;
pci->get_pci_info(device, &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"); ERROR("No registers to map\n");
return B_IO_ERROR; return B_IO_ERROR;
} }
int msiCount = sPCIx86Module->get_msi_count(pciInfo.bus, int msiCount = sPCIx86Module->get_msi_count(pciInfo.bus,
pciInfo.device, pciInfo.function); 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... // FIXME if available, use MSI rather than good old IRQ...
// enable bus master and io // enable bus master and io
@ -695,8 +713,7 @@ init_bus(device_node* node, void** bus_cookie)
area_id regs_area; area_id regs_area;
struct registers* _regs; struct registers* _regs;
regs_area = map_physical_memory("sdhc_regs_map", regs_area = map_physical_memory("sdhc_regs_map",
pciInfo.u.h0.base_registers[bar], physicalAddress, barSize, B_ANY_KERNEL_BLOCK_ADDRESS,
pciInfo.u.h0.base_register_sizes[bar], B_ANY_KERNEL_BLOCK_ADDRESS,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&_regs); B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&_regs);
if (regs_area < B_OK) { if (regs_area < B_OK) {
@ -763,22 +780,23 @@ register_child_devices(void* cookie)
device_node* parent = gDeviceManager->get_parent_node(context->fNode); device_node* parent = gDeviceManager->get_parent_node(context->fNode);
pci_device_module_info* pci; pci_device_module_info* pci;
pci_device* device; pci_device* device;
uint8 slots_count, bar, slotsInfo;
gDeviceManager->get_driver(parent, (driver_module_info**)&pci, gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
(void**)&device); (void**)&device);
slotsInfo = pci->read_pci_config(device, SDHCI_PCI_SLOT_INFO, 1); uint8 slotsInfo = pci->read_pci_config(device, SDHCI_PCI_SLOT_INFO, 1);
bar = SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(slotsInfo); uint8 bar = SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(slotsInfo);
slots_count = SDHCI_PCI_SLOTS(slotsInfo); uint8 slotsCount = SDHCI_PCI_SLOTS(slotsInfo);
TRACE("register_child_devices: %u, %u\n", bar, slotsCount);
char prettyName[25]; char prettyName[25];
if (slots_count > 6 || bar > 5) { if (slotsCount > 6 || bar > 5) {
ERROR("Invalid slots count: %d or BAR count: %d \n", slots_count, bar); ERROR("Invalid slots count: %d or BAR count: %d \n", slotsCount, bar);
return B_BAD_VALUE; 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); sprintf(prettyName, "SDHC bus %" B_PRIu8, slot);
device_attr attrs[] = { device_attr attrs[] = {
// properties of this controller for mmc bus manager // properties of this controller for mmc bus manager
@ -799,7 +817,7 @@ register_child_devices(void* cookie)
// private data to identify device // private data to identify device
{ SLOT_NUMBER, B_UINT8_TYPE, { ui8: slot} }, { SLOT_NUMBER, B_UINT8_TYPE, { ui8: slot} },
{ BAR_INDEX, B_UINT8_TYPE, { ui8: bar + slot} }, { BAR_INDEX, B_UINT8_TYPE, { ui8: bar} },
{ NULL } { NULL }
}; };
device_node* node; device_node* node;

View File

@ -14,8 +14,8 @@
#define SDHCI_PCI_SLOT_INFO 0x40 #define SDHCI_PCI_SLOT_INFO 0x40
#define SDHCI_PCI_SLOTS(x) ((( x >> 4) & 7)) #define SDHCI_PCI_SLOTS(x) ((((x) >> 4) & 0x7) + 1)
#define SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(x) (( x ) & 7) #define SDHCI_PCI_SLOT_INFO_FIRST_BASE_INDEX(x) ((x) & 0x7)
// Ricoh specific PCI registers // Ricoh specific PCI registers
// Ricoh devices start in a vendor-specific mode but can be switched // Ricoh devices start in a vendor-specific mode but can be switched
@ -159,9 +159,13 @@ class SoftwareReset {
public: public:
uint8_t Bits() { return fBits; } uint8_t Bits() { return fBits; }
void ResetAll() { bool ResetAll() {
fBits |= 1; fBits = 1;
while(fBits & 1); int i = 0;
// wait up to 100ms
while ((fBits & 1) != 0 && i++ < 10)
snooze(10000);
return i < 10;
} }
void ResetCommandLine() { void ResetCommandLine() {