aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64')
-rw-r--r--arch/sparc64/kernel/pci.c15
-rw-r--r--arch/sparc64/kernel/pci_common.c123
2 files changed, 126 insertions, 12 deletions
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 55ad1b899bb8..77449a005752 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -422,10 +422,15 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
422 dev->multifunction = 0; /* maybe a lie? */ 422 dev->multifunction = 0; /* maybe a lie? */
423 423
424 if (host_controller) { 424 if (host_controller) {
425 dev->vendor = 0x108e; 425 if (tlb_type != hypervisor) {
426 dev->device = 0x8000; 426 pci_read_config_word(dev, PCI_VENDOR_ID,
427 dev->subsystem_vendor = 0x0000; 427 &dev->vendor);
428 dev->subsystem_device = 0x0000; 428 pci_read_config_word(dev, PCI_DEVICE_ID,
429 &dev->device);
430 } else {
431 dev->vendor = PCI_VENDOR_ID_SUN;
432 dev->device = 0x80f0;
433 }
429 dev->cfg_size = 256; 434 dev->cfg_size = 256;
430 dev->class = PCI_CLASS_BRIDGE_HOST << 8; 435 dev->class = PCI_CLASS_BRIDGE_HOST << 8;
431 sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), 436 sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
@@ -818,7 +823,7 @@ int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev,
818{ 823{
819 static u8 fake_pci_config[] = { 824 static u8 fake_pci_config[] = {
820 0x8e, 0x10, /* Vendor: 0x108e (Sun) */ 825 0x8e, 0x10, /* Vendor: 0x108e (Sun) */
821 0x00, 0x80, /* Device: 0x8000 (PBM) */ 826 0xf0, 0x80, /* Device: 0x80f0 (Fire) */
822 0x46, 0x01, /* Command: 0x0146 (SERR, PARITY, MASTER, MEM) */ 827 0x46, 0x01, /* Command: 0x0146 (SERR, PARITY, MASTER, MEM) */
823 0xa0, 0x22, /* Status: 0x02a0 (DEVSEL_MED, FB2B, 66MHZ) */ 828 0xa0, 0x22, /* Status: 0x02a0 (DEVSEL_MED, FB2B, 66MHZ) */
824 0x00, 0x00, 0x00, 0x06, /* Class: 0x06000000 host bridge */ 829 0x00, 0x00, 0x00, 0x06, /* Class: 0x06000000 host bridge */
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 4249214608af..2f61c4b12596 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -44,6 +44,67 @@ static void *sun4u_config_mkaddr(struct pci_pbm_info *pbm,
44 return (void *) (pbm->config_space | bus | devfn | reg); 44 return (void *) (pbm->config_space | bus | devfn | reg);
45} 45}
46 46
47/* At least on Sabre, it is necessary to access all PCI host controller
48 * registers at their natural size, otherwise zeros are returned.
49 * Strange but true, and I see no language in the UltraSPARC-IIi
50 * programmer's manual that mentions this even indirectly.
51 */
52static int sun4u_read_pci_cfg_host(struct pci_pbm_info *pbm,
53 unsigned char bus, unsigned int devfn,
54 int where, int size, u32 *value)
55{
56 u32 tmp32, *addr;
57 u16 tmp16;
58 u8 tmp8;
59
60 addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
61 if (!addr)
62 return PCIBIOS_SUCCESSFUL;
63
64 switch (size) {
65 case 1:
66 if (where < 8) {
67 unsigned long align = (unsigned long) addr;
68
69 align &= ~1;
70 pci_config_read16((u16 *)align, &tmp16);
71 if (where & 1)
72 *value = tmp16 >> 8;
73 else
74 *value = tmp16 & 0xff;
75 } else {
76 pci_config_read8((u8 *)addr, &tmp8);
77 *value = (u32) tmp8;
78 }
79 break;
80
81 case 2:
82 if (where < 8) {
83 pci_config_read16((u16 *)addr, &tmp16);
84 *value = (u32) tmp16;
85 } else {
86 pci_config_read8((u8 *)addr, &tmp8);
87 *value = (u32) tmp8;
88 pci_config_read8(((u8 *)addr) + 1, &tmp8);
89 *value |= ((u32) tmp8) << 8;
90 }
91 break;
92
93 case 4:
94 tmp32 = 0xffffffff;
95 sun4u_read_pci_cfg_host(pbm, bus, devfn,
96 where, 2, &tmp32);
97 *value = tmp32;
98
99 tmp32 = 0xffffffff;
100 sun4u_read_pci_cfg_host(pbm, bus, devfn,
101 where + 2, 2, &tmp32);
102 *value |= tmp32 << 16;
103 break;
104 }
105 return PCIBIOS_SUCCESSFUL;
106}
107
47static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, 108static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
48 int where, int size, u32 *value) 109 int where, int size, u32 *value)
49{ 110{
@@ -53,10 +114,6 @@ static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
53 u16 tmp16; 114 u16 tmp16;
54 u8 tmp8; 115 u8 tmp8;
55 116
56 if (bus_dev == pbm->pci_bus && devfn == 0x00)
57 return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
58 size, value);
59
60 switch (size) { 117 switch (size) {
61 case 1: 118 case 1:
62 *value = 0xff; 119 *value = 0xff;
@@ -69,6 +126,10 @@ static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
69 break; 126 break;
70 } 127 }
71 128
129 if (!bus_dev->number && !PCI_SLOT(devfn))
130 return sun4u_read_pci_cfg_host(pbm, bus, devfn, where,
131 size, value);
132
72 addr = sun4u_config_mkaddr(pbm, bus, devfn, where); 133 addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
73 if (!addr) 134 if (!addr)
74 return PCIBIOS_SUCCESSFUL; 135 return PCIBIOS_SUCCESSFUL;
@@ -101,6 +162,53 @@ static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
101 return PCIBIOS_SUCCESSFUL; 162 return PCIBIOS_SUCCESSFUL;
102} 163}
103 164
165static int sun4u_write_pci_cfg_host(struct pci_pbm_info *pbm,
166 unsigned char bus, unsigned int devfn,
167 int where, int size, u32 value)
168{
169 u32 *addr;
170
171 addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
172 if (!addr)
173 return PCIBIOS_SUCCESSFUL;
174
175 switch (size) {
176 case 1:
177 if (where < 8) {
178 unsigned long align = (unsigned long) addr;
179 u16 tmp16;
180
181 align &= ~1;
182 pci_config_read16((u16 *)align, &tmp16);
183 if (where & 1) {
184 tmp16 &= 0x00ff;
185 tmp16 |= value << 8;
186 } else {
187 tmp16 &= 0xff00;
188 tmp16 |= value;
189 }
190 pci_config_write16((u16 *)align, tmp16);
191 } else
192 pci_config_write8((u8 *)addr, value);
193 break;
194 case 2:
195 if (where < 8) {
196 pci_config_write16((u16 *)addr, value);
197 } else {
198 pci_config_write8((u8 *)addr, value & 0xff);
199 pci_config_write8(((u8 *)addr) + 1, value >> 8);
200 }
201 break;
202 case 4:
203 sun4u_write_pci_cfg_host(pbm, bus, devfn,
204 where, 2, value & 0xffff);
205 sun4u_write_pci_cfg_host(pbm, bus, devfn,
206 where + 2, 2, value >> 16);
207 break;
208 }
209 return PCIBIOS_SUCCESSFUL;
210}
211
104static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, 212static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
105 int where, int size, u32 value) 213 int where, int size, u32 value)
106{ 214{
@@ -108,9 +216,10 @@ static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
108 unsigned char bus = bus_dev->number; 216 unsigned char bus = bus_dev->number;
109 u32 *addr; 217 u32 *addr;
110 218
111 if (bus_dev == pbm->pci_bus && devfn == 0x00) 219 if (!bus_dev->number && !PCI_SLOT(devfn))
112 return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, 220 return sun4u_write_pci_cfg_host(pbm, bus, devfn, where,
113 size, value); 221 size, value);
222
114 addr = sun4u_config_mkaddr(pbm, bus, devfn, where); 223 addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
115 if (!addr) 224 if (!addr)
116 return PCIBIOS_SUCCESSFUL; 225 return PCIBIOS_SUCCESSFUL;