Esempio n. 1
0
int rwlock_release( struct rwlock *rw )
{
	acquire_spinlock( &(rw->spinlock) );

		if ( rw->num_writers != 0 )
		{
			rw->write_request = 0;
			rw->num_writers   = 0;
		}
		else
		{
			rw->num_readers -= 1;
		}
	
	release_spinlock( &(rw->spinlock) );
	return 0;
}
Esempio n. 2
0
static status_t
read_hook (void* cookie, off_t position, void *buf, size_t* num_bytes)
{
	dp83815_properties_t *data = cookie;
	cpu_status former;
	descriptor_t*	desc;
	size_t			length = 0;

	TRACE(( kDevName ": read_hook()\n" ));

	//if( !data->nonblocking )
		acquire_sem_etc( data->Rx.Sem, 1, B_CAN_INTERRUPT|data->blockFlag, NONBLOCK_WAIT );

	{
		former = disable_interrupts();
		acquire_spinlock(&data->Rx.Lock);
			desc = data->Rx.Curr;
			data->Rx.Curr = desc->virt_next;
		release_spinlock(&data->Rx.Lock);
		restore_interrupts(former);
	}

	length= DESC_LENGTH&desc->cmd;

	if( desc->cmd & (DESC_RXA|DESC_RXO|DESC_LONG|DESC_RUNT|DESC_ISE|DESC_CRCE|DESC_FAE|DESC_LBP|DESC_COL) )
		TRACE(( "desc cmd: %x\n", desc->cmd ));

	if( length < 64 ) {
		*num_bytes = 0;
		return B_ERROR;
	}

	if( *num_bytes < length )
		length = *num_bytes;

	memcpy(buf, desc->virt_buff,length);
	desc->cmd = DESC_LENGTH&MAX_PACKET_SIZE;
	*num_bytes = length;

	atomic_add(&data->stats.rx_att, 1);

	if( length == 0 )
		return B_ERROR;

	return B_OK;
}
Esempio n. 3
0
int irq_ack( struct thread *t, int irq, int status )
{
	acquire_spinlock( &irq_lock );

	dmesg("%!ACK with status %i for %i\n", status, irq );

		if ( status == 0 )
		{
			unmask_irq( irq );
			release_spinlock( &irq_lock );
			return 0;
		}

	dmesg("%!Unhandled IRQ %i\n", irq );
	release_spinlock( &irq_lock );
	return 0;
}
up(sem_t &sem) {

  disable_interrupts();
  acquire_spinlock(mu);

  sem->val++;

  if (not_empty(queue)) {
    // threads are waiting - wake one up
    
    other_thread = dequeue(queue);
    other_thread->state = READY;
    add_to_ready_queue(other_thread);
  }

  release_spinlock(mu);
  enable_interrupts();
}
Esempio n. 5
0
int release_irq( struct thread *t, int irq )
{
	int ans = -1;

	if ( (irq < 0) || (irq >= IRQ_COUNT) ) return -1;
	
	acquire_spinlock( &irq_lock );

	  if ( handlers[irq] == t )
	  {
		  handlers[irq] = NULL;
		  if ( masked(irq) == 0 ) mask_irq( irq );
		  ans = 0;
	  }
	
	release_spinlock( &irq_lock );
	return ans;
}
Esempio n. 6
0
int destroy_global_semaphore( int pid, int sem_id )
{
	struct sem_link *sl		= NULL;
	struct sem_link *tmp	= NULL;
	struct process *proc	= NULL;
	struct thread *tr		= NULL;

	if ( sem_id < 0 ) return -1;
	if ( sem_id >= GLOBAL_SEM_COUNT ) return -1;
	
	acquire_spinlock( & global_sems_lock );

		if ( ( global_sems[ sem_id ].sem_id != sem_id ) ||
			 ( global_sems[ sem_id ].pid 	!= pid ) )
		{
			// Invalid or not allowed.
			release_spinlock( & global_sems_lock );
			return -1;
		}
	
		// Tell the waiting guys to go away.
		sl = global_sems[ sem_id ].waiting_list;
		while ( sl != NULL )
		{
			tmp = sl;
			
			proc = checkout_process( sl->pid, WRITER );
			if ( proc != NULL ) 
			{
				tr = find_thread_with_id( proc, sl->tid );
				if ( tr != NULL ) 
						set_thread_state( tr, THREAD_RUNNING );
				commit_process( proc );
			}
			sl = sl->next;
			free( tmp );
		}

	 	global_sems[ sem_id ].waiting_list = NULL;
		global_sems[ sem_id ].sem_id 	= -1;	// DELETED!

	release_spinlock( & global_sems_lock );
	return 0;
}
void
arch_debug_serial_puts(const char *s)
{
    cpu_status state = 0;
    if (!debug_debugger_running()) {
        state = disable_interrupts();
        acquire_spinlock(&sSerialOutputSpinlock);
    }

    while (*s != '\0') {
        _arch_debug_serial_putchar(*s);
        s++;
    }

    if (!debug_debugger_running()) {
        release_spinlock(&sSerialOutputSpinlock);
        restore_interrupts(state);
    }
}
Esempio n. 8
0
int rwlock_get_write_access( struct rwlock *rw )
{
	while ( 1==1 )
	{
		acquire_spinlock( &(rw->spinlock) );

			if ( (rw->num_readers == 0) && (rw->num_writers == 0) )
			{
				rw->num_writers += 1;
				release_spinlock( &(rw->spinlock) );
				break;
			}
			else rw->write_request = 1;
	
		release_spinlock( &(rw->spinlock) );
	}

	return 0;
}
Esempio n. 9
0
static status_t
write_hook (void* cookie, off_t position, const void* buffer, size_t* num_bytes)
{
	dp83815_properties_t *data = cookie;
	cpu_status former;
	descriptor_t*	desc;

	TRACE(( kDevName " write_hook()\n" ));

	acquire_sem( data->lock );
	acquire_sem_etc( data->Tx.Sem, 1, B_CAN_INTERRUPT|data->blockFlag, NONBLOCK_WAIT );

	{
		former = disable_interrupts();
		acquire_spinlock(&data->Tx.Lock);
			desc = data->Tx.Curr;
			data->Tx.Curr = desc->virt_next;
		release_spinlock(&data->Tx.Lock);
		restore_interrupts(former);
	}

	if ( *num_bytes > MAX_PACKET_SIZE ) {			/* if needed						*/
		TRACE(( "Had to truncate the packet from %d to %d\n", *num_bytes, MAX_PACKET_SIZE));
		*num_bytes = MAX_PACKET_SIZE;				/*   truncate the packet			*/
	}


	while( desc->cmd&DESC_OWN )	{			/* make sure a buffer is available	*/
		TRACE(( "spinning in the write hook\n"));
		spin(1000);						/* wait a while if not				*/
	}

	memcpy(desc->virt_buff, buffer, *num_bytes);		/* now copy the data				*/
	desc->cmd = DESC_OWN|*num_bytes;				/* update the cmd bits				*/

	write32(REG_CR, CR_TXE);				/* tell the card to start tx		*/
	atomic_add(&data->stats.tx_att, 1);

	release_sem_etc( data->lock , 1 , B_DO_NOT_RESCHEDULE );

	return B_OK;
}
Esempio n. 10
0
SORAAPI 
insert_thread_safe_enlist_tail(struct thread_safe_enlist* tslist, 
	void*  value,
	char lock) {

	KIRQL irql;
	acquire_spinlock(lock, 
		tslist->m_sync,
		irql);
	struct LIST_ENTRY_EX* entry;
	entry = (struct LIST_ENTRY_EX*)ExAllocateFromNPagedLookasideList (&tslist->m_lookaside);
	entry->m_value = value;
	InsertTailList(&tslist->m_head.m_entry, 
		&entry->m_entry);
	InterlockedIncrement(&tslist->m_count);
	release_spinlock(lock,
		tslist->m_sync,
		irql);
	return entry;
}
Esempio n. 11
0
LM_STATUS
MM_IndicateRxPackets(PLM_DEVICE_BLOCK pDevice)
{
	struct be_b57_dev *dev = (struct be_b57_dev *)pDevice;
	PLM_PACKET pPacket;

	while (1) {
		pPacket = (PLM_PACKET)
			QQ_PopHead(&pDevice->RxPacketReceivedQ.Container);
		if (pPacket == 0)
			break;

		acquire_spinlock(&dev->lock);
		release_sem_etc(dev->packet_release_sem, 1, B_DO_NOT_RESCHEDULE);
		release_spinlock(&dev->lock);
		QQ_PushTail(&dev->RxPacketReadQ.Container, pPacket);
	}

	return LM_STATUS_SUCCESS;
}
Esempio n. 12
0
static status_t
b57_write(void *cookie,off_t pos,const void *data,size_t *numBytes)
{
	struct be_b57_dev *pUmDevice = (struct be_b57_dev *)cookie;
	PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice;
	PLM_PACKET pPacket;
	struct B_UM_PACKET *pUmPacket;
	cpu_status cpu;

	/*if ((pDevice->LinkStatus == LM_STATUS_LINK_DOWN) || !pDevice->InitDone)
	{
		return ENETDOWN;
	}*/

	pPacket = (PLM_PACKET)
		QQ_PopHead(&pDevice->TxPacketFreeQ.Container);

	if (pPacket == 0)
		return B_ERROR;

	pUmPacket = (struct B_UM_PACKET *)pPacket;
	pUmPacket->data = chunk_pool_get();

	memcpy(pUmPacket->data,data,*numBytes); /* no guarantee data is contiguous, so we have to copy */
	pPacket->PacketSize = pUmPacket->size = *numBytes;

	pPacket->u.Tx.FragCount = 1;
	pPacket->Flags = 0;

	tx_cleanup_thread(pUmDevice);

	cpu = disable_interrupts();
	acquire_spinlock(&pUmDevice->lock);

	LM_SendPacket(pDevice, pPacket);

	release_spinlock(&pUmDevice->lock);
	restore_interrupts(cpu);

	return B_OK;
}
void rtl8169_xmit(rtl8169 *r, const char *ptr, ssize_t len)
{
    //int i;

#if debug_level_flow >= 3
    dprintf("rtl8169_xmit dumping packet:");
    hexdump(ptr, len, 0, 0);
#endif

restart:
    hal_sem_acquire(&r->tx_sem);
    hal_mutex_lock(&r->lock);

    int_disable_interrupts();
    acquire_spinlock(&r->reg_spinlock);

    /* look at the descriptor pointed to by tx_idx_free */
    if (r->txdesc[r->tx_idx_free].flags & RTL_DESC_OWN) {
        /* card owns this one, wait and try again later */
        release_spinlock(&r->reg_spinlock);
        int_restore_interrupts();
        mutex_unlock(&r->lock);
        //		sem_release(r->tx_sem, 1);
        goto restart;
    }

    /* queue it up */
    memcpy(TXBUF(r, r->tx_idx_free), ptr, len);
    if (len < 64)
        len = 64;

    r->txdesc[r->tx_idx_free].frame_len = len;
    r->txdesc[r->tx_idx_free].flags = (r->txdesc[r->tx_idx_free].flags & RTL_DESC_EOR) | RTL_DESC_FS | RTL_DESC_LS | RTL_DESC_OWN;
    inc_tx_idx_free(r);
    RTL_WRITE_8(r, REG_TPPOLL, (1<<6)); // something is on the normal queue

    release_spinlock(&r->reg_spinlock);
    int_restore_interrupts();

    mutex_unlock(&r->lock);
}
Esempio n. 14
0
int64
_user_atomic_get64(vint64 *value)
{
	cpu_status status;
	int64 oldValue;
	if (!IS_USER_ADDRESS(value)
		|| lock_memory((void *)value, 8, B_READ_DEVICE) != B_OK)
		goto access_violation;

	status = disable_interrupts();
	acquire_spinlock(&atomic_lock);
	oldValue = *value;
	release_spinlock(&atomic_lock);
	restore_interrupts(status);
	unlock_memory((void *)value, 8, B_READ_DEVICE);
	return oldValue;

access_violation:
	// XXX kill application
	return -1;
}
Esempio n. 15
0
static int32
sis900_rxInterrupt(struct sis_info *info)
{
	int32 handled = B_UNHANDLED_INTERRUPT;
	int16 releaseRxSem = 0;
	int16 limit;

	acquire_spinlock(&info->rxSpinlock);

	HACK(spin(10000));

	// check for packet ownership
	for (limit = info->rxFree; limit > 0; limit--) {
		if (!(info->rxDescriptor[info->rxInterruptIndex].status & SiS900_DESCR_OWN)) {
//			if (limit == info->rxFree)
//			{
				//dprintf("here!\n");
//				limit++;
//				continue;
//			}
			break;
		}
		//dprintf("received frame %d!\n",info->rxInterruptIndex);

		releaseRxSem++;
		info->rxInterruptIndex = (info->rxInterruptIndex + 1) & NUM_Rx_MASK;
		info->rxFree--;
	}
	release_spinlock(&info->rxSpinlock);

	// reenable rx queue
	write32(info->registers + SiS900_MAC_COMMAND, SiS900_MAC_CMD_Rx_ENABLE);

	if (releaseRxSem) {
		release_sem_etc(info->rxSem, releaseRxSem, B_DO_NOT_RESCHEDULE);
		return B_INVOKE_SCHEDULER;
	}

	return handled;
}
Esempio n. 16
0
status_t
AHCIPort::WaitForTransfer(int *tfd, bigtime_t timeout)
{
    status_t result = acquire_sem_etc(fResponseSem, 1, B_RELATIVE_TIMEOUT,
                                      timeout);
    if (result < B_OK) {
        cpu_status cpu = disable_interrupts();
        acquire_spinlock(&fSpinlock);
        fCommandsActive &= ~1;
        release_spinlock(&fSpinlock);
        restore_interrupts(cpu);

        result = B_TIMED_OUT;
    } else if (fError) {
        *tfd = fRegs->tfd;
        result = B_ERROR;
        fError = false;
    } else {
        *tfd = fRegs->tfd;
    }
    return result;
}
Esempio n. 17
0
int request_irq( struct thread *t, int irq )
{
	int ans = -1;
	
	if ( (irq < 0) || (irq >= IRQ_COUNT) ) return -1;
	
	acquire_spinlock( &irq_lock );
	
	  if ( handlers[irq] == NULL )
	  {
		  handlers[irq] = t;
		  
		  t->state = THREAD_IRQ;

		  if ( masked( irq ) != 0 ) unmask_irq( irq );
		  ans = 0;
	  }

	
	release_spinlock( &irq_lock );
	return ans;
}
Esempio n. 18
0
err_code resume_thread(thread_id id) {
  err_code err = ERR_NONE;
  CAST_TO_THREAD(thrd, id);

  acquire_spinlock(&inactive.lock, 0);
  if (thrd->state == THREAD_STATE_PAUSED) {
    if (thrd->next)
      thrd->next->prev = thrd->prev;
    if (thrd->prev)
      thrd->prev->next = thrd->next;
    if (inactive.tail == thrd)
      inactive.tail = thrd->next;
    inactive.total_threads--;

    thrd->real_priority = thrd->priority;
    thrd->quantum = 0;
    update_priority_quantum(thrd);

    struct cpu_task task = { .type = CPU_TASK_RESUME, .thread = thrd };
    run_cpu_task(find_least_loaded_cpu(thrd->affinity), &task);
  }
  else
Esempio n. 19
0
int aqueue_add( struct aqueue *aq, void* obj )
{
	struct aqueue_page *page = NULL;
	void* position;

	acquire_spinlock( &(aq->lock) );
		
	int page_div = aq->last_position / aq->obj_count;
	int page_mod = aq->last_position % aq->obj_count;
	

	if ( (page_mod == 0) && (aq->pages <= page_div) )
	{
		size_t size = sizeof(struct aqueue_page) + aq->obj_count * aq->obj_size;
		page = (struct aqueue_page*)kmalloc( size );
		if ( page == NULL ) 
		{
			release_spinlock( &(aq->lock) );
			return -1;
		}

		page->next 	= NULL;
		aq->pages 	+= 1;

		if ( aq->page == NULL ) aq->page = page;
						else	aq->last_page->next = page;

		aq->last_page = page;
	}

	page = aq->last_page;

	position = page;
	position = position + sizeof( struct aqueue_page ) + aq->obj_size * page_mod;
	kmemcpy( position, obj, aq->obj_size );
	release_spinlock( &(aq->lock) );
	return 0;
}
Esempio n. 20
0
struct sem_t {
  spinlock mu;
  int val;
  thread *queue;
}

/*
 * down
 *
 *   If semaphore value is positive, decrement it.
 *   Otherwise, wait.
 *   
 */

down(sem_t &sem) {
  while (1) {
    disable_interrupts();
    acquire_spinlock(mu);

    if (sem->val > 0) {
      // Semaphore was available
      sem->val--;
      release_spinlock(mu);
      enable_interrupts();
      return;
    } 
    else {
      // Semaphore in use - go to sleep
      this_thread->state = WAITING;
      enqueue(queue,this_thread);
      
      release_spinlock(mu);
      enable_interrupts();
      schedule();  // pick a READY thread to run
      // when schedule returns, this thread will be RUNNING
    }
  } // repeat
}
Esempio n. 21
0
int destroy_local_semaphore( struct process *proc, int sem_id )
{
	struct sem_link *sl		= NULL;
	struct sem_link *tmp	= NULL;
	struct thread *tr		= NULL;

	if ( sem_id < 0 ) return -1;
	if ( sem_id >= LOCAL_SEM_COUNT ) return -1;
	
	acquire_spinlock( & (proc->sems_lock) );
		
		if ( proc->sems[ sem_id ].sem_id != sem_id ) 
		{
			release_spinlock( & (proc->sems_lock) );
			return -1;
		}
		

		// Tell the waiting guys to go away.
		sl = proc->sems[ sem_id ].waiting_list;
		while ( sl != NULL )
		{
			tmp = sl;

			tr = find_thread_with_id( proc, sl->tid );
			if ( tr != NULL )
					set_thread_state( tr, THREAD_RUNNING );

			sl = sl->next;
			free( tmp );
		}

		proc->sems[ sem_id ].waiting_list = NULL;
		proc->sems[ sem_id ].sem_id 	= -1; // DELETED!

	release_spinlock( & (proc->sems_lock) );
	return 0;
}
Esempio n. 22
0
char 
SORAAPI 
remove_thread_safe_enlist_entry(struct thread_safe_enlist* tslist, 
	struct LIST_ENTRY_EX* entry,
	char lock) {

	KIRQL irql;
	acquire_spinlock(lock,
		tslist->m_sync,
		irql);
	if (IsListEmpty(&tslist->m_head.m_entry)) {		
		release_spinlock(lock, 
			tslist->m_sync,
			irql);
		return false;
	}
	RemoveEntryList(&entry->m_entry);
	InterlockedDecrement(&tslist->m_count);
	release_spinlock(lock, 
		tslist->m_sync,
		irql);	
	return true;
}
Esempio n. 23
0
void reschedule(void)
{
    int hwthread = __builtin_nyuzi_read_control_reg(CR_CURRENT_THREAD);
    struct thread *old_thread;
    struct thread *next_thread;

    // Put current thread back on ready queue

    acquire_spinlock(&thread_q_lock);
    old_thread = cur_thread[hwthread];
    enqueue_thread(&ready_q, old_thread);
    next_thread = dequeue_thread(&ready_q);
    if (old_thread != next_thread)
    {
        cur_thread[hwthread] = next_thread;
        context_switch(&old_thread->current_stack,
            next_thread->current_stack,
            next_thread->map->page_dir,
            next_thread->map->asid);
    }

    release_spinlock(&thread_q_lock);
}
Esempio n. 24
0
int aqueue_next( struct aqueue *aq, void* obj )
{
	void* position;

	acquire_spinlock( &(aq->lock) );

	int page_div = aq->position / aq->obj_count;
	int page_mod = aq->position % aq->obj_count;

	assert( aq->position != aq->last_position );


	while ( page_div > 0 )
	{
		struct aqueue_page *tmp = aq->page;
		aq->page = aq->page->next;
		kfree( tmp );
		assert( aq->page != NULL );

		aq->last_position 	-= aq->obj_count;
		aq->position 		-= aq->obj_count;
		aq->pages -= 1;

		page_div -= 1;	// Down one.
	}


	position = aq->page;
	position += sizeof( struct aqueue_page ) + aq->obj_size * page_mod;

	aq->position += 1;

	kmemcpy( obj, position, aq->obj_size );
	release_spinlock( &(aq->lock) );
	return 0;
}
Esempio n. 25
0
int signal_global_semaphore( struct thread* tr, int sem_id )
{
	struct sem_link *sl;
	struct process *proc;
	struct thread *target;

	acquire_spinlock( & global_sems_lock );
		
		if ( global_sems[ sem_id ].sem_id != sem_id ) 
		{
			release_spinlock( & global_sems_lock );
			return -1;
		}
		
		global_sems[ sem_id ].count -= 1;
			
			// wake up any waiting threads
			sl = global_sems[ sem_id ].waiting_list;	
			if ( sl != NULL )
			{
				proc = checkout_process( sl->pid, WRITER );
				if ( proc != NULL )
				{
					target = find_thread_with_id( proc, sl->tid );
					if ( target != NULL )
						set_thread_state( target, THREAD_RUNNING );

					commit_process( proc );
				}
				global_sems[ sem_id ].waiting_list = sl->next;
				free( sl );
			}

	release_spinlock( & ( global_sems_lock ) );
	return 0;
}
Esempio n. 26
0
File: sync.c Progetto: AlexSnet/toy
INTERNAL err_code __sleep_in_mutex(struct mutex *mutex) {
  struct __mutex_node *node = NULL;
  bool acquired;

  acquire_spinlock(&mutex->ilock, 0);
  acquired = acquire_spinlock_int(&mutex->mlock, 1);
  if (!acquired) {
    node = alloc_block(&mutex_node_pool);
    if (node) {
      node->next = NULL;
      node->id = get_thread();
      if (mutex->head)
        mutex->head->next = node;
      mutex->head = node;
      if (!mutex->tail)
        mutex->tail = node;
      pause_this_thread(&mutex->ilock);
    }
  }
  if (!node)
    release_spinlock(&mutex->ilock);

  return (acquired || node) ? ERR_NONE : ERR_OUT_OF_MEMORY;
}
Esempio n. 27
0
int read_sdmmc_device(unsigned int block_address, void *ptr)
{
    int result;
    int old_flags;

    old_flags = disable_interrupts();
    acquire_spinlock(&sd_lock);

    result = send_sd_command(SD_CMD_READ_BLOCK, block_address);
    if (result != 0)
        return -1;

    for (int i = 0; i < BLOCK_SIZE; i++)
        ((char*) ptr)[i] = spi_transfer(0xff);

    // checksum (ignored)
    spi_transfer(0xff);
    spi_transfer(0xff);

    release_spinlock(&sd_lock);
    restore_interrupts(old_flags);

    return BLOCK_SIZE;
}
Esempio n. 28
0
void
AHCIPort::Interrupt()
{
    uint32 is = fRegs->is;
    fRegs->is = is; // clear interrupts

    if (is & PORT_INT_ERROR) {
        InterruptErrorHandler(is);
        return;
    }

    uint32 ci = fRegs->ci;

    RWTRACE("[%lld] %ld AHCIPort::Interrupt port %d, fCommandsActive 0x%08" B_PRIx32 ", "
            "is 0x%08" B_PRIx32 ", ci 0x%08" B_PRIx32 "\n", system_time(), find_thread(NULL),
            fIndex, fCommandsActive, is, ci);

    acquire_spinlock(&fSpinlock);
    if ((fCommandsActive & 1) && !(ci & 1)) {
        fCommandsActive &= ~1;
        release_sem_etc(fResponseSem, 1, B_DO_NOT_RESCHEDULE);
    }
    release_spinlock(&fSpinlock);
}
Esempio n. 29
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;
}
Esempio n. 30
0
File: 53c8xx.c Progetto: DonCN/haiku
static int32
scsi_int_dispatch(void *data)
{
	Symbios *s = (Symbios *) data;
	int reselected = 0;
	uchar istat;

	if(s->reset) return B_UNHANDLED_INTERRUPT;

	acquire_spinlock(&(s->hwlock));
	istat = inb(sym_istat);

	if(istat & sym_istat_dip){
		uchar dstat = inb(sym_dstat);

		if(dstat & sym_dstat_sir){
			/* Handle and interrupt from the SCRIPTS program */
		 	uint32 status = HE(in32(sym_dsps));
	//		kprintf("<%02x>",status);

			switch(status){
			case status_ready:
				kp("sym: ready\n");
				break;

			case status_iocomplete:
				kp("sym: done %08x\n",s->active);
				if(s->active){
					/* io is complete -- any more io is an error */
					s->active->datain_phys = s->sram_phys + Ent_phase_dataerr;
					s->active->dataout_phys = s->sram_phys + Ent_phase_dataerr;
				}
				break;

			case status_reselected:{
				uint32 id = inb(sym_ssid);
				if(id & sym_ssid_val) {
					s->active = &(s->targ[id & s->idmask]);
					kp("sym: resel %08x\n",s->active);
					if(s->active->status != status_waiting){
						s->active = NULL;
						kprintf("symbios: bad reselect %ld\n",id & sym_ssid_encid);
					} else {
						reselected = 1;
					}
				} else {
					kprintf("symbios: invalid reselection!?\n");
				}
				break;
			}

			case status_timeout:
				/* inform the unlucky party and dequeue it */
				kp("sym: timeout %08lx\n",s->startqueue);
				if(s->startqueue){
					s->startqueue->status = status_timeout;
					release_sem_etc(s->startqueue->sem_done, 1, B_DO_NOT_RESCHEDULE);
					if(!(s->startqueue = s->startqueue->next)){
						s->startqueuetail = NULL;
					}
				}
				break;

			case status_selected:
				/* selection succeeded.  Remove from start queue and make active */
				kp("sym: selected %08lx\n",s->startqueue);
				if(s->startqueue){
					s->active = s->startqueue;
					s->active->status = status_active;
					if(!(s->startqueue = s->startqueue->next)){
						s->startqueuetail = NULL;
					}
				}
				break;

			case status_syncin:
				setparams(s->active,
						  s->active->priv->_syncmsg[1]*4,
						  s->active->priv->_syncmsg[2],
						  s->active->wide);
				break;

			case status_widein:
				setparams(s->active, s->active->period, s->active->offset,
						  s->active->priv->_widemsg[1]);
				break;

			case status_ignore_residue:
				kprintf("ignore residue 0x%02x\n",s->active->priv->_extdmsg[0]);
				break;

			case status_disconnect:
				kp("sym: disc %08lx\n",s->active);
				/* device disconnected. make inactive */
				if(s->active){
					s->active->status = status_waiting;
					s->active = NULL;
				}
				break;

			case status_badmsg:
				kp("sym: badmsg %02x\n",s->active->priv->_recvmsg[0]);

			case status_complete:
			case status_badstatus:
			case status_overrun:
			case status_underrun:
			case status_badphase:
			case status_badextmsg:
				kp("sym: error %08lx / %02x\n",s->active,status);
				/* transaction completed successfully or in error. report our status. */
				if(s->active){
					s->active->status = status;
					release_sem_etc(s->active->sem_done, 1, B_DO_NOT_RESCHEDULE);
					s->active = NULL;
				}
				break;

			case status_selftest:
				/* signal a response to the selftest ... don't actually start up the
				   SCRIPTS like we normally do */
				s->status = OFFLINE;
				goto done;
				break;

			default:
				kp("sym: int 0x%08lx ...\n",status);
			}
			goto reschedule;
		} else {
			kprintf("symbios: weird error, dstat = %02x\n",dstat);
		}
	}

	if(istat & sym_istat_sip){
		uchar sist0;
		sist0 = inb(sym_sist1);

		if(sist0 & sym_sist1_sbmc){
			kprintf("sym: SBMC %02x!\n",inb(sym_stest4) & 0xc0);
		}

		if(sist0 & sym_sist1_sto){
			/* select timeout */
			kp("sym: Timeout %08lx\n",s->startqueue);
			/* inform the unlucky party and dequeue it */
			if(s->startqueue){
				s->startqueue->status = status_timeout;
				release_sem_etc(s->startqueue->sem_done, 1, B_DO_NOT_RESCHEDULE);
				if(!(s->startqueue = s->startqueue->next)){
					s->startqueuetail = NULL;
				}
			} else {
				kprintf("symbios: ghost target timed out\n");
			}
			inb(sym_sist0);	//   apparently we MUST read sist0 as well
			goto reschedule;
		}

		sist0 = inb(sym_sist0) & 0x8f;

		if(sist0 && s->active){
			if(sist0 & sym_sist0_ma){
				/* phase mismatch -- we experienced a disconnect while in
				   a DataIn or DataOut... gotta figure out how much we
				   transferred, update the sgtable, take the FIFOs into
				   account, etc (see 9-9 in Symbios PCI-SCSI Programming Guide) */
				SymInd *t;
				uint32 dfifo_val, bytesleft, dbc;
				uint32 dsp = HE(in32(sym_dsp));
				uint32 n = (dsp - s->active->table_phys) / 8 - 1;

				if((dsp < s->active->priv_phys) || (n > 129)) {
					/* we mismatched during some other phase ?! */
					kprintf("Phase Mismatch (dsp = 0x%08lx)\n",dsp);
					goto reschedule;
				}

				t = &(s->active->priv->table[n]);

#if 0
				t->count = HE(t->count);
				t->address = HE(t->count);
#endif
				/* dbc initially = table[n].count, counts down */
				dbc = (uint32) HE(in32(sym_dbc)) & 0x00ffffffL;

				t->count &= 0xffffff;
#if DEBUG_PM
				kprintf("PM(%s) dbc=0x%08x, n=%02d, a=0x%08x, l=0x%08x\n",
						s->active->inbound ? " in" : "out", dbc, n, t->address, t->count);
#endif
				if(s->active->inbound){
					/* data in is easy... flush happens automatically */
					t->address += t->count - dbc;
					t->count = dbc;
#if DEBUG_PM
					kprintf("                              a=0x%08x, l=0x%08x\n",
					t->address, t->count);
#endif
					s->active->datain_phys = s->active->table_phys + 8*(t->count ? n : n+1);
					t->count |= s->op_in;
#if 0
					t->count = LE(t->count);
					t->address = LE(t->address);
#endif
					goto reschedule;
				} else {
					if(inb(sym_ctest5) & 0x20){
						/* wide FIFO */
						dfifo_val = ((inb(sym_ctest5) & 0x03) << 8) | inb(sym_dfifo);
						bytesleft = (dfifo_val - (dbc & 0x3ff)) & 0x3ff;
					} else {
						dfifo_val = (inb(sym_dfifo) & 0x7f);
						bytesleft = (dfifo_val - (dbc & 0x7f)) & 0x7f;
					}
					if(inb(sym_sstat0) & 0x20) bytesleft++;
					if(inb(sym_sstat2) & 0x20) bytesleft++;
					if(inb(sym_sstat0) & 0x40) bytesleft++;
					if(inb(sym_sstat2) & 0x40) bytesleft++;

					/* clear fifo */
					outb(sym_ctest3, 0x04);

					t->address += t->count - dbc;
					t->count = dbc;

					/* adjust for data that didn't make it to the target */
					t->address -= bytesleft;
					t->count += bytesleft;
#if DEBUG_PM
					kprintf("                              a=0x%08x, l=0x%08x\n",
					t->address, t->count);
#endif
					s->active->dataout_phys = s->active->table_phys + 8*(t->count ? n : n+1);
					t->count |= s->op_out;
#if 0
					t->count = LE(t->count);
					t->address = LE(t->address);
#endif
					spin(10);
					goto reschedule;
				}
			}

			if(sist0 & sym_sist0_udc){
				kprintf("symbios: Unexpected Disconnect (dsp = 0x%08lx)\n", in32(sym_dsp));
			}

			if(sist0 & sym_sist0_sge){
				kprintf("symbios: SCSI Gross Error\n");
			}

			if(sist0 & sym_sist0_rst){
				kprintf("symbios: SCSI Reset\n");
			}

			if(sist0 & sym_sist0_par){
				kprintf("symbios: Parity Error\n");
			}

			s->active->status = status_badphase;
			release_sem_etc(s->active->sem_done, 1, B_DO_NOT_RESCHEDULE);
			s->active = NULL;

			goto reschedule;
		}
	} else {
		/* nothing happened... must be somebody else's problem */
		release_spinlock(&(s->hwlock));
		 return B_UNHANDLED_INTERRUPT;
	}

reschedule:
	/* start the SCRIPTS processor at one of three places, depending on state
	**
	** 1. If there is an active transaction, insure that the script is patched
	**    correctly, the DSA is loaded, and start up at "switch".
	**
	** 2. If there is a transaction at the head of the startqueue, set the DSA
	**    and start up at "start" to try to select the target and start the
	**    transaction
	**
	** 3. If there is nothing else to do, go to "idle" and wait for signal or
	**    reselection
	*/

	if(s->active){
		out32(sym_dsa, s->active->priv_phys + ADJUST_PRIV_TO_DSA);
		s->script[PATCH_DATAIN] = LE(s->active->datain_phys);
		s->script[PATCH_DATAOUT] = LE(s->active->dataout_phys);

		s->active->status = status_active;
		s->status = ACTIVE;
		if(reselected){
			out32(sym_dsp, LE(s->sram_phys + Ent_switch_resel));
			//kp("sym: restart @ %08x / reselected\n",Ent_switch_resel);
		} else {
			out32(sym_dsp, LE(s->sram_phys + Ent_switch));
			//kp("sym: restart @ %08x / selected\n", Ent_switch);
		}
	} else {
		if(s->startqueue){
			out32(sym_dsa, LE(s->startqueue->priv_phys + ADJUST_PRIV_TO_DSA));

			s->startqueue->status = status_selecting;
			s->status = START;
			out32(sym_dsp, LE(s->sram_phys + Ent_start));
			//kp("sym: restart @ %08x / started\n", Ent_start);
		} else {
			s->status = IDLE;
			out32(sym_dsp, LE(s->sram_phys + Ent_idle));
			//kp("sym: restart @ %08x / idle\n", Ent_idle);
		}
	}

done:
	release_spinlock(&(s->hwlock));
    return B_HANDLED_INTERRUPT;
}