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");
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;

View File

@ -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() {