Fix for 'pci: mem_top too low' panic. Removed 'pci_next_dev: got nothing'

message.
This commit is contained in:
Philip Homburg 2006-04-03 12:12:04 +00:00
parent a65e215874
commit 846ae81717
2 changed files with 93 additions and 27 deletions

View file

@ -1147,10 +1147,49 @@ PRIVATE void complete_bridges()
*===========================================================================*/
PRIVATE void complete_bars()
{
int i, j, bar_nr, reg;
u32_t mem_top, io_bottom, io_top, io_high, base, size, v32;
int i, j, r, bar_nr, reg;
u32_t memgap_low, memgap_high, iogap_low, iogap_high, io_high,
base, size, v32, diff1, diff2;
char *cp, *next;
char memstr[256];
mem_top= 0xfe000000; /* Leave space for the CPU (APIC) */
r= env_get_param("memory", memstr, sizeof(memstr));
if (r != OK)
panic("pci", "env_get_param failed", r);
/* Set memgap_low to just above physical memory */
memgap_low= 0;
cp= memstr;
while (*cp != '\0')
{
base= strtoul(cp, &next, 16);
if (next == cp || *next != ':')
{
printf("pci: bad memory environment string '%s'\n",
memstr);
panic(NULL, NULL, NO_NUM);
}
cp= next+1;
size= strtoul(cp, &next, 16);
if (next == cp || (*next != ',' && *next != '\0'))
{
printf("pci: bad memory environment string '%s'\n",
memstr);
panic(NULL, NULL, NO_NUM);
}
cp= next+1;
if (base+size > memgap_low)
memgap_low= base+size;
}
memgap_high= 0xfe000000; /* Leave space for the CPU (APIC) */
if (debug)
{
printf("complete_bars: initial gap: [0x%x .. 0x%x>\n",
memgap_low, memgap_high);
}
/* Find the lowest memory base */
for (i= 0; i<nr_pcidev; i++)
@ -1162,17 +1201,40 @@ PRIVATE void complete_bars()
if (pcidev[i].pd_bar[j].pb_flags & PBF_INCOMPLETE)
continue;
base= pcidev[i].pd_bar[j].pb_base;
if (base < mem_top)
mem_top= base;
size= pcidev[i].pd_bar[j].pb_size;
if (base >= memgap_high)
continue; /* Not in the gap */
if (base+size <= memgap_low)
continue; /* Not in the gap */
/* Reduce the gap by the smallest amount */
diff1= base+size-memgap_low;
diff2= memgap_high-base;
if (diff1 < diff2)
memgap_low= base+size;
else
memgap_high= base;
}
}
/* Should check main memory size */
if (mem_top < 0x80000000)
panic("pci", "mem_top too low", mem_top);
if (debug)
{
printf("complete_bars: intermediate gap: [0x%x .. 0x%x>\n",
memgap_low, memgap_high);
}
io_top= 0x10000;
io_bottom= 0x400;
/* Should check main memory size */
if (memgap_high < memgap_low)
{
printf("pci: bad memory gap: [0x%x .. 0x%x>\n",
memgap_low, memgap_high);
panic(NULL, NULL, NO_NUM);
}
iogap_high= 0x10000;
iogap_low= 0x400;
/* Find the free I/O space */
for (i= 0; i<nr_pcidev; i++)
@ -1185,21 +1247,21 @@ PRIVATE void complete_bars()
continue;
base= pcidev[i].pd_bar[j].pb_base;
size= pcidev[i].pd_bar[j].pb_size;
if (base >= io_top)
if (base >= iogap_high)
continue;
if (base+size <= io_bottom)
if (base+size <= iogap_low)
continue;
if (base+size-io_bottom < io_top-base)
io_bottom= base+size;
if (base+size-iogap_low < iogap_high-base)
iogap_low= base+size;
else
io_top= base;
iogap_high= base;
}
}
if (io_top < io_bottom)
panic("pci", "io_top too low", io_top);
if (iogap_high < iogap_low)
panic("pci", "iogap_high too low", iogap_high);
if (debug)
printf("I/O range = [0x%x..0x%x>\n", io_bottom, io_top);
printf("I/O range = [0x%x..0x%x>\n", iogap_low, iogap_high);
for (i= 0; i<nr_pcidev; i++)
{
@ -1212,9 +1274,11 @@ PRIVATE void complete_bars()
size= pcidev[i].pd_bar[j].pb_size;
if (size < PAGE_SIZE)
size= PAGE_SIZE;
base= mem_top-size;
base= memgap_high-size;
base &= ~(u32_t)(size-1);
mem_top= base;
if (base < memgap_low)
panic("pci", "memory base too low", base);
memgap_high= base;
bar_nr= pcidev[i].pd_bar[j].pb_nr;
reg= PCI_BAR + 4*bar_nr;
v32= pci_attr_r32(i, reg);
@ -1231,7 +1295,7 @@ PRIVATE void complete_bars()
pcidev[i].pd_bar[j].pb_flags &= ~PBF_INCOMPLETE;
}
io_high= io_top;
io_high= iogap_high;
for (j= 0; j<pcidev[i].pd_bar_nr; j++)
{
if (!(pcidev[i].pd_bar[j].pb_flags & PBF_IO))
@ -1239,7 +1303,7 @@ PRIVATE void complete_bars()
if (!(pcidev[i].pd_bar[j].pb_flags & PBF_INCOMPLETE))
continue;
size= pcidev[i].pd_bar[j].pb_size;
base= io_top-size;
base= iogap_high-size;
base &= ~(u32_t)(size-1);
/* Assume that ISA compatibility is required. Only
@ -1247,10 +1311,10 @@ PRIVATE void complete_bars()
*/
base &= 0xfcff;
if (base < io_bottom)
if (base < iogap_low)
panic("pci", "I/O base too low", base);
io_top= base;
iogap_high= base;
bar_nr= pcidev[i].pd_bar[j].pb_nr;
reg= PCI_BAR + 4*bar_nr;
v32= pci_attr_r32(i, reg);
@ -1267,8 +1331,11 @@ PRIVATE void complete_bars()
pcidev[i].pd_bar[j].pb_flags &= ~PBF_INCOMPLETE;
}
if (io_top != io_high)
update_bridge4dev_io(i, io_top, io_high-io_top);
if (iogap_high != io_high)
{
update_bridge4dev_io(i, iogap_high,
io_high-iogap_high);
}
}
for (i= 0; i<nr_pcidev; i++)

View file

@ -38,7 +38,6 @@ u16_t *didp;
if (m.m_type != 0)
panic("pci", "pci_next_dev: got bad reply from PCI", m.m_type);
printf("pci_next_dev: got nothing\n");
return 0;
}