1 /* $NetBSD: if_eqos_pci.c,v 1.4 2023/12/19 09:39:55 skrll 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 <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: if_eqos_pci.c,v 1.4 2023/12/19 09:39:55 skrll Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/bus.h> 40 #include <sys/device.h> 41 #include <sys/rndsource.h> 42 43 #include <net/if_ether.h> 44 #include <net/if_media.h> 45 46 #include <dev/pci/pcireg.h> 47 #include <dev/pci/pcivar.h> 48 #include <dev/pci/pcidevs.h> 49 50 #include <dev/mii/miivar.h> 51 #include <dev/ic/dwc_eqos_var.h> 52 53 #define EQOS_PCI_MAX_INTR 1 54 55 static int eqos_pci_match(device_t, cfdata_t, void *); 56 static void eqos_pci_attach(device_t, device_t, void *); 57 58 struct eqos_pci_softc { 59 struct eqos_softc sc_eqos; 60 pci_chipset_tag_t sc_pc; 61 pcitag_t sc_tag; 62 void *sc_ihs[EQOS_PCI_MAX_INTR]; 63 pci_intr_handle_t *sc_intrs; 64 uint16_t sc_pcidevid; 65 }; 66 67 static const struct device_compatible_entry compat_data[] = { 68 { .id = PCI_ID_CODE(PCI_VENDOR_INTEL, 69 PCI_PRODUCT_INTEL_EHL_ETH) }, 70 { .id = PCI_ID_CODE(PCI_VENDOR_INTEL, 71 PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_RGMII) }, 72 { .id = PCI_ID_CODE(PCI_VENDOR_INTEL, 73 PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_RGMII) }, 74 { .id = PCI_ID_CODE(PCI_VENDOR_INTEL, 75 PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_SGMII_1G) }, 76 { .id = PCI_ID_CODE(PCI_VENDOR_INTEL, 77 PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_SGMII_1G) }, 78 { .id = PCI_ID_CODE(PCI_VENDOR_INTEL, 79 PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_SGMII_2_5G) }, 80 { .id = PCI_ID_CODE(PCI_VENDOR_INTEL, 81 PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_SGMII_2_5G) }, 82 83 PCI_COMPAT_EOL 84 }; 85 86 CFATTACH_DECL3_NEW(eqos_pci, sizeof(struct eqos_pci_softc), 87 eqos_pci_match, eqos_pci_attach, NULL, NULL, NULL, NULL, 88 0); 89 90 static int 91 eqos_pci_match(device_t parent, cfdata_t match, void *aux) 92 { 93 struct pci_attach_args *pa =aux; 94 95 return pci_compatible_match(pa, compat_data); 96 } 97 98 static void 99 eqos_pci_attach(device_t parent, device_t self, void *aux) 100 { 101 struct eqos_pci_softc * const psc = device_private(self); 102 struct eqos_softc * const sc = &psc->sc_eqos; 103 struct pci_attach_args *pa =aux; 104 const pci_chipset_tag_t pc = pa->pa_pc; 105 const pcitag_t tag = pa->pa_tag; 106 prop_dictionary_t prop; 107 bus_space_tag_t memt; 108 bus_space_handle_t memh; 109 int counts[PCI_INTR_TYPE_SIZE]; 110 char intrbuf[PCI_INTRSTR_LEN]; 111 bus_size_t memsize; 112 pcireg_t memtype; 113 const char *intrstr; 114 uint32_t dma_pbl = 0; 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 prop = device_properties(sc->sc_dev); 130 131 if (pci_dma64_available(pa)) 132 sc->sc_dmat = pa->pa_dmat64; 133 else 134 sc->sc_dmat = pa->pa_dmat; 135 136 sc->sc_phy_id = MII_PHY_ANY; 137 switch (psc->sc_pcidevid) { 138 case PCI_PRODUCT_INTEL_EHL_ETH: 139 sc->sc_csr_clock = 204800000; 140 dma_pbl = 32; 141 break; 142 case PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_RGMII: 143 case PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_RGMII: 144 case PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_SGMII_1G: 145 case PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_SGMII_1G: 146 case PCI_PRODUCT_INTEL_EHL_PSE_ETH_0_SGMII_2_5G: 147 case PCI_PRODUCT_INTEL_EHL_PSE_ETH_1_SGMII_2_5G: 148 sc->sc_dmat = pa->pa_dmat; /* 32bit DMA only */ 149 sc->sc_csr_clock = 200000000; 150 dma_pbl = 32; 151 break; 152 #if 0 153 case PCI_PRODUCT_INTEL_QUARTK_ETH: 154 dma_pbl = 16; 155 #endif 156 default: 157 sc->sc_csr_clock = 200000000; /* XXX */ 158 } 159 160 if (sc->sc_dmat == pa->pa_dmat64) 161 aprint_verbose(", 64-bit DMA"); 162 else 163 aprint_verbose(", 32-bit DMA"); 164 165 /* Defaults */ 166 if (dma_pbl != 0) { 167 prop = device_properties(sc->sc_dev); 168 prop_dictionary_set_uint32(prop, "snps,pbl", dma_pbl); 169 } 170 171 if (eqos_attach(sc) != 0) { 172 aprint_error_dev(sc->sc_dev, "failed in eqos_attach()\n"); 173 return; 174 } 175 176 /* Allocation settings */ 177 counts[PCI_INTR_TYPE_MSI] = 1; 178 counts[PCI_INTR_TYPE_INTX] = 1; 179 if (pci_intr_alloc(pa, &psc->sc_intrs, counts, PCI_INTR_TYPE_MSI) != 0) 180 { 181 aprint_error_dev(sc->sc_dev, "failed to allocate interrupt\n"); 182 return; 183 } 184 intrstr = pci_intr_string(pc, psc->sc_intrs[0], intrbuf, 185 sizeof(intrbuf)); 186 pci_intr_setattr(pc, &psc->sc_intrs[0], PCI_INTR_MPSAFE, true); 187 psc->sc_ihs[0] = pci_intr_establish_xname(pc, psc->sc_intrs[0], 188 IPL_NET, eqos_intr, sc, device_xname(self)); 189 190 aprint_normal_dev(self, "interrupting on %s\n", intrstr); 191 192 if (pmf_device_register(self, NULL, NULL)) 193 pmf_class_network_register(self, &sc->sc_ec.ec_if); 194 else 195 aprint_error_dev(self, "couldn't establish power handler\n"); 196 } 197