if_eqos_pci.c revision 1.1
1/* $NetBSD: if_eqos_pci.c,v 1.1 2023/10/20 10:09:43 msaitoh Exp $ */
2
3/*-
4 * Copyright (c) 2023 Masanobu SAITOH <msaitoh@netbsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * TODO:
31 *	Use multi vector MSI to support multiqueue.
32 *
33 */
34
35#include "opt_net_mpsafe.h"
36
37#include <sys/cdefs.h>
38__KERNEL_RCSID(0, "$NetBSD: if_eqos_pci.c,v 1.1 2023/10/20 10:09:43 msaitoh Exp $");
39
40#include <sys/param.h>
41#include <sys/bus.h>
42#include <sys/device.h>
43#include <sys/rndsource.h>
44
45#include <net/if_ether.h>
46#include <net/if_media.h>
47
48#include <dev/pci/pcireg.h>
49#include <dev/pci/pcivar.h>
50#include <dev/pci/pcidevs.h>
51
52#include <dev/mii/miivar.h>
53#include <dev/ic/dwc_eqos_var.h>
54
55#define EQOS_PCI_MAX_INTR	1
56
57static int eqos_pci_match(device_t, cfdata_t, void *);
58static void eqos_pci_attach(device_t, device_t, void *);
59
60struct eqos_pci_softc {
61	struct eqos_softc	sc_eqos;
62	pci_chipset_tag_t	sc_pc;
63	pcitag_t		sc_tag;
64	void			*sc_ihs[EQOS_PCI_MAX_INTR];
65	pci_intr_handle_t	*sc_intrs;
66	uint16_t		sc_pcidevid;
67};
68
69static const struct device_compatible_entry compat_data[] = {
70	{ .id = PCI_ID_CODE(PCI_VENDOR_INTEL,
71		    PCI_PRODUCT_INTEL_EHL_ETH) },
72	{ .id = PCI_ID_CODE(PCI_VENDOR_INTEL,
73		    PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_RGMII) },
74	{ .id = PCI_ID_CODE(PCI_VENDOR_INTEL,
75		    PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_RGMII) },
76	{ .id = PCI_ID_CODE(PCI_VENDOR_INTEL,
77		    PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_SGMII_1G) },
78	{ .id = PCI_ID_CODE(PCI_VENDOR_INTEL,
79		    PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_SGMII_1G) },
80	{ .id = PCI_ID_CODE(PCI_VENDOR_INTEL,
81		    PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_SGMII_2_5G) },
82	{ .id = PCI_ID_CODE(PCI_VENDOR_INTEL,
83		    PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_SGMII_2_5G) },
84
85	PCI_COMPAT_EOL
86};
87
88CFATTACH_DECL3_NEW(eqos_pci, sizeof(struct eqos_pci_softc),
89    eqos_pci_match, eqos_pci_attach, NULL, NULL, NULL, NULL,
90    0);
91
92static int
93eqos_pci_match(device_t parent, cfdata_t match, void *aux)
94{
95	struct pci_attach_args *pa =aux;
96
97	return pci_compatible_match(pa, compat_data);
98}
99
100static void
101eqos_pci_attach(device_t parent, device_t self, void *aux)
102{
103	struct eqos_pci_softc * const psc = device_private(self);
104	struct eqos_softc * const sc = &psc->sc_eqos;
105	struct pci_attach_args *pa =aux;
106	const pci_chipset_tag_t pc = pa->pa_pc;
107	const pcitag_t tag = pa->pa_tag;
108	bus_space_tag_t memt;
109	bus_space_handle_t memh;
110	int counts[PCI_INTR_TYPE_SIZE];
111	char intrbuf[PCI_INTRSTR_LEN];
112	bus_size_t memsize;
113	pcireg_t memtype;
114	const char *intrstr;
115
116	psc->sc_pc = pc;
117	psc->sc_tag = tag;
118	psc->sc_pcidevid = PCI_PRODUCT(pa->pa_id);
119
120	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, PCI_BAR0);
121	if (pci_mapreg_map(pa, PCI_BAR0, memtype, 0, &memt, &memh, NULL,
122		&memsize) != 0) {
123		aprint_error(": can't map mem space\n");
124		return;
125	}
126	sc->sc_dev = self;
127	sc->sc_bst = memt;
128	sc->sc_bsh = memh;
129
130#if 0 /* I don't know why dmat64 doesn't work... */
131	if (pci_dma64_available(pa)) {
132		aprint_verbose(", 64-bit DMA");
133		sc->sc_dmat = pa->pa_dmat64;
134	} else  {
135		aprint_verbose(", 32-bit DMA");
136		sc->sc_dmat = pa->pa_dmat;
137	}
138#else
139	sc->sc_dmat = pa->pa_dmat;
140#endif
141	sc->sc_phy_id = MII_PHY_ANY;
142	switch (psc->sc_pcidevid) {
143	case PCI_PRODUCT_INTEL_EHL_ETH:
144		sc->sc_csr_clock = 204800000;
145		break;
146	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_RGMII:
147	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_RGMII:
148	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_SGMII_1G:
149	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_SGMII_1G:
150	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_SGMII_2_5G:
151	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_SGMII_2_5G:
152		sc->sc_csr_clock = 200000000;
153		break;
154	default:
155		sc->sc_csr_clock = 200000000; /* XXX */
156	}
157	if (eqos_attach(sc) != 0) {
158		aprint_error_dev(sc->sc_dev, "failed in eqos_attach()\n");
159		return;
160	}
161
162	/* Allocation settings */
163	counts[PCI_INTR_TYPE_MSI] = 1;
164	counts[PCI_INTR_TYPE_INTX] = 1;
165	if (pci_intr_alloc(pa, &psc->sc_intrs, counts, PCI_INTR_TYPE_MSI) != 0)
166	{
167		aprint_error_dev(sc->sc_dev, "failed to allocate interrupt\n");
168		return;
169	}
170	intrstr = pci_intr_string(pc, psc->sc_intrs[0], intrbuf,
171	    sizeof(intrbuf));
172	pci_intr_setattr(pc, &psc->sc_intrs[0], PCI_INTR_MPSAFE, true);
173	psc->sc_ihs[0] = pci_intr_establish_xname(pc, psc->sc_intrs[0],
174	    IPL_NET, eqos_intr, sc, device_xname(self));
175
176	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
177
178	if (pmf_device_register(self, NULL, NULL))
179		pmf_class_network_register(self, &sc->sc_ec.ec_if);
180	else
181		aprint_error_dev(self, "couldn't establish power handler\n");
182}
183