1/* Intel PRO/1000 Family Driver
2 * Copyright (C) 2004 Marcus Overhagen <marcus@overhagen.de>. All rights reserved.
3 *
4 * Permission to use, copy, modify and distribute this software and its
5 * documentation for any purpose and without fee is hereby granted, provided
6 * that the above copyright notice appear in all copies, and that both the
7 * copyright notice and this permission notice appear in supporting documentation.
8 *
9 * Marcus Overhagen makes no representations about the suitability of this software
10 * for any purpose. It is provided "as is" without express or implied warranty.
11 *
12 * MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
13 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS
14 * OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
15 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20
21#include "debug.h"
22#include "device.h"
23#include "driver.h"
24#include "util.h"
25#include "if_em.h"
26#include "if_compat.h"
27
28#include <KernelExport.h>
29#include <driver_settings.h>
30
31#include <fcntl.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#ifdef HAIKU_TARGET_PLATFORM_HAIKU
36#	include <net/if_media.h>
37#endif
38
39#undef malloc
40#undef free
41
42static int32 gOpenMask = 0;
43
44int  em_attach(device_t);
45int  em_detach(device_t);
46void em_media_status(struct ifnet *, struct ifmediareq *);
47
48
49static void
50ipro1000_read_settings(ipro1000_device *device)
51{
52	void *handle;
53	const char *param;
54	int mtu;
55
56	handle = load_driver_settings("ipro1000");
57	if (!handle)
58		return;
59
60	param = get_driver_parameter(handle, "mtu", "-1", "-1");
61	mtu = atoi(param);
62	if (mtu >= 50 && mtu <= 1500)
63		device->maxframesize = mtu + ENET_HEADER_SIZE;
64	else if (mtu != -1)
65		dprintf("ipro1000: unsupported mtu setting '%s' ignored\n", param);
66
67	unload_driver_settings(handle);
68}
69
70
71status_t
72ipro1000_open(const char *name, uint32 flags, void** cookie)
73{
74	ipro1000_device *device;
75	char *deviceName;
76	int dev_id;
77	int mask;
78
79	DEVICE_DEBUGOUT("ipro1000_open()");
80
81	for (dev_id = 0; (deviceName = gDevNameList[dev_id]) != NULL; dev_id++) {
82		if (!strcmp(name, deviceName))
83			break;
84	}
85	if (deviceName == NULL) {
86		ERROROUT("invalid device name");
87		return B_ERROR;
88	}
89
90	// allow only one concurrent access
91	mask = 1 << dev_id;
92	if (atomic_or(&gOpenMask, mask) & mask)
93		return B_BUSY;
94
95	*cookie = device = (ipro1000_device *)malloc(sizeof(ipro1000_device));
96	if (!device) {
97		atomic_and(&gOpenMask, ~(1 << dev_id));
98		return B_NO_MEMORY;
99	}
100
101	memset(device, 0, sizeof(*device));
102
103	device->devId = dev_id;
104	device->pciInfo = gDevList[dev_id];
105	device->nonblocking = (flags & O_NONBLOCK) ? true : false;
106	device->closed = false;
107
108	device->pciBus 	= device->pciInfo->bus;
109	device->pciDev	= device->pciInfo->device;
110	device->pciFunc	= device->pciInfo->function;
111	device->adapter = 0;
112	device->maxframesize = 1514; // XXX is MAXIMUM_ETHERNET_FRAME_SIZE = 1518 too much?
113
114#ifdef HAIKU_TARGET_PLATFORM_HAIKU
115	device->linkChangeSem = -1;
116#endif
117
118	ipro1000_read_settings(device);
119
120	if (em_attach(device) != 0) {
121		DEVICE_DEBUGOUT("em_attach failed");
122		goto err;
123	}
124
125	return B_OK;
126
127err:
128	free(device);
129	atomic_and(&gOpenMask, ~(1 << dev_id));
130	return B_ERROR;
131}
132
133
134status_t
135ipro1000_close(void* cookie)
136{
137	ipro1000_device *device = (ipro1000_device *)cookie;
138	struct ifnet *ifp = &device->adapter->interface_data.ac_if;
139	DEVICE_DEBUGOUT("ipro1000_close()");
140
141	device->closed = true;
142	release_sem(ifp->if_rcv_sem);
143
144	return B_OK;
145}
146
147
148status_t
149ipro1000_free(void* cookie)
150{
151	ipro1000_device *device = (ipro1000_device *)cookie;
152	DEVICE_DEBUGOUT("ipro1000_free()");
153
154	if (em_detach(device) != 0) {
155		DEVICE_DEBUGOUT("em_detach failed");
156	}
157
158	free(device);
159	atomic_and(&gOpenMask, ~(1 << device->devId));
160	return B_OK;
161}
162
163
164status_t
165ipro1000_read(void* cookie, off_t position, void *buf, size_t* num_bytes)
166{
167	ipro1000_device *device = (ipro1000_device *)cookie;
168	struct ifnet *ifp = &device->adapter->interface_data.ac_if;
169	struct mbuf *mb;
170	status_t stat;
171	int len;
172
173//	DEVICE_DEBUGOUT("ipro1000_read() enter");
174
175	if (device->closed) {
176		DEVICE_DEBUGOUT("ipro1000_read() interrupted 1");
177		return B_INTERRUPTED;
178	}
179retry:
180	stat = acquire_sem_etc(ifp->if_rcv_sem, 1, B_CAN_INTERRUPT | (device->nonblocking ? B_TIMEOUT : 0), 0);
181	if (device->closed) {
182		// DEVICE_DEBUGOUT("ipro1000_read() interrupted 2"); // net_server will crash if we print this (race condition in net_server?)
183		return B_INTERRUPTED;
184	}
185	if (stat == B_WOULD_BLOCK) {
186		DEVICE_DEBUGOUT("ipro1000_read() would block (OK 0 bytes)");
187		*num_bytes = 0;
188		return B_OK;
189	}
190	if (stat != B_OK) {
191		DEVICE_DEBUGOUT("ipro1000_read() error");
192		return B_ERROR;
193	}
194
195	IF_DEQUEUE(&ifp->if_rcv, mb);
196	if (!mb) {
197		ERROROUT("ipro1000_read() mbuf not ready");
198		goto retry;
199	}
200
201	len = mb->m_len;
202	if (len < 0)
203		len = 0;
204	if (len > (int)*num_bytes)
205		len = *num_bytes;
206
207	memcpy(buf, mtod(mb, uint8 *), len); // XXX this is broken for jumbo frames
208	*num_bytes = len;
209
210	m_freem(mb);
211
212//	DEVICE_DEBUGOUT1("ipro1000_read() leave, %d bytes", len);
213	return B_OK;
214}
215
216
217status_t
218ipro1000_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
219{
220//	bigtime_t t = system_time();
221	ipro1000_device *device = (ipro1000_device *)cookie;
222	struct ifnet *ifp = &device->adapter->interface_data.ac_if;
223	struct mbuf *mb;
224
225//	DEVICE_DEBUGOUT("ipro1000_write() enter");
226
227	// allocate mbuf
228	for (;;) {
229		MGETHDR(mb, M_DONTWAIT, MT_DATA);
230		if (mb)
231			break;
232		snooze(700);
233		if (device->closed)
234			return B_INTERRUPTED;
235	}
236
237//	DEVICE_DEBUGOUT("ipro1000_write() 1");
238
239	// allocate memory
240	for (;;) {
241		MCLGET(mb, M_DONTWAIT);
242		if (mb->m_flags & M_EXT)
243			break;
244		snooze(700);
245		if (device->closed) {
246			m_freem(mb);
247			return B_INTERRUPTED;
248		}
249	}
250
251//	DEVICE_DEBUGOUT("ipro1000_write() 2");
252
253	// copy data
254	mb->m_len = *num_bytes;
255	if (mb->m_len > MCLBYTES)
256		mb->m_len = MCLBYTES;
257	memcpy(mtod(mb, uint8 *), buffer, mb->m_len);
258
259//	DEVICE_DEBUGOUT("ipro1000_write() 3");
260
261	// add mbuf to send queue
262	IF_APPEND(&ifp->if_snd, mb);
263
264//	DEVICE_DEBUGOUT("ipro1000_write() 4");
265
266	// wait for output available
267	while (ifp->if_flags & IFF_OACTIVE) {
268		snooze(700);
269		if (device->closed)
270			return B_INTERRUPTED;
271	}
272
273//	DEVICE_DEBUGOUT("ipro1000_write() 5");
274
275	// send everything (if still required)
276	if (ifp->if_snd.ifq_head != NULL)
277		ifp->if_start(ifp);
278
279//	while (ifp->if_snd.ifq_head != NULL) {
280//		ifp->if_start(ifp);
281//		if (ifp->if_snd.ifq_head != NULL) {
282//			snooze(1000);
283//			if (device->closed)
284//				return B_INTERRUPTED;
285//		}
286//	}
287
288//	t = system_time() - t;
289
290//	if (t > 20)
291//		DEVICE_DEBUGOUT("write %Ld", t);
292
293//	DEVICE_DEBUGOUT("ipro1000_write() finished");
294
295	return B_OK;
296}
297
298
299static struct ifnet *
300device_ifp(ipro1000_device *device)
301{
302	return &device->adapter->interface_data.ac_if;
303}
304
305
306status_t
307ipro1000_control(void *cookie, uint32 op, void *arg, size_t len)
308{
309	ipro1000_device *device = (ipro1000_device *)cookie;
310
311	switch (op) {
312		case ETHER_INIT:
313			DEVICE_DEBUGOUT("ipro1000_control() ETHER_INIT");
314			return B_OK;
315
316		case ETHER_GETADDR:
317			DEVICE_DEBUGOUT("ipro1000_control() ETHER_GETADDR");
318			memcpy(arg, &device->macaddr, sizeof(device->macaddr));
319			return B_OK;
320
321		case ETHER_NONBLOCK:
322			if (*(int32 *)arg) {
323				DEVICE_DEBUGOUT("non blocking mode on");
324				device->nonblocking = true;
325			} else {
326				DEVICE_DEBUGOUT("non blocking mode off");
327				device->nonblocking = false;
328			}
329			return B_OK;
330
331		case ETHER_ADDMULTI:
332		case ETHER_REMMULTI:
333		{
334			struct ifnet *ifp = device_ifp(device);
335			struct sockaddr_dl address;
336
337			if (len != ETHER_ADDR_LEN)
338				return EINVAL;
339
340			memset(&address, 0, sizeof(address));
341			address.sdl_family = AF_LINK;
342			memcpy(LLADDR(&address), arg, ETHER_ADDR_LEN);
343
344			if (op == ETHER_ADDMULTI)
345				return ether_add_multi(ifp, (struct sockaddr *)&address);
346			else
347				return ether_rem_multi(ifp, (struct sockaddr *)&address);
348		}
349
350		case ETHER_SETPROMISC:
351			if (*(int32 *)arg) {
352				DEVICE_DEBUGOUT("promiscuous mode on not supported");
353			} else {
354				DEVICE_DEBUGOUT("promiscuous mode off");
355			}
356			return B_OK;
357
358		case ETHER_GETFRAMESIZE:
359			DEVICE_DEBUGOUT2("ipro1000_control() ETHER_GETFRAMESIZE, framesize = %d (MTU = %d)", device->maxframesize,  device->maxframesize - ENET_HEADER_SIZE);
360			*(uint32*)arg = device->maxframesize;
361			return B_OK;
362
363#ifdef HAIKU_TARGET_PLATFORM_HAIKU
364		case ETHER_GET_LINK_STATE:
365		{
366			struct ifmediareq mediareq;
367			ether_link_state_t state;
368
369			if (len < sizeof(ether_link_state_t))
370				return ENOBUFS;
371
372			em_media_status(device_ifp(device), &mediareq);
373
374			state.media = mediareq.ifm_active;
375			if (mediareq.ifm_status & IFM_ACTIVE)
376				state.media |= IFM_ACTIVE;
377			if (mediareq.ifm_active & IFM_10_T)
378				state.speed = 10000000;
379			else if (mediareq.ifm_active & IFM_100_TX)
380				state.speed = 100000000;
381			else
382				state.speed = 1000000000;
383			state.quality = 1000;
384
385			return user_memcpy(arg, &state, sizeof(ether_link_state_t));
386		}
387
388		case ETHER_SET_LINK_STATE_SEM:
389		{
390			if (user_memcpy(&device->linkChangeSem, arg, sizeof(sem_id)) < B_OK) {
391				device->linkChangeSem = -1;
392				return B_BAD_ADDRESS;
393			}
394			return B_OK;
395		}
396#endif
397
398		default:
399			DEVICE_DEBUGOUT("ipro1000_control() Invalid command");
400			break;
401	}
402
403	return B_BAD_VALUE;
404}
405