1/*-
2 * Copyright (c) 1998, 2001 Nicolas Souchu
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: stable/11/sys/dev/iicbus/if_ic.c 315221 2017-03-14 02:06:03Z pfg $");
29
30/*
31 * I2C bus IP driver
32 */
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/mbuf.h>
37#include <sys/socket.h>
38#include <sys/filio.h>
39#include <sys/sockio.h>
40#include <sys/kernel.h>
41#include <sys/lock.h>
42#include <sys/module.h>
43#include <sys/mutex.h>
44#include <sys/bus.h>
45#include <sys/time.h>
46#include <sys/malloc.h>
47
48#include <net/if.h>
49#include <net/if_var.h>
50#include <net/if_types.h>
51#include <net/netisr.h>
52
53#include <net/route.h>
54#include <netinet/in.h>
55#include <netinet/in_systm.h>
56#include <netinet/in_var.h>
57#include <netinet/ip.h>
58#include <netinet/if_ether.h>
59
60#include <net/bpf.h>
61
62#include <dev/iicbus/iiconf.h>
63#include <dev/iicbus/iicbus.h>
64
65#include "iicbus_if.h"
66
67#define PCF_MASTER_ADDRESS 0xaa
68
69#define ICHDRLEN	sizeof(u_int32_t)
70#define ICMTU		1500		/* default mtu */
71
72struct ic_softc {
73	struct ifnet *ic_ifp;
74	device_t ic_dev;
75
76	u_char ic_addr;			/* peer I2C address */
77
78	int ic_flags;
79
80	char *ic_obuf;
81	char *ic_ifbuf;
82	char *ic_cp;
83
84	int ic_xfercnt;
85
86	int ic_iferrs;
87
88	struct mtx ic_lock;
89};
90
91#define	IC_SENDING		0x0001
92#define	IC_OBUF_BUSY		0x0002
93#define	IC_IFBUF_BUSY		0x0004
94#define	IC_BUFFERS_BUSY		(IC_OBUF_BUSY | IC_IFBUF_BUSY)
95#define	IC_BUFFER_WAITER	0x0004
96
97static devclass_t ic_devclass;
98
99static int icprobe(device_t);
100static int icattach(device_t);
101
102static int icioctl(struct ifnet *, u_long, caddr_t);
103static int icoutput(struct ifnet *, struct mbuf *, const struct sockaddr *,
104               struct route *);
105
106static int icintr(device_t, int, char *);
107
108static device_method_t ic_methods[] = {
109	/* device interface */
110	DEVMETHOD(device_probe,		icprobe),
111	DEVMETHOD(device_attach,	icattach),
112
113	/* iicbus interface */
114	DEVMETHOD(iicbus_intr,		icintr),
115
116	{ 0, 0 }
117};
118
119static driver_t ic_driver = {
120	"ic",
121	ic_methods,
122	sizeof(struct ic_softc),
123};
124
125static void
126ic_alloc_buffers(struct ic_softc *sc, int mtu)
127{
128	char *obuf, *ifbuf;
129
130	obuf = malloc(mtu + ICHDRLEN, M_DEVBUF, M_WAITOK);
131	ifbuf = malloc(mtu + ICHDRLEN, M_DEVBUF, M_WAITOK);
132
133	mtx_lock(&sc->ic_lock);
134	while (sc->ic_flags & IC_BUFFERS_BUSY) {
135		sc->ic_flags |= IC_BUFFER_WAITER;
136		mtx_sleep(sc, &sc->ic_lock, 0, "icalloc", 0);
137		sc->ic_flags &= ~IC_BUFFER_WAITER;
138	}
139
140	free(sc->ic_obuf, M_DEVBUF);
141	free(sc->ic_ifbuf, M_DEVBUF);
142	sc->ic_obuf = obuf;
143	sc->ic_ifbuf = ifbuf;
144	sc->ic_ifp->if_mtu = mtu;
145	mtx_unlock(&sc->ic_lock);
146}
147
148/*
149 * icprobe()
150 */
151static int
152icprobe(device_t dev)
153{
154	return (BUS_PROBE_NOWILDCARD);
155}
156
157/*
158 * icattach()
159 */
160static int
161icattach(device_t dev)
162{
163	struct ic_softc *sc = (struct ic_softc *)device_get_softc(dev);
164	struct ifnet *ifp;
165
166	ifp = sc->ic_ifp = if_alloc(IFT_PARA);
167	if (ifp == NULL)
168		return (ENOSPC);
169
170	mtx_init(&sc->ic_lock, device_get_nameunit(dev), MTX_NETWORK_LOCK,
171	    MTX_DEF);
172	sc->ic_addr = PCF_MASTER_ADDRESS;	/* XXX only PCF masters */
173	sc->ic_dev = dev;
174
175	ifp->if_softc = sc;
176	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
177	ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
178	ifp->if_ioctl = icioctl;
179	ifp->if_output = icoutput;
180	ifp->if_hdrlen = 0;
181	ifp->if_addrlen = 0;
182	ifp->if_snd.ifq_maxlen = ifqmaxlen;
183
184	ic_alloc_buffers(sc, ICMTU);
185
186	if_attach(ifp);
187
188	bpfattach(ifp, DLT_NULL, ICHDRLEN);
189
190	return (0);
191}
192
193/*
194 * iciotcl()
195 */
196static int
197icioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
198{
199	struct ic_softc *sc = ifp->if_softc;
200	device_t icdev = sc->ic_dev;
201	device_t parent = device_get_parent(icdev);
202	struct ifaddr *ifa = (struct ifaddr *)data;
203	struct ifreq *ifr = (struct ifreq *)data;
204	int error;
205
206	switch (cmd) {
207
208	case SIOCAIFADDR:
209	case SIOCSIFADDR:
210		if (ifa->ifa_addr->sa_family != AF_INET)
211			return (EAFNOSUPPORT);
212		mtx_lock(&sc->ic_lock);
213		ifp->if_flags |= IFF_UP;
214		goto locked;
215	case SIOCSIFFLAGS:
216		mtx_lock(&sc->ic_lock);
217	locked:
218		if ((!(ifp->if_flags & IFF_UP)) &&
219		    (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
220
221			/* XXX disable PCF */
222			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
223			mtx_unlock(&sc->ic_lock);
224
225			/* IFF_UP is not set, try to release the bus anyway */
226			iicbus_release_bus(parent, icdev);
227			break;
228		}
229		if (((ifp->if_flags & IFF_UP)) &&
230		    (!(ifp->if_drv_flags & IFF_DRV_RUNNING))) {
231			mtx_unlock(&sc->ic_lock);
232			if ((error = iicbus_request_bus(parent, icdev,
233			    IIC_WAIT | IIC_INTR)))
234				return (error);
235			mtx_lock(&sc->ic_lock);
236			iicbus_reset(parent, IIC_FASTEST, 0, NULL);
237			ifp->if_drv_flags |= IFF_DRV_RUNNING;
238		}
239		mtx_unlock(&sc->ic_lock);
240		break;
241
242	case SIOCSIFMTU:
243		ic_alloc_buffers(sc, ifr->ifr_mtu);
244		break;
245
246	case SIOCGIFMTU:
247		mtx_lock(&sc->ic_lock);
248		ifr->ifr_mtu = sc->ic_ifp->if_mtu;
249		mtx_unlock(&sc->ic_lock);
250		break;
251
252	case SIOCADDMULTI:
253	case SIOCDELMULTI:
254		if (ifr == NULL)
255			return (EAFNOSUPPORT);		/* XXX */
256		switch (ifr->ifr_addr.sa_family) {
257		case AF_INET:
258			break;
259		default:
260			return (EAFNOSUPPORT);
261		}
262		break;
263	default:
264		return (EINVAL);
265	}
266	return (0);
267}
268
269/*
270 * icintr()
271 */
272static int
273icintr(device_t dev, int event, char *ptr)
274{
275	struct ic_softc *sc = (struct ic_softc *)device_get_softc(dev);
276	struct mbuf *top;
277	int len;
278
279	mtx_lock(&sc->ic_lock);
280
281	switch (event) {
282
283	case INTR_GENERAL:
284	case INTR_START:
285		sc->ic_cp = sc->ic_ifbuf;
286		sc->ic_xfercnt = 0;
287		sc->ic_flags |= IC_IFBUF_BUSY;
288		break;
289
290	case INTR_STOP:
291
292		/* if any error occurred during transfert,
293		 * drop the packet */
294		sc->ic_flags &= ~IC_IFBUF_BUSY;
295		if ((sc->ic_flags & (IC_BUFFERS_BUSY | IC_BUFFER_WAITER)) ==
296		    IC_BUFFER_WAITER)
297			wakeup(&sc);
298		if (sc->ic_iferrs)
299			goto err;
300		if ((len = sc->ic_xfercnt) == 0)
301			break;					/* ignore */
302		if (len <= ICHDRLEN)
303			goto err;
304		len -= ICHDRLEN;
305		if_inc_counter(sc->ic_ifp, IFCOUNTER_IPACKETS, 1);
306		if_inc_counter(sc->ic_ifp, IFCOUNTER_IBYTES, len);
307		BPF_TAP(sc->ic_ifp, sc->ic_ifbuf, len + ICHDRLEN);
308		top = m_devget(sc->ic_ifbuf + ICHDRLEN, len, 0, sc->ic_ifp, 0);
309		if (top) {
310			mtx_unlock(&sc->ic_lock);
311			M_SETFIB(top, sc->ic_ifp->if_fib);
312			netisr_dispatch(NETISR_IP, top);
313			mtx_lock(&sc->ic_lock);
314		}
315		break;
316	err:
317		if_printf(sc->ic_ifp, "errors (%d)!\n", sc->ic_iferrs);
318		sc->ic_iferrs = 0;			/* reset error count */
319		if_inc_counter(sc->ic_ifp, IFCOUNTER_IERRORS, 1);
320		break;
321
322	case INTR_RECEIVE:
323		if (sc->ic_xfercnt >= sc->ic_ifp->if_mtu + ICHDRLEN) {
324			sc->ic_iferrs++;
325		} else {
326			*sc->ic_cp++ = *ptr;
327			sc->ic_xfercnt++;
328		}
329		break;
330
331	case INTR_NOACK:			/* xfer terminated by master */
332		break;
333
334	case INTR_TRANSMIT:
335		*ptr = 0xff;					/* XXX */
336	  	break;
337
338	case INTR_ERROR:
339		sc->ic_iferrs++;
340		break;
341
342	default:
343		panic("%s: unknown event (%d)!", __func__, event);
344	}
345
346	mtx_unlock(&sc->ic_lock);
347	return (0);
348}
349
350/*
351 * icoutput()
352 */
353static int
354icoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
355    struct route *ro)
356{
357	struct ic_softc *sc = ifp->if_softc;
358	device_t icdev = sc->ic_dev;
359	device_t parent = device_get_parent(icdev);
360	int len, sent;
361	struct mbuf *mm;
362	u_char *cp;
363	u_int32_t hdr;
364
365	/* BPF writes need to be handled specially. */
366	if (dst->sa_family == AF_UNSPEC)
367		bcopy(dst->sa_data, &hdr, sizeof(hdr));
368	else
369		hdr = dst->sa_family;
370
371	mtx_lock(&sc->ic_lock);
372	ifp->if_drv_flags |= IFF_DRV_RUNNING;
373
374	/* already sending? */
375	if (sc->ic_flags & IC_SENDING) {
376		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
377		goto error;
378	}
379
380	/* insert header */
381	bcopy ((char *)&hdr, sc->ic_obuf, ICHDRLEN);
382
383	cp = sc->ic_obuf + ICHDRLEN;
384	len = 0;
385	mm = m;
386	do {
387		if (len + mm->m_len > sc->ic_ifp->if_mtu) {
388			/* packet too large */
389			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
390			goto error;
391		}
392
393		bcopy(mtod(mm,char *), cp, mm->m_len);
394		cp += mm->m_len;
395		len += mm->m_len;
396
397	} while ((mm = mm->m_next));
398
399	BPF_MTAP2(ifp, &hdr, sizeof(hdr), m);
400
401	sc->ic_flags |= (IC_SENDING | IC_OBUF_BUSY);
402
403	m_freem(m);
404	mtx_unlock(&sc->ic_lock);
405
406	/* send the packet */
407	if (iicbus_block_write(parent, sc->ic_addr, sc->ic_obuf,
408				len + ICHDRLEN, &sent))
409
410		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
411	else {
412		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
413		if_inc_counter(ifp, IFCOUNTER_OBYTES, len);
414	}
415
416	mtx_lock(&sc->ic_lock);
417	sc->ic_flags &= ~(IC_SENDING | IC_OBUF_BUSY);
418	if ((sc->ic_flags & (IC_BUFFERS_BUSY | IC_BUFFER_WAITER)) ==
419	    IC_BUFFER_WAITER)
420		wakeup(&sc);
421	mtx_unlock(&sc->ic_lock);
422
423	return (0);
424
425error:
426	m_freem(m);
427	mtx_unlock(&sc->ic_lock);
428
429	return(0);
430}
431
432DRIVER_MODULE(ic, iicbus, ic_driver, ic_devclass, 0, 0);
433MODULE_DEPEND(ic, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
434MODULE_VERSION(ic, 1);
435