Annotation of sys/dev/pci/if_gem_pci.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: if_gem_pci.c,v 1.28 2007/04/19 19:00:01 kettenis Exp $ */
2: /* $NetBSD: if_gem_pci.c,v 1.1 2001/09/16 00:11:42 eeh Exp $ */
3:
4: /*
5: *
6: * Copyright (C) 2001 Eduardo Horvath.
7: * All rights reserved.
8: *
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: *
31: */
32:
33: /*
34: * PCI bindings for Sun GEM ethernet controllers.
35: */
36:
37: #include <sys/param.h>
38: #include <sys/systm.h>
39: #include <sys/malloc.h>
40: #include <sys/kernel.h>
41: #include <sys/socket.h>
42: #include <sys/errno.h>
43: #include <sys/device.h>
44:
45: #include <machine/endian.h>
46:
47: #include <net/if.h>
48: #include <net/if_dl.h>
49: #include <net/if_media.h>
50:
51: #ifdef INET
52: #include <netinet/in.h>
53: #include <netinet/if_ether.h>
54: #endif
55:
56: #if NBPFILTER > 0
57: #include <net/bpf.h>
58: #endif
59:
60: #include <machine/bus.h>
61: #include <machine/intr.h>
62:
63: #ifdef __sparc64__
64: #include <dev/ofw/openfirm.h>
65: #endif
66:
67: #include <dev/mii/mii.h>
68: #include <dev/mii/miivar.h>
69: #include <dev/mii/mii_bitbang.h>
70:
71: #include <dev/ic/gemreg.h>
72: #include <dev/ic/gemvar.h>
73:
74: #include <dev/pci/pcivar.h>
75: #include <dev/pci/pcireg.h>
76: #include <dev/pci/pcidevs.h>
77:
78: struct gem_pci_softc {
79: struct gem_softc gsc_gem; /* GEM device */
80: bus_space_tag_t gsc_memt;
81: bus_space_handle_t gsc_memh;
82: void *gsc_ih;
83: };
84:
85: int gem_match_pci(struct device *, void *, void *);
86: void gem_attach_pci(struct device *, struct device *, void *);
87: int gem_pci_enaddr(struct gem_softc *, struct pci_attach_args *);
88:
89: struct cfattach gem_pci_ca = {
90: sizeof(struct gem_pci_softc), gem_match_pci, gem_attach_pci
91: };
92:
93: /*
94: * Attach routines need to be split out to different bus-specific files.
95: */
96:
97: const struct pci_matchid gem_pci_devices[] = {
98: { PCI_VENDOR_SUN, PCI_PRODUCT_SUN_ERINETWORK },
99: { PCI_VENDOR_SUN, PCI_PRODUCT_SUN_GEMNETWORK },
100: { PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_INTREPID2_GMAC },
101: { PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_K2_GMAC },
102: { PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_PANGEA_GMAC },
103: { PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_SHASTA_GMAC },
104: { PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_UNINORTHGMAC },
105: { PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_UNINORTH2GMAC },
106: };
107:
108: int
109: gem_match_pci(struct device *parent, void *cf, void *aux)
110: {
111: return (pci_matchbyid((struct pci_attach_args *)aux, gem_pci_devices,
112: sizeof(gem_pci_devices)/sizeof(gem_pci_devices[0])));
113: }
114:
115: #define PROMHDR_PTR_DATA 0x18
116: #define PROMDATA_PTR_VPD 0x08
117: #define PROMDATA_DATA2 0x0a
118:
119: static const u_int8_t gem_promhdr[] = { 0x55, 0xaa };
120: static const u_int8_t gem_promdat[] = {
121: 'P', 'C', 'I', 'R',
122: PCI_VENDOR_SUN & 0xff, PCI_VENDOR_SUN >> 8,
123: PCI_PRODUCT_SUN_GEMNETWORK & 0xff, PCI_PRODUCT_SUN_GEMNETWORK >> 8
124: };
125:
126: static const u_int8_t gem_promdat2[] = {
127: 0x18, 0x00, /* structure length */
128: 0x00, /* structure revision */
129: 0x00, /* interface revision */
130: PCI_SUBCLASS_NETWORK_ETHERNET, /* subclass code */
131: PCI_CLASS_NETWORK /* class code */
132: };
133:
134: int
135: gem_pci_enaddr(struct gem_softc *sc, struct pci_attach_args *pa)
136: {
137: struct pci_vpd *vpd;
138: bus_space_handle_t romh;
139: bus_space_tag_t romt;
140: bus_size_t romsize;
141: u_int8_t buf[32];
142: pcireg_t address, mask;
143: int dataoff, vpdoff;
144: int rv = -1;
145:
146: address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
147: pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, 0xfffffffe);
148: mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
149: address |= PCI_ROM_ENABLE;
150: pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address);
151:
152: romt = pa->pa_memt;
153: romsize = PCI_ROM_SIZE(mask);
154: if (bus_space_map(romt, PCI_ROM_ADDR(address), romsize, 0, &romh)) {
155: romsize = 0;
156: goto fail;
157: }
158:
159: bus_space_read_region_1(romt, romh, 0, buf, sizeof(buf));
160: if (bcmp(buf, gem_promhdr, sizeof(gem_promhdr)))
161: goto fail;
162:
163: dataoff = buf[PROMHDR_PTR_DATA] | (buf[PROMHDR_PTR_DATA + 1] << 8);
164: if (dataoff < 0x1c)
165: goto fail;
166:
167: bus_space_read_region_1(romt, romh, dataoff, buf, sizeof(buf));
168: if (bcmp(buf, gem_promdat, sizeof(gem_promdat)) ||
169: bcmp(buf + PROMDATA_DATA2, gem_promdat2, sizeof(gem_promdat2)))
170: goto fail;
171:
172: vpdoff = buf[PROMDATA_PTR_VPD] | (buf[PROMDATA_PTR_VPD + 1] << 8);
173: if (vpdoff < 0x1c)
174: goto fail;
175:
176: bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf));
177:
178: /*
179: * The VPD of gem is not in PCI 2.2 standard format. The length
180: * in the resource header is in big endian.
181: */
182: vpd = (struct pci_vpd *)(buf + 3);
183: if (!PCI_VPDRES_ISLARGE(buf[0]) ||
184: PCI_VPDRES_LARGE_NAME(buf[0]) != PCI_VPDRES_TYPE_VPD)
185: goto fail;
186: if (vpd->vpd_key0 != 'N' || vpd->vpd_key1 != 'A')
187: goto fail;
188:
189: bcopy(buf + 6, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
190: rv = 0;
191:
192: fail:
193: if (romsize != 0)
194: bus_space_unmap(romt, romh, romsize);
195:
196: address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
197: address &= ~PCI_ROM_ENABLE;
198: pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address);
199:
200: return (rv);
201: }
202:
203: void
204: gem_attach_pci(struct device *parent, struct device *self, void *aux)
205: {
206: struct pci_attach_args *pa = aux;
207: struct gem_pci_softc *gsc = (void *)self;
208: struct gem_softc *sc = &gsc->gsc_gem;
209: pci_intr_handle_t ih;
210: #ifdef __sparc64__
211: /* XXX the following declarations should be elsewhere */
212: extern void myetheraddr(u_char *);
213: #endif
214: const char *intrstr = NULL;
215: bus_size_t size;
216: int type, gotenaddr = 0;
217:
218: if (pa->pa_memt) {
219: type = PCI_MAPREG_TYPE_MEM;
220: sc->sc_bustag = pa->pa_memt;
221: } else {
222: type = PCI_MAPREG_TYPE_IO;
223: sc->sc_bustag = pa->pa_iot;
224: }
225:
226: sc->sc_dmatag = pa->pa_dmat;
227:
228: sc->sc_pci = 1; /* XXXXX should all be done in bus_dma. */
229:
230: if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_GEMNETWORK)
231: sc->sc_variant = GEM_SUN_GEM;
232: else if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_ERINETWORK)
233: sc->sc_variant = GEM_SUN_ERI;
234: else if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_INTREPID2_GMAC)
235: sc->sc_variant = GEM_APPLE_GMAC;
236: else if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_PANGEA_GMAC)
237: sc->sc_variant = GEM_APPLE_GMAC;
238: else if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_SHASTA_GMAC)
239: sc->sc_variant = GEM_APPLE_GMAC;
240: else if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_UNINORTHGMAC)
241: sc->sc_variant = GEM_APPLE_GMAC;
242: else if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_UNINORTH2GMAC)
243: sc->sc_variant = GEM_APPLE_GMAC;
244: else if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_K2_GMAC)
245: sc->sc_variant = GEM_APPLE_K2_GMAC;
246:
247: #define PCI_GEM_BASEADDR 0x10
248: if (pci_mapreg_map(pa, PCI_GEM_BASEADDR, type, 0,
249: &gsc->gsc_memt, &gsc->gsc_memh, NULL, &size, 0) != 0) {
250: printf(": could not map registers\n");
251: return;
252: }
253:
254: sc->sc_bustag = gsc->gsc_memt;
255: sc->sc_h1 = gsc->gsc_memh;
256:
257: if (bus_space_subregion(sc->sc_bustag, sc->sc_h1,
258: GEM_PCI_BANK2_OFFSET, GEM_PCI_BANK2_SIZE, &sc->sc_h2)) {
259: printf(": unable to create bank 2 subregion\n");
260: bus_space_unmap(gsc->gsc_memt, gsc->gsc_memh, size);
261: return;
262: }
263:
264: if (gem_pci_enaddr(sc, pa) == 0)
265: gotenaddr = 1;
266:
267: #ifdef __sparc64__
268: if (!gotenaddr) {
269: if (OF_getprop(PCITAG_NODE(pa->pa_tag), "local-mac-address",
270: sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN) <= 0)
271: myetheraddr(sc->sc_arpcom.ac_enaddr);
272: gotenaddr = 1;
273: }
274: #endif
275: #ifdef __powerpc__
276: if (!gotenaddr) {
277: pci_ether_hw_addr(pa->pa_pc, sc->sc_arpcom.ac_enaddr);
278: gotenaddr = 1;
279: }
280: #endif
281:
282: sc->sc_burst = 16; /* XXX */
283:
284: if (pci_intr_map(pa, &ih) != 0) {
285: printf(": couldn't map interrupt\n");
286: bus_space_unmap(gsc->gsc_memt, gsc->gsc_memh, size);
287: return;
288: }
289: intrstr = pci_intr_string(pa->pa_pc, ih);
290: gsc->gsc_ih = pci_intr_establish(pa->pa_pc,
291: ih, IPL_NET, gem_intr, sc, self->dv_xname);
292: if (gsc->gsc_ih == NULL) {
293: printf(": couldn't establish interrupt");
294: if (intrstr != NULL)
295: printf(" at %s", intrstr);
296: printf("\n");
297: bus_space_unmap(gsc->gsc_memt, gsc->gsc_memh, size);
298: return;
299: }
300:
301: printf(": %s", intrstr);
302:
303: /*
304: * call the main configure
305: */
306: gem_config(sc);
307: }
CVSweb