From f08af637037f4647e51f1e283e070a9a8ace496e Mon Sep 17 00:00:00 2001 From: beveloper Date: Sat, 15 May 2004 23:42:14 +0000 Subject: [PATCH] Added timer support, taken from the ipro1000 driver. We really should have support for a similar functionality in the new kernel. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7592 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/drivers/network/rtl8169/Jamfile | 1 + .../kernel/drivers/network/rtl8169/driver.c | 19 +- .../kernel/drivers/network/rtl8169/timer.c | 215 ++++++++++++++++++ .../kernel/drivers/network/rtl8169/timer.h | 44 ++++ 4 files changed, 275 insertions(+), 4 deletions(-) create mode 100644 src/add-ons/kernel/drivers/network/rtl8169/timer.c create mode 100644 src/add-ons/kernel/drivers/network/rtl8169/timer.h diff --git a/src/add-ons/kernel/drivers/network/rtl8169/Jamfile b/src/add-ons/kernel/drivers/network/rtl8169/Jamfile index 2dbf7edfa4..41e48105f7 100644 --- a/src/add-ons/kernel/drivers/network/rtl8169/Jamfile +++ b/src/add-ons/kernel/drivers/network/rtl8169/Jamfile @@ -9,6 +9,7 @@ UsePrivateHeaders net ; R5KernelAddon rtl8169 : kernel drivers bin : driver.c device.c + timer.c util.c ; diff --git a/src/add-ons/kernel/drivers/network/rtl8169/driver.c b/src/add-ons/kernel/drivers/network/rtl8169/driver.c index 331a38b731..78218799d1 100644 --- a/src/add-ons/kernel/drivers/network/rtl8169/driver.c +++ b/src/add-ons/kernel/drivers/network/rtl8169/driver.c @@ -28,6 +28,7 @@ #include "device.h" #include "driver.h" #include "setup.h" +#include "timer.h" int32 api_version = B_CUR_DRIVER_API_VERSION; @@ -103,12 +104,20 @@ init_driver(void) free(item); - if (!cards) { - put_module(B_PCI_MODULE_NAME); - return B_ERROR; + if (!cards) + goto err_cards; + + if (initialize_timer() != B_OK) { + ERROR("timer init failed\n"); + goto err_timer; } - + return B_OK; + +err_timer: +err_cards: + put_module(B_PCI_MODULE_NAME); + return B_ERROR; } @@ -119,6 +128,8 @@ uninit_driver(void) TRACE("uninit_driver()\n"); + terminate_timer(); + for (i = 0; gDevNameList[i] != NULL; i++) { free(gDevList[i]); free(gDevNameList[i]); diff --git a/src/add-ons/kernel/drivers/network/rtl8169/timer.c b/src/add-ons/kernel/drivers/network/rtl8169/timer.c new file mode 100644 index 0000000000..e7c3946de0 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/rtl8169/timer.c @@ -0,0 +1,215 @@ +/* Realtek RTL8169 Family Driver + * Copyright (C) 2004 Marcus Overhagen . All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies, and that both the + * copyright notice and this permission notice appear in supporting documentation. + * + * Marcus Overhagen makes no representations about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * + * MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS + * OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include + +#include "debug.h" +#include "timer.h" + +#define MAX_TIMERS 8 + + +struct timer_info +{ + timer_id id; + timer_function func; + void * cookie; + bigtime_t next_event; + bigtime_t interval; + bool periodic; +}; + + +static struct timer_info sTimerData[MAX_TIMERS]; +static int sTimerCount; +static timer_id sTimerNextId; +static thread_id sTimerThread; +static sem_id sTimerSem; +static spinlock sTimerSpinlock; + + +static int32 +timer_thread(void *cookie) +{ + status_t status = 0; + + do { + bigtime_t timeout; + bigtime_t now; + cpu_status cpu; + timer_function func; + void * cookie; + int i; + int index; + + cpu = disable_interrupts(); + acquire_spinlock(&sTimerSpinlock); + + now = system_time(); + cookie = 0; + func = 0; + + // find timer with smallest event time + index = -1; + timeout = B_INFINITE_TIMEOUT; + for (i = 0; i < sTimerCount; i++) { + if (sTimerData[i].next_event < timeout) { + timeout = sTimerData[i].next_event; + index = i; + } + } + + if (timeout < now) { + // timer is ready for execution, load func and cookie + ASSERT(index >= 0 && index < sTimerCount); + func = sTimerData[index].func; + cookie = sTimerData[index].cookie; + if (sTimerData[index].periodic) { + // periodic timer is ready, update the entry + sTimerData[index].next_event += sTimerData[index].interval; + } else { + // single shot timer is ready, delete the entry + if (index != (sTimerCount - 1) && sTimerCount != 1) { + memcpy(&sTimerData[index], &sTimerData[sTimerCount - 1], sizeof(struct timer_info)); + } + sTimerCount--; + } + } + + release_spinlock(&sTimerSpinlock); + restore_interrupts(cpu); + + // execute timer hook + if (timeout < now) { + ASSERT(func); + func(cookie); + continue; + } + + status = acquire_sem_etc(sTimerSem, 1, B_ABSOLUTE_TIMEOUT, timeout); + } while (status != B_BAD_SEM_ID); + + return 0; +} + + +timer_id +create_timer(timer_function func, void *cookie, bigtime_t interval, uint32 flags) +{ + cpu_status cpu; + timer_id id; + + if (func == 0) + return -1; + + // Attention: flags are not real flags, as B_PERIODIC_TIMER is 3 + + cpu = disable_interrupts(); + acquire_spinlock(&sTimerSpinlock); + + if (sTimerCount < MAX_TIMERS) { + id = sTimerNextId; + sTimerData[sTimerCount].id = id; + sTimerData[sTimerCount].func = func; + sTimerData[sTimerCount].cookie = cookie; + sTimerData[sTimerCount].next_event = (flags == B_ONE_SHOT_ABSOLUTE_TIMER) ? interval : system_time() + interval; + sTimerData[sTimerCount].interval = interval; + sTimerData[sTimerCount].periodic = flags == B_PERIODIC_TIMER; + sTimerNextId++; + sTimerCount++; + } else { + id = -1; + } + + release_spinlock(&sTimerSpinlock); + restore_interrupts(cpu); + + if (id != -1) + release_sem_etc(sTimerSem, 1, B_DO_NOT_RESCHEDULE); + + return id; +} + + +status_t +delete_timer(timer_id id) +{ + cpu_status cpu; + bool deleted; + int i; + + deleted = false; + + cpu = disable_interrupts(); + acquire_spinlock(&sTimerSpinlock); + + for (i = 0; i < sTimerCount; i++) { + if (sTimerData[i].id == id) { + if (i != (sTimerCount - 1) && sTimerCount != 1) { + memcpy(&sTimerData[i], &sTimerData[sTimerCount - 1], sizeof(struct timer_info)); + } + sTimerCount--; + deleted = true; + break; + } + } + + release_spinlock(&sTimerSpinlock); + restore_interrupts(cpu); + + if (!deleted) + return B_ERROR; + + release_sem_etc(sTimerSem, 1, B_DO_NOT_RESCHEDULE); + return B_OK; +} + + +status_t +initialize_timer(void) +{ + sTimerCount = 0; + sTimerNextId = 1; + sTimerSpinlock = 0; + + sTimerThread = spawn_kernel_thread(timer_thread, "rtl8169 timer", 80, 0); + sTimerSem = create_sem(0, "rtl8169 timer"); + set_sem_owner(sTimerSem, B_SYSTEM_TEAM); + + if (sTimerSem < 0 || sTimerThread < 0) { + delete_sem(sTimerSem); + kill_thread(sTimerThread); + return B_ERROR; + } + + resume_thread(sTimerThread); + return B_OK; +} + + +status_t +terminate_timer(void) +{ + status_t thread_return_value; + + delete_sem(sTimerSem); + return wait_for_thread(sTimerThread, &thread_return_value); +} + diff --git a/src/add-ons/kernel/drivers/network/rtl8169/timer.h b/src/add-ons/kernel/drivers/network/rtl8169/timer.h new file mode 100644 index 0000000000..0c3cc97177 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/rtl8169/timer.h @@ -0,0 +1,44 @@ +/* Realtek RTL8169 Family Driver + * Copyright (C) 2004 Marcus Overhagen . All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies, and that both the + * copyright notice and this permission notice appear in supporting documentation. + * + * Marcus Overhagen makes no representations about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * + * MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS + * OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef __TIMER_H +#define __TIMER_H + +#include + +// Since the BeOS kernel timers are executed in interrupt context, +// a new timer has been created. The timers are executed in thread +// context, and are passed a cookie. + +typedef int32 timer_id; + +typedef void (*timer_function)(void *cookie); + +// create_timer() can be called from interrupt context. +// Only up to 8 concurrent timers are supported. +// Flags can be one of B_ONE_SHOT_ABSOLUTE_TIMER, +// B_ONE_SHOT_RELATIVE_TIMER or B_PERIODIC_TIMER. + +timer_id create_timer(timer_function func, void *cookie, bigtime_t interval, uint32 flags); +status_t delete_timer(timer_id id); + + +status_t initialize_timer(void); +status_t terminate_timer(void); + +#endif