if_re_pci.c revision 1.56
1/*	$OpenBSD: if_re_pci.c,v 1.56 2022/03/11 18:00:48 mpi 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 * PCI 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_media.h>
36
37#include <netinet/in.h>
38#include <netinet/if_ether.h>
39
40#include <dev/mii/miivar.h>
41
42#include <dev/pci/pcireg.h>
43#include <dev/pci/pcivar.h>
44#include <dev/pci/pcidevs.h>
45
46#include <dev/ic/rtl81x9reg.h>
47#include <dev/ic/revar.h>
48
49struct re_pci_softc {
50	/* General */
51	struct rl_softc sc_rl;
52
53	/* PCI-specific data */
54	pci_chipset_tag_t sc_pc;
55	pcitag_t sc_pcitag;
56
57	bus_size_t sc_iosize;
58};
59
60const struct pci_matchid re_pci_devices[] = {
61	{ PCI_VENDOR_COREGA, PCI_PRODUCT_COREGA_CGLAPCIGT },
62	{ PCI_VENDOR_DLINK, PCI_PRODUCT_DLINK_DGE528T },
63	{ PCI_VENDOR_DLINK, PCI_PRODUCT_DLINK_DGE530T_C1 },
64	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_E2500V2 },
65	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_E2600 },
66	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8101E },
67	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8168 },
68	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8168_2 },
69	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169 },
70	{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169SC },
71	{ PCI_VENDOR_TTTECH, PCI_PRODUCT_TTTECH_MC322 },
72	{ PCI_VENDOR_USR2, PCI_PRODUCT_USR2_USR997902 }
73};
74
75#define RE_LINKSYS_EG1032_SUBID 0x00241737
76
77int	re_pci_probe(struct device *, void *, void *);
78void	re_pci_attach(struct device *, struct device *, void *);
79int	re_pci_detach(struct device *, int);
80int	re_pci_activate(struct device *, int);
81
82/*
83 * PCI autoconfig definitions
84 */
85const struct cfattach re_pci_ca = {
86	sizeof(struct re_pci_softc),
87	re_pci_probe,
88	re_pci_attach,
89	re_pci_detach,
90	re_pci_activate
91};
92
93/*
94 * Probe for a Realtek 8169/8110 chip. Check the PCI vendor and device
95 * IDs against our list and return a device name if we find a match.
96 */
97int
98re_pci_probe(struct device *parent, void *match, void *aux)
99{
100	struct pci_attach_args *pa = aux;
101	pci_chipset_tag_t pc = pa->pa_pc;
102	pcireg_t subid;
103
104	subid = pci_conf_read(pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
105
106	/* C+ mode 8139's */
107	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_REALTEK &&
108	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_REALTEK_RT8139 &&
109	    PCI_REVISION(pa->pa_class) == 0x20)
110		return (1);
111
112	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_LINKSYS &&
113	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_LINKSYS_EG1032 &&
114	    subid == RE_LINKSYS_EG1032_SUBID)
115		return (1);
116
117	return (pci_matchbyid((struct pci_attach_args *)aux, re_pci_devices,
118	    nitems(re_pci_devices)));
119}
120
121/*
122 * PCI-specific attach routine
123 */
124void
125re_pci_attach(struct device *parent, struct device *self, void *aux)
126{
127	struct re_pci_softc	*psc = (struct re_pci_softc *)self;
128	struct rl_softc		*sc = &psc->sc_rl;
129	struct pci_attach_args	*pa = aux;
130	pci_chipset_tag_t	pc = pa->pa_pc;
131	pci_intr_handle_t	ih;
132	const char		*intrstr = NULL;
133	pcireg_t		reg;
134	int			offset;
135
136	pci_set_powerstate(pa->pa_pc, pa->pa_tag, PCI_PMCSR_STATE_D0);
137
138#ifndef SMALL_KERNEL
139	/* Enable power management for wake on lan. */
140	pci_conf_write(pc, pa->pa_tag, RL_PCI_PMCSR, RL_PME_EN);
141#endif
142
143	/*
144	 * Map control/status registers.
145	 */
146	if (pci_mapreg_map(pa, RL_PCI_LOMEM64, PCI_MAPREG_TYPE_MEM |
147	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->rl_btag, &sc->rl_bhandle,
148	    NULL, &psc->sc_iosize, 0)) {
149		if (pci_mapreg_map(pa, RL_PCI_LOMEM, PCI_MAPREG_TYPE_MEM |
150		    PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->rl_btag, &sc->rl_bhandle,
151		    NULL, &psc->sc_iosize, 0)) {
152			if (pci_mapreg_map(pa, RL_PCI_LOIO, PCI_MAPREG_TYPE_IO,
153			    0, &sc->rl_btag, &sc->rl_bhandle, NULL,
154			    &psc->sc_iosize, 0)) {
155				printf(": can't map mem or i/o space\n");
156				return;
157			}
158		}
159	}
160
161	/* Allocate interrupt */
162	if (pci_intr_map_msi(pa, &ih) == 0)
163		sc->rl_flags |= RL_FLAG_MSI;
164	else if (pci_intr_map(pa, &ih) != 0) {
165		printf(": couldn't map interrupt\n");
166		return;
167	}
168	intrstr = pci_intr_string(pc, ih);
169	sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET | IPL_MPSAFE, re_intr,
170	    sc, sc->sc_dev.dv_xname);
171	if (sc->sc_ih == NULL) {
172		printf(": couldn't establish interrupt");
173		if (intrstr != NULL)
174			printf(" at %s", intrstr);
175		return;
176	}
177
178	sc->sc_dmat = pa->pa_dmat;
179	psc->sc_pc = pc;
180
181	/*
182	 * PCI Express check.
183	 */
184	if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PCIEXPRESS,
185	    &offset, NULL)) {
186		/* Disable PCIe ASPM and ECPM. */
187		reg = pci_conf_read(pc, pa->pa_tag, offset + PCI_PCIE_LCSR);
188		reg &= ~(PCI_PCIE_LCSR_ASPM_L0S | PCI_PCIE_LCSR_ASPM_L1 |
189		    PCI_PCIE_LCSR_ECPM);
190		pci_conf_write(pc, pa->pa_tag, offset + PCI_PCIE_LCSR, reg);
191		sc->rl_flags |= RL_FLAG_PCIE;
192	}
193
194	if (!(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_REALTEK &&
195	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_REALTEK_RT8139)) {
196		u_int8_t	cfg;
197
198		CSR_WRITE_1(sc, RL_EECMD, RL_EE_MODE);
199		cfg = CSR_READ_1(sc, RL_CFG2);
200		if (sc->rl_flags & RL_FLAG_MSI) {
201			cfg |= RL_CFG2_MSI;
202			CSR_WRITE_1(sc, RL_CFG2, cfg);
203		} else {
204			if ((cfg & RL_CFG2_MSI) != 0) {
205				cfg &= ~RL_CFG2_MSI;
206				CSR_WRITE_1(sc, RL_CFG2, cfg);
207			}
208		}
209		CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
210	}
211
212	sc->sc_product = PCI_PRODUCT(pa->pa_id);
213
214	/* Call bus-independent attach routine */
215	if (re_attach(sc, intrstr)) {
216		pci_intr_disestablish(pc, sc->sc_ih);
217		bus_space_unmap(sc->rl_btag, sc->rl_bhandle, psc->sc_iosize);
218	}
219}
220
221int
222re_pci_detach(struct device *self, int flags)
223{
224	struct re_pci_softc	*psc = (struct re_pci_softc *)self;
225	struct rl_softc		*sc = &psc->sc_rl;
226	struct ifnet		*ifp = &sc->sc_arpcom.ac_if;
227
228	/* Remove timeout handler */
229	timeout_del(&sc->timer_handle);
230
231	/* Detach PHY */
232	if (LIST_FIRST(&sc->sc_mii.mii_phys) != NULL)
233		mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
234
235	/* Delete media stuff */
236	ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
237	ether_ifdetach(ifp);
238	if_detach(ifp);
239
240	/* Disable interrupts */
241	if (sc->sc_ih != NULL)
242		pci_intr_disestablish(psc->sc_pc, sc->sc_ih);
243
244	/* Free pci resources */
245	bus_space_unmap(sc->rl_btag, sc->rl_bhandle, psc->sc_iosize);
246
247	return (0);
248}
249
250int
251re_pci_activate(struct device *self, int act)
252{
253	struct re_pci_softc	*psc = (struct re_pci_softc *)self;
254	struct rl_softc		*sc = &psc->sc_rl;
255	struct ifnet 		*ifp = &sc->sc_arpcom.ac_if;
256
257	switch (act) {
258	case DVACT_SUSPEND:
259		if (ifp->if_flags & IFF_RUNNING)
260			re_stop(ifp);
261		break;
262	case DVACT_RESUME:
263		if (ifp->if_flags & IFF_UP)
264			re_init(ifp);
265		break;
266	}
267
268	return (0);
269}
270