ambassador.c
来自「linux 内核源代码」· C语言 代码 · 共 2,334 行 · 第 1/5 页
C
2,334 行
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_dev *) arg; // could collect device-specific (not driver/atm-linux) stats here // last resort refill once every ten seconds fill_rx_pools (dev); mod_timer(&dev->housekeeping, jiffies + 10*HZ); return;}/********** creation of communication queues **********/static int __devinit 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};static 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 __devinit 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] * 10; while (!lb->result || lb->result == cpu_to_be32 (COMMAND_IN_PROGRESS)) if (timeout) { timeout = msleep_interruptible(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 = 100; while (rd_plain (dev, offsetof(amb_mem, doorbell))) if (timeout) { timeout = msleep_interruptible(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 __devinit get_loader_version (loader_block * lb, const amb_dev * dev, u32 * version) { int res; PRINTD (DBG_FLOW|DBG_LOAD, "get_loader_version"); res = do_loader_command (lb, dev, get_version_number); if (res) return res; if (version) *version = be32_to_cpu (lb->payload.version); return 0;}/* loader: write memory data blocks */static int __devinit loader_write (loader_block * lb, const amb_dev * dev, const u32 * data, u32 address, unsigned int count) { unsigned int i; transfer_block * tb = &lb->payload.transfer; PRINTD (DBG_FLOW|DBG_LOAD, "loader_write"); if (count > MAX_TRANSFER_DATA) return -EINVAL; tb->address = cpu_to_be32 (address); tb->count = cpu_to_be32 (count); for (i = 0; i < count; ++i) tb->data[i] = cpu_to_be32 (data[i]); return do_loader_command (lb, dev, write_adapter_memory);}/* loader: verify memory data blocks */static int __devinit loader_verify (loader_block * lb, const amb_dev * dev, const u32 * data, u32 address, unsigned int count) { unsigned int i; transfer_block * tb = &lb->payload.transfer; int res;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?