|
Lines 44-49
static void *sun4u_config_mkaddr(struct pci_pbm_info *pbm,
|
Link Here
|
|---|
|
return (void *) (pbm->config_space | bus | devfn | reg); | return (void *) (pbm->config_space | bus | devfn | reg); |
} | } |
| |
|
/* At least on Sabre, it is necessary to access all PCI host controller |
|
* registers at their natural size, otherwise zeros are returned. |
|
* Strange but true, and I see no language in the UltraSPARC-IIi |
|
* programmer's manual that mentions this even indirectly. |
|
*/ |
|
static int sun4u_read_pci_cfg_host(struct pci_pbm_info *pbm, |
|
unsigned char bus, unsigned int devfn, |
|
int where, int size, u32 *value) |
|
{ |
|
u32 tmp32, *addr; |
|
u16 tmp16; |
|
u8 tmp8; |
|
|
|
addr = sun4u_config_mkaddr(pbm, bus, devfn, where); |
|
if (!addr) |
|
return PCIBIOS_SUCCESSFUL; |
|
|
|
switch (size) { |
|
case 1: |
|
if (where < 8) { |
|
unsigned long align = (unsigned long) addr; |
|
|
|
align &= ~1; |
|
pci_config_read16((u16 *)align, &tmp16); |
|
if (where & 1) |
|
*value = tmp16 >> 8; |
|
else |
|
*value = tmp16 & 0xff; |
|
} else { |
|
pci_config_read8((u8 *)addr, &tmp8); |
|
*value = (u32) tmp8; |
|
} |
|
break; |
|
|
|
case 2: |
|
if (where < 8) { |
|
pci_config_read16((u16 *)addr, &tmp16); |
|
*value = (u32) tmp16; |
|
} else { |
|
pci_config_read8((u8 *)addr, &tmp8); |
|
*value = (u32) tmp8; |
|
pci_config_read8(((u8 *)addr) + 1, &tmp8); |
|
*value |= ((u32) tmp8) << 8; |
|
} |
|
break; |
|
|
|
case 4: |
|
tmp32 = 0xffffffff; |
|
sun4u_read_pci_cfg_host(pbm, bus, devfn, |
|
where, 2, &tmp32); |
|
*value = tmp32; |
|
|
|
tmp32 = 0xffffffff; |
|
sun4u_read_pci_cfg_host(pbm, bus, devfn, |
|
where + 2, 2, &tmp32); |
|
*value |= tmp32 << 16; |
|
break; |
|
} |
|
return PCIBIOS_SUCCESSFUL; |
|
} |
|
|
static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, | static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, |
int where, int size, u32 *value) | int where, int size, u32 *value) |
{ | { |
|
Lines 53-62
static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
|
Link Here
|
|---|
|
u16 tmp16; | u16 tmp16; |
u8 tmp8; | u8 tmp8; |
| |
if (bus_dev == pbm->pci_bus && devfn == 0x00) |
|
return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, |
|
size, value); |
|
|
|
switch (size) { | switch (size) { |
case 1: | case 1: |
*value = 0xff; | *value = 0xff; |
|
Lines 69-74
static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
|
Link Here
|
|---|
|
break; | break; |
} | } |
| |
|
if (!bus_dev->number && !PCI_SLOT(devfn)) |
|
return sun4u_read_pci_cfg_host(pbm, bus, devfn, where, |
|
size, value); |
|
|
addr = sun4u_config_mkaddr(pbm, bus, devfn, where); | addr = sun4u_config_mkaddr(pbm, bus, devfn, where); |
if (!addr) | if (!addr) |
return PCIBIOS_SUCCESSFUL; | return PCIBIOS_SUCCESSFUL; |
|
Lines 101-106
static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
|
Link Here
|
|---|
|
return PCIBIOS_SUCCESSFUL; | return PCIBIOS_SUCCESSFUL; |
} | } |
| |
|
static int sun4u_write_pci_cfg_host(struct pci_pbm_info *pbm, |
|
unsigned char bus, unsigned int devfn, |
|
int where, int size, u32 value) |
|
{ |
|
u32 *addr; |
|
|
|
addr = sun4u_config_mkaddr(pbm, bus, devfn, where); |
|
if (!addr) |
|
return PCIBIOS_SUCCESSFUL; |
|
|
|
switch (size) { |
|
case 1: |
|
if (where < 8) { |
|
unsigned long align = (unsigned long) addr; |
|
u16 tmp16; |
|
|
|
align &= ~1; |
|
pci_config_read16((u16 *)align, &tmp16); |
|
if (where & 1) { |
|
tmp16 &= 0x00ff; |
|
tmp16 |= value << 8; |
|
} else { |
|
tmp16 &= 0xff00; |
|
tmp16 |= value; |
|
} |
|
pci_config_write16((u16 *)align, tmp16); |
|
} else |
|
pci_config_write8((u8 *)addr, value); |
|
break; |
|
case 2: |
|
if (where < 8) { |
|
pci_config_write16((u16 *)addr, value); |
|
} else { |
|
pci_config_write8((u8 *)addr, value & 0xff); |
|
pci_config_write8(((u8 *)addr) + 1, value >> 8); |
|
} |
|
break; |
|
case 4: |
|
sun4u_write_pci_cfg_host(pbm, bus, devfn, |
|
where, 2, value & 0xffff); |
|
sun4u_write_pci_cfg_host(pbm, bus, devfn, |
|
where + 2, 2, value >> 16); |
|
break; |
|
} |
|
return PCIBIOS_SUCCESSFUL; |
|
} |
|
|
static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, | static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, |
int where, int size, u32 value) | int where, int size, u32 value) |
{ | { |
|
Lines 108-116
static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
|
Link Here
|
|---|
|
unsigned char bus = bus_dev->number; | unsigned char bus = bus_dev->number; |
u32 *addr; | u32 *addr; |
| |
if (bus_dev == pbm->pci_bus && devfn == 0x00) |
if (!bus_dev->number && !PCI_SLOT(devfn)) |
return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, |
return sun4u_write_pci_cfg_host(pbm, bus, devfn, where, |
size, value); |
size, value); |
|
|
addr = sun4u_config_mkaddr(pbm, bus, devfn, where); | addr = sun4u_config_mkaddr(pbm, bus, devfn, where); |
if (!addr) | if (!addr) |
return PCIBIOS_SUCCESSFUL; | return PCIBIOS_SUCCESSFUL; |