Minor SMP fixes. Fix to linuxpci to catch buggy chipsets

This commit is contained in:
Ronald G. Minnich 2001-10-15 18:19:40 +00:00
commit ce6c4c7195
7 changed files with 70 additions and 19 deletions

View file

@ -238,7 +238,8 @@ void smp_write_processor(struct mp_config_table *mc,
unsigned char apicid, unsigned char apicver,
unsigned char cpuflag, unsigned int cpufeature,
unsigned int featureflag);
void smp_write_processors(struct mp_config_table *mc);
void smp_write_processors(struct mp_config_table *mc,
unsigned long *processor_map);
void smp_write_bus(struct mp_config_table *mc,
unsigned char id, unsigned char *bustype);
void smp_write_ioapic(struct mp_config_table *mc,
@ -264,7 +265,7 @@ void smp_write_compatibility_address_space(struct mp_config_table *mc,
unsigned int range_list);
unsigned char smp_compute_checksum(void *v, int len);
void smp_write_floating_table(void *v);
void write_smp_table(void *v);
void write_smp_table(void *v, unsigned long *processor_map);
#else /* HAVE_MP_TABLE */

View file

@ -109,10 +109,12 @@ void secondary_cpu_init(void)
unsigned long totalram;
int processor_id;
printk_spew(__FUNCTION__ "\n");
atomic_inc(&active_cpus);
totalram = get_ramsize();
processor_id = cpu_initialize(totalram);
atomic_dec(&active_cpus);
printk_spew(__FUNCTION__ " id is %d\n", processor_id);
stop_cpu(processor_id);
}
@ -135,6 +137,18 @@ static void wait_for_other_cpus(void)
void hardwaremain(int boot_complete)
{
// The processor map.
// Now that SMP is in linuxbios, and Linux counts on us
// giving accurate information about processors, we need a map
// of what processors are out there. This could be a bit mask,
// but we will be optimistic and hope we someday run on
// REALLY BIG SMPs. Also we may need more than one bit of
// info per processor at some point. I hope we don't need
// anything more complex than an int.
unsigned long processor_map[MAX_CPUS];
// Processor ID of the BOOT cpu (i.e. the one running this code
int boot_cpu;
// Comment: the NEW_SUPERIO architecture is actually pretty good.
// I think we need to move to the same sort of architecture for
// everything: A config file generated sequence of calls
@ -189,12 +203,14 @@ void hardwaremain(int boot_complete)
printk_info("totalram: %ldM\n", totalram/1024);
/* Fully initialize the cpu before configuring the bus */
cpu_initialize(totalram);
boot_cpu = cpu_initialize(totalram);
printk_spew("BOOT CPU is %d\n", boot_cpu);
processor_map[boot_cpu] = CPU_BOOTPROCESSOR|CPU_ENABLED;
/* Now start the other cpus initializing
* The sooner they start the sooner they stop.
*/
startup_other_cpus();
startup_other_cpus(processor_map);
// Now do the real bus
// we round the total ram up a lot for thing like the SISFB, which
@ -233,7 +249,7 @@ void hardwaremain(int boot_complete)
pci_zero_irq_settings();
/* copy the smp block to address 0 */
write_smp_table((void *)16);
write_smp_table((void *)16, processor_map);
post_code(0x96);
check_pirq_routing_table();

View file

@ -90,7 +90,8 @@ void smp_write_processor(struct mp_config_table *mc,
* Having the proper apicid's in the table so the non-bootstrap
* processors can be woken up should be enough.
*/
void smp_write_processors(struct mp_config_table *mc)
void smp_write_processors(struct mp_config_table *mc,
unsigned long *processor_map)
{
int i;
int processor_id;
@ -105,7 +106,7 @@ void smp_write_processors(struct mp_config_table *mc)
cpu_feature_flags = edx;
for(i = 0; i < MAX_CPUS; i++) {
smp_write_processor(mc, i, apic_version,
((processor_id == i)? CPU_BOOTPROCESSOR:0) | CPU_ENABLED,
processor_map[i],
cpu_features, cpu_feature_flags
);

View file

@ -1,4 +1,5 @@
#include <smp/start_stop.h>
#include <arch/smp/mpspec.h>
#include <cpu/p6/apic.h>
#include <delay.h>
@ -57,7 +58,10 @@ void stop_cpu(int apicid)
}
void start_cpu(int apicid)
// This is a lot more paranoid now, since Linux can NOT handle
// being told there is a CPU when none exists. So any errors
// will return 0, meaning no CPU.
int start_cpu(int apicid)
{
int timeout;
unsigned long send_status, accept_status, start_eip;
@ -87,7 +91,10 @@ void start_cpu(int apicid)
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
} while (send_status && (timeout++ < 1000));
if (timeout >= 1000) {
printk_spew("timed out\n");
printk_err("CPU %d: First apic write timed out. Disabling\n",
apicid);
// too bad.
return 0;
}
mdelay(10);
@ -108,7 +115,10 @@ void start_cpu(int apicid)
send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
} while (send_status && (timeout++ < 1000));
if (timeout >= 1000) {
printk_spew("timed out\n");
printk_err("CPU %d: Second apic write timed out. Disabling\n",
apicid);
// too bad.
return 0;
}
/* FIXME start_eip should be more flexible! */
@ -178,9 +188,12 @@ void start_cpu(int apicid)
printk_warning("APIC never delivered???\n");
if (accept_status)
printk_warning("APIC delivery error (%lx).\n", accept_status);
if (send_status || accept_status)
return 0;
return 1;
}
void startup_other_cpus(void)
void startup_other_cpus(unsigned long *processor_map)
{
int apicid = this_processors_id();
int i;
@ -189,6 +202,8 @@ void startup_other_cpus(void)
if (i == apicid ) {
continue;
}
start_cpu(i);
if (start_cpu(i))
processor_map[i] = CPU_ENABLED;
}
}

