aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-07-26 02:30:16 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-07-30 03:27:29 -0400
commita2d6ea0180531b5ace2dc1e64b6e22465ed51267 (patch)
tree773600077d9575059878e880311e41a3184e52a2 /arch
parentb84d879639f83d35d3fcd909222522c928bf974b (diff)
[SPARC64]: Fix sun4u PCI config space accesses on sun4u.
Don't provide fake PCI config space for sun4u. Also, put back the funny host controller space handling that at least Sabre needs. You have to read PCI host controller registers at their nature size otherwise you get zeros instead of correct values. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch')
-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;