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