Пример #1
0
static void
virtio_net_check_queues(void)
{
	struct packet *p;
	size_t len;

	/* Put the received packets into the recv list */
	while (virtio_from_queue(net_dev, RX_Q, (void **)&p, &len) == 0) {
		p->len = len;
		STAILQ_INSERT_TAIL(&recv_list, p, next);
		in_rx--;
		virtio_net_stats.ets_packetR++;
	}

	/*
	 * Packets from the TX queue just indicated they are free to
	 * be reused now. inet already knows about them as being sent.
	 */
	while (virtio_from_queue(net_dev, TX_Q, (void **)&p, NULL) == 0) {
		memset(p->vhdr, 0, sizeof(*p->vhdr));
		memset(p->vdata, 0, MAX_PACK_SIZE);
		STAILQ_INSERT_HEAD(&free_list, p, next);
		virtio_net_stats.ets_packetT++;
	}
}
Пример #2
0
cursor_t *
cursor_create(store_t *store)
{
    cursor_t *cursor;

    cursor = nc_alloc(sizeof(*cursor));
    if (cursor == NULL) {
        return NULL;
    }

    cursor->iter = leveldb_create_iterator(store->db, store->roptions);
    if (cursor->iter == NULL) {
        nc_free(cursor);
        return NULL;
    }

    leveldb_iter_seek_to_first(cursor->iter);

    cursor->id = g_cursor_id++;
    cursor->owner = store;

    ncursor++;
    STAILQ_INSERT_HEAD(&cursorq, cursor, next);

    return cursor;
}
Пример #3
0
/**
 * mutt_list_insert_head - Insert a string at the beginning of a List
 * @param h Head of the List
 * @param s String to insert
 * @retval ptr Newly inserted ListNode containing the string
 */
struct ListNode *mutt_list_insert_head(struct ListHead *h, char *s)
{
  struct ListNode *np = mutt_mem_calloc(1, sizeof(struct ListNode));
  np->data = s;
  STAILQ_INSERT_HEAD(h, np, entries);
  return np;
}
Пример #4
0
/*! \fn int io_device_read(uint16_t procnum)
 *  \brief Richiede un accesso al dispositivo di I/O
 *  \details La funzione si occupa di accodare la richiesta d'accesso al
 *  dispositivo di I/O da parte di uno dei processi. Qualora l'MMU abbia
 *  gia terminato la propria esecuzione, la funzione non accetta
 *  ulteriori richieste.
 *  \param procnum      ID del processo
 *  \return             Restituisce l'esito dell'operazione:
 *                      1  la richiesta e' stata accodata
 *                      0  quando non sono piu' ammesse richieste
 */
