Annotation of sys/dev/cardbus/if_re_cardbus.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: if_re_cardbus.c,v 1.11 2006/11/28 20:04:02 brad Exp $ */
2:
3: /*
4: * Copyright (c) 2005 Peter Valchev <pvalchev@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: /*
20: * Cardbus front-end for the Realtek 8169
21: */
22:
23: #include <sys/param.h>
24: #include <sys/endian.h>
25: #include <sys/systm.h>
26: #include <sys/sockio.h>
27: #include <sys/mbuf.h>
28: #include <sys/malloc.h>
29: #include <sys/kernel.h>
30: #include <sys/device.h>
31: #include <sys/timeout.h>
32: #include <sys/socket.h>
33:
34: #include <net/if.h>
35: #include <net/if_dl.h>
36: #include <net/if_media.h>
37:
38: #ifdef INET
39: #include <netinet/in.h>
40: #include <netinet/in_systm.h>
41: #include <netinet/in_var.h>
42: #include <netinet/ip.h>
43: #include <netinet/if_ether.h>
44: #endif
45:
46: #include <dev/mii/mii.h>
47: #include <dev/mii/miivar.h>
48:
49: #include <dev/pci/pcidevs.h>
50:
51: #include <dev/cardbus/cardbusvar.h>
52:
53: #include <dev/ic/rtl81x9reg.h>
54: #include <dev/ic/revar.h>
55:
56: struct re_cardbus_softc {
57: /* General */
58: struct rl_softc sc_rl;
59:
60: /* Cardbus-specific data */
61: void *sc_ih;
62: cardbus_devfunc_t ct;
63: cardbustag_t sc_tag;
64: int sc_csr;
65: int sc_cben;
66: int sc_bar_reg;
67: pcireg_t sc_bar_val;
68: int sc_intrline;
69:
70: bus_size_t sc_mapsize;
71: };
72:
73: int re_cardbus_probe(struct device *, void *, void *);
74: void re_cardbus_attach(struct device *, struct device *, void *);
75: int re_cardbus_detach(struct device *, int);
76: void re_cardbus_setup(struct rl_softc *);
77:
78: void re_cardbus_shutdown(void *);
79: void re_cardbus_powerhook(int, void *);
80:
81: /*
82: * Cardbus autoconfig definitions
83: */
84: struct cfattach re_cardbus_ca = {
85: sizeof(struct re_cardbus_softc),
86: re_cardbus_probe,
87: re_cardbus_attach,
88: re_cardbus_detach
89: };
90:
91: const struct cardbus_matchid re_cardbus_devices[] = {
92: { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169 },
93: };
94:
95: /*
96: * Probe for a RealTek 8169/8110 chip. Check the PCI vendor and device
97: * IDs against our list and return a device name if we find a match.
98: */
99: int
100: re_cardbus_probe(struct device *parent, void *match, void *aux)
101: {
102: return (cardbus_matchbyid((struct cardbus_attach_args *)aux,
103: re_cardbus_devices,
104: sizeof(re_cardbus_devices)/sizeof(re_cardbus_devices[0])));
105: }
106:
107: /*
108: * Attach the interface. Allocate softc structures, do ifmedia
109: * setup and ethernet/BPF attach.
110: */
111: void
112: re_cardbus_attach(struct device *parent, struct device *self, void *aux)
113: {
114: struct re_cardbus_softc *csc = (struct re_cardbus_softc *)self;
115: struct rl_softc *sc = &csc->sc_rl;
116: struct cardbus_attach_args *ca = aux;
117: struct cardbus_softc *psc =
118: (struct cardbus_softc *)sc->sc_dev.dv_parent;
119: cardbus_chipset_tag_t cc = psc->sc_cc;
120: cardbus_function_tag_t cf = psc->sc_cf;
121: cardbus_devfunc_t ct = ca->ca_ct;
122: bus_addr_t adr;
123: char intrstr[16];
124:
125: sc->sc_dmat = ca->ca_dmat;
126: csc->ct = ct;
127: csc->sc_tag = ca->ca_tag;
128: csc->sc_intrline = ca->ca_intrline;
129:
130: /*
131: * Map control/status registers.
132: */
133: if (Cardbus_mapreg_map(ct, RL_PCI_LOMEM, CARDBUS_MAPREG_TYPE_MEM, 0,
134: &sc->rl_btag, &sc->rl_bhandle, &adr, &csc->sc_mapsize) == 0) {
135: csc->sc_cben = CARDBUS_MEM_ENABLE;
136: csc->sc_csr |= CARDBUS_COMMAND_MEM_ENABLE;
137: csc->sc_bar_reg = RL_PCI_LOMEM;
138: csc->sc_bar_val = adr | CARDBUS_MAPREG_TYPE_MEM;
139: } else {
140: printf(": can't map mem space\n");
141: return;
142: }
143:
144: /* Enable power */
145: Cardbus_function_enable(ct);
146:
147: /* Get chip out of powersave mode (if applicable), initialize
148: * config registers */
149: re_cardbus_setup(sc);
150:
151: /* Allocate interrupt */
152: csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline,
153: IPL_NET, re_intr, sc, sc->sc_dev.dv_xname);
154: if (csc->sc_ih == NULL) {
155: printf(": couldn't establish interrupt at %s",
156: ca->ca_intrline);
157: Cardbus_function_disable(csc->ct);
158: return;
159: }
160: snprintf(intrstr, sizeof(intrstr), "irq %d", ca->ca_intrline);
161:
162: sc->sc_flags |= RL_ENABLED;
163: sc->rl_type = RL_8169;
164:
165: sc->sc_sdhook = shutdownhook_establish(re_cardbus_shutdown, sc);
166: sc->sc_pwrhook = powerhook_establish(re_cardbus_powerhook, sc);
167:
168: /* Call bus-independent (common) attach routine */
169: re_attach(sc, intrstr);
170: }
171:
172: /*
173: * Get chip out of power-saving mode, init registers
174: */
175: void
176: re_cardbus_setup(struct rl_softc *sc)
177: {
178: struct re_cardbus_softc *csc = (struct re_cardbus_softc *)sc;
179: cardbus_devfunc_t ct = csc->ct;
180: cardbus_chipset_tag_t cc = ct->ct_cc;
181: cardbus_function_tag_t cf = ct->ct_cf;
182: pcireg_t reg, command;
183: int pmreg;
184:
185: /* Handle power management nonsense */
186: if (cardbus_get_capability(cc, cf, csc->sc_tag,
187: PCI_CAP_PWRMGMT, &pmreg, 0)) {
188: command = cardbus_conf_read(cc, cf, csc->sc_tag,
189: pmreg + PCI_PMCSR);
190:
191: if (command & RL_PSTATE_MASK) {
192: pcireg_t iobase, membase, irq;
193:
194: /* Save important PCI config data */
195: iobase = cardbus_conf_read(cc, cf, csc->sc_tag, RL_PCI_LOIO);
196: membase = cardbus_conf_read(cc, cf, csc->sc_tag, RL_PCI_LOMEM);
197: irq = cardbus_conf_read(cc, cf, csc->sc_tag, RL_PCI_INTLINE);
198:
199: /* Reset the power state */
200: printf("%s: chip is in D%d power mode "
201: "-- setting to D0\n", sc->sc_dev.dv_xname,
202: command & RL_PSTATE_MASK);
203: command &= RL_PSTATE_MASK;
204: cardbus_conf_write(cc, cf, csc->sc_tag, pmreg + PCI_PMCSR,
205: command);
206:
207: /* Restore PCI config data */
208: cardbus_conf_write(cc, cf, csc->sc_tag, RL_PCI_LOIO, iobase);
209: cardbus_conf_write(cc, cf, csc->sc_tag, RL_PCI_LOMEM, membase);
210: cardbus_conf_write(cc, cf, csc->sc_tag, RL_PCI_INTLINE, irq);
211: }
212: }
213:
214: /* Make sure the right access type is on the Cardbus bridge */
215: (*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben);
216: (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
217:
218: /* Program the BAR */
219: cardbus_conf_write(cc, cf, csc->sc_tag, csc->sc_bar_reg, csc->sc_bar_val);
220:
221: /* Enable proper bits in CARDBUS CSR */
222: reg = cardbus_conf_read(cc, cf, csc->sc_tag, CARDBUS_COMMAND_STATUS_REG);
223: reg &= ~(CARDBUS_COMMAND_IO_ENABLE|CARDBUS_COMMAND_MEM_ENABLE);
224: reg |= csc->sc_csr;
225: cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_COMMAND_STATUS_REG, reg);
226:
227: /* Make sure the latency timer is set to some reasonable value */
228: reg = cardbus_conf_read(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG);
229: if (CARDBUS_LATTIMER(reg) < 0x20) {
230: reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
231: reg |= (0x20 << CARDBUS_LATTIMER_SHIFT);
232: cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG, reg);
233: }
234: }
235:
236: /*
237: * Cardbus detach function: deallocate all resources
238: */
239: int
240: re_cardbus_detach(struct device *self, int flags)
241: {
242: struct re_cardbus_softc *csc = (void *)self;
243: struct rl_softc *sc = &csc->sc_rl;
244: struct cardbus_devfunc *ct = csc->ct;
245: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
246:
247: /* Remove timeout handler */
248: timeout_del(&sc->timer_handle);
249:
250: /* Detach PHY */
251: if (LIST_FIRST(&sc->sc_mii.mii_phys) != NULL)
252: mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
253:
254: /* Delete media stuff */
255: ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
256: ether_ifdetach(ifp);
257: if_detach(ifp);
258:
259: /* No more hooks */
260: if (sc->sc_sdhook != NULL)
261: shutdownhook_disestablish(sc->sc_sdhook);
262: if (sc->sc_pwrhook != NULL)
263: powerhook_disestablish(sc->sc_pwrhook);
264:
265: /* Disable interrupts */
266: if (csc->sc_ih != NULL)
267: cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih);
268:
269: /* Free cardbus resources */
270: Cardbus_mapreg_unmap(ct, csc->sc_bar_reg, sc->rl_btag, sc->rl_bhandle,
271: csc->sc_mapsize);
272:
273: return (0);
274: }
275:
276: void
277: re_cardbus_shutdown(void *arg)
278: {
279: struct rl_softc *sc = arg;
280: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
281:
282: re_stop(ifp, 1);
283: }
284:
285: void
286: re_cardbus_powerhook(int why, void *arg)
287: {
288: struct rl_softc *sc = arg;
289: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
290:
291: if (why == PWR_RESUME)
292: re_init(ifp);
293: }
CVSweb