#include <sys/types.h>
#include <sys/pci.h>
#include <sys/mutex.h>
#include <sys/pci_cfgspace_impl.h>
#define PCI_82454_RW_CONTROL 0x54
static int ncDevNo;
boolean_t
pci_is_broken_orion()
{
int Num82454 = 0;
boolean_t A2B0Found = B_FALSE;
boolean_t c82454PostingEnabled = B_FALSE;
uint8_t PciReg;
uint16_t VendorID;
uint16_t DeviceID;
boolean_t A2B0WorkAroundReqd;
int BusNo = 0;
int FunctionNo = 0;
int DeviceNo;
uint8_t RevisionID;
for (DeviceNo = 0; DeviceNo < PCI_MAX_DEVS; DeviceNo++) {
VendorID = pci_mech1_getw(BusNo, DeviceNo, FunctionNo,
PCI_CONF_VENID);
DeviceID = pci_mech1_getw(BusNo, DeviceNo, FunctionNo,
PCI_CONF_DEVID);
RevisionID = pci_mech1_getb(BusNo, DeviceNo, FunctionNo,
PCI_CONF_REVID);
if (VendorID == 0x8086 && DeviceID == 0x84c4) {
Num82454++;
if (RevisionID <= 4) {
A2B0Found = B_TRUE;
}
if (DeviceNo == (0xc8 >> 3)) {
PciReg = pci_mech1_getb(BusNo, DeviceNo,
FunctionNo, PCI_82454_RW_CONTROL);
if (PciReg & 0x01) {
c82454PostingEnabled = B_TRUE;
}
} else {
ncDevNo = DeviceNo;
}
}
}
if (Num82454 >= 2 && A2B0Found &&
c82454PostingEnabled) {
A2B0WorkAroundReqd = B_TRUE;
PciReg = pci_mech1_getb(0, ncDevNo, 0,
PCI_82454_RW_CONTROL);
PciReg |= 0x01;
pci_mech1_putb(0, ncDevNo, 0,
PCI_82454_RW_CONTROL, PciReg);
} else {
A2B0WorkAroundReqd = B_FALSE;
}
return (A2B0WorkAroundReqd);
}
static void
FuncDisableInboundPostingnc82454()
{
uint32_t test;
uint8_t PciReg;
mutex_enter(&pcicfg_chipset_mutex);
do {
test = pci_mech1_getl(0, ncDevNo, 0, PCI_CONF_VENID);
} while (test != 0x84c48086UL);
do {
test = pci_mech1_getl(0, ncDevNo, 0, PCI_82454_RW_CONTROL);
} while (test == 0x84c48086UL);
PciReg = pci_mech1_getb(0, ncDevNo, 0, PCI_82454_RW_CONTROL);
PciReg &= ~0x01;
pci_mech1_putb(0, ncDevNo, 0, PCI_82454_RW_CONTROL, PciReg);
}
static void
FuncEnableInboundPostingnc82454()
{
uint8_t PciReg;
PciReg = pci_mech1_getb(0, ncDevNo, 0, PCI_82454_RW_CONTROL);
PciReg |= 0x01;
pci_mech1_putb(0, ncDevNo, 0, PCI_82454_RW_CONTROL, PciReg);
mutex_exit(&pcicfg_chipset_mutex);
}
uint8_t
pci_orion_getb(int bus, int device, int function, int reg)
{
uint8_t val;
FuncDisableInboundPostingnc82454();
val = pci_mech1_getb(bus, device, function, reg);
FuncEnableInboundPostingnc82454();
return (val);
}
uint16_t
pci_orion_getw(int bus, int device, int function, int reg)
{
uint16_t val;
FuncDisableInboundPostingnc82454();
val = pci_mech1_getw(bus, device, function, reg);
FuncEnableInboundPostingnc82454();
return (val);
}
uint32_t
pci_orion_getl(int bus, int device, int function, int reg)
{
uint32_t val;
FuncDisableInboundPostingnc82454();
val = pci_mech1_getl(bus, device, function, reg);
FuncEnableInboundPostingnc82454();
return (val);
}
void
pci_orion_putb(int bus, int device, int function, int reg, uint8_t val)
{
FuncDisableInboundPostingnc82454();
pci_mech1_putb(bus, device, function, reg, val);
FuncEnableInboundPostingnc82454();
}
void
pci_orion_putw(int bus, int device, int function, int reg, uint16_t val)
{
FuncDisableInboundPostingnc82454();
pci_mech1_putw(bus, device, function, reg, val);
FuncEnableInboundPostingnc82454();
}
void
pci_orion_putl(int bus, int device, int function, int reg, uint32_t val)
{
FuncDisableInboundPostingnc82454();
pci_mech1_putl(bus, device, function, reg, val);
FuncEnableInboundPostingnc82454();
}