int io_device_read(uint16_t procnum)
{
    io_entry_t *req;
    int ret;

    pthread_mutex_lock(&request_lock);

    if (!io_device_should_exit) {
        pthread_mutex_lock(&wait_lock);
        req = XMALLOC(io_entry_t, 1);
        req->pid = proc_table[procnum]->pid;
        req->procnum = procnum;
        pthread_mutex_lock(&fifo_lock);
        if (STAILQ_EMPTY(&io_request_head))
            STAILQ_INSERT_HEAD(&io_request_head, req, entries);
        else
            STAILQ_INSERT_TAIL(&io_request_head, req, entries);
        ioreq_count++;
        pthread_mutex_unlock(&fifo_lock);

        fprintf(LOG_FILE(procnum),
                "\nRichiesta d'accesso a dispositivo I/O accodata\n");

        pthread_mutex_unlock(&wait_lock);
        pthread_cond_signal(&wait_cond);
        ret = 1;
    } else
        ret = 0;

    pthread_mutex_unlock(&request_lock);

    return ret;
}
Пример #5
0
void mbuf_recycle(struct context *ctx, struct mbuf *mbuf)
{
    ctx->stats.buffers--;
    STAILQ_NEXT(mbuf, next) = NULL;
    STAILQ_INSERT_HEAD(&ctx->free_mbufq, mbuf, next);
    ctx->nfree_mbufq++;
}
Пример #6
0
/* Async. stream output */
static void
fwe_as_output(struct fwe_softc *fwe, struct ifnet *ifp)
{
	struct mbuf *m;
	struct fw_xfer *xfer;
	struct fw_xferq *xferq;
	struct fw_pkt *fp;
	int i = 0;

	xfer = NULL;
	xferq = fwe->fd.fc->atq;
	while ((xferq->queued < xferq->maxq - 1) &&
			(ifp->if_snd.ifq_head != NULL)) {
		FWE_LOCK(fwe);
		xfer = STAILQ_FIRST(&fwe->xferlist);
		if (xfer == NULL) {
#if 0
			printf("if_fwe: lack of xfer\n");
#endif
			FWE_UNLOCK(fwe);
			break;
		}
		STAILQ_REMOVE_HEAD(&fwe->xferlist, link);
		FWE_UNLOCK(fwe);

		IF_DEQUEUE(&ifp->if_snd, m);
		if (m == NULL) {
			FWE_LOCK(fwe);
			STAILQ_INSERT_HEAD(&fwe->xferlist, xfer, link);
			FWE_UNLOCK(fwe);
			break;
		}
		BPF_MTAP(ifp, m);

		/* keep ip packet alignment for alpha */
		M_PREPEND(m, ETHER_ALIGN, M_NOWAIT);
		fp = &xfer->send.hdr;
		*(uint32_t *)&xfer->send.hdr = *(int32_t *)&fwe->pkt_hdr;
		fp->mode.stream.len = m->m_pkthdr.len;
		xfer->mbuf = m;
		xfer->send.pay_len = m->m_pkthdr.len;

		if (fw_asyreq(fwe->fd.fc, -1, xfer) != 0) {
			/* error */
			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
			/* XXX set error code */
			fwe_output_callback(xfer);
		} else {
			if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
			i++;
		}
	}
#if 0
	if (i > 1)
		printf("%d queued\n", i);
#endif
	if (i > 0)
		xferq->start(fwe->fd.fc);
}
Пример #7
0
static void virtio_net_check_queues(void)
{
    struct packet *p;
    size_t len;

    /* Put the received packets into the recv list */
    while (virtio_from_queue(to_virtio_dev_t(&pci_vn), RX_Q, (void **)&p, &len)
           == 0) {
        pci_d("virtio_from_queue:%lx,len:%x\n", p, len);
        p->len = len;
        pci_d("vhdr:%lx,phdr:%lx,vdata:%lx,pdata:%lx,len:%d\n",
              p->vhdr, p->phdr, p->vdata, p->pdata, p->len);
        struct virtio_net_hdr {
            u8 flags;
            u8 gso_type;
            u16 hdr_len;        /* Ethernet + IP + tcp/udp hdrs */
            u16 gso_size;       /* Bytes to append to hdr_len per frame */
            u16 csum_start;     /* Position to start checksumming from */
            u16 csum_offset;    /* Offset after that to place checksum */
        };

        pci_d
            ("flags:%x,gso_type:%x,hdr_len:%x,gso_size:%x,csum_start:%x,csum_offset:%x\n",
             p->vhdr->flags, p->vhdr->gso_type, p->vhdr->hdr_len,
             p->vhdr->gso_size, p->vhdr->csum_start, p->vhdr->csum_offset);
        ulong *pl = (ulong *) p->vdata;

        pci_d("%lx,%lx,%lx,%lx,%lx,%lx,%lx\n", pl[0], pl[1], pl[2], pl[3],
              pl[4], pl[5], pl[6]);
        u16 *pw = (u16 *) p->vdata;

        pci_d("%lx,%lx,%lx\n", pw[5], pw[6], pw[7]);
        uchar *pc = (uchar *) p->vdata+8;
        pci_d("To:%x:%x:%x:%x:%x:%x,From:%x:%x:%x:%x:%x:%x: len:%x,type:%x\n",
              pc[0], pc[1], pc[2], pc[3], pc[4], pc[5], pc[6], pc[7], pc[8],
              pc[9], pc[10], pc[11],pw[10],pw[11]);
        STAILQ_INSERT_TAIL(&recv_list, p, next);
        in_rx--;
        virtio_net_stats.ets_packetR++;
    }
    /*
     * Packets from the TX queue just indicated they are free to
     * be reused now. inet already knows about them as being sent.
     */
    while (virtio_from_queue(to_virtio_dev_t(&pci_vn), TX_Q, (void **)&p, NULL)
           == 0) {
        pci_d("virtio_from_queue:%lx,len:%x\n", p, len);
        ulong *pl = (ulong *) p;

        pci_d("%lx,%lx,%lx,%lx,%lx,%lx,%lx\n", pl[0], pl[1], pl[2], pl[3],
              pl[4], pl[5], pl[6]);
        memset(p->vhdr, 0, sizeof(*p->vhdr));
        memset(p->vdata, 0, MAX_PACK_SIZE);
        STAILQ_INSERT_HEAD(&free_list, p, next);
        virtio_net_stats.ets_packetT++;
    }
}
Пример #8
0
void
mbuf_put(struct mbuf *mbuf)
{
    log_debug(LOG_VVERB, "put mbuf %p len %d", mbuf, mbuf->last - mbuf->pos);

    ASSERT(STAILQ_NEXT(mbuf, next) == NULL);
    ASSERT(mbuf->magic == MBUF_MAGIC);

    nfree_mbufq++;
    STAILQ_INSERT_HEAD(&free_mbufq, mbuf, next);
}
Пример #9
0
void
flowadv_add_entry(struct flowadv_fcentry *fce) {
    lck_mtx_lock_spin(&fadv_lock);
    STAILQ_INSERT_HEAD(&fadv_list, fce, fce_link);
    VERIFY(!STAILQ_EMPTY(&fadv_list));

    if (!fadv_active && fadv_thread != THREAD_NULL)
        wakeup_one((caddr_t)&fadv_list);

    lck_mtx_unlock(&fadv_lock);
}
Пример #10
0
int
taskqueue_enqueue(struct taskqueue *queue, struct task *task)
{
	struct task *ins;
	struct task *prev;

	int s = splhigh();

	/*
	 * Don't allow new tasks on a queue which is being freed.
	 */
	if (queue->tq_draining) {
		splx(s);
		return EPIPE;
	}

	/*
	 * Count multiple enqueues.
	 */
	if (task->ta_pending) {
		task->ta_pending++;
		splx(s);
		return 0;
	}

	/*
	 * Optimise the case when all tasks have the same priority.
	 */
	prev = STAILQ_LAST(&queue->tq_queue);
	if (!prev || prev->ta_priority >= task->ta_priority) {
		STAILQ_INSERT_TAIL(&queue->tq_queue, task, ta_link);
	} else {
		prev = 0;
		for (ins = STAILQ_FIRST(&queue->tq_queue); ins;
		     prev = ins, ins = STAILQ_NEXT(ins, ta_link))
			if (ins->ta_priority < task->ta_priority)
				break;

		if (prev)
			STAILQ_INSERT_AFTER(&queue->tq_queue, prev, task, ta_link);
		else
			STAILQ_INSERT_HEAD(&queue->tq_queue, task, ta_link);
	}

	task->ta_pending = 1;
	if (queue->tq_enqueue)
		queue->tq_enqueue(queue->tq_context);

	splx(s);

	return 0;
}
Пример #11
0
void buf_time_free(struct buf_time *t)
{
    t->ctx->mstats.buf_times--;

    if (t->ctx->mstats.free_buf_times > BUF_TIME_LIMIT) {
        cv_free(t);
        return;
    }

    STAILQ_NEXT(t, next) = NULL;
    STAILQ_INSERT_HEAD(&t->ctx->free_buf_timeq, t, next);
    t->ctx->mstats.free_buf_times++;
}
Пример #12
0
static void
ktrace_init(void *dummy)
{
	struct ktr_request *req;
	int i;

	mtx_init(&ktrace_mtx, "ktrace", NULL, MTX_DEF | MTX_QUIET);
	sx_init(&ktrace_sx, "ktrace_sx");
	STAILQ_INIT(&ktr_free);
	for (i = 0; i < ktr_requestpool; i++) {
		req = malloc(sizeof(struct ktr_request), M_KTRACE, M_WAITOK);
		STAILQ_INSERT_HEAD(&ktr_free, req, ktr_list);
	}
}
Пример #13
0
/*===========================================================================*
 *				mq_init					     *
 *===========================================================================*/
