if_eqos_pci.c revision 1.2
1/* $NetBSD: if_eqos_pci.c,v 1.2 2023/10/26 18:02:51 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.2 2023/10/26 18:02:51 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	prop_dictionary_t prop;
109	bus_space_tag_t memt;
110	bus_space_handle_t memh;
111	int counts[PCI_INTR_TYPE_SIZE];
112	char intrbuf[PCI_INTRSTR_LEN];
113	bus_size_t memsize;
114	pcireg_t memtype;
115	const char *intrstr;
116	uint32_t dma_pbl = 0;
117
118	psc->sc_pc = pc;
119	psc->sc_tag = tag;
120	psc->sc_pcidevid = PCI_PRODUCT(pa->pa_id);
121
122	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, PCI_BAR0);
123	if (pci_mapreg_map(pa, PCI_BAR0, memtype, 0, &memt, &memh, NULL,
124		&memsize) != 0) {
125		aprint_error(": can't map mem space\n");
126		return;
127	}
128	sc->sc_dev = self;
129	sc->sc_bst = memt;
130	sc->sc_bsh = memh;
131	prop = device_properties(sc->sc_dev);
132
133#if 0 /* I don't know why dmat64 doesn't work... */
134	if (pci_dma64_available(pa)) {
135		aprint_verbose(", 64-bit DMA");
136		sc->sc_dmat = pa->pa_dmat64;
137	} else  {
138		aprint_verbose(", 32-bit DMA");
139		sc->sc_dmat = pa->pa_dmat;
140	}
141#else
142	sc->sc_dmat = pa->pa_dmat;
143#endif
144	sc->sc_phy_id = MII_PHY_ANY;
145	switch (psc->sc_pcidevid) {
146	case PCI_PRODUCT_INTEL_EHL_ETH:
147		sc->sc_csr_clock = 204800000;
148		dma_pbl = 32;
149		break;
150	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_RGMII:
151	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_RGMII:
152	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_SGMII_1G:
153	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_SGMII_1G:
154	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_SGMII_2_5G:
155	case PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_SGMII_2_5G:
156		sc->sc_csr_clock = 200000000;
157		dma_pbl = 32;
158		break;
159#if 0
160	case PCI_PRODUCT_INTEL_QUARTK_ETH:
161		dma_pbl = 16;
162#endif
163	default:
164		sc->sc_csr_clock = 200000000; /* XXX */
165	}
166	/* Defaults */
167	if (dma_pbl != 0) {
168		prop = device_properties(sc->sc_dev);
169		prop_dictionary_set_uint32(prop, "snps,pbl", dma_pbl);
170	}
171
172	if (eqos_attach(sc) != 0) {
173		aprint_error_dev(sc->sc_dev, "failed in eqos_attach()\n");
174		return;
175	}
176
177	/* Allocation settings */
178	counts[PCI_INTR_TYPE_MSI] = 1;
179	counts[PCI_INTR_TYPE_INTX] = 1;
180	if (pci_intr_alloc(pa, &psc->sc_intrs, counts, PCI_INTR_TYPE_MSI) != 0)
181	{
182		aprint_error_dev(sc->sc_dev, "failed to allocate interrupt\n");
183		return;
184	}
185	intrstr = pci_intr_string(pc, psc->sc_intrs[0], intrbuf,
186	    sizeof(intrbuf));
187	pci_intr_setattr(pc, &psc->sc_intrs[0], PCI_INTR_MPSAFE, true);
188	psc->sc_ihs[0] = pci_intr_establish_xname(pc, psc->sc_intrs[0],
189	    IPL_NET, eqos_intr, sc, device_xname(self));
190
191	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
192
193	if (pmf_device_register(self, NULL, NULL))
194		pmf_class_network_register(self, &sc->sc_ec.ec_if);
195	else
196		aprint_error_dev(self, "couldn't establish power handler\n");
197}
198