ambassador.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,331 行 · 第 1/5 页

C
2,331
字号
    return -ENOMEM; // ?  }    // allocate memory for fragments  tx_descr = kmalloc (sizeof(tx_simple), GFP_KERNEL);  if (!tx_descr) {    PRINTK (KERN_ERR, "could not allocate TX descriptor");    return -ENOMEM;  }  if (check_area (tx_descr, sizeof(tx_simple))) {    kfree (tx_descr);    return -ENOMEM;  }  PRINTD (DBG_TX, "fragment list allocated at %p", tx_descr);    tx_descr->skb = skb;    tx_descr->tx_frag.bytes = cpu_to_be32 (tx_len);  tx_descr->tx_frag.address = cpu_to_be32 (virt_to_bus (tx_data));    tx_descr->tx_frag_end.handle = virt_to_bus (tx_descr);  tx_descr->tx_frag_end.vc = 0;  tx_descr->tx_frag_end.next_descriptor_length = 0;  tx_descr->tx_frag_end.next_descriptor = 0;#ifdef AMB_NEW_MICROCODE  tx_descr->tx_frag_end.cpcs_uu = 0;  tx_descr->tx_frag_end.cpi = 0;  tx_descr->tx_frag_end.pad = 0;#endif    tx.vc = cpu_to_be16 (vcc->tx_frame_bits | vc);  tx.tx_descr_length = cpu_to_be16 (sizeof(tx_frag)+sizeof(tx_frag_end));  tx.tx_descr_addr = cpu_to_be32 (virt_to_bus (&tx_descr->tx_frag));    while (tx_give (dev, &tx))    schedule();  return 0;}/********** Change QoS on a VC **********/// int amb_change_qos (struct atm_vcc * atm_vcc, struct atm_qos * qos, int flags);/********** Free RX Socket Buffer **********/#if 0static void amb_free_rx_skb (struct atm_vcc * atm_vcc, struct sk_buff * skb) {  amb_dev * dev = AMB_DEV (atm_vcc->dev);  amb_vcc * vcc = AMB_VCC (atm_vcc);  unsigned char pool = vcc->rx_info.pool;  rx_in rx;    // This may be unsafe for various reasons that I cannot really guess  // at. However, I note that the ATM layer calls kfree_skb rather  // than dev_kfree_skb at this point so we are least covered as far  // as buffer locking goes. There may be bugs if pcap clones RX skbs.  PRINTD (DBG_FLOW|DBG_SKB, "amb_rx_free skb %p (atm_vcc %p, vcc %p)",	  skb, atm_vcc, vcc);    rx.handle = virt_to_bus (skb);  rx.host_address = cpu_to_be32 (virt_to_bus (skb->data));    skb->data = skb->head;  skb->tail = skb->head;  skb->len = 0;    if (!rx_give (dev, &rx, pool)) {    // success    PRINTD (DBG_SKB|DBG_POOL, "recycled skb for pool %hu", pool);    return;  }    // just do what the ATM layer would have done  dev_kfree_skb_any (skb);    return;}#endif/********** Proc File Output **********/static int amb_proc_read (struct atm_dev * atm_dev, loff_t * pos, char * page) {  amb_dev * dev = AMB_DEV (atm_dev);  int left = *pos;  unsigned char pool;    PRINTD (DBG_FLOW, "amb_proc_read");    /* more diagnostics here? */    if (!left--) {    amb_stats * s = &dev->stats;    return sprintf (page,		    "frames: TX OK %lu, RX OK %lu, RX bad %lu "		    "(CRC %lu, long %lu, aborted %lu, unused %lu).\n",		    s->tx_ok, s->rx.ok, s->rx.error,		    s->rx.badcrc, s->rx.toolong,		    s->rx.aborted, s->rx.unused);  }    if (!left--) {    amb_cq * c = &dev->cq;    return sprintf (page, "cmd queue [cur/hi/max]: %u/%u/%u. ",		    c->pending, c->high, c->maximum);  }    if (!left--) {    amb_txq * t = &dev->txq;    return sprintf (page, "TX queue [cur/max high full]: %u/%u %u %u.\n",		    t->pending, t->maximum, t->high, t->filled);  }    if (!left--) {    unsigned int count = sprintf (page, "RX queues [cur/max/req low empty]:");    for (pool = 0; pool < NUM_RX_POOLS; ++pool) {      amb_rxq * r = &dev->rxq[pool];      count += sprintf (page+count, " %u/%u/%u %u %u",			r->pending, r->maximum, r->buffers_wanted, r->low, r->emptied);    }    count += sprintf (page+count, ".\n");    return count;  }    if (!left--) {    unsigned int count = sprintf (page, "RX buffer sizes:");    for (pool = 0; pool < NUM_RX_POOLS; ++pool) {      amb_rxq * r = &dev->rxq[pool];      count += sprintf (page+count, " %u", r->buffer_size);    }    count += sprintf (page+count, ".\n");    return count;  }  #if 0  if (!left--) {    // suni block etc?  }#endif    return 0;}/********** Operation Structure **********/static const struct atmdev_ops amb_ops = {  .open         = amb_open,  .close	= amb_close,  .send         = amb_send,  .proc_read	= amb_proc_read,  .owner	= THIS_MODULE,};/********** housekeeping **********/static void do_housekeeping (unsigned long arg) {  amb_dev * dev = amb_devs;  // data is set to zero at module unload  (void) arg;    if (housekeeping.data) {    while (dev) {            // could collect device-specific (not driver/atm-linux) stats here            // last resort refill once every ten seconds      fill_rx_pools (dev);            dev = dev->prev;    }    mod_timer(&housekeeping, jiffies + 10*HZ);  }    return;}/********** creation of communication queues **********/static int __init create_queues (amb_dev * dev, unsigned int cmds,				 unsigned int txs, unsigned int * rxs,				 unsigned int * rx_buffer_sizes) {  unsigned char pool;  size_t total = 0;  void * memory;  void * limit;    PRINTD (DBG_FLOW, "create_queues %p", dev);    total += cmds * sizeof(command);    total += txs * (sizeof(tx_in) + sizeof(tx_out));    for (pool = 0; pool < NUM_RX_POOLS; ++pool)    total += rxs[pool] * (sizeof(rx_in) + sizeof(rx_out));    memory = kmalloc (total, GFP_KERNEL);  if (!memory) {    PRINTK (KERN_ERR, "could not allocate queues");    return -ENOMEM;  }  if (check_area (memory, total)) {    PRINTK (KERN_ERR, "queues allocated in nasty area");    kfree (memory);    return -ENOMEM;  }    limit = memory + total;  PRINTD (DBG_INIT, "queues from %p to %p", memory, limit);    PRINTD (DBG_CMD, "command queue at %p", memory);    {    command * cmd = memory;    amb_cq * cq = &dev->cq;        cq->pending = 0;    cq->high = 0;    cq->maximum = cmds - 1;        cq->ptrs.start = cmd;    cq->ptrs.in = cmd;    cq->ptrs.out = cmd;    cq->ptrs.limit = cmd + cmds;        memory = cq->ptrs.limit;  }    PRINTD (DBG_TX, "TX queue pair at %p", memory);    {    tx_in * in = memory;    tx_out * out;    amb_txq * txq = &dev->txq;        txq->pending = 0;    txq->high = 0;    txq->filled = 0;    txq->maximum = txs - 1;        txq->in.start = in;    txq->in.ptr = in;    txq->in.limit = in + txs;        memory = txq->in.limit;    out = memory;        txq->out.start = out;    txq->out.ptr = out;    txq->out.limit = out + txs;        memory = txq->out.limit;  }    PRINTD (DBG_RX, "RX queue pairs at %p", memory);    for (pool = 0; pool < NUM_RX_POOLS; ++pool) {    rx_in * in = memory;    rx_out * out;    amb_rxq * rxq = &dev->rxq[pool];        rxq->buffer_size = rx_buffer_sizes[pool];    rxq->buffers_wanted = 0;        rxq->pending = 0;    rxq->low = rxs[pool] - 1;    rxq->emptied = 0;    rxq->maximum = rxs[pool] - 1;        rxq->in.start = in;    rxq->in.ptr = in;    rxq->in.limit = in + rxs[pool];        memory = rxq->in.limit;    out = memory;        rxq->out.start = out;    rxq->out.ptr = out;    rxq->out.limit = out + rxs[pool];        memory = rxq->out.limit;  }    if (memory == limit) {    return 0;  } else {    PRINTK (KERN_ERR, "bad queue alloc %p != %p (tell maintainer)", memory, limit);    kfree (limit - total);    return -ENOMEM;  }  }/********** destruction of communication queues **********/static void destroy_queues (amb_dev * dev) {  // all queues assumed empty  void * memory = dev->cq.ptrs.start;  // includes txq.in, txq.out, rxq[].in and rxq[].out    PRINTD (DBG_FLOW, "destroy_queues %p", dev);    PRINTD (DBG_INIT, "freeing queues at %p", memory);  kfree (memory);    return;}/********** basic loader commands and error handling **********/// centisecond timeouts - guessing away herestatic unsigned int command_timeouts [] = {	[host_memory_test]     = 15,	[read_adapter_memory]  = 2,	[write_adapter_memory] = 2,	[adapter_start]        = 50,	[get_version_number]   = 10,	[interrupt_host]       = 1,	[flash_erase_sector]   = 1,	[adap_download_block]  = 1,	[adap_erase_flash]     = 1,	[adap_run_in_iram]     = 1,	[adap_end_download]    = 1};unsigned int command_successes [] = {	[host_memory_test]     = COMMAND_PASSED_TEST,	[read_adapter_memory]  = COMMAND_READ_DATA_OK,	[write_adapter_memory] = COMMAND_WRITE_DATA_OK,	[adapter_start]        = COMMAND_COMPLETE,	[get_version_number]   = COMMAND_COMPLETE,	[interrupt_host]       = COMMAND_COMPLETE,	[flash_erase_sector]   = COMMAND_COMPLETE,	[adap_download_block]  = COMMAND_COMPLETE,	[adap_erase_flash]     = COMMAND_COMPLETE,	[adap_run_in_iram]     = COMMAND_COMPLETE,	[adap_end_download]    = COMMAND_COMPLETE};  static  int decode_loader_result (loader_command cmd, u32 result){	int res;	const char *msg;	if (result == command_successes[cmd])		return 0;	switch (result) {		case BAD_COMMAND:			res = -EINVAL;			msg = "bad command";			break;		case COMMAND_IN_PROGRESS:			res = -ETIMEDOUT;			msg = "command in progress";			break;		case COMMAND_PASSED_TEST:			res = 0;			msg = "command passed test";			break;		case COMMAND_FAILED_TEST:			res = -EIO;			msg = "command failed test";			break;		case COMMAND_READ_DATA_OK:			res = 0;			msg = "command read data ok";			break;		case COMMAND_READ_BAD_ADDRESS:			res = -EINVAL;			msg = "command read bad address";			break;		case COMMAND_WRITE_DATA_OK:			res = 0;			msg = "command write data ok";			break;		case COMMAND_WRITE_BAD_ADDRESS:			res = -EINVAL;			msg = "command write bad address";			break;		case COMMAND_WRITE_FLASH_FAILURE:			res = -EIO;			msg = "command write flash failure";			break;		case COMMAND_COMPLETE:			res = 0;			msg = "command complete";			break;		case COMMAND_FLASH_ERASE_FAILURE:			res = -EIO;			msg = "command flash erase failure";			break;		case COMMAND_WRITE_BAD_DATA:			res = -EINVAL;			msg = "command write bad data";			break;		default:			res = -EINVAL;			msg = "unknown error";			PRINTD (DBG_LOAD|DBG_ERR,				"decode_loader_result got %d=%x !",				result, result);			break;	}	PRINTK (KERN_ERR, "%s", msg);	return res;}static int __init do_loader_command (volatile loader_block * lb,				     const amb_dev * dev, loader_command cmd) {    unsigned long timeout;    PRINTD (DBG_FLOW|DBG_LOAD, "do_loader_command");    /* do a command          Set the return value to zero, set the command type and set the     valid entry to the right magic value. The payload is already     correctly byte-ordered so we leave it alone. Hit the doorbell     with the bus address of this structure.       */    lb->result = 0;  lb->command = cpu_to_be32 (cmd);  lb->valid = cpu_to_be32 (DMA_VALID);  // dump_registers (dev);  // dump_loader_block (lb);  wr_mem (dev, offsetof(amb_mem, doorbell), virt_to_bus (lb) & ~onegigmask);    timeout = command_timeouts[cmd] * HZ/100;    while (!lb->result || lb->result == cpu_to_be32 (COMMAND_IN_PROGRESS))    if (timeout) {      set_current_state(TASK_UNINTERRUPTIBLE);      timeout = schedule_timeout (timeout);    } else {      PRINTD (DBG_LOAD|DBG_ERR, "command %d timed out", cmd);      dump_registers (dev);      dump_loader_block (lb);      return -ETIMEDOUT;    }    if (cmd == adapter_start) {    // wait for start command to acknowledge...    timeout = HZ/10;    while (rd_plain (dev, offsetof(amb_mem, doorbell)))      if (timeout) {	timeout = schedule_timeout (timeout);      } else {	PRINTD (DBG_LOAD|DBG_ERR, "start command did not clear doorbell, res=%08x",		be32_to_cpu (lb->result));	dump_registers (dev);	return -ETIMEDOUT;      }    return 0;  } else {    return decode_loader_result (cmd, be32_to_cpu (lb->result));  }  }/* loader: determine loader version */static int __init get_loader_version (loader_block * lb,				      const amb_dev * dev, u32 * version) {  int res;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?