diff options
Diffstat (limited to 'arch/sparc64')
-rw-r--r-- | arch/sparc64/kernel/pci.c | 15 | ||||
-rw-r--r-- | arch/sparc64/kernel/pci_common.c | 123 |
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 | */ | ||
52 | static 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 | |||
47 | static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, | 108 | static 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 | ||
165 | static 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 | |||
104 | static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, | 212 | static 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; |