void mq_init(void)
{
/* Initialize the message queues and message cells.
 */
  int i;

  STAILQ_INIT(&free_list);

  for (i = 0; i < MAX_DEVICES; i++)
	STAILQ_INIT(&queue[i]);

  for (i = 0; i < MQ_SIZE; i++)
	STAILQ_INSERT_HEAD(&free_list, &pool[i], next);
}
Пример #14
0
void
ath_txfrag_cleanup(struct ath_softc *sc,
	ath_bufhead *frags, struct ieee80211_node *ni)
{
	struct ath_buf *bf, *next;

	ATH_TXBUF_LOCK_ASSERT(sc);

	STAILQ_FOREACH_SAFE(bf, frags, bf_list, next) {
		/* NB: bf assumed clean */
		STAILQ_REMOVE_HEAD(frags, bf_list);
		STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
		ieee80211_node_decref(ni);
	}
Пример #15
0
static void
virtio_net_init_queues(void)
{
	int i;
	STAILQ_INIT(&free_list);
	STAILQ_INIT(&recv_list);

	for (i = 0; i < BUF_PACKETS; i++) {
		packets[i].idx = i;
		packets[i].vhdr = &hdrs_vir[i];
		packets[i].phdr = hdrs_phys + i * sizeof(hdrs_vir[i]);
		packets[i].vdata = data_vir + i * MAX_PACK_SIZE;
		packets[i].pdata = data_phys + i * MAX_PACK_SIZE;
		STAILQ_INSERT_HEAD(&free_list, &packets[i], next);
	}
}
Пример #16
0
EP_STAT
gdp_event_free(gdp_event_t *gev)
{
	EP_ASSERT_POINTER_VALID(gev);

	ep_dbg_cprintf(Dbg, 48, "gdp_event_free(%p)\n", gev);

	if (gev->datum != NULL)
		gdp_datum_free(gev->datum);
	gev->datum = NULL;
	gev->type = _GDP_EVENT_FREE;
	ep_thr_mutex_lock(&FreeListMutex);
	STAILQ_INSERT_HEAD(&FreeList, gev, queue);
	ep_thr_mutex_unlock(&FreeListMutex);
	return EP_STAT_OK;
}
Пример #17
0
static int
virtio_net_cpy_to_user(message *m)
{
	/* Hmm, this looks so similar to cpy_from_user... TODO */
	int i, r, size, ivsz;
	int left = MAX_PACK_SIZE;	/* Try copying the whole packet */
	int bytes = 0;
	iovec_s_t iovec[NR_IOREQS];
	struct packet *p;

	/* This should only be called if recv_list has some entries */
	assert(!STAILQ_EMPTY(&recv_list));

	p = STAILQ_FIRST(&recv_list);
	STAILQ_REMOVE_HEAD(&recv_list, next);

	virtio_net_fetch_iovec(iovec, m, m->m_net_netdrv_dl_readv_s.grant,
		 m->m_net_netdrv_dl_readv_s.count);

	for (i = 0; i < m->m_net_netdrv_dl_readv_s.count && left > 0; i++) {
		ivsz = iovec[i].iov_size;
		size = left > ivsz ? ivsz : left;
		r = sys_safecopyto(m->m_source, iovec[i].iov_grant, 0,
				   (vir_bytes) p->vdata + bytes, size);

		if (r != OK)
			panic("%s: copy to %d failed (%d)", name,
							    m->m_source,
							    r);

		left -= size;
		bytes += size;
	}

	if (left != 0)
		dput(("Uhm... left=%d", left));

	/* Clean the packet */
	memset(p->vhdr, 0, sizeof(*p->vhdr));
	memset(p->vdata, 0, MAX_PACK_SIZE);
	STAILQ_INSERT_HEAD(&free_list, p, next);

	return bytes;
}
Пример #18
0
void
mpc_url_put(mpc_url_t *mpc_url)
{
    pthread_mutex_lock(&mutex_free);

    ASSERT(mpc_url->no_put == 0);
    ASSERT(STAILQ_NEXT(mpc_url, next) == NULL);
    ASSERT(mpc_url->magic == MPC_URL_MAGIC);

    if (mpc_url_max_nfree != 0 && mpc_url_nfree + 1 > mpc_url_max_nfree) {
        mpc_url_free(mpc_url);
        
    } else {
        mpc_url_nfree++;
        STAILQ_INSERT_HEAD(&mpc_url_free_queue, mpc_url, next);
    }

    pthread_mutex_unlock(&mutex_free);
}
Пример #19
0
static int
rtwn_usb_alloc_rx_list(struct rtwn_softc *sc)
{
	struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc);
	int error, i;

	error = rtwn_usb_alloc_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT,
	    uc->uc_rx_buf_size * RTWN_USB_RXBUFSZ_UNIT);
	if (error != 0)
		return (error);

	STAILQ_INIT(&uc->uc_rx_active);
	STAILQ_INIT(&uc->uc_rx_inactive);

	for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++)
		STAILQ_INSERT_HEAD(&uc->uc_rx_inactive, &uc->uc_rx[i], next);

	return (0);
}
Пример #20
0
/* Push a new entry into the slow log.
 * This function will make sure to trim the slow log accordingly to the
 * configured max length. 
 * The unit of duration is microseconds */
