csr.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:14k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * IEEE 1394 for Linux
  3.  *
  4.  * CSR implementation, iso/bus manager implementation.
  5.  *
  6.  * Copyright (C) 1999 Andreas E. Bombe
  7.  *
  8.  * This code is licensed under the GPL.  See the file COPYING in the root
  9.  * directory of the kernel sources for details.
  10.  */
  11. #include <linux/string.h>
  12. #include "ieee1394_types.h"
  13. #include "hosts.h"
  14. #include "ieee1394.h"
  15. #include "highlevel.h"
  16. /* FIXME: this one won't work on little endian with big endian data */
  17. static u16 csr_crc16(unsigned *data, int length)
  18. {
  19.         int check=0, i;
  20.         int shift, sum, next=0;
  21.         for (i = length; i; i--) {
  22.                 for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
  23.                         sum = ((next >> 12) ^ (*data >> shift)) & 0xf;
  24.                         next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
  25.                 }
  26.                 check = next & 0xffff;
  27.                 data++;
  28.         }
  29.         return check;
  30. }
  31. static void host_reset(struct hpsb_host *host)
  32. {
  33.         host->csr.state &= 0x300;
  34.         host->csr.bus_manager_id = 0x3f;
  35.         host->csr.bandwidth_available = 4915;
  36.         host->csr.channels_available_hi = ~0;
  37.         host->csr.channels_available_lo = ~0;
  38.         host->csr.node_ids = host->node_id << 16;
  39.         if (!host->is_root) {
  40.                 /* clear cmstr bit */
  41.                 host->csr.state &= ~0x100;
  42.         }
  43.         host->csr.topology_map[1] = 
  44.                 cpu_to_be32(be32_to_cpu(host->csr.topology_map[1]) + 1);
  45.         host->csr.topology_map[2] = cpu_to_be32(host->node_count << 16 
  46.                                                 | host->selfid_count);
  47.         host->csr.topology_map[0] = 
  48.                 cpu_to_be32((host->selfid_count + 2) << 16
  49.                             | csr_crc16(host->csr.topology_map + 1,
  50.                                         host->selfid_count + 2));
  51.         host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16 
  52.                                              | csr_crc16(host->csr.speed_map+1,
  53.                                                          0x3f1));
  54. }
  55. static void add_host(struct hpsb_host *host)
  56. {
  57.         host->csr.lock = SPIN_LOCK_UNLOCKED;
  58.         host->csr.rom_size = host->driver->get_rom(host, &host->csr.rom);
  59.         host->csr.state                 = 0;
  60.         host->csr.node_ids              = 0;
  61.         host->csr.split_timeout_hi      = 0;
  62.         host->csr.split_timeout_lo      = 800 << 19;
  63.         host->csr.cycle_time            = 0;
  64.         host->csr.bus_time              = 0;
  65.         host->csr.bus_manager_id        = 0x3f;
  66.         host->csr.bandwidth_available   = 4915;
  67.         host->csr.channels_available_hi = ~0;
  68.         host->csr.channels_available_lo = ~0;
  69. }
  70. /* Read topology / speed maps and configuration ROM */
  71. static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
  72.                      u64 addr, unsigned int length)
  73. {
  74.         int csraddr = addr - CSR_REGISTER_BASE;
  75.         const char *src;
  76.         if (csraddr < CSR_TOPOLOGY_MAP) {
  77.                 if (csraddr + length > CSR_CONFIG_ROM + host->csr.rom_size) {
  78.                         return RCODE_ADDRESS_ERROR;
  79.                 }
  80.                 src = ((char *)host->csr.rom) + csraddr - CSR_CONFIG_ROM;
  81.         } else if (csraddr < CSR_SPEED_MAP) {
  82.                 src = ((char *)host->csr.topology_map) + csraddr 
  83.                         - CSR_TOPOLOGY_MAP;
  84.         } else {
  85.                 src = ((char *)host->csr.speed_map) + csraddr - CSR_SPEED_MAP;
  86.         }
  87.         memcpy(buffer, src, length);
  88.         return RCODE_COMPLETE;
  89. }
  90. #define out if (--length == 0) break
  91. static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
  92.                      u64 addr, unsigned int length)
  93. {
  94.         int csraddr = addr - CSR_REGISTER_BASE;
  95.         int oldcycle;
  96.         quadlet_t ret;
  97.         
  98.         if ((csraddr | length) & 0x3)
  99.                 return RCODE_TYPE_ERROR;
  100.         length /= 4;
  101.         switch (csraddr) {
  102.         case CSR_STATE_CLEAR:
  103.                 *(buf++) = cpu_to_be32(host->csr.state);
  104.                 out;
  105.         case CSR_STATE_SET:
  106.                 *(buf++) = cpu_to_be32(host->csr.state);
  107.                 out;
  108.         case CSR_NODE_IDS:
  109.                 *(buf++) = cpu_to_be32(host->csr.node_ids);
  110.                 out;
  111.         case CSR_RESET_START:
  112.                 return RCODE_TYPE_ERROR;
  113.                 /* address gap - handled by default below */
  114.         case CSR_SPLIT_TIMEOUT_HI:
  115.                 *(buf++) = cpu_to_be32(host->csr.split_timeout_hi);
  116.                 out;
  117.         case CSR_SPLIT_TIMEOUT_LO:
  118.                 *(buf++) = cpu_to_be32(host->csr.split_timeout_lo);
  119.                 out;
  120.                 /* address gap */
  121.                 return RCODE_ADDRESS_ERROR;
  122.         case CSR_CYCLE_TIME:
  123.                 oldcycle = host->csr.cycle_time;
  124.                 host->csr.cycle_time =
  125.                         host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
  126.                 if (oldcycle > host->csr.cycle_time) {
  127.                         /* cycle time wrapped around */
  128.                         host->csr.bus_time += 1 << 7;
  129.                 }
  130.                 *(buf++) = cpu_to_be32(host->csr.cycle_time);
  131.                 out;
  132.         case CSR_BUS_TIME:
  133.                 oldcycle = host->csr.cycle_time;
  134.                 host->csr.cycle_time =
  135.                         host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
  136.                 if (oldcycle > host->csr.cycle_time) {
  137.                         /* cycle time wrapped around */
  138.                         host->csr.bus_time += (1 << 7);
  139.                 }
  140.                 *(buf++) = cpu_to_be32(host->csr.bus_time 
  141.                                        | (host->csr.cycle_time >> 25));
  142.                 out;
  143.                 /* address gap */
  144.                 return RCODE_ADDRESS_ERROR;
  145.         case CSR_BUSY_TIMEOUT:
  146.                 /* not yet implemented */
  147.                 return RCODE_ADDRESS_ERROR;
  148.         case CSR_BUS_MANAGER_ID:
  149.                 if (host->driver->hw_csr_reg)
  150.                         ret = host->driver->hw_csr_reg(host, 0, 0, 0);
  151.                 else
  152.                         ret = host->csr.bus_manager_id;
  153.                 *(buf++) = cpu_to_be32(ret);
  154.                 out;
  155.         case CSR_BANDWIDTH_AVAILABLE:
  156.                 if (host->driver->hw_csr_reg)
  157.                         ret = host->driver->hw_csr_reg(host, 1, 0, 0);
  158.                 else
  159.                         ret = host->csr.bandwidth_available;
  160.                 *(buf++) = cpu_to_be32(ret);
  161.                 out;
  162.         case CSR_CHANNELS_AVAILABLE_HI:
  163.                 if (host->driver->hw_csr_reg)
  164.                         ret = host->driver->hw_csr_reg(host, 2, 0, 0);
  165.                 else
  166.                         ret = host->csr.channels_available_hi;
  167.                 *(buf++) = cpu_to_be32(ret);
  168.                 out;
  169.         case CSR_CHANNELS_AVAILABLE_LO:
  170.                 if (host->driver->hw_csr_reg)
  171.                         ret = host->driver->hw_csr_reg(host, 3, 0, 0);
  172.                 else
  173.                         ret = host->csr.channels_available_lo;
  174.                 *(buf++) = cpu_to_be32(ret);
  175.                 out;
  176.                 /* address gap to end - fall through to default */
  177.         default:
  178.                 return RCODE_ADDRESS_ERROR;
  179.         }
  180.         return RCODE_COMPLETE;
  181. }
  182. static int write_regs(struct hpsb_host *host, int nodeid, int destid,
  183.       quadlet_t *data, u64 addr, unsigned int length)
  184. {
  185.         int csraddr = addr - CSR_REGISTER_BASE;
  186.         
  187.         if ((csraddr | length) & 0x3)
  188.                 return RCODE_TYPE_ERROR;
  189.         length /= 4;
  190.         switch (csraddr) {
  191.         case CSR_STATE_CLEAR:
  192.                 /* FIXME FIXME FIXME */
  193.                 printk("doh, someone wants to mess with state clearn");
  194.                 out;
  195.         case CSR_STATE_SET:
  196.                 printk("doh, someone wants to mess with state setn");
  197.                 out;
  198.         case CSR_NODE_IDS:
  199.                 host->csr.node_ids &= NODE_MASK << 16;
  200.                 host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16);
  201.                 host->node_id = host->csr.node_ids >> 16;
  202.                 host->driver->devctl(host, SET_BUS_ID, host->node_id >> 6);
  203.                 out;
  204.         case CSR_RESET_START:
  205.                 /* FIXME - perform command reset */
  206.                 out;
  207.                 /* address gap */
  208.                 return RCODE_ADDRESS_ERROR;
  209.         case CSR_SPLIT_TIMEOUT_HI:
  210.                 host->csr.split_timeout_hi = 
  211.                         be32_to_cpu(*(data++)) & 0x00000007;
  212.                 out;
  213.         case CSR_SPLIT_TIMEOUT_LO:
  214.                 host->csr.split_timeout_lo = 
  215.                         be32_to_cpu(*(data++)) & 0xfff80000;
  216.                 out;
  217.                 /* address gap */
  218.                 return RCODE_ADDRESS_ERROR;
  219.         case CSR_CYCLE_TIME:
  220.                 /* should only be set by cycle start packet, automatically */
  221.                 host->csr.cycle_time = be32_to_cpu(*data);
  222.                 host->driver->devctl(host, SET_CYCLE_COUNTER,
  223.                                        be32_to_cpu(*(data++)));
  224.                 out;
  225.         case CSR_BUS_TIME:
  226.                 host->csr.bus_time = be32_to_cpu(*(data++)) & 0xffffff80;
  227.                 out;
  228.                 /* address gap */
  229.                 return RCODE_ADDRESS_ERROR;
  230.         case CSR_BUSY_TIMEOUT:
  231.                 /* not yet implemented */
  232.                 return RCODE_ADDRESS_ERROR;
  233.         case CSR_BUS_MANAGER_ID:
  234.         case CSR_BANDWIDTH_AVAILABLE:
  235.         case CSR_CHANNELS_AVAILABLE_HI:
  236.         case CSR_CHANNELS_AVAILABLE_LO:
  237.                 /* these are not writable, only lockable */
  238.                 return RCODE_TYPE_ERROR;
  239.                 /* address gap to end - fall through */
  240.         default:
  241.                 return RCODE_ADDRESS_ERROR;
  242.         }
  243.         return RCODE_COMPLETE;
  244. }
  245. #undef out
  246. static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
  247.                      u64 addr, quadlet_t data, quadlet_t arg, int extcode)
  248. {
  249.         int csraddr = addr - CSR_REGISTER_BASE;
  250.         unsigned long flags;
  251.         quadlet_t *regptr = NULL;
  252.         if (csraddr & 0x3)
  253. return RCODE_TYPE_ERROR;
  254.         if (csraddr < CSR_BUS_MANAGER_ID || csraddr > CSR_CHANNELS_AVAILABLE_LO
  255.             || extcode != EXTCODE_COMPARE_SWAP)
  256.                 goto unsupported_lockreq;
  257.         data = be32_to_cpu(data);
  258.         arg = be32_to_cpu(arg);
  259.         if (host->driver->hw_csr_reg) {
  260.                 quadlet_t old;
  261.                 old = host->driver->
  262.                         hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
  263.                                    data, arg);
  264.                 *store = cpu_to_be32(old);
  265.                 return RCODE_COMPLETE;
  266.         }
  267.         spin_lock_irqsave(&host->csr.lock, flags);
  268.         switch (csraddr) {
  269.         case CSR_BUS_MANAGER_ID:
  270.                 regptr = &host->csr.bus_manager_id;
  271.                 break;
  272.         case CSR_BANDWIDTH_AVAILABLE:
  273.                 regptr = &host->csr.bandwidth_available;
  274.                 break;
  275.         case CSR_CHANNELS_AVAILABLE_HI:
  276.                 regptr = &host->csr.channels_available_hi;
  277.                 break;
  278.         case CSR_CHANNELS_AVAILABLE_LO:
  279.                 regptr = &host->csr.channels_available_lo;
  280.                 break;
  281.         }
  282.         *store = cpu_to_be32(*regptr);
  283.         if (*regptr == arg) *regptr = data;
  284.         spin_unlock_irqrestore(&host->csr.lock, flags);
  285.         return RCODE_COMPLETE;
  286.  unsupported_lockreq:
  287.         switch (csraddr) {
  288.         case CSR_STATE_CLEAR:
  289.         case CSR_STATE_SET:
  290.         case CSR_RESET_START:
  291.         case CSR_NODE_IDS:
  292.         case CSR_SPLIT_TIMEOUT_HI:
  293.         case CSR_SPLIT_TIMEOUT_LO:
  294.         case CSR_CYCLE_TIME:
  295.         case CSR_BUS_TIME:
  296.         case CSR_BUS_MANAGER_ID:
  297.         case CSR_BANDWIDTH_AVAILABLE:
  298.         case CSR_CHANNELS_AVAILABLE_HI:
  299.         case CSR_CHANNELS_AVAILABLE_LO:
  300.                 return RCODE_TYPE_ERROR;
  301.         case CSR_BUSY_TIMEOUT:
  302.                 /* not yet implemented - fall through */
  303.         default:
  304.                 return RCODE_ADDRESS_ERROR;
  305.         }
  306. }
  307. static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
  308.      quadlet_t *data, u64 addr, unsigned int length)
  309. {
  310.         int csraddr = addr - CSR_REGISTER_BASE;
  311.         if (length > 512)
  312.                 return RCODE_TYPE_ERROR;
  313.         switch (csraddr) {
  314.         case CSR_FCP_COMMAND:
  315.                 highlevel_fcp_request(host, nodeid, 0, (u8 *)data, length);
  316.                 break;
  317.         case CSR_FCP_RESPONSE:
  318.                 highlevel_fcp_request(host, nodeid, 1, (u8 *)data, length);
  319.                 break;
  320.         default:
  321.                 return RCODE_TYPE_ERROR;
  322.         }
  323.         return RCODE_COMPLETE;
  324. }
  325. static struct hpsb_highlevel_ops csr_ops = {
  326. .add_host = add_host,
  327.         .host_reset = host_reset,
  328. };
  329. static struct hpsb_address_ops map_ops = {
  330.         .read = read_maps,
  331. };
  332. static struct hpsb_address_ops fcp_ops = {
  333.         .write = write_fcp,
  334. };
  335. static struct hpsb_address_ops reg_ops = {
  336.         .read = read_regs,
  337.         .write = write_regs,
  338.         .lock = lock_regs,
  339. };
  340. static struct hpsb_highlevel *hl;
  341. void init_csr(void)
  342. {
  343.         hl = hpsb_register_highlevel("standard registers", &csr_ops);
  344.         if (hl == NULL) {
  345.                 HPSB_ERR("out of memory during ieee1394 initialization");
  346.                 return;
  347.         }
  348.         hpsb_register_addrspace(hl, &reg_ops, CSR_REGISTER_BASE,
  349.                                 CSR_REGISTER_BASE + CSR_CONFIG_ROM);
  350.         hpsb_register_addrspace(hl, &map_ops, 
  351.                                 CSR_REGISTER_BASE + CSR_CONFIG_ROM,
  352.                                 CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
  353.         hpsb_register_addrspace(hl, &fcp_ops,
  354.                                 CSR_REGISTER_BASE + CSR_FCP_COMMAND,
  355.                                 CSR_REGISTER_BASE + CSR_FCP_END);
  356.         hpsb_register_addrspace(hl, &map_ops,
  357.                                 CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
  358.                                 CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
  359.         hpsb_register_addrspace(hl, &map_ops,
  360.                                 CSR_REGISTER_BASE + CSR_SPEED_MAP,
  361.                                 CSR_REGISTER_BASE + CSR_SPEED_MAP_END);
  362. }
  363. void cleanup_csr(void)
  364. {
  365.         hpsb_unregister_highlevel(hl);
  366. }