1176348Smarcel/*-
2176348Smarcel * Copyright (c) 2000-2001 Benno Rice
3176348Smarcel * Copyright (c) 2007 Semihalf, Rafal Jaworowski <raj@semihalf.com>
4176348Smarcel * All rights reserved.
5176348Smarcel *
6176348Smarcel * Redistribution and use in source and binary forms, with or without
7176348Smarcel * modification, are permitted provided that the following conditions
8176348Smarcel * are met:
9176348Smarcel * 1. Redistributions of source code must retain the above copyright
10176348Smarcel *    notice, this list of conditions and the following disclaimer.
11176348Smarcel * 2. Redistributions in binary form must reproduce the above copyright
12176348Smarcel *    notice, this list of conditions and the following disclaimer in the
13176348Smarcel *    documentation and/or other materials provided with the distribution.
14176348Smarcel *
15176348Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16176348Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17176348Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18176348Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19176348Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20176348Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21176348Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22176348Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23176348Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24176348Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25176348Smarcel * SUCH DAMAGE.
26176348Smarcel */
27176348Smarcel
28176348Smarcel#include <sys/cdefs.h>
29176348Smarcel__FBSDID("$FreeBSD$");
30176348Smarcel
31176348Smarcel#include <sys/param.h>
32176348Smarcel#include <sys/types.h>
33176348Smarcel#include <sys/socket.h>
34176348Smarcel
35176348Smarcel#include <net/if.h>
36176348Smarcel#include <netinet/in.h>
37176348Smarcel#include <netinet/in_systm.h>
38176348Smarcel#include <netinet/if_ether.h>
39176348Smarcel#include <netinet/ip.h>
40176348Smarcel
41176348Smarcel#include <stand.h>
42176348Smarcel#include <net.h>
43176348Smarcel#include <netif.h>
44176348Smarcel
45176348Smarcel#include "api_public.h"
46182723Sraj#include "glue.h"
47176348Smarcel#include "libuboot.h"
48176348Smarcel
49176348Smarcelstatic int	net_probe(struct netif *, void *);
50176348Smarcelstatic int	net_match(struct netif *, void *);
51176348Smarcelstatic void	net_init(struct iodesc *, void *);
52176348Smarcelstatic int	net_get(struct iodesc *, void *, size_t, time_t);
53176348Smarcelstatic int	net_put(struct iodesc *, void *, size_t);
54176348Smarcelstatic void	net_end(struct netif *);
55176348Smarcel
56183599Srajextern struct netif_stats net_stats[];
57176348Smarcel
58176348Smarcelstruct netif_dif net_ifs[] = {
59177152Sobrien	/*	dif_unit	dif_nsel	dif_stats	dif_private */
60176348Smarcel	{	0,		1,		&net_stats[0],	0,	},
61176348Smarcel};
62176348Smarcel
63176348Smarcelstruct netif_stats net_stats[NENTS(net_ifs)];
64176348Smarcel
65176348Smarcelstruct netif_driver uboot_net = {
66176348Smarcel	"uboot_eth",		/* netif_bname */
67176348Smarcel	net_match,		/* netif_match */
68176348Smarcel	net_probe,		/* netif_probe */
69176348Smarcel	net_init,		/* netif_init */
70176348Smarcel	net_get,		/* netif_get */
71176348Smarcel	net_put,		/* netif_put */
72176348Smarcel	net_end,		/* netif_end */
73176348Smarcel	net_ifs,		/* netif_ifs */
74176348Smarcel	NENTS(net_ifs)		/* netif_nifs */
75176348Smarcel};
76176348Smarcel
77176348Smarcelstruct uboot_softc {
78183599Sraj	uint32_t	sc_pad;
79183599Sraj	uint8_t		sc_rxbuf[ETHER_MAX_LEN];
80183599Sraj	uint8_t		sc_txbuf[ETHER_MAX_LEN + PKTALIGN];
81183599Sraj	uint8_t		*sc_txbufp;
82176348Smarcel	int		sc_handle;	/* device handle for ub_dev_xxx */
83176348Smarcel};
84176348Smarcel
85176348Smarcelstatic struct uboot_softc uboot_softc;
86176348Smarcel
87176348Smarcelstatic int
88176348Smarcelnet_match(struct netif *nif, void *machdep_hint)
89176348Smarcel{
90176348Smarcel	char **a = (char **)machdep_hint;
91176348Smarcel
92176348Smarcel	if (memcmp("net", *a, 3) == 0)
93177108Sraj		return (1);
94177108Sraj
95176348Smarcel	printf("net_match: could not match network device\n");
96177108Sraj	return (0);
97176348Smarcel}
98176348Smarcel
99176348Smarcelstatic int
100176348Smarcelnet_probe(struct netif *nif, void *machdep_hint)
101176348Smarcel{
102182723Sraj	struct device_info *di;
103182723Sraj	int i;
104176348Smarcel
105176348Smarcel	for (i = 0; i < devs_no; i++)
106182723Sraj		if ((di = ub_dev_get(i)) != NULL)
107176348Smarcel			if (di->type == DEV_TYP_NET)
108176348Smarcel				break;
109182723Sraj
110176348Smarcel	if (i == devs_no) {
111177152Sobrien		printf("net_probe: no network devices found, maybe not"
112177152Sobrien		    " enumerated yet..?\n");
113177108Sraj		return (-1);
114176348Smarcel	}
115176348Smarcel
116176348Smarcel#if defined(NETIF_DEBUG)
117176348Smarcel	printf("net_probe: network device found: %d\n", i);
118176348Smarcel#endif
119176348Smarcel	uboot_softc.sc_handle = i;
120177108Sraj
121177108Sraj	return (0);
122176348Smarcel}
123176348Smarcel
124176348Smarcelstatic int
125176348Smarcelnet_put(struct iodesc *desc, void *pkt, size_t len)
126176348Smarcel{
127182723Sraj	struct netif *nif = desc->io_netif;
128182723Sraj	struct uboot_softc *sc = nif->nif_devdata;
129182723Sraj	size_t sendlen;
130182723Sraj	ssize_t rv;
131176348Smarcel
132182723Sraj#if defined(NETIF_DEBUG)
133182723Sraj	struct ether_header *eh;
134176348Smarcel
135193111Smarcel	printf("net_put: desc %p, pkt %p, len %d\n", desc, pkt, len);
136176348Smarcel	eh = pkt;
137176348Smarcel	printf("dst: %s ", ether_sprintf(eh->ether_dhost));
138176348Smarcel	printf("src: %s ", ether_sprintf(eh->ether_shost));
139176348Smarcel	printf("type: 0x%x\n", eh->ether_type & 0xffff);
140176348Smarcel#endif
141176348Smarcel
142176348Smarcel	if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) {
143176348Smarcel		sendlen = ETHER_MIN_LEN - ETHER_CRC_LEN;
144176348Smarcel		bzero(sc->sc_txbufp, sendlen);
145176348Smarcel	} else
146176348Smarcel		sendlen = len;
147176348Smarcel
148176348Smarcel	memcpy(sc->sc_txbufp, pkt, len);
149176348Smarcel
150176348Smarcel	rv = ub_dev_send(sc->sc_handle, sc->sc_txbufp, sendlen);
151176348Smarcel
152176348Smarcel#if defined(NETIF_DEBUG)
153176348Smarcel	printf("net_put: ub_send returned %d\n", rv);
154176348Smarcel#endif
155176348Smarcel	if (rv == 0)
156176348Smarcel		rv = len;
157176348Smarcel	else
158176348Smarcel		rv = -1;
159176348Smarcel
160177108Sraj	return (rv);
161176348Smarcel}
162176348Smarcel
163176348Smarcelstatic int
164176348Smarcelnet_get(struct iodesc *desc, void *pkt, size_t len, time_t timeout)
165176348Smarcel{
166183599Sraj	struct netif *nif = desc->io_netif;
167183599Sraj	struct uboot_softc *sc = nif->nif_devdata;
168183599Sraj	time_t t;
169183599Sraj	int err, rlen;
170176348Smarcel
171176348Smarcel#if defined(NETIF_DEBUG)
172193111Smarcel	printf("net_get: pkt %p, len %d, timeout %d\n", pkt, len, timeout);
173176348Smarcel#endif
174176348Smarcel	t = getsecs();
175176348Smarcel	do {
176183598Sraj		err = ub_dev_recv(sc->sc_handle, sc->sc_rxbuf, len, &rlen);
177176348Smarcel
178183598Sraj		if (err != 0) {
179183598Sraj			printf("net_get: ub_dev_recv() failed, error=%d\n",
180183598Sraj			    err);
181183598Sraj			rlen = 0;
182183598Sraj			break;
183183598Sraj		}
184183598Sraj	} while ((rlen == -1 || rlen == 0) && (getsecs() - t < timeout));
185183598Sraj
186176348Smarcel#if defined(NETIF_DEBUG)
187183598Sraj	printf("net_get: received len %d (%x)\n", rlen, rlen);
188176348Smarcel#endif
189176348Smarcel
190183598Sraj	if (rlen > 0) {
191183598Sraj		memcpy(pkt, sc->sc_rxbuf, MIN(len, rlen));
192183598Sraj		if (rlen != len) {
193176348Smarcel#if defined(NETIF_DEBUG)
194183598Sraj			printf("net_get: len %x, rlen %x\n", len, rlen);
195176348Smarcel#endif
196176348Smarcel		}
197183598Sraj		return (rlen);
198176348Smarcel	}
199176348Smarcel
200177108Sraj	return (-1);
201176348Smarcel}
202176348Smarcel
203176348Smarcelstatic void
204176348Smarcelnet_init(struct iodesc *desc, void *machdep_hint)
205176348Smarcel{
206182723Sraj	struct netif *nif = desc->io_netif;
207182723Sraj	struct uboot_softc *sc;
208182723Sraj	struct device_info *di;
209182723Sraj	int err;
210177152Sobrien
211176348Smarcel	sc = nif->nif_devdata = &uboot_softc;
212176348Smarcel
213182723Sraj	if ((err = ub_dev_open(sc->sc_handle)) != 0)
214176348Smarcel		panic("%s%d: initialisation failed with error %d\n",
215177108Sraj		    nif->nif_driver->netif_bname, nif->nif_unit, err);
216176348Smarcel
217176348Smarcel	/* Get MAC address */
218176348Smarcel	di = ub_dev_get(sc->sc_handle);
219176348Smarcel	memcpy(desc->myea, di->di_net.hwaddr, 6);
220176348Smarcel	if (memcmp (desc->myea, "\0\0\0\0\0\0", 6) == 0) {
221176348Smarcel		panic("%s%d: empty ethernet address!",
222177108Sraj		    nif->nif_driver->netif_bname, nif->nif_unit);
223176348Smarcel	}
224176348Smarcel
225176348Smarcel#if defined(NETIF_DEBUG)
226176348Smarcel	printf("network: %s%d attached to %s\n", nif->nif_driver->netif_bname,
227177108Sraj	    nif->nif_unit, ether_sprintf(desc->myea));
228176348Smarcel#endif
229176348Smarcel
230176348Smarcel	/* Set correct alignment for TX packets */
231176348Smarcel	sc->sc_txbufp = sc->sc_txbuf;
232176348Smarcel	if ((unsigned long)sc->sc_txbufp % PKTALIGN)
233177152Sobrien		sc->sc_txbufp += PKTALIGN -
234177152Sobrien		    (unsigned long)sc->sc_txbufp % PKTALIGN;
235176348Smarcel}
236176348Smarcel
237176348Smarcelstatic void
238176348Smarcelnet_end(struct netif *nif)
239176348Smarcel{
240182723Sraj	struct uboot_softc *sc = nif->nif_devdata;
241182723Sraj	int err;
242176348Smarcel
243182723Sraj	if ((err = ub_dev_close(sc->sc_handle)) != 0)
244176348Smarcel		panic("%s%d: net_end failed with error %d\n",
245177108Sraj		    nif->nif_driver->netif_bname, nif->nif_unit, err);
246176348Smarcel}
247