View file

@ -5,8 +5,8 @@
#include <smp/atomic.h>
int this_processors_id(void);
void stop_cpu(int processor_id);
void start_cpu(int processor_id);
void startup_other_cpus(void);
int start_cpu(int processor_id);
void startup_other_cpus(unsigned long *processor_map);
#else
#define this_processors_id() 0
#define startup_other_cpus() do {} while(0)

View file

@ -129,8 +129,26 @@ void pci_get_size(struct pci_dev *dev, unsigned long reg, unsigned long addr)
// restore addr
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (reg << 2), addr);
// some broken hardware has read-only registers that do not
// really size correctly. You can tell this if addr == size
// Example: the acer m7229 has BARs 1-4 normally read-only.
// so BAR1 at offset 0x10 reads 0x1f1. If you size that register
// by writing 0xffffffff to it, it will read back as 0x1f1 -- a
// violation of the spec.
// We catch this case and ignore it by settting size and type to 0.
// This incidentally catches the common case where registers
// read back as 0 for both address and size.
if (addr == size) {
printk_err(__FUNCTION__
"dev_fn 0x%x, register %d, read-only"
" SO, ignoring it\n",
dev->devfn, reg);
printk_err("addr was 0x%x, size was 0x%x\n",addr,size);
type = 0;
size = 0;
}
// Now compute the actual size, See PCI Spec 6.2.5.1 ...
if (size & PCI_BASE_ADDRESS_SPACE_IO) {
else if (size & PCI_BASE_ADDRESS_SPACE_IO) {
type = size & (~PCI_BASE_ADDRESS_IO_MASK);
size &= (PCI_BASE_ADDRESS_IO_MASK);
// BUG! Top 16 bits can be zero (or not)

View file

@ -2,7 +2,7 @@
#include <string.h>
#include <printk.h>
void smp_write_config_table(void *v)
void smp_write_config_table(void *v, unsigned long * processor_map)
{
int ioapicid = 0;
static const char sig[4] = "PCMP";
@ -28,7 +28,7 @@ void smp_write_config_table(void *v)
mc->reserved = 0;
smp_write_processors(mc);
smp_write_processors(mc, processor_map);
ioapicid = 2;
smp_write_bus(mc, 0, "PCI ");
@ -122,10 +122,10 @@ void smp_write_config_table(void *v)
mc, smp_next_mpe_entry(mc));
}
void write_smp_table(void *v)
void write_smp_table(void *v, unsigned long *processor_map)
{
smp_write_floating_table(v);
smp_write_config_table(v);
smp_write_config_table(v, processor_map);
}