1 /* Copyright (c) 2003-2011 2 * Stefano Ceccherini <stefano.ceccherini@gmail.com>. All rights reserved. 3 * This file is released under the MIT license 4 */ 5 #include <KernelExport.h> 6 #include <Errors.h> 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <string.h> 10 11 #include <net/if_media.h> 12 13 #include "debug.h" 14 #include "device.h" 15 #include "driver.h" 16 #include "interface.h" 17 #include "wb840.h" 18 19 20 #define MAX_CARDS 4 21 22 extern char* gDevNameList[]; 23 extern pci_info* gDevList[]; 24 25 static int32 sOpenMask = 0; 26 27 static status_t 28 wb840_open(const char* name, uint32 flags, void** cookie) 29 { 30 char* deviceName = NULL; 31 int32 i; 32 int32 mask; 33 struct wb_device* data; 34 status_t status; 35 36 LOG((DEVICE_NAME ": open()\n")); 37 38 for (i = 0; (deviceName = gDevNameList[i]) != NULL; i++) { 39 if (!strcmp(name, deviceName)) 40 break; 41 } 42 43 if (deviceName == NULL) { 44 LOG(("invalid device name")); 45 return EINVAL; 46 } 47 48 // There can be only one access at time 49 mask = 1L << i; 50 if (atomic_or(&sOpenMask, mask) & mask) 51 return B_BUSY; 52 53 // Allocate a wb_device structure 54 if (!(data = (wb_device*)calloc(1, sizeof(wb_device)))) { 55 sOpenMask &= ~(1L << i); 56 return B_NO_MEMORY; 57 } 58 59 *cookie = data; 60 61 data->devId = i; 62 data->pciInfo = gDevList[i]; 63 data->deviceName = gDevNameList[i]; 64 data->blockFlag = 0; 65 data->reg_base = data->pciInfo->u.h0.base_registers[0]; 66 data->wb_cachesize = gPci->read_pci_config(data->pciInfo->bus, 67 data->pciInfo->device, data->pciInfo->function, PCI_line_size, 68 sizeof(PCI_line_size)) & 0xff; 69 70 wb_read_eeprom(data, &data->MAC_Address, 0, 3, false); 71 72 status = wb_create_semaphores(data); 73 if (status < B_OK) { 74 LOG((DEVICE_NAME": couldn't create semaphores\n")); 75 goto err; 76 } 77 78 status = wb_stop(data); 79 if (status < B_OK) { 80 LOG((DEVICE_NAME": can't stop device\n")); 81 goto err1; 82 } 83 84 status = wb_initPHYs(data); 85 if (status < B_OK) { 86 LOG((DEVICE_NAME": can't init PHYs\n")); 87 goto err1; 88 } 89 90 wb_init(data); 91 92 /* Setup interrupts */ 93 data->irq = data->pciInfo->u.h0.interrupt_line; 94 status = install_io_interrupt_handler(data->irq, wb_interrupt, data, 0); 95 if (status < B_OK) { 96 LOG((DEVICE_NAME 97 ": can't install interrupt handler: %s\n", strerror(status))); 98 goto err1; 99 } 100 101 LOG((DEVICE_NAME ": interrupts installed at irq line %x\n", data->irq)); 102 103 status = wb_create_rings(data); 104 if (status < B_OK) { 105 LOG((DEVICE_NAME": can't create ring buffers\n")); 106 goto err2; 107 } 108 109 wb_enable_interrupts(data); 110 111 WB_SETBIT(data->reg_base + WB_NETCFG, WB_NETCFG_RX_ON); 112 write32(data->reg_base + WB_RXSTART, 0xFFFFFFFF); 113 WB_SETBIT(data->reg_base + WB_NETCFG, WB_NETCFG_TX_ON); 114 115 add_timer(&data->timer, wb_tick, 1000000LL, B_PERIODIC_TIMER); 116 117 return B_OK; // Everything after this line is an error 118 119 err2: 120 remove_io_interrupt_handler(data->irq, wb_interrupt, data); 121 122 err1: 123 wb_delete_semaphores(data); 124 125 err: 126 sOpenMask &= ~(1L << i); 127 128 free(data); 129 LOG(("wb840: Open Failed\n")); 130 131 return status; 132 } 133 134 135 static status_t 136 wb840_read(void* cookie, off_t position, void* buf, size_t* num_bytes) 137 { 138 wb_device* device = (wb_device*)cookie; 139 int16 current; 140 status_t status; 141 size_t size; 142 int32 blockFlag; 143 uint32 check; 144 145 LOG((DEVICE_NAME ": read()\n")); 146 147 blockFlag = device->blockFlag; 148 149 if (atomic_or(&device->rxLock, 1)) { 150 *num_bytes = 0; 151 return B_ERROR; 152 } 153 154 status = acquire_sem_etc(device->rxSem, 1, B_CAN_INTERRUPT | blockFlag, 0); 155 if (status < B_OK) { 156 atomic_and(&device->rxLock, 0); 157 *num_bytes = 0; 158 return status; 159 } 160 161 current = device->rxCurrent; 162 check = device->rxDescriptor[current].wb_status; 163 if (check & WB_RXSTAT_OWN) { 164 LOG((DEVICE_NAME ":ERROR: read: buffer %d still in use: %x\n", 165 (int)current, (int)status)); 166 atomic_and(&device->rxLock, 0); 167 *num_bytes = 0; 168 return B_BUSY; 169 } 170 171 if (check & (WB_RXSTAT_RXERR | WB_RXSTAT_CRCERR | WB_RXSTAT_RUNT)) { 172 LOG(("Error read: packet with errors.")); 173 *num_bytes = 0; 174 } else { 175 size = WB_RXBYTES(check); 176 size -= CRC_SIZE; 177 LOG((DEVICE_NAME": received %ld bytes\n", size)); 178 if (size > WB_MAX_FRAMELEN || size > *num_bytes) { 179 LOG(("ERROR: Bad frame size: %ld", size)); 180 size = *num_bytes; 181 } 182 *num_bytes = size; 183 memcpy(buf, (void*)device->rxBuffer[current], size); 184 } 185 186 device->rxCurrent = (current + 1) & WB_RX_CNT_MASK; 187 { 188 cpu_status former; 189 former = disable_interrupts(); 190 acquire_spinlock(&device->rxSpinlock); 191 192 // release buffer to ring 193 wb_put_rx_descriptor(&device->rxDescriptor[current]); 194 device->rxFree++; 195 196 release_spinlock(&device->rxSpinlock); 197 restore_interrupts(former); 198 } 199 200 atomic_and(&device->rxLock, 0); 201 202 return B_OK; 203 } 204 205 206 static status_t 207 wb840_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes) 208 { 209 wb_device* device = (wb_device*)cookie; 210 status_t status = B_OK; 211 uint16 frameSize; 212 int16 current; 213 uint32 check; 214 215 LOG((DEVICE_NAME ": write()\n")); 216 217 atomic_add(&device->txLock, 1); 218 219 if (*num_bytes > WB_MAX_FRAMELEN) 220 *num_bytes = WB_MAX_FRAMELEN; 221 222 frameSize = *num_bytes; 223 current = device->txCurrent; 224 225 // block until a free tx descriptor is available 226 status = acquire_sem_etc(device->txSem, 1, B_TIMEOUT, ETHER_TRANSMIT_TIMEOUT); 227 if (status < B_OK) { 228 write32(device->reg_base + WB_TXSTART, 0xFFFFFFFF); 229 LOG((DEVICE_NAME": write: acquiring sem failed: %ld, %s\n", 230 status, strerror(status))); 231 atomic_add(&device->txLock, -1); 232 *num_bytes = 0; 233 return status; 234 } 235 236 check = device->txDescriptor[current].wb_status; 237 if (check & WB_TXSTAT_OWN) { 238 // descriptor is still in use 239 dprintf(DEVICE_NAME ": card owns buffer %d\n", (int)current); 240 atomic_add(&device->txLock, -1); 241 *num_bytes = 0; 242 return B_ERROR; 243 } 244 245 /* Copy data to tx buffer */ 246 memcpy((void*)device->txBuffer[current], buffer, frameSize); 247 device->txCurrent = (current + 1) & WB_TX_CNT_MASK; 248 LOG((DEVICE_NAME ": %d bytes written\n", frameSize)); 249 250 { 251 cpu_status former = disable_interrupts(); 252 acquire_spinlock(&device->txSpinlock); 253 254 device->txDescriptor[current].wb_ctl = WB_TXCTL_TLINK | frameSize; 255 device->txDescriptor[current].wb_ctl |= WB_TXCTL_FIRSTFRAG 256 | WB_TXCTL_LASTFRAG; 257 device->txDescriptor[current].wb_status = WB_TXSTAT_OWN; 258 device->txSent++; 259 260 release_spinlock(&device->txSpinlock); 261 restore_interrupts(former); 262 } 263 264 // re-enable transmit state machine 265 write32(device->reg_base + WB_TXSTART, 0xFFFFFFFF); 266 267 atomic_add(&device->txLock, -1); 268 269 return B_OK; 270 } 271 272 273 static status_t 274 wb840_control (void* cookie, uint32 op, void* arg, size_t len) 275 { 276 wb_device* data = (wb_device*)cookie; 277 278 LOG((DEVICE_NAME ": control()\n")); 279 switch (op) { 280 case ETHER_INIT: 281 LOG(("%s: ETHER_INIT\n", data->deviceName)); 282 return B_OK; 283 284 case ETHER_GETADDR: 285 LOG(("%s: ETHER_GETADDR\n", data->deviceName)); 286 memcpy(arg, &data->MAC_Address, sizeof(data->MAC_Address)); 287 print_address(arg); 288 return B_OK; 289 290 case ETHER_NONBLOCK: 291 LOG(("ETHER_NON_BLOCK\n")); 292 data->blockFlag = *(int32*)arg ? B_TIMEOUT : 0; 293 return B_OK; 294 295 case ETHER_GETFRAMESIZE: 296 LOG(("ETHER_GETFRAMESIZE\n")); 297 *(uint32 *)arg = WB_MAX_FRAMELEN; 298 return B_OK; 299 300 case ETHER_GET_LINK_STATE: 301 { 302 ether_link_state_t state; 303 LOG(("ETHER_GET_LINK_STATE")); 304 305 state.media = (data->link ? IFM_ACTIVE : 0) | IFM_ETHER 306 | (data->full_duplex ? IFM_FULL_DUPLEX : IFM_HALF_DUPLEX) 307 | (data->speed == LINK_SPEED_100_MBIT ? IFM_100_TX : IFM_10_T); 308 state.speed = data->speed == LINK_SPEED_100_MBIT 309 ? 100000000 : 10000000; 310 state.quality = 1000; 311 312 return user_memcpy(arg, &state, sizeof(ether_link_state_t)); 313 } 314 315 case ETHER_ADDMULTI: 316 LOG(("ETHER_ADDMULTI\n")); 317 break; 318 319 case ETHER_REMMULTI: 320 LOG(("ETHER_REMMULTI\n")); 321 break; 322 323 case ETHER_SETPROMISC: 324 LOG(("ETHER_SETPROMISC\n")); 325 break; 326 327 default: 328 LOG(("Invalid command\n")); 329 break; 330 } 331 332 return B_ERROR; 333 } 334 335 336 static status_t 337 wb840_close(void* cookie) 338 { 339 wb_device* device = (wb_device*)cookie; 340 341 LOG((DEVICE_NAME ": close()\n")); 342 343 cancel_timer(&device->timer); 344 345 wb_stop(device); 346 347 write32(device->reg_base + WB_TXADDR, 0x00000000); 348 write32(device->reg_base + WB_RXADDR, 0x00000000); 349 350 wb_disable_interrupts(device); 351 remove_io_interrupt_handler(device->irq, wb_interrupt, device); 352 353 delete_sem(device->rxSem); 354 delete_sem(device->txSem); 355 356 return B_OK; 357 } 358 359 360 static status_t 361 wb840_free(void* cookie) 362 { 363 wb_device* device = (wb_device*)cookie; 364 365 LOG((DEVICE_NAME ": free()\n")); 366 367 sOpenMask &= ~(1L << device->devId); 368 369 wb_delete_rings(device); 370 free(device->firstPHY); 371 free(device); 372 373 return B_OK; 374 } 375 376 377 device_hooks 378 gDeviceHooks = { 379 wb840_open, /* -> open entry point */ 380 wb840_close, /* -> close entry point */ 381 wb840_free, /* -> free cookie */ 382 wb840_control, /* -> control entry point */ 383 wb840_read, /* -> read entry point */ 384 wb840_write, /* -> write entry point */ 385 NULL, 386 NULL, 387 NULL, 388 NULL 389 }; 390