xref: /openbsd/sys/dev/pci/if_nep.c (revision a6445c1d)
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