driver_gige.c revision aab547ce0d1493d400b6468c521a0137cd8c1edf
1aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch/*
2aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch * Sonics Silicon Backplane
3aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch * Broadcom Gigabit Ethernet core driver
4aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch *
5aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch * Copyright 2008, Broadcom Corporation
6aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch * Copyright 2008, Michael Buesch <mb@bu3sch.de>
7aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch *
8aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch * Licensed under the GNU/GPL. See COPYING for details.
9aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch */
10aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
11aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch#include <linux/ssb/ssb.h>
12aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch#include <linux/ssb/ssb_driver_gige.h>
13aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch#include <linux/pci.h>
14aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch#include <linux/pci_regs.h>
15aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
16aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
17aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch/*
18aab547ce0d1493d400b6468c521a0137cd8c1edfMichael BueschMODULE_DESCRIPTION("SSB Broadcom Gigabit Ethernet driver");
19aab547ce0d1493d400b6468c521a0137cd8c1edfMichael BueschMODULE_AUTHOR("Michael Buesch");
20aab547ce0d1493d400b6468c521a0137cd8c1edfMichael BueschMODULE_LICENSE("GPL");
21aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch*/
22aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
23aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic const struct ssb_device_id ssb_gige_tbl[] = {
24aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET_GBIT, SSB_ANY_REV),
25aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	SSB_DEVTABLE_END
26aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch};
27aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch/* MODULE_DEVICE_TABLE(ssb, ssb_gige_tbl); */
28aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
29aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
30aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline u8 gige_read8(struct ssb_gige *dev, u16 offset)
31aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
32aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return ssb_read8(dev->dev, offset);
33aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
34aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
35aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline u16 gige_read16(struct ssb_gige *dev, u16 offset)
36aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
37aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return ssb_read16(dev->dev, offset);
38aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
39aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
40aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline u32 gige_read32(struct ssb_gige *dev, u16 offset)
41aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
42aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return ssb_read32(dev->dev, offset);
43aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
44aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
45aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline void gige_write8(struct ssb_gige *dev,
46aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch			       u16 offset, u8 value)
47aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
48aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	ssb_write8(dev->dev, offset, value);
49aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
50aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
51aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline void gige_write16(struct ssb_gige *dev,
52aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch				u16 offset, u16 value)
53aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
54aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	ssb_write16(dev->dev, offset, value);
55aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
56aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
57aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline void gige_write32(struct ssb_gige *dev,
58aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch				u16 offset, u32 value)
59aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
60aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	ssb_write32(dev->dev, offset, value);
61aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
62aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
63aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline
64aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschu8 gige_pcicfg_read8(struct ssb_gige *dev, unsigned int offset)
65aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
66aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	BUG_ON(offset >= 256);
67aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return gige_read8(dev, SSB_GIGE_PCICFG + offset);
68aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
69aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
70aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline
71aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschu16 gige_pcicfg_read16(struct ssb_gige *dev, unsigned int offset)
72aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
73aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	BUG_ON(offset >= 256);
74aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return gige_read16(dev, SSB_GIGE_PCICFG + offset);
75aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
76aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
77aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline
78aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschu32 gige_pcicfg_read32(struct ssb_gige *dev, unsigned int offset)
79aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
80aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	BUG_ON(offset >= 256);
81aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return gige_read32(dev, SSB_GIGE_PCICFG + offset);
82aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
83aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
84aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline
85aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschvoid gige_pcicfg_write8(struct ssb_gige *dev,
86aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch			unsigned int offset, u8 value)
87aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
88aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	BUG_ON(offset >= 256);
89aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	gige_write8(dev, SSB_GIGE_PCICFG + offset, value);
90aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
91aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
92aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline
93aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschvoid gige_pcicfg_write16(struct ssb_gige *dev,
94aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch			 unsigned int offset, u16 value)
95aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
96aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	BUG_ON(offset >= 256);
97aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	gige_write16(dev, SSB_GIGE_PCICFG + offset, value);
98aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
99aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
100aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic inline
101aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschvoid gige_pcicfg_write32(struct ssb_gige *dev,
102aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch			 unsigned int offset, u32 value)
103aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
104aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	BUG_ON(offset >= 256);
105aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	gige_write32(dev, SSB_GIGE_PCICFG + offset, value);
106aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
107aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
108aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic int ssb_gige_pci_read_config(struct pci_bus *bus, unsigned int devfn,
109aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch				    int reg, int size, u32 *val)
110aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
111aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops);
112aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	unsigned long flags;
113aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
114aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if ((PCI_SLOT(devfn) > 0) || (PCI_FUNC(devfn) > 0))
115aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return PCIBIOS_DEVICE_NOT_FOUND;
116aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (reg >= 256)
117aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return PCIBIOS_DEVICE_NOT_FOUND;
118aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
119aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	spin_lock_irqsave(&dev->lock, flags);
120aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	switch (size) {
121aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	case 1:
122aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		*val = gige_pcicfg_read8(dev, reg);
123aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		break;
124aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	case 2:
125aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		*val = gige_pcicfg_read16(dev, reg);
126aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		break;
127aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	case 4:
128aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		*val = gige_pcicfg_read32(dev, reg);
129aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		break;
130aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	default:
131aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		WARN_ON(1);
132aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	}
133aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	spin_unlock_irqrestore(&dev->lock, flags);
134aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
135aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return PCIBIOS_SUCCESSFUL;
136aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
137aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
138aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic int ssb_gige_pci_write_config(struct pci_bus *bus, unsigned int devfn,
139aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch				     int reg, int size, u32 val)
140aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
141aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops);
142aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	unsigned long flags;
143aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
144aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if ((PCI_SLOT(devfn) > 0) || (PCI_FUNC(devfn) > 0))
145aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return PCIBIOS_DEVICE_NOT_FOUND;
146aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (reg >= 256)
147aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return PCIBIOS_DEVICE_NOT_FOUND;
148aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
149aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	spin_lock_irqsave(&dev->lock, flags);
150aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	switch (size) {
151aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	case 1:
152aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		gige_pcicfg_write8(dev, reg, val);
153aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		break;
154aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	case 2:
155aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		gige_pcicfg_write16(dev, reg, val);
156aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		break;
157aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	case 4:
158aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		gige_pcicfg_write32(dev, reg, val);
159aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		break;
160aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	default:
161aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		WARN_ON(1);
162aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	}
163aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	spin_unlock_irqrestore(&dev->lock, flags);
164aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
165aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return PCIBIOS_SUCCESSFUL;
166aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
167aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
168aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic int ssb_gige_probe(struct ssb_device *sdev, const struct ssb_device_id *id)
169aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
170aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	struct ssb_gige *dev;
171aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	u32 base, tmslow, tmshigh;
172aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
173aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
174aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (!dev)
175aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return -ENOMEM;
176aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->dev = sdev;
177aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
178aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	spin_lock_init(&dev->lock);
179aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->pci_controller.pci_ops = &dev->pci_ops;
180aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->pci_controller.io_resource = &dev->io_resource;
181aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->pci_controller.mem_resource = &dev->mem_resource;
182aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->pci_controller.io_map_base = 0x800;
183aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->pci_ops.read = ssb_gige_pci_read_config;
184aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->pci_ops.write = ssb_gige_pci_write_config;
185aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
186aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->io_resource.name = SSB_GIGE_IO_RES_NAME;
187aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->io_resource.start = 0x800;
188aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->io_resource.end = 0x8FF;
189aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->io_resource.flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED;
190aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
191aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (!ssb_device_is_enabled(sdev))
192aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		ssb_device_enable(sdev, 0);
193aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
194aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	/* Setup BAR0. This is a 64k MMIO region. */
195aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	base = ssb_admatch_base(ssb_read32(sdev, SSB_ADMATCH1));
196aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	gige_pcicfg_write32(dev, PCI_BASE_ADDRESS_0, base);
197aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	gige_pcicfg_write32(dev, PCI_BASE_ADDRESS_1, 0);
198aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
199aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->mem_resource.name = SSB_GIGE_MEM_RES_NAME;
200aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->mem_resource.start = base;
201aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->mem_resource.end = base + 0x10000 - 1;
202aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	dev->mem_resource.flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED;
203aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
204aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	/* Enable the memory region. */
205aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	gige_pcicfg_write16(dev, PCI_COMMAND,
206aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch			    gige_pcicfg_read16(dev, PCI_COMMAND)
207aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch			    | PCI_COMMAND_MEMORY);
208aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
209aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	/* Write flushing is controlled by the Flush Status Control register.
210aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	 * We want to flush every register write with a timeout and we want
211aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	 * to disable the IRQ mask while flushing to avoid concurrency.
212aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	 * Note that automatic write flushing does _not_ work from
213aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	 * an IRQ handler. The driver must flush manually by reading a register.
214aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	 */
215aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	gige_write32(dev, SSB_GIGE_SHIM_FLUSHSTAT, 0x00000068);
216aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
217aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	/* Check if we have an RGMII or GMII PHY-bus.
218aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	 * On RGMII do not bypass the DLLs */
219aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	tmslow = ssb_read32(sdev, SSB_TMSLOW);
220aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	tmshigh = ssb_read32(sdev, SSB_TMSHIGH);
221aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (tmshigh & SSB_GIGE_TMSHIGH_RGMII) {
222aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		tmslow &= ~SSB_GIGE_TMSLOW_TXBYPASS;
223aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		tmslow &= ~SSB_GIGE_TMSLOW_RXBYPASS;
224aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		dev->has_rgmii = 1;
225aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	} else {
226aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		tmslow |= SSB_GIGE_TMSLOW_TXBYPASS;
227aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		tmslow |= SSB_GIGE_TMSLOW_RXBYPASS;
228aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		dev->has_rgmii = 0;
229aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	}
230aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	tmslow |= SSB_GIGE_TMSLOW_DLLEN;
231aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	ssb_write32(sdev, SSB_TMSLOW, tmslow);
232aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
233aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	ssb_set_drvdata(sdev, dev);
234aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	register_pci_controller(&dev->pci_controller);
235aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
236aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return 0;
237aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
238aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
239aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschbool pdev_is_ssb_gige_core(struct pci_dev *pdev)
240aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
241aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (!pdev->resource[0].name)
242aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return 0;
243aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return (strcmp(pdev->resource[0].name, SSB_GIGE_MEM_RES_NAME) == 0);
244aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
245aab547ce0d1493d400b6468c521a0137cd8c1edfMichael BueschEXPORT_SYMBOL(pdev_is_ssb_gige_core);
246aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
247aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschint ssb_gige_pcibios_plat_dev_init(struct ssb_device *sdev,
248aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch				   struct pci_dev *pdev)
249aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
250aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	struct ssb_gige *dev = ssb_get_drvdata(sdev);
251aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	struct resource *res;
252aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
253aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (pdev->bus->ops != &dev->pci_ops) {
254aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		/* The PCI device is not on this SSB GigE bridge device. */
255aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return -ENODEV;
256aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	}
257aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
258aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	/* Fixup the PCI resources. */
259aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	res = &(pdev->resource[0]);
260aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	res->flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED;
261aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	res->name = dev->mem_resource.name;
262aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	res->start = dev->mem_resource.start;
263aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	res->end = dev->mem_resource.end;
264aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
265aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	/* Fixup interrupt lines. */
266aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	pdev->irq = ssb_mips_irq(sdev) + 2;
267aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, pdev->irq);
268aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
269aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return 0;
270aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
271aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
272aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschint ssb_gige_map_irq(struct ssb_device *sdev,
273aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		     const struct pci_dev *pdev)
274aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
275aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	struct ssb_gige *dev = ssb_get_drvdata(sdev);
276aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
277aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	if (pdev->bus->ops != &dev->pci_ops) {
278aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		/* The PCI device is not on this SSB GigE bridge device. */
279aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch		return -ENODEV;
280aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	}
281aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
282aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return ssb_mips_irq(sdev) + 2;
283aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
284aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
285aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschstatic struct ssb_driver ssb_gige_driver = {
286aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	.name		= "BCM-GigE",
287aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	.id_table	= ssb_gige_tbl,
288aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	.probe		= ssb_gige_probe,
289aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch};
290aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch
291aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Bueschint ssb_gige_init(void)
292aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch{
293aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch	return ssb_driver_register(&ssb_gige_driver);
294aab547ce0d1493d400b6468c521a0137cd8c1edfMichael Buesch}
295