1 /* $OpenBSD: if_nep.c,v 1.1 2014/02/15 15:19:46 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2014 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/ioctl.h> 22 #include <sys/socket.h> 23 24 #include <net/if.h> 25 #include <net/if_dl.h> 26 #include <net/if_media.h> 27 28 #ifdef INET 29 #include <netinet/in.h> 30 #include <netinet/if_ether.h> 31 #endif 32 33 #include <dev/mii/mii.h> 34 #include <dev/mii/miivar.h> 35 36 #include <dev/pci/pcireg.h> 37 #include <dev/pci/pcivar.h> 38 #include <dev/pci/pcidevs.h> 39 40 #ifdef __sparc64__ 41 #include <dev/ofw/openfirm.h> 42 extern void myetheraddr(u_char *); 43 #endif 44 45 #define FZC_MAC 0x180000 46 47 #define MIF_FRAME_OUTPUT (FZC_MAC + 0x16018) 48 #define MIF_FRAME_DATA 0xffff 49 #define MIF_FRAME_TA0 (1ULL << 16) 50 #define MIF_FRAME_TA1 (1ULL << 17) 51 #define MIF_FRAME_REG_SHIFT 18 52 #define MIF_FRAME_PHY_SHIFT 23 53 #define MIF_FRAME_READ 0x60020000 54 #define MIF_FRAME_WRITE 0x50020000 55 #define MIF_CONFIG (FZC_MAC + 0x16020) 56 #define MIF_CONFIG_INDIRECT_MODE (1ULL << 15) 57 58 struct nep_softc { 59 struct device sc_dev; 60 struct arpcom sc_ac; 61 struct mii_data sc_mii; 62 63 bus_dma_tag_t sc_dmat; 64 bus_space_tag_t sc_memt; 65 bus_space_handle_t sc_memh; 66 bus_size_t sc_mems; 67 void *sc_ih; 68 69 int sc_port; 70 71 struct timeout sc_tick_ch; 72 }; 73 74 int nep_match(struct device *, void *, void *); 75 void nep_attach(struct device *, struct device *, void *); 76 77 struct cfattach nep_ca = { 78 sizeof(struct nep_softc), nep_match, nep_attach 79 }; 80 81 struct cfdriver nep_cd = { 82 NULL, "nep", DV_DULL 83 }; 84 85 uint64_t nep_read(struct nep_softc *, uint32_t); 86 void nep_write(struct nep_softc *, uint32_t, uint64_t); 87 int nep_mii_readreg(struct device *, int, int); 88 void nep_mii_writereg(struct device *, int, int, int); 89 void nep_mii_statchg(struct device *); 90 int nep_mediachange(struct ifnet *); 91 void nep_mediastatus(struct ifnet *, struct ifmediareq *); 92 int nep_init(struct ifnet *ifp); 93 void nep_stop(struct ifnet *); 94 void nep_iff(struct nep_softc *); 95 void nep_tick(void *); 96 int nep_ioctl(struct ifnet *, u_long, caddr_t); 97 98 int 99 nep_match(struct device *parent, void *match, void *aux) 100 { 101 struct pci_attach_args *pa = aux; 102 103 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN && 104 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_NEPTUNE) 105 return 1; 106 return 0; 107 } 108 109 void 110 nep_attach(struct device *parent, struct device *self, void *aux) 111 { 112 struct nep_softc *sc = (struct nep_softc *)self; 113 struct pci_attach_args *pa = aux; 114 struct ifnet *ifp = &sc->sc_ac.ac_if; 115 struct mii_data *mii = &sc->sc_mii; 116 pcireg_t memtype; 117 uint64_t cfg; 118 119 sc->sc_dmat = pa->pa_dmat; 120 121 memtype = PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT; 122 if (pci_mapreg_map(pa, PCI_MAPREG_START, memtype, 0, 123 &sc->sc_memt, &sc->sc_memh, NULL, &sc->sc_mems, 0)) { 124 printf(": can't map registers\n"); 125 return; 126 } 127 128 sc->sc_port = pa->pa_function; 129 130 #ifdef __sparc64__ 131 if (OF_getprop(PCITAG_NODE(pa->pa_tag), "local-mac-address", 132 sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN) <= 0) 133 myetheraddr(sc->sc_ac.ac_enaddr); 134 #endif 135 136 printf(", address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr)); 137 138 cfg = nep_read(sc, MIF_CONFIG); 139 cfg &= ~MIF_CONFIG_INDIRECT_MODE; 140 nep_write(sc, MIF_CONFIG, cfg); 141 142 strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, sizeof(ifp->if_xname)); 143 ifp->if_softc = sc; 144 ifp->if_ioctl = nep_ioctl; 145 146 mii->mii_ifp = ifp; 147 mii->mii_readreg = nep_mii_readreg; 148 mii->mii_writereg = nep_mii_writereg; 149 mii->mii_statchg = nep_mii_statchg; 150 151 ifmedia_init(&mii->mii_media, 0, nep_mediachange, nep_mediastatus); 152 153 mii_attach(&sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY, sc->sc_port, 0); 154 ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_AUTO); 155 156 if_attach(ifp); 157 ether_ifattach(ifp); 158 159 timeout_set(&sc->sc_tick_ch, nep_tick, sc); 160 } 161 162 uint64_t 163 nep_read(struct nep_softc *sc, uint32_t reg) 164 { 165 return bus_space_read_8(sc->sc_memt, sc->sc_memh, reg); 166 } 167 168 void 169 nep_write(struct nep_softc *sc, uint32_t reg, uint64_t value) 170 { 171 bus_space_write_8(sc->sc_memt, sc->sc_memh, reg, value); 172 } 173 174 int 175 nep_mii_readreg(struct device *self, int phy, int reg) 176 { 177 struct nep_softc *sc = (struct nep_softc *)self; 178 uint64_t frame; 179 int n; 180 181 frame = MIF_FRAME_READ; 182 frame |= (reg << MIF_FRAME_REG_SHIFT) | (phy << MIF_FRAME_PHY_SHIFT); 183 nep_write(sc, MIF_FRAME_OUTPUT, frame); 184 for (n = 0; n < 1000; n++) { 185 delay(10); 186 frame = nep_read(sc, MIF_FRAME_OUTPUT); 187 if (frame & MIF_FRAME_TA0) 188 return (frame & MIF_FRAME_DATA); 189 } 190 191 printf("%s: %s timeout\n", __func__); 192 return (0); 193 } 194 195 void 196 nep_mii_writereg(struct device *self, int phy, int reg, int val) 197 { 198 struct nep_softc *sc = (struct nep_softc *)self; 199 uint64_t frame; 200 int n; 201 202 frame = MIF_FRAME_WRITE; 203 frame |= (reg << MIF_FRAME_REG_SHIFT) | (phy << MIF_FRAME_PHY_SHIFT); 204 frame |= (val & MIF_FRAME_DATA); 205 nep_write(sc, MIF_FRAME_OUTPUT, frame); 206 for (n = 0; n < 1000; n++) { 207 delay(10); 208 frame = nep_read(sc, MIF_FRAME_OUTPUT); 209 if (frame & MIF_FRAME_TA0) 210 return; 211 } 212 213 printf("%s: %s timeout\n", __func__); 214 return; 215 } 216 217 void 218 nep_mii_statchg(struct device *dev) 219 { 220 printf("%s\n", __func__); 221 } 222 223 int 224 nep_mediachange(struct ifnet *ifp) 225 { 226 printf("%s\n", __func__); 227 return 0; 228 } 229 230 void 231 nep_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 232 { 233 struct nep_softc *sc = (struct nep_softc *)ifp->if_softc; 234 235 mii_pollstat(&sc->sc_mii); 236 ifmr->ifm_active = sc->sc_mii.mii_media_active; 237 ifmr->ifm_status = sc->sc_mii.mii_media_status; 238 } 239 240 int 241 nep_init(struct ifnet *ifp) 242 { 243 struct nep_softc *sc = (struct nep_softc *)ifp->if_softc; 244 int s; 245 246 s = splnet(); 247 248 timeout_add_sec(&sc->sc_tick_ch, 1); 249 250 ifp->if_flags |= IFF_RUNNING; 251 ifp->if_flags &= ~IFF_OACTIVE; 252 ifp->if_timer = 0; 253 254 splx(s); 255 256 return 0; 257 } 258 259 void 260 nep_stop(struct ifnet *ifp) 261 { 262 struct nep_softc *sc = (struct nep_softc *)ifp->if_softc; 263 264 timeout_del(&sc->sc_tick_ch); 265 } 266 267 void 268 nep_iff(struct nep_softc *sc) 269 { 270 printf("%s\n", __func__); 271 } 272 273 void 274 nep_tick(void *arg) 275 { 276 struct nep_softc *sc = arg; 277 int s; 278 279 s = splnet(); 280 mii_tick(&sc->sc_mii); 281 splx(s); 282 283 timeout_add_sec(&sc->sc_tick_ch, 1); 284 } 285 286 int 287 nep_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 288 { 289 struct nep_softc *sc = (struct nep_softc *)ifp->if_softc; 290 struct ifaddr *ifa = (struct ifaddr *)data; 291 struct ifreq *ifr = (struct ifreq *)data; 292 int s, error = 0; 293 294 s = splnet(); 295 296 switch (cmd) { 297 case SIOCSIFADDR: 298 ifp->if_flags |= IFF_UP; 299 #ifdef INET 300 if (ifa->ifa_addr->sa_family == AF_INET) 301 arp_ifinit(&sc->sc_ac, ifa); 302 #endif 303 /* FALLTHROUGH */ 304 305 case SIOCSIFFLAGS: 306 if (ISSET(ifp->if_flags, IFF_UP)) { 307 if (ISSET(ifp->if_flags, IFF_RUNNING)) 308 error = ENETRESET; 309 else 310 nep_init(ifp); 311 } else { 312 if (ISSET(ifp->if_flags, IFF_RUNNING)) 313 nep_stop(ifp); 314 } 315 break; 316 317 case SIOCGIFMEDIA: 318 case SIOCSIFMEDIA: 319 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd); 320 break; 321 322 default: 323 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 324 } 325 326 if (error == ENETRESET) { 327 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == 328 (IFF_UP | IFF_RUNNING)) 329 nep_iff(sc); 330 error = 0; 331 } 332 333 splx(s); 334 return (error); 335 } 336