void slowlog_push_entry_if_needed(struct msg *r, long long duration) {
    if (slowlog_log_slower_than < 0) return; /* Slowlog disabled */
    if (duration >= slowlog_log_slower_than) {
        slowlog_entry *se = slowlog_create_entry(r,duration);
        pthread_rwlock_wrlock(&rwlocker);
        se->id = slowlog_entry_id++;
        STAILQ_INSERT_HEAD(&slowlog, se, next);

        if (slowlog_len >= slowlog_max_len) {
            se = STAILQ_LAST(&slowlog, slowlog_entry, next);
            STAILQ_REMOVE(&slowlog, se, slowlog_entry, next);
            slowlog_free_entry(se);
        } else {
            slowlog_len ++;
        }
        pthread_rwlock_unlock(&rwlocker);

        slowlog_statistics_input();
    }
}
Пример #21
0
void
mbuf_block_put(struct mbuf_block *mbuf_block)
{
	#ifdef MBUF_DEBUG
		printf("[%p] mbuf_block put %p\n", oxt::thread_signature, mbuf_block);
	#endif

	assert(STAILQ_NEXT(mbuf_block, next) == NULL);
	assert(mbuf_block->magic == MBUF_BLOCK_MAGIC);
	assert(mbuf_block->refcount == 0);
	assert(mbuf_block->pool->nactive_mbuf_blockq > 0);

	mbuf_block->refcount = 1;
	mbuf_block->pool->nfree_mbuf_blockq++;
	mbuf_block->pool->nactive_mbuf_blockq--;
	STAILQ_INSERT_HEAD(&mbuf_block->pool->free_mbuf_blockq, mbuf_block, next);

	#ifdef MBUF_ENABLE_DEBUGGING
		TAILQ_REMOVE(&mbuf_block->pool->active_mbuf_blockq, mbuf_block, active_q);
	#endif
}
Пример #22
0
/*===========================================================================*
 *				mq_dequeue				     *
 *===========================================================================*/
int mq_dequeue(device_id_t device_id, message *mess, int *ipc_status)
{
/* Return and remove a message, including its IPC status, from the message
 * queue of a thread. Return TRUE iff a message was available.
 */
  struct mq_cell *cell;

  assert(device_id >= 0 && device_id < MAX_DEVICES);

  if (STAILQ_EMPTY(&queue[device_id]))
	return FALSE;

  cell = STAILQ_FIRST(&queue[device_id]);
  STAILQ_REMOVE_HEAD(&queue[device_id], next);

  *mess = cell->mess;
  *ipc_status = cell->ipc_status;

  STAILQ_INSERT_HEAD(&free_list, cell, next);

  return TRUE;
}
Пример #23
0
/*
 * Put a packet receive from the RX queue into a user buffer, and return the
 * packet length.  If there are no received packets, return SUSPEND.
 */
static ssize_t
virtio_net_recv(struct netdriver_data * data, size_t max)
{
	struct packet *p;
	ssize_t len;

	/* Get the first received packet, if any. */
	if (STAILQ_EMPTY(&recv_list))
		return SUSPEND;

	p = STAILQ_FIRST(&recv_list);
	STAILQ_REMOVE_HEAD(&recv_list, next);

	/* Copy out the packet contents. */
	len = p->len - sizeof(struct virtio_net_hdr);
	if (len > max)
		len = max;

	/*
	 * HACK: due to lack of padding, received packets may in fact be
	 * smaller than the minimum ethernet packet size.  Inet will accept the
	 * packets just fine if we increase the length to its minimum.  We
	 * already zeroed out the rest of the packet data, so this is safe.
	 */
	if (len < ETH_MIN_PACK_SIZE)
		len = ETH_MIN_PACK_SIZE;

	netdriver_copyout(data, 0, p->vdata, len);

	/* Clean the packet. */
	memset(p->vhdr, 0, sizeof(*p->vhdr));
	memset(p->vdata, 0, MAX_PACK_SIZE);
	STAILQ_INSERT_HEAD(&free_list, p, next);

	/* Readd packets to the receive queue as necessary. */
	virtio_net_refill_rx_queue();

	return len;
}
Пример #24
0
void
mbuf_insert_head(struct mhdr *mhdr, struct mbuf *mbuf)
{
    STAILQ_INSERT_HEAD(mhdr, mbuf, next);
    log_debug(LOG_VVERB, "insert head mbuf %p len %d", mbuf, mbuf->last - mbuf->pos);
}
Пример #25
0
void mbuf_recycle(struct context *ctx, struct mbuf *mbuf)
{
    STAILQ_INSERT_HEAD(&ctx->free_mbufq, mbuf, next);
    ctx->nfree_mbufq++;
}
Пример #26
0
void ath_cont_data(struct ath_softc *sc ,int val,ath_callback ath_draintxq, ath_callback ath_stoprecv)
{
  static struct sk_buff *skb = NULL;
  struct ieee80211_frame *hdr;
  static struct ieee80211com *ic;
  static struct ath_buf *bf,*prev,*first;
  static struct ath_desc *ds;
  static struct ath_hal *ah;
  static STAILQ_HEAD(tpc_buf,ath_buf) tmp_q;
  static int is_inited=0;
  struct ath_txq *txq;
  const HAL_RATE_TABLE *rt;
  u_int8_t *p;
  u_int32_t flags, txrate, r,i;
  u_int16_t hdrlen, framelen, dmalen,delay=0;
#define	MIN(a,b)	((a) < (b) ? (a) : (b))

  if(ath_hal_getdiagstate(sc->sc_ah, 19,0,10,NULL,NULL) == AH_FALSE)
  {
	  printk("HAL does not support TX99 mode \n");
	  printk("compile HAL with AH_PRIVATE_DIAG turned on \n");
      return;
  } 
  if(is_inited == 0)
  {
    STAILQ_INIT(&tmp_q);
    is_inited=1;
  }
	
  /* enter CONT_DATA mode */
  if (val && skb==NULL) {
    skb = ath_alloc_skb(4096, 32);
    if (skb == NULL)
      goto out;

    /* build output packet */
    hdr = (struct ieee80211_frame *)skb_put(skb, sizeof(*hdr));
    IEEE80211_ADDR_COPY(&hdr->i_addr1, test_addr);
    IEEE80211_ADDR_COPY(&hdr->i_addr2, test_addr);
    IEEE80211_ADDR_COPY(&hdr->i_addr3, test_addr);
    hdr->i_dur[0] = 0x0;
    hdr->i_dur[1] = 0x0;
    hdr->i_seq[0] = 0x5a;
    hdr->i_seq[1] = 0x5a;
    hdr->i_fc[0] = IEEE80211_FC0_TYPE_DATA;
    hdr->i_fc[1] = 0;
    hdrlen = sizeof(*hdr);
    for(r=0; r<2000; ) {
      p = skb_put(skb, sizeof(PN9Data));
      memcpy(p, PN9Data, sizeof(PN9Data));
      r += sizeof(PN9Data);
    }
    framelen = hdrlen + r + IEEE80211_CRC_LEN;

    ic = &sc->sc_ic;
    ah = sc->sc_ah;
	rt = sc->sc_currates;
	if (rt==NULL) {
	  printk("no rate table\n");
	  goto out;
	}
	txrate = rt->info[rt->rateCount-1].rateCode;	/* send at highest rate */
	{
	  int rix;
	  if (sc->sc_txrx99.txrate==0)
	    sc->sc_txrx99.txrate = 6000;
	  for(rix=0; rix<rt->rateCount; rix++) {
	    if (rt->info[rix].rateKbps==sc->sc_txrx99.txrate) {
	      txrate = rt->info[rix].rateCode;
	      printk("txrate set to %dKbps\n", sc->sc_txrx99.txrate);
	      break;
	    }
	  }
	}
    ath_draintxq(sc);
    prev=first=NULL;
	printk("txpower set to %d\n", sc->sc_txrx99.txpower);
    /* send 20 frames for the Power Amp to settle down */
    for(i=0;i<20;++i)
    {
	ATH_TXBUF_LOCK_BH(sc);						

	bf = STAILQ_FIRST(&sc->sc_txbuf);
	if (bf != NULL) {
	  STAILQ_REMOVE_HEAD(&sc->sc_txbuf,bf_list);
	}
	ATH_TXBUF_UNLOCK_BH(sc);				
	
	if (bf==NULL) {
	    printk("no tx buf\n");
	    goto out; 
	}
        if(!i)  first=bf;
	framelen = skb->len + IEEE80211_CRC_LEN;
	dmalen = skb->len;
	txq = sc->sc_ac2q[WME_AC_VO];

	bf->bf_skbaddr = bus_map_single(sc->sc_bdev, skb->data, framelen, BUS_DMA_TODEVICE);
	bf->bf_skb = skb;
	bf->bf_node = 0;
	flags = HAL_TXDESC_CLRDMASK;  
	ds = bf->bf_desc;
        if(prev)
	  prev->bf_desc->ds_link = bf->bf_daddr;		/* link from prev desc  */
	ds->ds_data = bf->bf_skbaddr;

	r = ath_hal_setuptxdesc(ah, ds, framelen, hdrlen,
				HAL_PKT_TYPE_NORMAL,
				sc->sc_txrx99.txpower,
				txrate,			    /* tx rate */
				1,			    /* max retries */
				HAL_TXKEYIX_INVALID,	    /* no WEP */
				1,			    /* select Omni Antenna 0 */
				flags,
				0,			    /* rts/cts rate */
				0			    /* rts/cts duration */
				);

	if (r==AH_FALSE) {
	  printk("fail setuptxdesc r(%d)\n", r);
	  goto out;
	}  

	r = ath_hal_filltxdesc(ah, ds, skb->len, AH_TRUE, AH_TRUE,ds);
	if (r==AH_FALSE) {
	  printk("fail fill tx desc r(%d)\n", r);
	  goto out;
	}
	ath_hal_setupxtxdesc(ah, ds
			     , txrate, 15	/* series 1 */
			     , txrate, 15	/* series 2 */
			     , txrate, 15	/* series 3 */
			     );

        /* insert the buffers in to tmp_q */
        STAILQ_INSERT_HEAD(&tmp_q,bf,bf_list);

        prev=bf;
      }
      ath_hal_intrset(ah, 0);	    	/* disable interrupts */
      //sc->sc_imask = HAL_INT_RX | HAL_INT_TX
      //		  | HAL_INT_RXEOL | HAL_INT_RXORN
      //		  | HAL_INT_FATAL | HAL_INT_GLOBAL;
      sc->sc_imask = 0; 
      //ath_hal_intrset(ah, sc->sc_imask);

      bf->bf_desc->ds_link = 0;
      r = ath_hal_puttxbuf(ah, txq->axq_qnum, first->bf_daddr);
      ath_hal_txstart(ah, txq->axq_qnum);

      while(ath_hal_txprocdesc(ah,bf->bf_desc)  == HAL_EINPROGRESS)
      {
        udelay(2000);
        ++delay;
      }
      
      /* sleep for 20ms */
      udelay(20000);
      printk("took %d msec to transmit the 20 frames \n",2*delay);

      /* start TX99 mode */
      ath_stoprecv(sc);		    	/* stop recv side */
      bf->bf_desc->ds_link = first->bf_daddr;		/* link to self */
      ath_hal_getdiagstate(ah, 19,(void *) sc->sc_txrx99.prefetch,9,NULL,NULL);
      ath_hal_getdiagstate(ah, 19, (void *)txq->axq_qnum, val,NULL,NULL);
      r = ath_hal_puttxbuf(ah, txq->axq_qnum, first->bf_daddr);
      ath_hal_txstart(ah, txq->axq_qnum);
  }

  /* leave CONT_DATA mode, reset the chip */
  if (val==0 && skb) {
    int j=0;
    ath_hal_getdiagstate(ah, 19, 0, 0,NULL,NULL);
    /* insert the buffers back into txbuf list */

	ATH_TXBUF_LOCK_BH(sc);						

        bf = STAILQ_FIRST(&tmp_q);
        while(bf)
	{
	  bf->bf_skb=NULL;
	     STAILQ_REMOVE_HEAD(&tmp_q,bf_list);
             STAILQ_INSERT_HEAD(&sc->sc_txbuf,bf,bf_list);
             bf = STAILQ_FIRST(&tmp_q);
	     ++j;
	}
	ATH_TXBUF_UNLOCK_BH(sc);				
        printk("inserted back %d buffers \n",j);
    ic->ic_reset(ic->ic_dev);
    skb = NULL;
    bf = NULL;
  }

  if (val==7 && skb) {
    ath_hal_getdiagstate(ah, 19, ds, 7,NULL,NULL);
  }

  sc->sc_txrx99.tx99mode=val;
 out:
  return;
#undef MIN
}