diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-02-29 05:36:12 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-03-06 17:09:43 -0500 |
commit | aab547ce0d1493d400b6468c521a0137cd8c1edf (patch) | |
tree | 84625da40d905669a28a5770de111225667d5f27 /drivers | |
parent | 69d3b6f491545d326135a1def4e290cd577c9a36 (diff) |
ssb: Add Gigabit Ethernet driver
This adds the Gigabit Ethernet driver for the SSB
Gigabit Ethernet core. This driver actually is a frontend to
the Tigon3 driver. So the real work is done by tg3.
This device is used in the Linksys WRT350N.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ssb/Kconfig | 9 | ||||
-rw-r--r-- | drivers/ssb/Makefile | 1 | ||||
-rw-r--r-- | drivers/ssb/driver_gige.c | 294 | ||||
-rw-r--r-- | drivers/ssb/driver_mipscore.c | 1 | ||||
-rw-r--r-- | drivers/ssb/driver_pcicore.c | 160 | ||||
-rw-r--r-- | drivers/ssb/embedded.c | 90 | ||||
-rw-r--r-- | drivers/ssb/main.c | 30 | ||||
-rw-r--r-- | drivers/ssb/ssb_private.h | 2 |
8 files changed, 515 insertions, 72 deletions
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index adea792fb675..f69ef0ba2613 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig | |||
@@ -125,4 +125,13 @@ config SSB_DRIVER_EXTIF | |||
125 | 125 | ||
126 | If unsure, say N | 126 | If unsure, say N |
127 | 127 | ||
128 | config SSB_DRIVER_GIGE | ||
129 | bool "SSB Broadcom Gigabit Ethernet driver" | ||
130 | depends on SSB_PCIHOST_POSSIBLE && SSB_EMBEDDED && MIPS | ||
131 | help | ||
132 | Driver for the Sonics Silicon Backplane attached | ||
133 | Broadcom Gigabit Ethernet. | ||
134 | |||
135 | If unsure, say N | ||
136 | |||
128 | endmenu | 137 | endmenu |
diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile index de94c2eb7a37..910f35e32fc9 100644 --- a/drivers/ssb/Makefile +++ b/drivers/ssb/Makefile | |||
@@ -11,6 +11,7 @@ ssb-y += driver_chipcommon.o | |||
11 | ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o | 11 | ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o |
12 | ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o | 12 | ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o |
13 | ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o | 13 | ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o |
14 | ssb-$(CONFIG_SSB_DRIVER_GIGE) += driver_gige.o | ||
14 | 15 | ||
15 | # b43 pci-ssb-bridge driver | 16 | # b43 pci-ssb-bridge driver |
16 | # Not strictly a part of SSB, but kept here for convenience | 17 | # Not strictly a part of SSB, but kept here for convenience |
diff --git a/drivers/ssb/driver_gige.c b/drivers/ssb/driver_gige.c new file mode 100644 index 000000000000..172f90407b93 --- /dev/null +++ b/drivers/ssb/driver_gige.c | |||
@@ -0,0 +1,294 @@ | |||
1 | /* | ||
2 | * Sonics Silicon Backplane | ||
3 | * Broadcom Gigabit Ethernet core driver | ||
4 | * | ||
5 | * Copyright 2008, Broadcom Corporation | ||
6 | * Copyright 2008, Michael Buesch <mb@bu3sch.de> | ||
7 | * | ||
8 | * Licensed under the GNU/GPL. See COPYING for details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/ssb/ssb.h> | ||
12 | #include <linux/ssb/ssb_driver_gige.h> | ||
13 | #include <linux/pci.h> | ||
14 | #include <linux/pci_regs.h> | ||
15 | |||
16 | |||
17 | /* | ||
18 | MODULE_DESCRIPTION("SSB Broadcom Gigabit Ethernet driver"); | ||
19 | MODULE_AUTHOR("Michael Buesch"); | ||
20 | MODULE_LICENSE("GPL"); | ||
21 | */ | ||
22 | |||
23 | static const struct ssb_device_id ssb_gige_tbl[] = { | ||
24 | SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET_GBIT, SSB_ANY_REV), | ||
25 | SSB_DEVTABLE_END | ||
26 | }; | ||
27 | /* MODULE_DEVICE_TABLE(ssb, ssb_gige_tbl); */ | ||
28 | |||
29 | |||
30 | static inline u8 gige_read8(struct ssb_gige *dev, u16 offset) | ||
31 | { | ||
32 | return ssb_read8(dev->dev, offset); | ||
33 | } | ||
34 | |||
35 | static inline u16 gige_read16(struct ssb_gige *dev, u16 offset) | ||
36 | { | ||
37 | return ssb_read16(dev->dev, offset); | ||
38 | } | ||
39 | |||
40 | static inline u32 gige_read32(struct ssb_gige *dev, u16 offset) | ||
41 | { | ||
42 | return ssb_read32(dev->dev, offset); | ||
43 | } | ||
44 | |||
45 | static inline void gige_write8(struct ssb_gige *dev, | ||
46 | u16 offset, u8 value) | ||
47 | { | ||
48 | ssb_write8(dev->dev, offset, value); | ||
49 | } | ||
50 | |||
51 | static inline void gige_write16(struct ssb_gige *dev, | ||
52 | u16 offset, u16 value) | ||
53 | { | ||
54 | ssb_write16(dev->dev, offset, value); | ||
55 | } | ||
56 | |||
57 | static inline void gige_write32(struct ssb_gige *dev, | ||
58 | u16 offset, u32 value) | ||
59 | { | ||
60 | ssb_write32(dev->dev, offset, value); | ||
61 | } | ||
62 | |||
63 | static inline | ||
64 | u8 gige_pcicfg_read8(struct ssb_gige *dev, unsigned int offset) | ||
65 | { | ||
66 | BUG_ON(offset >= 256); | ||
67 | return gige_read8(dev, SSB_GIGE_PCICFG + offset); | ||
68 | } | ||
69 | |||
70 | static inline | ||
71 | u16 gige_pcicfg_read16(struct ssb_gige *dev, unsigned int offset) | ||
72 | { | ||
73 | BUG_ON(offset >= 256); | ||
74 | return gige_read16(dev, SSB_GIGE_PCICFG + offset); | ||
75 | } | ||
76 | |||
77 | static inline | ||
78 | u32 gige_pcicfg_read32(struct ssb_gige *dev, unsigned int offset) | ||
79 | { | ||
80 | BUG_ON(offset >= 256); | ||
81 | return gige_read32(dev, SSB_GIGE_PCICFG + offset); | ||
82 | } | ||
83 | |||
84 | static inline | ||
85 | void gige_pcicfg_write8(struct ssb_gige *dev, | ||
86 | unsigned int offset, u8 value) | ||
87 | { | ||
88 | BUG_ON(offset >= 256); | ||
89 | gige_write8(dev, SSB_GIGE_PCICFG + offset, value); | ||
90 | } | ||
91 | |||
92 | static inline | ||
93 | void gige_pcicfg_write16(struct ssb_gige *dev, | ||
94 | unsigned int offset, u16 value) | ||
95 | { | ||
96 | BUG_ON(offset >= 256); | ||
97 | gige_write16(dev, SSB_GIGE_PCICFG + offset, value); | ||
98 | } | ||
99 | |||
100 | static inline | ||
101 | void gige_pcicfg_write32(struct ssb_gige *dev, | ||
102 | unsigned int offset, u32 value) | ||
103 | { | ||
104 | BUG_ON(offset >= 256); | ||
105 | gige_write32(dev, SSB_GIGE_PCICFG + offset, value); | ||
106 | } | ||
107 | |||
108 | static int ssb_gige_pci_read_config(struct pci_bus *bus, unsigned int devfn, | ||
109 | int reg, int size, u32 *val) | ||
110 | { | ||
111 | struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops); | ||
112 | unsigned long flags; | ||
113 | |||
114 | if ((PCI_SLOT(devfn) > 0) || (PCI_FUNC(devfn) > 0)) | ||
115 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
116 | if (reg >= 256) | ||
117 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
118 | |||
119 | spin_lock_irqsave(&dev->lock, flags); | ||
120 | switch (size) { | ||
121 | case 1: | ||
122 | *val = gige_pcicfg_read8(dev, reg); | ||
123 | break; | ||
124 | case 2: | ||
125 | *val = gige_pcicfg_read16(dev, reg); | ||
126 | break; | ||
127 | case 4: | ||
128 | *val = gige_pcicfg_read32(dev, reg); | ||
129 | break; | ||
130 | default: | ||
131 | WARN_ON(1); | ||
132 | } | ||
133 | spin_unlock_irqrestore(&dev->lock, flags); | ||
134 | |||
135 | return PCIBIOS_SUCCESSFUL; | ||
136 | } | ||
137 | |||
138 | static int ssb_gige_pci_write_config(struct pci_bus *bus, unsigned int devfn, | ||
139 | int reg, int size, u32 val) | ||
140 | { | ||
141 | struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops); | ||
142 | unsigned long flags; | ||
143 | |||
144 | if ((PCI_SLOT(devfn) > 0) || (PCI_FUNC(devfn) > 0)) | ||
145 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
146 | if (reg >= 256) | ||
147 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
148 | |||
149 | spin_lock_irqsave(&dev->lock, flags); | ||
150 | switch (size) { | ||
151 | case 1: | ||
152 | gige_pcicfg_write8(dev, reg, val); | ||
153 | break; | ||
154 | case 2: | ||
155 | gige_pcicfg_write16(dev, reg, val); | ||
156 | break; | ||
157 | case 4: | ||
158 | gige_pcicfg_write32(dev, reg, val); | ||
159 | break; | ||
160 | default: | ||
161 | WARN_ON(1); | ||
162 | } | ||
163 | spin_unlock_irqrestore(&dev->lock, flags); | ||
164 | |||
165 | return PCIBIOS_SUCCESSFUL; | ||
166 | } | ||
167 | |||
168 | static int ssb_gige_probe(struct ssb_device *sdev, const struct ssb_device_id *id) | ||
169 | { | ||
170 | struct ssb_gige *dev; | ||
171 | u32 base, tmslow, tmshigh; | ||
172 | |||
173 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
174 | if (!dev) | ||
175 | return -ENOMEM; | ||
176 | dev->dev = sdev; | ||
177 | |||
178 | spin_lock_init(&dev->lock); | ||
179 | dev->pci_controller.pci_ops = &dev->pci_ops; | ||
180 | dev->pci_controller.io_resource = &dev->io_resource; | ||
181 | dev->pci_controller.mem_resource = &dev->mem_resource; | ||
182 | dev->pci_controller.io_map_base = 0x800; | ||
183 | dev->pci_ops.read = ssb_gige_pci_read_config; | ||
184 | dev->pci_ops.write = ssb_gige_pci_write_config; | ||
185 | |||
186 | dev->io_resource.name = SSB_GIGE_IO_RES_NAME; | ||
187 | dev->io_resource.start = 0x800; | ||
188 | dev->io_resource.end = 0x8FF; | ||
189 | dev->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED; | ||
190 | |||
191 | if (!ssb_device_is_enabled(sdev)) | ||
192 | ssb_device_enable(sdev, 0); | ||
193 | |||
194 | /* Setup BAR0. This is a 64k MMIO region. */ | ||
195 | base = ssb_admatch_base(ssb_read32(sdev, SSB_ADMATCH1)); | ||
196 | gige_pcicfg_write32(dev, PCI_BASE_ADDRESS_0, base); | ||
197 | gige_pcicfg_write32(dev, PCI_BASE_ADDRESS_1, 0); | ||
198 | |||
199 | dev->mem_resource.name = SSB_GIGE_MEM_RES_NAME; | ||
200 | dev->mem_resource.start = base; | ||
201 | dev->mem_resource.end = base + 0x10000 - 1; | ||
202 | dev->mem_resource.flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED; | ||
203 | |||
204 | /* Enable the memory region. */ | ||
205 | gige_pcicfg_write16(dev, PCI_COMMAND, | ||
206 | gige_pcicfg_read16(dev, PCI_COMMAND) | ||
207 | | PCI_COMMAND_MEMORY); | ||
208 | |||
209 | /* Write flushing is controlled by the Flush Status Control register. | ||
210 | * We want to flush every register write with a timeout and we want | ||
211 | * to disable the IRQ mask while flushing to avoid concurrency. | ||
212 | * Note that automatic write flushing does _not_ work from | ||
213 | * an IRQ handler. The driver must flush manually by reading a register. | ||
214 | */ | ||
215 | gige_write32(dev, SSB_GIGE_SHIM_FLUSHSTAT, 0x00000068); | ||
216 | |||
217 | /* Check if we have an RGMII or GMII PHY-bus. | ||
218 | * On RGMII do not bypass the DLLs */ | ||
219 | tmslow = ssb_read32(sdev, SSB_TMSLOW); | ||
220 | tmshigh = ssb_read32(sdev, SSB_TMSHIGH); | ||
221 | if (tmshigh & SSB_GIGE_TMSHIGH_RGMII) { | ||
222 | tmslow &= ~SSB_GIGE_TMSLOW_TXBYPASS; | ||
223 | tmslow &= ~SSB_GIGE_TMSLOW_RXBYPASS; | ||
224 | dev->has_rgmii = 1; | ||
225 | } else { | ||
226 | tmslow |= SSB_GIGE_TMSLOW_TXBYPASS; | ||
227 | tmslow |= SSB_GIGE_TMSLOW_RXBYPASS; | ||
228 | dev->has_rgmii = 0; | ||
229 | } | ||
230 | tmslow |= SSB_GIGE_TMSLOW_DLLEN; | ||
231 | ssb_write32(sdev, SSB_TMSLOW, tmslow); | ||
232 | |||
233 | ssb_set_drvdata(sdev, dev); | ||
234 | register_pci_controller(&dev->pci_controller); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | bool pdev_is_ssb_gige_core(struct pci_dev *pdev) | ||
240 | { | ||
241 | if (!pdev->resource[0].name) | ||
242 | return 0; | ||
243 | return (strcmp(pdev->resource[0].name, SSB_GIGE_MEM_RES_NAME) == 0); | ||
244 | } | ||
245 | EXPORT_SYMBOL(pdev_is_ssb_gige_core); | ||
246 | |||
247 | int ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev, | ||
248 | struct pci_dev *pdev) | ||
249 | { | ||
250 | struct ssb_gige *dev = ssb_get_drvdata(sdev); | ||
251 | struct resource *res; | ||
252 | |||
253 | if (pdev->bus->ops != &dev->pci_ops) { | ||
254 | /* The PCI device is not on this SSB GigE bridge device. */ | ||
255 | return -ENODEV; | ||
256 | } | ||
257 | |||
258 | /* Fixup the PCI resources. */ | ||
259 | res = &(pdev->resource[0]); | ||
260 | res->flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED; | ||
261 | res->name = dev->mem_resource.name; | ||
262 | res->start = dev->mem_resource.start; | ||
263 | res->end = dev->mem_resource.end; | ||
264 | |||
265 | /* Fixup interrupt lines. */ | ||
266 | pdev->irq = ssb_mips_irq(sdev) + 2; | ||
267 | pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, pdev->irq); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | int ssb_gige_map_irq(struct ssb_device *sdev, | ||
273 | const struct pci_dev *pdev) | ||
274 | { | ||
275 | struct ssb_gige *dev = ssb_get_drvdata(sdev); | ||
276 | |||
277 | if (pdev->bus->ops != &dev->pci_ops) { | ||
278 | /* The PCI device is not on this SSB GigE bridge device. */ | ||
279 | return -ENODEV; | ||
280 | } | ||
281 | |||
282 | return ssb_mips_irq(sdev) + 2; | ||
283 | } | ||
284 | |||
285 | static struct ssb_driver ssb_gige_driver = { | ||
286 | .name = "BCM-GigE", | ||
287 | .id_table = ssb_gige_tbl, | ||
288 | .probe = ssb_gige_probe, | ||
289 | }; | ||
290 | |||
291 | int ssb_gige_init(void) | ||
292 | { | ||
293 | return ssb_driver_register(&ssb_gige_driver); | ||
294 | } | ||
diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c index 3d3dd32bf3ab..e3fad3123ecb 100644 --- a/drivers/ssb/driver_mipscore.c +++ b/drivers/ssb/driver_mipscore.c | |||
@@ -209,6 +209,7 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore) | |||
209 | /* fallthrough */ | 209 | /* fallthrough */ |
210 | case SSB_DEV_PCI: | 210 | case SSB_DEV_PCI: |
211 | case SSB_DEV_ETHERNET: | 211 | case SSB_DEV_ETHERNET: |
212 | case SSB_DEV_ETHERNET_GBIT: | ||
212 | case SSB_DEV_80211: | 213 | case SSB_DEV_80211: |
213 | case SSB_DEV_USB20_HOST: | 214 | case SSB_DEV_USB20_HOST: |
214 | /* These devices get their own IRQ line if available, the rest goes on IRQ0 */ | 215 | /* These devices get their own IRQ line if available, the rest goes on IRQ0 */ |
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 74b9a8aea52b..33a7d5620474 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c | |||
@@ -60,77 +60,6 @@ static DEFINE_SPINLOCK(cfgspace_lock); | |||
60 | /* Core to access the external PCI config space. Can only have one. */ | 60 | /* Core to access the external PCI config space. Can only have one. */ |
61 | static struct ssb_pcicore *extpci_core; | 61 | static struct ssb_pcicore *extpci_core; |
62 | 62 | ||
63 | static u32 ssb_pcicore_pcibus_iobase = 0x100; | ||
64 | static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA; | ||
65 | |||
66 | int pcibios_plat_dev_init(struct pci_dev *d) | ||
67 | { | ||
68 | struct resource *res; | ||
69 | int pos, size; | ||
70 | u32 *base; | ||
71 | |||
72 | ssb_printk(KERN_INFO "PCI: Fixing up device %s\n", | ||
73 | pci_name(d)); | ||
74 | |||
75 | /* Fix up resource bases */ | ||
76 | for (pos = 0; pos < 6; pos++) { | ||
77 | res = &d->resource[pos]; | ||
78 | if (res->flags & IORESOURCE_IO) | ||
79 | base = &ssb_pcicore_pcibus_iobase; | ||
80 | else | ||
81 | base = &ssb_pcicore_pcibus_membase; | ||
82 | res->flags |= IORESOURCE_PCI_FIXED; | ||
83 | if (res->end) { | ||
84 | size = res->end - res->start + 1; | ||
85 | if (*base & (size - 1)) | ||
86 | *base = (*base + size) & ~(size - 1); | ||
87 | res->start = *base; | ||
88 | res->end = res->start + size - 1; | ||
89 | *base += size; | ||
90 | pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start); | ||
91 | } | ||
92 | /* Fix up PCI bridge BAR0 only */ | ||
93 | if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0) | ||
94 | break; | ||
95 | } | ||
96 | /* Fix up interrupt lines */ | ||
97 | d->irq = ssb_mips_irq(extpci_core->dev) + 2; | ||
98 | pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static void __init ssb_fixup_pcibridge(struct pci_dev *dev) | ||
104 | { | ||
105 | u8 lat; | ||
106 | |||
107 | if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0) | ||
108 | return; | ||
109 | |||
110 | ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev)); | ||
111 | |||
112 | /* Enable PCI bridge bus mastering and memory space */ | ||
113 | pci_set_master(dev); | ||
114 | if (pcibios_enable_device(dev, ~0) < 0) { | ||
115 | ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n"); | ||
116 | return; | ||
117 | } | ||
118 | |||
119 | /* Enable PCI bridge BAR1 prefetch and burst */ | ||
120 | pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); | ||
121 | |||
122 | /* Make sure our latency is high enough to handle the devices behind us */ | ||
123 | lat = 168; | ||
124 | ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n", | ||
125 | pci_name(dev), lat); | ||
126 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); | ||
127 | } | ||
128 | DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge); | ||
129 | |||
130 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
131 | { | ||
132 | return ssb_mips_irq(extpci_core->dev) + 2; | ||
133 | } | ||
134 | 63 | ||
135 | static u32 get_cfgspace_addr(struct ssb_pcicore *pc, | 64 | static u32 get_cfgspace_addr(struct ssb_pcicore *pc, |
136 | unsigned int bus, unsigned int dev, | 65 | unsigned int bus, unsigned int dev, |
@@ -320,6 +249,95 @@ static struct pci_controller ssb_pcicore_controller = { | |||
320 | .mem_offset = 0x24000000, | 249 | .mem_offset = 0x24000000, |
321 | }; | 250 | }; |
322 | 251 | ||
252 | static u32 ssb_pcicore_pcibus_iobase = 0x100; | ||
253 | static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA; | ||
254 | |||
255 | /* This function is called when doing a pci_enable_device(). | ||
256 | * We must first check if the device is a device on the PCI-core bridge. */ | ||
257 | int ssb_pcicore_plat_dev_init(struct pci_dev *d) | ||
258 | { | ||
259 | struct resource *res; | ||
260 | int pos, size; | ||
261 | u32 *base; | ||
262 | |||
263 | if (d->bus->ops != &ssb_pcicore_pciops) { | ||
264 | /* This is not a device on the PCI-core bridge. */ | ||
265 | return -ENODEV; | ||
266 | } | ||
267 | |||
268 | ssb_printk(KERN_INFO "PCI: Fixing up device %s\n", | ||
269 | pci_name(d)); | ||
270 | |||
271 | /* Fix up resource bases */ | ||
272 | for (pos = 0; pos < 6; pos++) { | ||
273 | res = &d->resource[pos]; | ||
274 | if (res->flags & IORESOURCE_IO) | ||
275 | base = &ssb_pcicore_pcibus_iobase; | ||
276 | else | ||
277 | base = &ssb_pcicore_pcibus_membase; | ||
278 | res->flags |= IORESOURCE_PCI_FIXED; | ||
279 | if (res->end) { | ||
280 | size = res->end - res->start + 1; | ||
281 | if (*base & (size - 1)) | ||
282 | *base = (*base + size) & ~(size - 1); | ||
283 | res->start = *base; | ||
284 | res->end = res->start + size - 1; | ||
285 | *base += size; | ||
286 | pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start); | ||
287 | } | ||
288 | /* Fix up PCI bridge BAR0 only */ | ||
289 | if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0) | ||
290 | break; | ||
291 | } | ||
292 | /* Fix up interrupt lines */ | ||
293 | d->irq = ssb_mips_irq(extpci_core->dev) + 2; | ||
294 | pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | /* Early PCI fixup for a device on the PCI-core bridge. */ | ||
300 | static void ssb_pcicore_fixup_pcibridge(struct pci_dev *dev) | ||
301 | { | ||
302 | u8 lat; | ||
303 | |||
304 | if (dev->bus->ops != &ssb_pcicore_pciops) { | ||
305 | /* This is not a device on the PCI-core bridge. */ | ||
306 | return; | ||
307 | } | ||
308 | if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0) | ||
309 | return; | ||
310 | |||
311 | ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev)); | ||
312 | |||
313 | /* Enable PCI bridge bus mastering and memory space */ | ||
314 | pci_set_master(dev); | ||
315 | if (pcibios_enable_device(dev, ~0) < 0) { | ||
316 | ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n"); | ||
317 | return; | ||
318 | } | ||
319 | |||
320 | /* Enable PCI bridge BAR1 prefetch and burst */ | ||
321 | pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3); | ||
322 | |||
323 | /* Make sure our latency is high enough to handle the devices behind us */ | ||
324 | lat = 168; | ||
325 | ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n", | ||
326 | pci_name(dev), lat); | ||
327 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); | ||
328 | } | ||
329 | DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_pcicore_fixup_pcibridge); | ||
330 | |||
331 | /* PCI device IRQ mapping. */ | ||
332 | int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
333 | { | ||
334 | if (dev->bus->ops != &ssb_pcicore_pciops) { | ||
335 | /* This is not a device on the PCI-core bridge. */ | ||
336 | return -ENODEV; | ||
337 | } | ||
338 | return ssb_mips_irq(extpci_core->dev) + 2; | ||
339 | } | ||
340 | |||
323 | static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) | 341 | static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc) |
324 | { | 342 | { |
325 | u32 val; | 343 | u32 val; |
diff --git a/drivers/ssb/embedded.c b/drivers/ssb/embedded.c index d3ade821555c..7dc3a6b41397 100644 --- a/drivers/ssb/embedded.c +++ b/drivers/ssb/embedded.c | |||
@@ -10,6 +10,9 @@ | |||
10 | 10 | ||
11 | #include <linux/ssb/ssb.h> | 11 | #include <linux/ssb/ssb.h> |
12 | #include <linux/ssb/ssb_embedded.h> | 12 | #include <linux/ssb/ssb_embedded.h> |
13 | #include <linux/ssb/ssb_driver_pci.h> | ||
14 | #include <linux/ssb/ssb_driver_gige.h> | ||
15 | #include <linux/pci.h> | ||
13 | 16 | ||
14 | #include "ssb_private.h" | 17 | #include "ssb_private.h" |
15 | 18 | ||
@@ -130,3 +133,90 @@ u32 ssb_gpio_polarity(struct ssb_bus *bus, u32 mask, u32 value) | |||
130 | return res; | 133 | return res; |
131 | } | 134 | } |
132 | EXPORT_SYMBOL(ssb_gpio_polarity); | 135 | EXPORT_SYMBOL(ssb_gpio_polarity); |
136 | |||
137 | #ifdef CONFIG_SSB_DRIVER_GIGE | ||
138 | static int gige_pci_init_callback(struct ssb_bus *bus, unsigned long data) | ||
139 | { | ||
140 | struct pci_dev *pdev = (struct pci_dev *)data; | ||
141 | struct ssb_device *dev; | ||
142 | unsigned int i; | ||
143 | int res; | ||
144 | |||
145 | for (i = 0; i < bus->nr_devices; i++) { | ||
146 | dev = &(bus->devices[i]); | ||
147 | if (dev->id.coreid != SSB_DEV_ETHERNET_GBIT) | ||
148 | continue; | ||
149 | if (!dev->dev || | ||
150 | !dev->dev->driver || | ||
151 | !device_is_registered(dev->dev)) | ||
152 | continue; | ||
153 | res = ssb_gige_pcibios_plat_dev_init(dev, pdev); | ||
154 | if (res >= 0) | ||
155 | return res; | ||
156 | } | ||
157 | |||
158 | return -ENODEV; | ||
159 | } | ||
160 | #endif /* CONFIG_SSB_DRIVER_GIGE */ | ||
161 | |||
162 | int ssb_pcibios_plat_dev_init(struct pci_dev *dev) | ||
163 | { | ||
164 | int err; | ||
165 | |||
166 | err = ssb_pcicore_plat_dev_init(dev); | ||
167 | if (!err) | ||
168 | return 0; | ||
169 | #ifdef CONFIG_SSB_DRIVER_GIGE | ||
170 | err = ssb_for_each_bus_call((unsigned long)dev, gige_pci_init_callback); | ||
171 | if (err >= 0) | ||
172 | return err; | ||
173 | #endif | ||
174 | /* This is not a PCI device on any SSB device. */ | ||
175 | |||
176 | return -ENODEV; | ||
177 | } | ||
178 | |||
179 | #ifdef CONFIG_SSB_DRIVER_GIGE | ||
180 | static int gige_map_irq_callback(struct ssb_bus *bus, unsigned long data) | ||
181 | { | ||
182 | const struct pci_dev *pdev = (const struct pci_dev *)data; | ||
183 | struct ssb_device *dev; | ||
184 | unsigned int i; | ||
185 | int res; | ||
186 | |||
187 | for (i = 0; i < bus->nr_devices; i++) { | ||
188 | dev = &(bus->devices[i]); | ||
189 | if (dev->id.coreid != SSB_DEV_ETHERNET_GBIT) | ||
190 | continue; | ||
191 | if (!dev->dev || | ||
192 | !dev->dev->driver || | ||
193 | !device_is_registered(dev->dev)) | ||
194 | continue; | ||
195 | res = ssb_gige_map_irq(dev, pdev); | ||
196 | if (res >= 0) | ||
197 | return res; | ||
198 | } | ||
199 | |||
200 | return -ENODEV; | ||
201 | } | ||
202 | #endif /* CONFIG_SSB_DRIVER_GIGE */ | ||
203 | |||
204 | int ssb_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
205 | { | ||
206 | int res; | ||
207 | |||
208 | /* Check if this PCI device is a device on a SSB bus or device | ||
209 | * and return the IRQ number for it. */ | ||
210 | |||
211 | res = ssb_pcicore_pcibios_map_irq(dev, slot, pin); | ||
212 | if (res >= 0) | ||
213 | return res; | ||
214 | #ifdef CONFIG_SSB_DRIVER_GIGE | ||
215 | res = ssb_for_each_bus_call((unsigned long)dev, gige_map_irq_callback); | ||
216 | if (res >= 0) | ||
217 | return res; | ||
218 | #endif | ||
219 | /* This is not a PCI device on any SSB device. */ | ||
220 | |||
221 | return -ENODEV; | ||
222 | } | ||
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 8db40c4b86e9..49d7bbb9bea7 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <linux/ssb/ssb.h> | 15 | #include <linux/ssb/ssb.h> |
16 | #include <linux/ssb/ssb_regs.h> | 16 | #include <linux/ssb/ssb_regs.h> |
17 | #include <linux/ssb/ssb_driver_gige.h> | ||
17 | #include <linux/dma-mapping.h> | 18 | #include <linux/dma-mapping.h> |
18 | #include <linux/pci.h> | 19 | #include <linux/pci.h> |
19 | 20 | ||
@@ -68,6 +69,25 @@ found: | |||
68 | } | 69 | } |
69 | #endif /* CONFIG_SSB_PCIHOST */ | 70 | #endif /* CONFIG_SSB_PCIHOST */ |
70 | 71 | ||
72 | int ssb_for_each_bus_call(unsigned long data, | ||
73 | int (*func)(struct ssb_bus *bus, unsigned long data)) | ||
74 | { | ||
75 | struct ssb_bus *bus; | ||
76 | int res; | ||
77 | |||
78 | ssb_buses_lock(); | ||
79 | list_for_each_entry(bus, &buses, list) { | ||
80 | res = func(bus, data); | ||
81 | if (res >= 0) { | ||
82 | ssb_buses_unlock(); | ||
83 | return res; | ||
84 | } | ||
85 | } | ||
86 | ssb_buses_unlock(); | ||
87 | |||
88 | return -ENODEV; | ||
89 | } | ||
90 | |||
71 | static struct ssb_device *ssb_device_get(struct ssb_device *dev) | 91 | static struct ssb_device *ssb_device_get(struct ssb_device *dev) |
72 | { | 92 | { |
73 | if (dev) | 93 | if (dev) |
@@ -1171,7 +1191,14 @@ static int __init ssb_modinit(void) | |||
1171 | err = b43_pci_ssb_bridge_init(); | 1191 | err = b43_pci_ssb_bridge_init(); |
1172 | if (err) { | 1192 | if (err) { |
1173 | ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge " | 1193 | ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge " |
1174 | "initialization failed"); | 1194 | "initialization failed\n"); |
1195 | /* don't fail SSB init because of this */ | ||
1196 | err = 0; | ||
1197 | } | ||
1198 | err = ssb_gige_init(); | ||
1199 | if (err) { | ||
1200 | ssb_printk(KERN_ERR "SSB Broadcom Gigabit Ethernet " | ||
1201 | "driver initialization failed\n"); | ||
1175 | /* don't fail SSB init because of this */ | 1202 | /* don't fail SSB init because of this */ |
1176 | err = 0; | 1203 | err = 0; |
1177 | } | 1204 | } |
@@ -1185,6 +1212,7 @@ fs_initcall(ssb_modinit); | |||
1185 | 1212 | ||
1186 | static void __exit ssb_modexit(void) | 1213 | static void __exit ssb_modexit(void) |
1187 | { | 1214 | { |
1215 | ssb_gige_exit(); | ||
1188 | b43_pci_ssb_bridge_exit(); | 1216 | b43_pci_ssb_bridge_exit(); |
1189 | bus_unregister(&ssb_bustype); | 1217 | bus_unregister(&ssb_bustype); |
1190 | } | 1218 | } |
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index 21eca2b5118b..d03b20983b1e 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h | |||
@@ -118,6 +118,8 @@ extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m); | |||
118 | extern int ssb_devices_freeze(struct ssb_bus *bus); | 118 | extern int ssb_devices_freeze(struct ssb_bus *bus); |
119 | extern int ssb_devices_thaw(struct ssb_bus *bus); | 119 | extern int ssb_devices_thaw(struct ssb_bus *bus); |
120 | extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); | 120 | extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev); |
121 | int ssb_for_each_bus_call(unsigned long data, | ||
122 | int (*func)(struct ssb_bus *bus, unsigned long data)); | ||
121 | 123 | ||
122 | /* b43_pci_bridge.c */ | 124 | /* b43_pci_bridge.c */ |
123 | #ifdef CONFIG_SSB_B43_PCI_BRIDGE | 125 | #ifdef CONFIG_SSB_B43_PCI_BRIDGE |