📄 csr.c
字号:
/** IEEE 1394 for Linux** CSR implementation, iso/bus manager implementation.** Copyright (C) 1999 Andreas E. Bombe* 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>** This code is licensed under the GPL. See the file COPYING in the root* directory of the kernel sources for details.*** Contributions:** Manfred Weihs <weihs@ict.tuwien.ac.at>* configuration ROM manipulation**/#include <linux/string.h>#include <linux/module.h> /* needed for MODULE_PARM */#include <linux/param.h>#include <linux/spinlock.h>#include "ieee1394_types.h"#include "hosts.h"#include "ieee1394.h"#include "highlevel.h"/* Module Parameters *//* this module parameter can be used to disable mapping of the FCP registers */MODULE_PARM(fcp,"i");MODULE_PARM_DESC(fcp, "FCP-registers");static int fcp = 1;static u16 csr_crc16(unsigned *data, int length){ int check=0, i; int shift, sum, next=0; for (i = length; i; i--) { for (next = check, shift = 28; shift >= 0; shift -= 4 ) { sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf; next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum); } check = next & 0xffff; data++; } return check;}static void host_reset(struct hpsb_host *host){ host->csr.state &= 0x300; host->csr.bus_manager_id = 0x3f; host->csr.bandwidth_available = 4915; host->csr.channels_available_hi = 0xfffffffe; /* pre-alloc ch 31 per 1394a-2000 */ host->csr.channels_available_lo = ~0; host->csr.broadcast_channel = 0x80000000 | 31; if (host->is_irm) { if (host->driver->hw_csr_reg) { host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0); } } host->csr.node_ids = host->node_id << 16; if (!host->is_root) { /* clear cmstr bit */ host->csr.state &= ~0x100; } host->csr.topology_map[1] = cpu_to_be32(be32_to_cpu(host->csr.topology_map[1]) + 1); host->csr.topology_map[2] = cpu_to_be32(host->node_count << 16 | host->selfid_count); host->csr.topology_map[0] = cpu_to_be32((host->selfid_count + 2) << 16 | csr_crc16(host->csr.topology_map + 1, host->selfid_count + 2)); host->csr.speed_map[1] = cpu_to_be32(be32_to_cpu(host->csr.speed_map[1]) + 1); host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16 | csr_crc16(host->csr.speed_map+1, 0x3f1));}/* * HI == seconds (bits 0:2)* LO == fraction units of 1/8000 of a second, as per 1394 (bits 19:31)** Convert to units and then to HZ, for comparison to jiffies.** By default this will end up being 800 units, or 100ms (125usec per* unit).** NOTE: The spec says 1/8000, but also says we can compute based on 1/8192* like CSR specifies. Should make our math less complex.*/static inline void calculate_expire(struct csr_control *csr){ unsigned long units; /* Take the seconds, and convert to units */ units = (unsigned long)(csr->split_timeout_hi & 0x07) << 13; /* Add in the fractional units */ units += (unsigned long)(csr->split_timeout_lo >> 19); /* Convert to jiffies */ csr->expire = (unsigned long)(units * HZ) >> 13UL; /* Just to keep from rounding low */ csr->expire++; HPSB_VERBOSE("CSR: setting expire to %lu, HZ=%d", csr->expire, HZ);}static void add_host(struct hpsb_host *host){ host->csr.lock = SPIN_LOCK_UNLOCKED; host->csr.rom_size = host->driver->get_rom(host, &host->csr.rom); host->csr.rom_version = 0; host->csr.state = 0; host->csr.node_ids = 0; host->csr.split_timeout_hi = 0; host->csr.split_timeout_lo = 800 << 19; calculate_expire(&host->csr); host->csr.cycle_time = 0; host->csr.bus_time = 0; host->csr.bus_manager_id = 0x3f; host->csr.bandwidth_available = 4915; host->csr.channels_available_hi = 0xfffffffe; /* pre-alloc ch 31 per 1394a-2000 */ host->csr.channels_available_lo = ~0; host->csr.broadcast_channel = 0x80000000 | 31; if (host->is_irm) { if (host->driver->hw_csr_reg) { host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0); } }}int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom, size_t size, unsigned char rom_version){ unsigned long flags; int ret; spin_lock_irqsave(&host->csr.lock, flags); if (rom_version != host->csr.rom_version) ret = -1; else if (size > (CSR_CONFIG_ROM_SIZE << 2)) ret = -2; else { memcpy(host->csr.rom,new_rom,size); host->csr.rom_size=size; host->csr.rom_version++; ret=0; } spin_unlock_irqrestore(&host->csr.lock, flags); return ret;}int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer, size_t buffersize, size_t *rom_size, unsigned char *rom_version){ unsigned long flags; int ret; spin_lock_irqsave(&host->csr.lock, flags); *rom_version=host->csr.rom_version; *rom_size=host->csr.rom_size; if (buffersize < host->csr.rom_size) ret = -1; else { memcpy(buffer,host->csr.rom,host->csr.rom_size); ret=0; } spin_unlock_irqrestore(&host->csr.lock, flags); return ret;}/* Read topology / speed maps and configuration ROM */static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer, u64 addr, size_t length, u16 fl){ unsigned long flags; int csraddr = addr - CSR_REGISTER_BASE; const char *src; spin_lock_irqsave(&host->csr.lock, flags); if (csraddr < CSR_TOPOLOGY_MAP) { if (csraddr + length > CSR_CONFIG_ROM + host->csr.rom_size) { spin_unlock_irqrestore(&host->csr.lock, flags); return RCODE_ADDRESS_ERROR; } src = ((char *)host->csr.rom) + csraddr - CSR_CONFIG_ROM; } else if (csraddr < CSR_SPEED_MAP) { src = ((char *)host->csr.topology_map) + csraddr - CSR_TOPOLOGY_MAP; } else { src = ((char *)host->csr.speed_map) + csraddr - CSR_SPEED_MAP; } memcpy(buffer, src, length); spin_unlock_irqrestore(&host->csr.lock, flags); return RCODE_COMPLETE;}#define out if (--length == 0) breakstatic int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf, u64 addr, size_t length, u16 flags){ int csraddr = addr - CSR_REGISTER_BASE; int oldcycle; quadlet_t ret; if ((csraddr | length) & 0x3) return RCODE_TYPE_ERROR; length /= 4; switch (csraddr) { case CSR_STATE_CLEAR: *(buf++) = cpu_to_be32(host->csr.state); out; case CSR_STATE_SET: *(buf++) = cpu_to_be32(host->csr.state); out; case CSR_NODE_IDS: *(buf++) = cpu_to_be32(host->csr.node_ids); out; case CSR_RESET_START: return RCODE_TYPE_ERROR; /* address gap - handled by default below */ case CSR_SPLIT_TIMEOUT_HI: *(buf++) = cpu_to_be32(host->csr.split_timeout_hi); out; case CSR_SPLIT_TIMEOUT_LO: *(buf++) = cpu_to_be32(host->csr.split_timeout_lo); out; /* address gap */ return RCODE_ADDRESS_ERROR; case CSR_CYCLE_TIME: oldcycle = host->csr.cycle_time; host->csr.cycle_time = host->driver->devctl(host, GET_CYCLE_COUNTER, 0); if (oldcycle > host->csr.cycle_time) { /* cycle time wrapped around */ host->csr.bus_time += 1 << 7; } *(buf++) = cpu_to_be32(host->csr.cycle_time); out; case CSR_BUS_TIME: oldcycle = host->csr.cycle_time; host->csr.cycle_time = host->driver->devctl(host, GET_CYCLE_COUNTER, 0); if (oldcycle > host->csr.cycle_time) { /* cycle time wrapped around */ host->csr.bus_time += (1 << 7); } *(buf++) = cpu_to_be32(host->csr.bus_time | (host->csr.cycle_time >> 25)); out; /* address gap */ return RCODE_ADDRESS_ERROR; case CSR_BUSY_TIMEOUT: /* not yet implemented */ return RCODE_ADDRESS_ERROR; case CSR_BUS_MANAGER_ID: if (host->driver->hw_csr_reg) ret = host->driver->hw_csr_reg(host, 0, 0, 0); else ret = host->csr.bus_manager_id; *(buf++) = cpu_to_be32(ret); out; case CSR_BANDWIDTH_AVAILABLE: if (host->driver->hw_csr_reg) ret = host->driver->hw_csr_reg(host, 1, 0, 0); else ret = host->csr.bandwidth_available; *(buf++) = cpu_to_be32(ret); out; case CSR_CHANNELS_AVAILABLE_HI: if (host->driver->hw_csr_reg) ret = host->driver->hw_csr_reg(host, 2, 0, 0); else ret = host->csr.channels_available_hi; *(buf++) = cpu_to_be32(ret); out; case CSR_CHANNELS_AVAILABLE_LO: if (host->driver->hw_csr_reg) ret = host->driver->hw_csr_reg(host, 3, 0, 0); else ret = host->csr.channels_available_lo; *(buf++) = cpu_to_be32(ret); out; case CSR_BROADCAST_CHANNEL: *(buf++) = cpu_to_be32(host->csr.broadcast_channel); out; /* address gap to end - fall through to default */ default: return RCODE_ADDRESS_ERROR; } return RCODE_COMPLETE;}static int write_regs(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data, u64 addr, size_t length, u16 flags){ int csraddr = addr - CSR_REGISTER_BASE; if ((csraddr | length) & 0x3) return RCODE_TYPE_ERROR; length /= 4; switch (csraddr) { case CSR_STATE_CLEAR: /* FIXME FIXME FIXME */ printk("doh, someone wants to mess with state clear\n"); out; case CSR_STATE_SET: printk("doh, someone wants to mess with state set\n"); out; case CSR_NODE_IDS: host->csr.node_ids &= NODE_MASK << 16; host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16); host->node_id = host->csr.node_ids >> 16; host->driver->devctl(host, SET_BUS_ID, host->node_id >> 6); out; case CSR_RESET_START: /* FIXME - perform command reset */ out; /* address gap */ return RCODE_ADDRESS_ERROR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -