/*---------------------------------------------------------------------------*/ static void collision(struct rdc_buf_list *q, struct neighbor_queue *n, int num_transmissions) { struct qbuf_metadata *metadata; metadata = (struct qbuf_metadata *)q->ptr; csma_collisions += num_transmissions; n->collisions += num_transmissions; if(n->collisions > CSMA_MAX_BACKOFF) { n->collisions = CSMA_MIN_BE; /* Increment to indicate a next retry */ n->transmissions++; } if(n->transmissions >= metadata->max_transmissions) { csma_dropped++; tx_done(MAC_TX_COLLISION, q, n); } else { PRINTF("csma: rexmit collision %d\n", n->transmissions); rexmit(q, n); } }
/*---------------------------------------------------------------------------*/ static void tx_ok(struct rdc_buf_list *q, struct neighbor_queue *n, int num_transmissions) { csma_sent_packets++; n->collisions = CSMA_MIN_BE; n->transmissions += num_transmissions; tx_done(MAC_TX_OK, q, n); }
static void txn(int n) { while (n--) { tx(); tx(); tx_done(); } }
static int net_send_packet(struct sk_buff *skb, struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; if (dev->tbusy) { /* If we get here, some higher level has decided we are broken. There should really be a "kick me" function call instead. */ int tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) return 1; printk("%s: transmit timed out, %s?\n", dev->name, tx_done(dev) ? "IRQ conflict" : "network cable problem"); /* Try to restart the adaptor. */ chipset_init(dev, 1); dev->tbusy=0; dev->trans_start = jiffies; } /* If some higher layer thinks we've missed an tx-done interrupt we are passed NULL. Caution: dev_tint() handles the cli()/sti() itself. */ if (skb == NULL) { dev_tint(dev); return 0; } /* For ethernet, fill in the header. This should really be done by a higher level, rather than duplicated for each ethernet adaptor. */ if (!skb->arp && dev->rebuild_header(skb->data, dev)) { skb->dev = dev; arp_queue (skb); return 0; } skb->arp=1; /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; hardware_send_packet(ioaddr, buf, length); dev->trans_start = jiffies; } if (skb->free) kfree_skb (skb, FREE_WRITE); /* You might need to clean up and record Tx statistics here. */ if (inw(ioaddr) == /*RU*/81) lp->stats.tx_aborted_errors++; return 0; }
static int net_send_packet(struct sk_buff *skb, struct net_device *dev) { if (dev->tbusy) { /* If we get here, some higher level has decided we are broken. There should really be a "kick me" function call instead. */ int tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) return 1; if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name, tx_done(dev) ? "IRQ conflict" : "network cable problem"); /* Try to restart the adaptor. */ dev->tbusy=0; dev->trans_start = jiffies; } /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { struct net_local *lp = (struct net_local *)dev->priv; unsigned long flags; if (net_debug > 3) printk("%s: sent %d byte packet of type %x\n", dev->name, skb->len, (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); /* keep the upload from being interrupted, since we ask the chip to start transmitting before the whole packet has been completely uploaded. */ local_irq_save(flags); /* initiate a transmit sequence */ writereg(dev, PP_TxCMD, lp->send_cmd); writereg(dev, PP_TxLength, skb->len); /* Test to see if the chip has allocated memory for the packet */ if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { /* Gasp! It hasn't. But that shouldn't happen since we're waiting for TxOk, so return 1 and requeue this packet. */ local_irq_restore(flags); return 1; } /* Write the contents of the packet */ memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1); local_irq_restore(flags); dev->trans_start = jiffies; } dev_kfree_skb (skb); return 0; }
static void seeq8005_timeout(struct net_device *dev) { int ioaddr = dev->base_addr; printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, tx_done(dev) ? "IRQ conflict" : "network cable problem"); /* Try to restart the adaptor. */ seeq8005_init(dev, 1); dev->trans_start = jiffies; netif_wake_queue(dev); }
/*---------------------------------------------------------------------------*/ static void noack(struct rdc_buf_list *q, struct neighbor_queue *n, int num_transmissions) { struct qbuf_metadata *metadata; metadata = (struct qbuf_metadata *)q->ptr; csma_noack++; csma_sent_packets++; n->collisions = CSMA_MIN_BE; n->transmissions += num_transmissions; if(n->transmissions >= metadata->max_transmissions) { csma_dropped++; tx_done(MAC_TX_NOACK, q, n); } else { PRINTF("csma: rexmit noack %d\n", n->transmissions); rexmit(q, n); } }
static int seeq8005_send_packet(struct sk_buff *skb, struct device *dev) { int ioaddr = dev->base_addr; struct net_local *lp = (struct net_local *)dev->priv; if (dev->tbusy) { /* If we get here, some higher level has decided we are broken. There should really be a "kick me" function call instead. */ int tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) return 1; printk("%s: transmit timed out, %s?\n", dev->name, tx_done(dev) ? "IRQ conflict" : "network cable problem"); /* Try to restart the adaptor. */ seeq8005_init(dev, 1); dev->tbusy=0; dev->trans_start = jiffies; } /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; hardware_send_packet(dev, buf, length); dev->trans_start = jiffies; lp->stats.tx_bytes += length; } dev_kfree_skb (skb); /* You might need to clean up and record Tx statistics here. */ return 0; }
/** * \brief State machine handling slotted CSMA */ void slotted_csma_state_handling(void) { switch (tal_csma_state) { case BACKOFF_WAITING_FOR_CCA_TIMER: break; case BACKOFF_WAITING_FOR_BEACON: /* * Do not perform any operation and wait until the next beacon * reception. If several beacons are not received, the beacon * loss * timer expires and stops the entire transaction. */ break; case CSMA_HANDLE_BEACON: /* debug pin to switch on: define ENABLE_DEBUG_PINS, * pal_config.h */ PIN_WAITING_FOR_BEACON_END(); PIN_BEACON_LOSS_TIMER_END(); pal_timer_stop(TAL_CSMA_BEACON_LOSS_TIMER); csma_backoff_calculation(); break; case CSMA_ACCESS_FAILURE: NB++; BE++; /* ensure that BE is no more than macMaxBE */ if (BE > tal_pib.MaxBE) { /* macMaxBE */ BE = tal_pib.MaxBE; /* macMaxBE */ } if (NB > macMaxCSMABackoffs) { /* terminate with channel access failure */ tx_done(MAC_CHANNEL_ACCESS_FAILURE); } else { /* restart backoff */ csma_backoff_calculation(); } break; case NO_BEACON_TRACKING: /* terminate with channel access failure */ tx_done(MAC_CHANNEL_ACCESS_FAILURE); break; case FRAME_SENDING: /* waiting for end of frame transmission */ break; case TX_DONE_SUCCESS: tx_done(MAC_SUCCESS); break; case TX_DONE_FRAME_PENDING: tx_done(TAL_FRAME_PENDING); break; case TX_DONE_NO_ACK: if (number_of_tx_retries < tal_pib.MaxFrameRetries) { number_of_tx_retries++; set_trx_state(CMD_RX_AACK_ON); /* * Start the entire CSMA procedure again, * but do not reset the number of transmission attempts. */ BE++; /* ensure that BE is no more than macMaxBE */ if (BE > tal_pib.MaxBE) { /* macMaxBE */ BE = tal_pib.MaxBE; /* macMaxBE */ } NB = 0; remaining_backoff_periods = (uint8_t)(rand() & ((1 << BE) - 1)); csma_backoff_calculation(); } else { tx_done(MAC_NO_ACK); } PIN_NO_ACK_END(); break; default: Assert("INVALID CSMA status" == 0); break; } } /* csma_ca_state_handling() */
/*---------------------------------------------------------------------------*/ static void packet_sent(void *ptr, int status, int num_transmissions) { struct neighbor_queue *n; struct rdc_buf_list *q; n = ptr; if(n == NULL) { return; } /* Find out what packet this callback refers to */ for(q = list_head(n->queued_packet_list); q != NULL; q = list_item_next(q)) { #if CETIC_6LBR_MULTI_RADIO if(queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO) == packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO) && (q->ptr == NULL || ((struct qbuf_metadata *)q->ptr)->ifindex == multi_radio_input_ifindex)) { #else if(queuebuf_attr(q->buf, PACKETBUF_ATTR_MAC_SEQNO) == packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)) { #endif break; } } if(q == NULL) { PRINTF("csma: seqno %d not found\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)); return; } else if(q->ptr == NULL) { PRINTF("csma: no metadata\n"); return; } switch(status) { case MAC_TX_OK: tx_ok(q, n, num_transmissions); break; case MAC_TX_NOACK: noack(q, n, num_transmissions); break; case MAC_TX_COLLISION: collision(q, n, num_transmissions); break; case MAC_TX_DEFERRED: break; default: tx_done(status, q, n); break; } } /*---------------------------------------------------------------------------*/ static void send_packet(mac_callback_t sent, void *ptr) { struct rdc_buf_list *q; struct neighbor_queue *n; const linkaddr_t *addr = packetbuf_addr(PACKETBUF_ADDR_RECEIVER); /* Look for the neighbor entry */ n = neighbor_queue_from_addr(addr); if(n == NULL) { /* Allocate a new neighbor entry */ n = memb_alloc(&neighbor_memb); if(n != NULL) { /* Init neighbor entry */ linkaddr_copy(&n->addr, addr); n->transmissions = 0; n->collisions = CSMA_MIN_BE; /* Init packet list for this neighbor */ LIST_STRUCT_INIT(n, queued_packet_list); /* Add neighbor to the list */ list_add(neighbor_list, n); } } if(n != NULL) { /* Add packet to the neighbor's queue */ if(list_length(n->queued_packet_list) < CSMA_MAX_PACKET_PER_NEIGHBOR) { q = memb_alloc(&packet_memb); if(q != NULL) { q->ptr = memb_alloc(&metadata_memb); if(q->ptr != NULL) { q->buf = queuebuf_new_from_packetbuf(); if(q->buf != NULL) { struct qbuf_metadata *metadata = (struct qbuf_metadata *)q->ptr; /* Neighbor and packet successfully allocated */ if(packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS) == 0) { /* Use default configuration for max transmissions */ metadata->max_transmissions = CSMA_MAX_MAX_FRAME_RETRIES + 1; } else { metadata->max_transmissions = packetbuf_attr(PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS); } metadata->sent = sent; metadata->cptr = ptr; #if CETIC_6LBR_MULTI_RADIO metadata->ifindex = multi_radio_output_ifindex; #endif #if PACKETBUF_WITH_PACKET_TYPE if(packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE) == PACKETBUF_ATTR_PACKET_TYPE_ACK) { list_push(n->queued_packet_list, q); } else #endif { list_add(n->queued_packet_list, q); } PRINTF("csma: send_packet, queue length %d, free packets %d\n", list_length(n->queued_packet_list), memb_numfree(&packet_memb)); /* If q is the first packet in the neighbor's queue, send asap */ if(list_head(n->queued_packet_list) == q) { schedule_transmission(n); } return; } memb_free(&metadata_memb, q->ptr); PRINTF("csma: could not allocate queuebuf, dropping packet\n"); } memb_free(&packet_memb, q); PRINTF("csma: could not allocate queuebuf, dropping packet\n"); } /* The packet allocation failed. Remove and free neighbor entry if empty. */ if(list_length(n->queued_packet_list) == 0) { list_remove(neighbor_list, n); memb_free(&neighbor_memb, n); } } else { PRINTF("csma: Neighbor queue full\n"); } PRINTF("csma: could not allocate packet, dropping packet\n"); csma_packet_overflow++; } else { PRINTF("csma: could not allocate neighbor, dropping packet\n"); csma_neighbor_overflow++; } mac_call_sent_callback(sent, ptr, MAC_TX_ERR, 1); } /*---------------------------------------------------------------------------*/ static void input_packet(void) { csma_received_packets++; NETSTACK_LLSEC.input(); }
static int net_send_packet(struct sk_buff *skb, struct device *dev) { if (dev->tbusy) { /* If we get here, some higher level has decided we are broken. There should really be a "kick me" function call instead. */ int tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) return 1; if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name, tx_done(dev) ? "IRQ conflict" : "network cable problem"); /* Try to restart the adaptor. */ dev->tbusy=0; dev->trans_start = jiffies; } /* If some higher layer thinks we've missed an tx-done interrupt we are passed NULL. Caution: dev_tint() handles the cli()/sti() itself. */ if (skb == NULL) { dev_tint(dev); return 0; } /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { struct net_local *lp = (struct net_local *)dev->priv; unsigned long ioaddr = dev->base_addr; unsigned long flags; if (net_debug > 3)printk("%s: sent %ld byte packet of type %x\n", dev->name, skb->len, (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); /* keep the upload from being interrupted, since we ask the chip to start transmitting before the whole packet has been completely uploaded. */ save_flags(flags); cli(); /* initiate a transmit sequence */ outw(lp->send_cmd, ioaddr + TX_CMD_PORT); outw(skb->len, ioaddr + TX_LEN_PORT); /* Test to see if the chip has allocated memory for the packet */ if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { /* Gasp! It hasn't. But that shouldn't happen since we're waiting for TxOk, so return 1 and requeue this packet. */ restore_flags(flags); printk("cs8900 did not allocate memory for tx!\n"); return 1; } /* Write the contents of the packet */ outsw(ioaddr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1); restore_flags(flags); dev->trans_start = jiffies; } dev_kfree_skb (skb, FREE_WRITE); return 0; }