add support for peeking at pci busses on UltraSparc systems. This prevents
data access errors when trying to read/write to non-existant PCI devices. fix the psycho bridge to use peek for probing devices. This no longer fakes it if the OFW node doesn't exist (and the reg == 0). Reviewed by: jake, tmm
This commit is contained in:
parent
d98ddc4615
commit
dffca5a624
@ -811,6 +811,33 @@ bus_space_copy_region_stream_8(bus_space_tag_t t, bus_space_handle_t h1,
|
||||
bus_space_write_stream_8(t, h1, o1, bus_space_read_8(t, h2, o2));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
bus_space_peek_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
|
||||
u_int8_t *a)
|
||||
{
|
||||
|
||||
__BUS_DEBUG_ACCESS(h, o, "peek", 1);
|
||||
return (fasword8(bus_type_asi[t->bst_type], (caddr_t)(h + o), a));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
bus_space_peek_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
|
||||
u_int16_t *a)
|
||||
{
|
||||
|
||||
__BUS_DEBUG_ACCESS(h, o, "peek", 2);
|
||||
return (fasword16(bus_type_asi[t->bst_type], (caddr_t)(h + o), a));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
bus_space_peek_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o,
|
||||
u_int32_t *a)
|
||||
{
|
||||
|
||||
__BUS_DEBUG_ACCESS(h, o, "peek", 4);
|
||||
return (fasword32(bus_type_asi[t->bst_type], (caddr_t)(h + o), a));
|
||||
}
|
||||
|
||||
/* Back-compat functions for old ISA drivers */
|
||||
extern bus_space_tag_t isa_io_bt;
|
||||
extern bus_space_handle_t isa_io_hdl;
|
||||
|
@ -136,6 +136,15 @@ STNC_GEN(u_long, stxa);
|
||||
#define stwa(va, asi, val) ST_GENERIC(va, asi, val, stwa)
|
||||
#define stxa(va, asi, val) ST_GENERIC(va, asi, val, stxa)
|
||||
|
||||
/*
|
||||
* Attempt to read from addr, val. If a Data Access Error trap happens,
|
||||
* they return -1 and the contents of val is undefined. A return of 0
|
||||
* means no trap happened, and the contents of val is valid.
|
||||
*/
|
||||
int fasword8(u_long asi, void *addr, uint8_t *val);
|
||||
int fasword16(u_long asi, void *addr, uint16_t *val);
|
||||
int fasword32(u_long asi, void *addr, uint32_t *val);
|
||||
|
||||
#define membar(mask) do { \
|
||||
__asm __volatile("membar %0" : : "n" (mask) : "memory"); \
|
||||
} while (0)
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include <machine/nexusvar.h>
|
||||
#include <machine/ofw_upa.h>
|
||||
#include <machine/resource.h>
|
||||
#include <machine/cpu.h>
|
||||
|
||||
#include <sys/rman.h>
|
||||
|
||||
@ -872,33 +873,39 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
|
||||
bus_space_handle_t bh;
|
||||
u_long offset = 0;
|
||||
u_int32_t r, devid;
|
||||
u_int8_t byte;
|
||||
u_int16_t shrt;
|
||||
u_int32_t wrd;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* The psycho bridge does not tolerate accesses to unconfigured PCI
|
||||
* devices' or function's config space, so look up the device in the
|
||||
* firmware device tree first, and if it is not present, return a value
|
||||
* that will make the detection code think that there is no device here.
|
||||
* This is ugly...
|
||||
*/
|
||||
if (reg == 0 && ofw_pci_find_node(bus, slot, func) == 0)
|
||||
return (0xffffffff);
|
||||
sc = (struct psycho_softc *)device_get_softc(dev);
|
||||
offset = PSYCHO_CONF_OFF(bus, slot, func, reg);
|
||||
bh = sc->sc_bh[PCI_CS_CONFIG];
|
||||
switch (width) {
|
||||
case 1:
|
||||
r = bus_space_read_1(sc->sc_cfgt, bh, offset);
|
||||
i = bus_space_peek_1(sc->sc_cfgt, bh, offset, &byte);
|
||||
r = byte;
|
||||
break;
|
||||
case 2:
|
||||
r = bus_space_read_2(sc->sc_cfgt, bh, offset);
|
||||
i = bus_space_peek_2(sc->sc_cfgt, bh, offset, &shrt);
|
||||
r = shrt;
|
||||
break;
|
||||
case 4:
|
||||
r = bus_space_read_4(sc->sc_cfgt, bh, offset);
|
||||
i = bus_space_peek_4(sc->sc_cfgt, bh, offset, &wrd);
|
||||
r = wrd;
|
||||
break;
|
||||
default:
|
||||
panic("psycho_read_config: bad width");
|
||||
}
|
||||
|
||||
if (i) {
|
||||
#ifdef PSYCHO_DEBUG
|
||||
printf("psycho read data error reading: %d.%d.%d: 0x%x\n",
|
||||
bus, slot, func, reg);
|
||||
#endif
|
||||
r = -1;
|
||||
}
|
||||
|
||||
if (reg == PCIR_INTPIN && r == 0) {
|
||||
/* Check for DQT_BAD_INTPIN quirk. */
|
||||
devid = psycho_read_config(dev, bus, slot, func,
|
||||
|
@ -527,6 +527,58 @@ ENTRY(fs_fault)
|
||||
mov -1, %o0
|
||||
END(fsfault)
|
||||
|
||||
.globl fas_nofault_begin
|
||||
fas_nofault_begin:
|
||||
|
||||
/*
|
||||
* int fasword8(u_long asi, uint64_t addr, uint8_t *val)
|
||||
*/
|
||||
ENTRY(fasword8)
|
||||
wr %o0, 0, %asi
|
||||
membar #Sync
|
||||
lduba [%o1] %asi, %o3
|
||||
membar #Sync
|
||||
stb %o3, [%o2]
|
||||
retl
|
||||
clr %o0
|
||||
END(fasword8)
|
||||
|
||||
/*
|
||||
* int fasword16(u_long asi, uint64_t addr, uint16_t *val)
|
||||
*/
|
||||
ENTRY(fasword16)
|
||||
wr %o0, 0, %asi
|
||||
membar #Sync
|
||||
lduha [%o1] %asi, %o3
|
||||
membar #Sync
|
||||
sth %o3, [%o2]
|
||||
retl
|
||||
clr %o0
|
||||
END(fasword16)
|
||||
|
||||
/*
|
||||
* int fasword32(u_long asi, uint64_t addr, uint32_t *val)
|
||||
*/
|
||||
ENTRY(fasword32)
|
||||
wr %o0, 0, %asi
|
||||
membar #Sync
|
||||
lduwa [%o1] %asi, %o3
|
||||
membar #Sync
|
||||
stw %o3, [%o2]
|
||||
retl
|
||||
clr %o0
|
||||
END(fasword32)
|
||||
|
||||
.globl fas_nofault_end
|
||||
fas_nofault_end:
|
||||
nop
|
||||
|
||||
.globl fas_fault
|
||||
ENTRY(fas_fault)
|
||||
retl
|
||||
mov -1, %o0
|
||||
END(fas_fault)
|
||||
|
||||
.globl fpu_fault_begin
|
||||
fpu_fault_begin:
|
||||
nop
|
||||
|
@ -101,6 +101,10 @@ extern char fs_nofault_end[];
|
||||
extern char fs_nofault_intr_begin[];
|
||||
extern char fs_nofault_intr_end[];
|
||||
|
||||
extern char fas_fault[];
|
||||
extern char fas_nofault_begin[];
|
||||
extern char fas_nofault_end[];
|
||||
|
||||
extern char *syscallnames[];
|
||||
|
||||
const char *trap_msg[] = {
|
||||
@ -329,6 +333,27 @@ trap(struct trapframe *tf)
|
||||
}
|
||||
error = 1;
|
||||
break;
|
||||
case T_DATA_ERROR:
|
||||
/*
|
||||
* handle PCI poke/peek as per UltraSPARC IIi
|
||||
* User's Manual 16.2.1.
|
||||
*
|
||||
* XXX - We really should make sure that tpc is
|
||||
* pointing to the membar #Sync we are expecting.
|
||||
*/
|
||||
#define MEMBARSYNC_INST ((u_int32_t)0x8143e040)
|
||||
if (tf->tf_tpc > (u_long)fas_nofault_begin &&
|
||||
tf->tf_tpc < (u_long)fas_nofault_end &&
|
||||
*(u_int32_t *)tf->tf_tpc == MEMBARSYNC_INST &&
|
||||
((u_int32_t *)tf->tf_tpc)[-2] == MEMBARSYNC_INST) {
|
||||
tf->tf_tpc = (u_long)fas_fault;
|
||||
tf->tf_tnpc = tf->tf_tpc + 4;
|
||||
error = 0;
|
||||
break;
|
||||
}
|
||||
#undef MEMBARSYNC_INST
|
||||
error = 1;
|
||||
break;
|
||||
default:
|
||||
error = 1;
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user