Commit 56880b13 authored by Ben Collins's avatar Ben Collins

Merge http://linux.bkbits.net/linux-2.5

into debian.org:/usr/src/kernel/ieee1394-2.6
parents 95a08114 01bdc78f
......@@ -110,8 +110,12 @@ config IEEE1394_ETH1394
tristate "Ethernet over 1394"
depends on IEEE1394
help
Extremely Experimental! This driver is a Linux specific way to use your
IEEE1394 Host as an Ethernet type device. This is _NOT_ IP1394.
This driver implements a functional majority of RFC 2734: IPv4 over
1394. It will provide IP connectivity with implementations of RFC
2734 found on other operating systems. It will not communicate with
older versions of this driver found in stock kernels prior to 2.6.3.
This driver is still considered experimental. It does not yet support
MCAP, therefore multicast support is significantly limited.
config IEEE1394_DV1394
tristate "OHCI-DV I/O support"
......
......@@ -3,7 +3,8 @@
#
ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
highlevel.o csr.o nodemgr.o oui.o dma.o iso.o
highlevel.o csr.o nodemgr.o oui.o dma.o iso.o \
csr1212.o
obj-$(CONFIG_IEEE1394) += ieee1394.o
obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
......
......@@ -862,14 +862,14 @@ static int stream_alloc_packet_lists(struct stream *s)
static void stream_free_packet_lists(struct stream *s)
{
struct list_head *lh, *next;
struct packet_list *packet_l, *packet_l_next;
if (s->current_packet_list != NULL)
packet_list_free(s->current_packet_list, s);
list_for_each_safe(lh, next, &s->dma_packet_lists)
packet_list_free(list_entry(lh, struct packet_list, link), s);
list_for_each_safe(lh, next, &s->free_packet_lists)
packet_list_free(list_entry(lh, struct packet_list, link), s);
list_for_each_entry_safe(packet_l, packet_l_next, &s->dma_packet_lists, link)
packet_list_free(packet_l, s);
list_for_each_entry_safe(packet_l, packet_l_next, &s->free_packet_lists, link)
packet_list_free(packet_l, s);
if (s->packet_pool != NULL)
pci_pool_destroy(s->packet_pool);
......
......@@ -23,6 +23,7 @@
#include <linux/param.h>
#include <linux/spinlock.h>
#include "csr1212.h"
#include "ieee1394_types.h"
#include "hosts.h"
#include "ieee1394.h"
......@@ -35,7 +36,10 @@ static int fcp = 1;
module_param(fcp, int, 0444);
MODULE_PARM_DESC(fcp, "Map FCP registers (default = 1, disable = 0).");
static struct csr1212_keyval *node_cap = NULL;
static void add_host(struct hpsb_host *host);
static void remove_host(struct hpsb_host *host);
static void host_reset(struct hpsb_host *host);
static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
u64 addr, size_t length, u16 fl);
......@@ -49,10 +53,15 @@ static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl);
static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl);
static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
u64 addr, size_t length, u16 fl);
static u64 allocate_addr_range(u64 size, u32 alignment, void *__host);
static void release_addr_range(u64 addr, void *__host);
static struct hpsb_highlevel csr_highlevel = {
.name = "standard registers",
.add_host = add_host,
.remove_host = remove_host,
.host_reset = host_reset,
};
......@@ -71,6 +80,15 @@ static struct hpsb_address_ops reg_ops = {
.lock64 = lock64_regs,
};
static struct hpsb_address_ops config_rom_ops = {
.read = read_config_rom,
};
struct csr1212_bus_ops csr_bus_ops = {
.allocate_addr_range = allocate_addr_range,
.release_addr = release_addr_range,
};
static u16 csr_crc16(unsigned *data, int length)
{
......@@ -162,10 +180,13 @@ static inline void calculate_expire(struct csr_control *csr)
static void add_host(struct hpsb_host *host)
{
struct csr1212_keyval *root;
quadlet_t bus_info[CSR_BUS_INFO_SIZE];
hpsb_register_addrspace(&csr_highlevel, host, &reg_ops,
CSR_REGISTER_BASE,
CSR_REGISTER_BASE + CSR_CONFIG_ROM);
hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
hpsb_register_addrspace(&csr_highlevel, host, &config_rom_ops,
CSR_REGISTER_BASE + CSR_CONFIG_ROM,
CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
if (fcp) {
......@@ -182,8 +203,6 @@ 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;
......@@ -202,43 +221,100 @@ static void add_host(struct hpsb_host *host)
host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
}
}
if (host->csr.max_rec >= 9)
host->csr.max_rom = 2;
else if (host->csr.max_rec >= 5)
host->csr.max_rom = 1;
else
host->csr.max_rom = 0;
host->csr.generation = 2;
bus_info[1] = __constant_cpu_to_be32(0x31333934);
bus_info[2] = cpu_to_be32((1 << CSR_IRMC_SHIFT) |
(1 << CSR_CMC_SHIFT) |
(1 << CSR_ISC_SHIFT) |
(0 << CSR_BMC_SHIFT) |
(0 << CSR_PMC_SHIFT) |
(host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
(host->csr.max_rec << CSR_MAX_REC_SHIFT) |
(host->csr.max_rom << CSR_MAX_ROM_SHIFT) |
(host->csr.generation << CSR_GENERATION_SHIFT) |
host->csr.lnk_spd);
bus_info[3] = cpu_to_be32(host->csr.guid_hi);
bus_info[4] = cpu_to_be32(host->csr.guid_lo);
/* The hardware copy of the bus info block will be set later when a
* bus reset is issued. */
csr1212_init_local_csr(host->csr.rom, bus_info, host->csr.max_rom);
host->csr.rom->max_rom = host->csr.max_rom;
root = host->csr.rom->root_kv;
if(csr1212_attach_keyval_to_directory(root, node_cap) != CSR1212_SUCCESS) {
HPSB_ERR("Failed to attach Node Capabilities to root directory");
}
host->update_config_rom = 1;
}
int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
size_t size, unsigned char rom_version)
static void remove_host(struct hpsb_host *host)
{
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;
quadlet_t bus_info[CSR_BUS_INFO_SIZE];
bus_info[1] = __constant_cpu_to_be32(0x31333934);
bus_info[2] = cpu_to_be32((0 << CSR_IRMC_SHIFT) |
(0 << CSR_CMC_SHIFT) |
(0 << CSR_ISC_SHIFT) |
(0 << CSR_BMC_SHIFT) |
(0 << CSR_PMC_SHIFT) |
(host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
(host->csr.max_rec << CSR_MAX_REC_SHIFT) |
(0 << CSR_MAX_ROM_SHIFT) |
(0 << CSR_GENERATION_SHIFT) |
host->csr.lnk_spd);
bus_info[3] = cpu_to_be32(host->csr.guid_hi);
bus_info[4] = cpu_to_be32(host->csr.guid_lo);
csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, node_cap);
csr1212_init_local_csr(host->csr.rom, bus_info, 0);
host->update_config_rom = 1;
}
int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer,
size_t buffersize, size_t *rom_size, unsigned char *rom_version)
int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
size_t buffersize, unsigned char rom_version)
{
unsigned long flags;
int ret;
HPSB_NOTICE("hpsb_update_config_rom() is deprecated");
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;
if (rom_version != host->csr.generation)
ret = -1;
else if (buffersize > host->csr.rom->cache_head->size)
ret = -2;
else {
memcpy(buffer,host->csr.rom,host->csr.rom_size);
ret=0;
/* Just overwrite the generated ConfigROM image with new data,
* it can be regenerated later. */
memcpy(host->csr.rom->cache_head->data, new_rom, buffersize);
host->csr.rom->cache_head->len = buffersize;
if (host->driver->set_hw_config_rom)
host->driver->set_hw_config_rom(host, host->csr.rom->bus_info_data);
/* Increment the generation number to keep some sort of sync
* with the newer ConfigROM manipulation method. */
host->csr.generation++;
if (host->csr.generation > 0xf || host->csr.generation < 2)
host->csr.generation = 2;
ret=0;
}
spin_unlock_irqrestore(&host->csr.lock, flags);
return ret;
......@@ -255,13 +331,7 @@ static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
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) {
if (csraddr < CSR_SPEED_MAP) {
src = ((char *)host->csr.topology_map) + csraddr
- CSR_TOPOLOGY_MAP;
} else {
......@@ -738,14 +808,52 @@ static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
return RCODE_COMPLETE;
}
static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
u64 addr, size_t length, u16 fl)
{
u32 offset = addr - CSR1212_REGISTER_SPACE_BASE;
if (csr1212_read(host->csr.rom, offset, buffer, length) == CSR1212_SUCCESS)
return RCODE_COMPLETE;
else
return RCODE_ADDRESS_ERROR;
}
static u64 allocate_addr_range(u64 size, u32 alignment, void *__host)
{
struct hpsb_host *host = (struct hpsb_host*)__host;
return hpsb_allocate_and_register_addrspace(&csr_highlevel,
host,
&config_rom_ops,
size, alignment,
CSR1212_UNITS_SPACE_BASE,
CSR1212_UNITS_SPACE_END);
}
static void release_addr_range(u64 addr, void *__host)
{
struct hpsb_host *host = (struct hpsb_host*)__host;
hpsb_unregister_addrspace(&csr_highlevel, host, addr);
}
void init_csr(void)
int init_csr(void)
{
node_cap = csr1212_new_immediate(CSR1212_KV_ID_NODE_CAPABILITIES, 0x0083c0);
if (!node_cap) {
HPSB_ERR("Failed to allocate memory for Node Capabilties ConfigROM entry!");
return -ENOMEM;
}
hpsb_register_highlevel(&csr_highlevel);
return 0;
}
void cleanup_csr(void)
{
if (node_cap)
csr1212_release_keyval(node_cap);
hpsb_unregister_highlevel(&csr_highlevel);
}
......@@ -6,6 +6,8 @@
#include <linux/sched.h>
#endif
#include "csr1212.h"
#define CSR_REGISTER_BASE 0xfffff0000000ULL
/* register offsets relative to CSR_REGISTER_BASE */
......@@ -34,6 +36,27 @@
#define CSR_SPEED_MAP 0x2000
#define CSR_SPEED_MAP_END 0x3000
/* IEEE 1394 bus specific Configuration ROM Key IDs */
#define IEEE1394_KV_ID_POWER_REQUIREMENTS (0x30)
/* IEEE 1394 Bus Inforamation Block specifics */
#define CSR_BUS_INFO_SIZE (5 * sizeof(quadlet_t))
#define CSR_IRMC_SHIFT 31
#define CSR_CMC_SHIFT 30
#define CSR_ISC_SHIFT 29
#define CSR_BMC_SHIFT 28
#define CSR_PMC_SHIFT 27
#define CSR_CYC_CLK_ACC_SHIFT 16
#define CSR_MAX_REC_SHIFT 12
#define CSR_MAX_ROM_SHIFT 8
#define CSR_GENERATION_SHIFT 4
#define CSR_SET_BUS_INFO_GENERATION(csr, gen) \
((csr)->bus_info_data[2] = \
cpu_to_be32((be32_to_cpu((csr)->bus_info_data[2]) & \
~(0xf << CSR_GENERATION_SHIFT)) | \
(gen) << CSR_GENERATION_SHIFT))
struct csr_control {
spinlock_t lock;
......@@ -49,17 +72,25 @@ struct csr_control {
quadlet_t channels_available_hi, channels_available_lo;
quadlet_t broadcast_channel;
quadlet_t *rom;
size_t rom_size;
unsigned char rom_version;
/* Bus Info */
quadlet_t guid_hi, guid_lo;
u8 cyc_clk_acc;
u8 max_rec;
u8 max_rom;
u8 generation; /* Only use values between 0x2 and 0xf */
u8 lnk_spd;
unsigned long gen_timestamp[16];
struct csr1212_csr *rom;
quadlet_t topology_map[256];
quadlet_t speed_map[1024];
};
extern struct csr1212_bus_ops csr_bus_ops;
void init_csr(void);
int init_csr(void);
void cleanup_csr(void);
#endif /* _IEEE1394_CSR_H */
This diff is collapsed.
This diff is collapsed.
......@@ -1801,15 +1801,12 @@ static int dv1394_open(struct inode *inode, struct file *file)
} else {
/* look up the card by ID */
struct list_head *lh;
unsigned long flags;
spin_lock_irqsave(&dv1394_cards_lock, flags);
if (!list_empty(&dv1394_cards)) {
struct video_card *p;
list_for_each(lh, &dv1394_cards) {
p = list_entry(lh, struct video_card, list);
list_for_each_entry(p, &dv1394_cards, list) {
if ((p->id) == ieee1394_file_to_instance(file)) {
video = p;
break;
......@@ -2374,7 +2371,6 @@ static void dv1394_host_reset(struct hpsb_host *host)
struct ti_ohci *ohci;
struct video_card *video = NULL;
unsigned long flags;
struct list_head *lh;
/* We only work with the OHCI-1394 driver */
if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
......@@ -2386,8 +2382,7 @@ static void dv1394_host_reset(struct hpsb_host *host)
/* find the corresponding video_cards */
spin_lock_irqsave(&dv1394_cards_lock, flags);
if (!list_empty(&dv1394_cards)) {
list_for_each(lh, &dv1394_cards) {
video = list_entry(lh, struct video_card, list);
list_for_each_entry(video, &dv1394_cards, list) {
if ((video->id >> 2) == ohci->id)
break;
}
......
This diff is collapsed.
......@@ -29,8 +29,8 @@
/* Register for incoming packets. This is 4096 bytes, which supports up to
* S3200 (per Table 16-3 of IEEE 1394b-2002). */
#define ETHER1394_REGION_ADDR_LEN 4096
#define ETHER1394_REGION_ADDR 0xfffff0200000ULL
#define ETHER1394_REGION_ADDR_END (ETHER1394_REGION_ADDR + ETHER1394_REGION_ADDR_LEN)
#define ETHER1394_INVALID_ADDR ~0ULL
/* GASP identifier numbers for IPv4 over IEEE 1394 */
#define ETHER1394_GASP_SPECIFIER_ID 0x00005E
......@@ -40,37 +40,30 @@
#define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t)) /* GASP header overhead */
#define ETHER1394_GASP_BUFFERS 16
/* Node set == 64 */
#define NODE_SET (ALL_NODES + 1)
enum eth1394_bc_states { ETHER1394_BC_CLOSED, ETHER1394_BC_OPENED,
ETHER1394_BC_CHECK };
enum eth1394_bc_states { ETHER1394_BC_ERROR,
ETHER1394_BC_RUNNING,
ETHER1394_BC_STOPPED };
struct pdg_list {
struct list_head list; /* partial datagram list per node */
unsigned int sz; /* partial datagram list size per node */
spinlock_t lock; /* partial datagram lock */
};
/* Private structure for our ethernet driver */
struct eth1394_priv {
struct net_device_stats stats; /* Device stats */
struct hpsb_host *host; /* The card for this dev */
u16 maxpayload[NODE_SET]; /* Max payload per node */
unsigned char sspd[NODE_SET]; /* Max speed per node */
u64 fifo[ALL_NODES]; /* FIFO offset per node */
u64 eui[ALL_NODES]; /* EUI-64 per node */
u16 bc_maxpayload; /* Max broadcast payload */
u8 bc_sspd; /* Max broadcast speed */
u64 local_fifo; /* Local FIFO Address */
spinlock_t lock; /* Private lock */
int broadcast_channel; /* Async stream Broadcast Channel */
enum eth1394_bc_states bc_state; /* broadcast channel state */
struct hpsb_iso *iso; /* Async stream recv handle */
struct pdg_list pdg[ALL_NODES]; /* partial RX datagram lists */
int dgl[NODE_SET]; /* Outgoing datagram label per node */
};
struct host_info {
struct hpsb_host *host;
struct net_device *dev;
int bc_dgl; /* Outgoing broadcast datagram label */
struct list_head ip_node_list; /* List of IP capable nodes */
struct unit_directory *ud_list[ALL_NODES]; /* Cached unit dir list */
};
......
This diff is collapsed.
......@@ -4,9 +4,9 @@
struct hpsb_address_serve {
struct list_head as_list; /* global list */
struct list_head host_list; /* per host list */
struct list_head addr_list; /* hpsb_highlevel list */
struct list_head hl_list; /* hpsb_highlevel list */
struct hpsb_address_ops *op;
......@@ -140,6 +140,11 @@ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl);
* It returns true for successful allocation. There is no unregister function,
* all address spaces are deallocated together with the hpsb_highlevel.
*/
u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
struct hpsb_host *host,
struct hpsb_address_ops *ops,
u64 size, u64 alignment,
u64 start, u64 end);
int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
struct hpsb_address_ops *ops, u64 start, u64 end);
......
......@@ -17,14 +17,46 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/timer.h>
#include "csr1212.h"
#include "ieee1394.h"
#include "ieee1394_types.h"
#include "hosts.h"
#include "ieee1394_core.h"
#include "highlevel.h"
#include "nodemgr.h"
#include "csr.h"
static void delayed_reset_bus(unsigned long __reset_info)
{
struct hpsb_host *host = (struct hpsb_host*)__reset_info;
int generation = host->csr.generation + 1;
/* The generation field rolls over to 2 rather than 0 per IEEE
* 1394a-2000. */
if (generation > 0xf || generation < 2)
generation = 2;
CSR_SET_BUS_INFO_GENERATION(host->csr.rom, generation);
if (csr1212_generate_csr_image(host->csr.rom) != CSR1212_SUCCESS) {
/* CSR image creation failed, reset generation field and do not
* issue a bus reset. */
CSR_SET_BUS_INFO_GENERATION(host->csr.rom, host->csr.generation);
return;
}
host->csr.generation = generation;
host->update_config_rom = 0;
if (host->driver->set_hw_config_rom)
host->driver->set_hw_config_rom(host, host->csr.rom->bus_info_data);
host->csr.gen_timestamp[host->csr.generation] = jiffies;
hpsb_reset_bus(host, SHORT_RESET);
}
static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p)
{
return 0;
......@@ -83,6 +115,12 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
if (!h) return NULL;
memset(h, 0, sizeof(struct hpsb_host) + extra);
h->csr.rom = csr1212_create_csr(&csr_bus_ops, CSR_BUS_INFO_SIZE, h);
if (!h->csr.rom) {
kfree(h);
return NULL;
}
h->hostdata = h + 1;
h->driver = drv;
......@@ -91,6 +129,12 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
INIT_LIST_HEAD(&h->addr_space);
init_timer(&h->delayed_reset);
h->delayed_reset.function = delayed_reset_bus;
h->delayed_reset.data = (unsigned long)h;
for (i = 2; i < 16; i++)
h->csr.gen_timestamp[i] = jiffies - 60 * HZ;
for (i = 0; i < ARRAY_SIZE(h->tpool); i++)
HPSB_TPOOL_INIT(&h->tpool[i]);
......@@ -116,7 +160,14 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
memcpy(&h->device, &nodemgr_dev_template_host, sizeof(h->device));
h->device.parent = dev;
snprintf(h->device.bus_id, BUS_ID_SIZE, "fw-host%d", h->id);
h->class_dev.dev = &h->device;
h->class_dev.class = &hpsb_host_class;
snprintf(h->class_dev.class_id, BUS_ID_SIZE, "fw-host%d", h->id);
device_register(&h->device);
class_device_register(&h->class_dev);
get_device(&h->device);
return h;
}
......@@ -124,7 +175,6 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
void hpsb_add_host(struct hpsb_host *host)
{
highlevel_add_host(host);
host->driver->devctl(host, RESET_BUS, LONG_RESET);
}
void hpsb_remove_host(struct hpsb_host *host)
......@@ -134,5 +184,38 @@ void hpsb_remove_host(struct hpsb_host *host)
highlevel_remove_host(host);
class_device_unregister(&host->class_dev);
device_unregister(&host->device);
}
int hpsb_update_config_rom_image(struct hpsb_host *host)
{
unsigned long reset_time;
int next_gen = host->csr.generation + 1;
if (!host->update_config_rom)
return -EINVAL;
if (next_gen > 0xf)
next_gen = 2;
/* Stop the delayed interrupt, we're about to change the config rom and
* it would be a waste to do a bus reset twice. */
del_timer_sync(&host->delayed_reset);
/* IEEE 1394a-2000 prohibits using the same generation number
* twice in a 60 second period. */
if (jiffies - host->csr.gen_timestamp[next_gen] < 60 * HZ)
/* Wait 60 seconds from the last time this generation number was
* used. */
reset_time = (60 * HZ) + host->csr.gen_timestamp[next_gen];
else
/* Wait 1 second in case some other code wants to change the
* Config ROM in the near future. */
reset_time = jiffies + HZ;
/* This will add the timer as well as modify it */
mod_timer(&host->delayed_reset, reset_time);
return 0;
}
......@@ -10,14 +10,6 @@
#include "ieee1394_types.h"
#include "csr.h"
/* size of the array used to store config rom (in quadlets)
maximum is 0x100. About 0x40 is needed for the default
entries. So 0x80 should provide enough space for additional
directories etc.
Note: All lowlevel drivers are required to allocate at least
this amount of memory for the configuration rom!
*/
#define CSR_CONFIG_ROM_SIZE 0x100
struct hpsb_packet;
struct hpsb_iso;
......@@ -69,6 +61,10 @@ struct hpsb_host {
int id;
struct device device;
struct class_device class_dev;
int update_config_rom;
struct timer_list delayed_reset;
struct list_head addr_space;
};
......@@ -153,12 +149,10 @@ struct hpsb_host_driver {
struct module *owner;
const char *name;
/* This function must store a pointer to the configuration ROM into the
* location referenced to by pointer and return the size of the ROM. It
* may not fail. If any allocation is required, it must be done
* earlier.
*/
size_t (*get_rom) (struct hpsb_host *host, quadlet_t **pointer);
/* The hardware driver may optionally support a function that is used
* to set the hardware ConfigROM if the hardware supports handling
* reads to the ConfigROM on its own. */
void (*set_hw_config_rom) (struct hpsb_host *host, quadlet_t *config_rom);
/* This function shall implement packet transmission based on
* packet->type. It shall CRC both parts of the packet (unless
......@@ -200,24 +194,18 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
void hpsb_add_host(struct hpsb_host *host);
void hpsb_remove_host(struct hpsb_host *h);
/* updates the configuration rom of a host.
* rom_version must be the current version,
* otherwise it will fail with return value -1.
* Return value -2 indicates that the new
* rom version is too big.
* Return value 0 indicates success
*/
/* The following 2 functions are deprecated and will be removed when the
* raw1394/libraw1394 update is complete. */
int hpsb_update_config_rom(struct hpsb_host *host,
const quadlet_t *new_rom, size_t size, unsigned char rom_version);
/* reads the current version of the configuration rom of a host.
* buffersize is the size of the buffer, rom_size
* returns the size of the current rom image.
* rom_version is the version number of the fetched rom.
* return value -1 indicates, that the buffer was
* too small, 0 indicates success.
*/
int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer,
size_t buffersize, size_t *rom_size, unsigned char *rom_version);
/* Updates the configuration rom image of a host. rom_version must be the
* current version, otherwise it will fail with return value -1. If this
* host does not support config-rom-update, it will return -EINVAL.
* Return value 0 indicates success.
*/
int hpsb_update_config_rom_image(struct hpsb_host *host);
#endif /* _IEEE1394_HOSTS_H */
......@@ -515,9 +515,9 @@ int hpsb_send_packet(struct hpsb_packet *packet)
if (packet->node_id == host->node_id)
{ /* it is a local request, so handle it locally */
quadlet_t *data;
size_t size=packet->data_size+packet->header_size;
size_t size = packet->data_size + packet->header_size;
data = kmalloc(packet->header_size + packet->data_size, GFP_ATOMIC);
data = kmalloc(size, GFP_ATOMIC);
if (!data) {
HPSB_ERR("unable to allocate memory for concatenating header and data");
return -ENOMEM;
......@@ -526,12 +526,12 @@ int hpsb_send_packet(struct hpsb_packet *packet)
memcpy(data, packet->header, packet->header_size);
if (packet->data_size)
memcpy(((u8*)data)+packet->header_size, packet->data, packet->data_size);
memcpy(((u8*)data) + packet->header_size, packet->data, packet->data_size);
dump_packet("send packet local:", packet->header,
packet->header_size);
hpsb_packet_sent(host, packet, packet->expect_response?ACK_PENDING:ACK_COMPLETE);
hpsb_packet_sent(host, packet, packet->expect_response ? ACK_PENDING : ACK_COMPLETE);
hpsb_packet_received(host, data, size, 0);
kfree(data);
......@@ -935,8 +935,7 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
void abort_requests(struct hpsb_host *host)
{
unsigned long flags;
struct hpsb_packet *packet;
struct list_head *lh, *tlh;
struct hpsb_packet *packet, *packet_next;
LIST_HEAD(llist);
host->driver->devctl(host, CANCEL_REQUESTS, 0);
......@@ -946,8 +945,7 @@ void abort_requests(struct hpsb_host *host)
INIT_LIST_HEAD(&host->pending_packets);
spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
list_for_each_safe(lh, tlh, &llist) {
packet = list_entry(lh, struct hpsb_packet, list);
list_for_each_entry_safe(packet, packet_next, &llist, list) {
list_del(&packet->list);
packet->state = hpsb_complete;
packet->ack_code = ACKX_ABORTED;
......@@ -959,9 +957,8 @@ void abort_timedouts(unsigned long __opaque)
{
struct hpsb_host *host = (struct hpsb_host *)__opaque;
unsigned long flags;
struct hpsb_packet *packet;
struct hpsb_packet *packet, *packet_next;
unsigned long expire;
struct list_head *lh, *tlh;
LIST_HEAD(expiredlist);
spin_lock_irqsave(&host->csr.lock, flags);
......@@ -970,8 +967,7 @@ void abort_timedouts(unsigned long __opaque)
spin_lock_irqsave(&host->pending_pkt_lock, flags);
list_for_each_safe(lh, tlh, &host->pending_packets) {
packet = list_entry(lh, struct hpsb_packet, list);
list_for_each_entry_safe(packet, packet_next, &host->pending_packets, list) {
if (time_before(packet->sendtime + expire, jiffies)) {
list_del(&packet->list);
list_add(&packet->list, &expiredlist);
......@@ -983,8 +979,7 @@ void abort_timedouts(unsigned long __opaque)
spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
list_for_each_safe(lh, tlh, &expiredlist) {
packet = list_entry(lh, struct hpsb_packet, list);
list_for_each_entry_safe(packet, packet_next, &expiredlist, list) {
list_del(&packet->list);
packet->state = hpsb_complete;
packet->ack_code = ACKX_TIMEOUT;
......@@ -995,6 +990,8 @@ void abort_timedouts(unsigned long __opaque)
static int __init ieee1394_init(void)
{
int i;
devfs_mk_dir("ieee1394");
if (register_chrdev_region(IEEE1394_CORE_DEV, 256, "ieee1394")) {
......@@ -1008,8 +1005,12 @@ static int __init ieee1394_init(void)
0, 0, NULL, NULL);
bus_register(&ieee1394_bus_type);
for (i = 0; fw_bus_attrs[i]; i++)
bus_create_file(&ieee1394_bus_type, fw_bus_attrs[i]);
class_register(&hpsb_host_class);
init_csr();
if (init_csr())
return -ENOMEM;
if (!disable_nodemgr)
init_ieee1394_nodemgr();
......@@ -1021,11 +1022,16 @@ static int __init ieee1394_init(void)
static void __exit ieee1394_cleanup(void)
{
int i;
if (!disable_nodemgr)
cleanup_ieee1394_nodemgr();
cleanup_csr();
class_unregister(&hpsb_host_class);
for (i = 0; fw_bus_attrs[i]; i++)
bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
bus_unregister(&ieee1394_bus_type);
kmem_cache_destroy(hpsb_packet_cache);
......@@ -1043,6 +1049,7 @@ module_exit(ieee1394_cleanup);
EXPORT_SYMBOL(hpsb_alloc_host);
EXPORT_SYMBOL(hpsb_add_host);
EXPORT_SYMBOL(hpsb_remove_host);
EXPORT_SYMBOL(hpsb_update_config_rom_image);
/** ieee1394_core.c **/
EXPORT_SYMBOL(hpsb_speedto_str);
......@@ -1081,6 +1088,7 @@ EXPORT_SYMBOL(hpsb_register_highlevel);
EXPORT_SYMBOL(hpsb_unregister_highlevel);
EXPORT_SYMBOL(hpsb_register_addrspace);
EXPORT_SYMBOL(hpsb_unregister_addrspace);
EXPORT_SYMBOL(hpsb_allocate_and_register_addrspace);
EXPORT_SYMBOL(hpsb_listen_channel);
EXPORT_SYMBOL(hpsb_unlisten_channel);
EXPORT_SYMBOL(hpsb_get_hostinfo);
......@@ -1113,7 +1121,6 @@ EXPORT_SYMBOL(nodemgr_for_each_host);
/** csr.c **/
EXPORT_SYMBOL(hpsb_update_config_rom);
EXPORT_SYMBOL(hpsb_get_config_rom);
/** dma.c **/
EXPORT_SYMBOL(dma_prog_region_init);
......@@ -1144,3 +1151,34 @@ EXPORT_SYMBOL(hpsb_iso_packet_sent);
EXPORT_SYMBOL(hpsb_iso_packet_received);
EXPORT_SYMBOL(hpsb_iso_wake);
EXPORT_SYMBOL(hpsb_iso_recv_flush);
/** csr1212.c **/
EXPORT_SYMBOL(csr1212_create_csr);
EXPORT_SYMBOL(csr1212_init_local_csr);
EXPORT_SYMBOL(csr1212_new_immediate);
EXPORT_SYMBOL(csr1212_new_leaf);
EXPORT_SYMBOL(csr1212_new_csr_offset);
EXPORT_SYMBOL(csr1212_new_directory);
EXPORT_SYMBOL(csr1212_associate_keyval);
EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
EXPORT_SYMBOL(csr1212_new_extended_immediate);
EXPORT_SYMBOL(csr1212_new_extended_leaf);
EXPORT_SYMBOL(csr1212_new_descriptor_leaf);
EXPORT_SYMBOL(csr1212_new_textual_descriptor_leaf);
EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf);
EXPORT_SYMBOL(csr1212_new_icon_descriptor_leaf);
EXPORT_SYMBOL(csr1212_new_modifiable_descriptor_leaf);
EXPORT_SYMBOL(csr1212_new_keyword_leaf);
EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
EXPORT_SYMBOL(csr1212_disassociate_keyval);
EXPORT_SYMBOL(csr1212_release_keyval);
EXPORT_SYMBOL(csr1212_destroy_csr);
EXPORT_SYMBOL(csr1212_read);
EXPORT_SYMBOL(csr1212_generate_positions);
EXPORT_SYMBOL(csr1212_generate_layout_order);
EXPORT_SYMBOL(csr1212_fill_cache);
EXPORT_SYMBOL(csr1212_generate_csr_image);
EXPORT_SYMBOL(csr1212_parse_keyval);
EXPORT_SYMBOL(csr1212_parse_csr);
EXPORT_SYMBOL(_csr1212_read_keyval);
EXPORT_SYMBOL(_csr1212_destroy_keyval);
......@@ -215,5 +215,6 @@ static inline unsigned char ieee1394_file_to_instance(struct file *file)
/* Our sysfs bus entry */
extern struct bus_type ieee1394_bus_type;
extern struct class hpsb_host_class;
#endif /* _IEEE1394_CORE_H */
This diff is collapsed.
......@@ -21,50 +21,12 @@
#define _IEEE1394_NODEMGR_H
#include <linux/device.h>
#include "csr1212.h"
#include "ieee1394_core.h"
#include "ieee1394_hotplug.h"
#define CONFIG_ROM_BUS_INFO_LENGTH(q) ((q) >> 24)
#define CONFIG_ROM_BUS_CRC_LENGTH(q) (((q) >> 16) & 0xff)
#define CONFIG_ROM_BUS_CRC(q) ((q) & 0xffff)
#define CONFIG_ROM_ROOT_LENGTH(q) ((q) >> 16)
#define CONFIG_ROM_ROOT_CRC(q) ((q) & 0xffff)
#define CONFIG_ROM_DIRECTORY_LENGTH(q) ((q) >> 16)
#define CONFIG_ROM_DIRECTORY_CRC(q) ((q) & 0xffff)
#define CONFIG_ROM_LEAF_LENGTH(q) ((q) >> 16)
#define CONFIG_ROM_LEAF_CRC(q) ((q) & 0xffff)
#define CONFIG_ROM_DESCRIPTOR_TYPE(q) ((q) >> 24)
#define CONFIG_ROM_DESCRIPTOR_SPECIFIER_ID(q) ((q) & 0xffffff)
#define CONFIG_ROM_DESCRIPTOR_WIDTH(q) ((q) >> 28)
#define CONFIG_ROM_DESCRIPTOR_CHAR_SET(q) (((q) >> 16) & 0xfff)
#define CONFIG_ROM_DESCRIPTOR_LANG(q) ((q) & 0xffff)
#define CONFIG_ROM_KEY_ID_MASK 0x3f
#define CONFIG_ROM_KEY_TYPE_MASK 0xc0
#define CONFIG_ROM_KEY_TYPE_IMMEDIATE 0x00
#define CONFIG_ROM_KEY_TYPE_OFFSET 0x40
#define CONFIG_ROM_KEY_TYPE_LEAF 0x80
#define CONFIG_ROM_KEY_TYPE_DIRECTORY 0xc0
#define CONFIG_ROM_KEY(q) ((q) >> 24)
#define CONFIG_ROM_VALUE(q) ((q) & 0xffffff)
#define CONFIG_ROM_VENDOR_ID 0x03
#define CONFIG_ROM_MODEL_ID 0x17
#define CONFIG_ROM_NODE_CAPABILITES 0x0C
#define CONFIG_ROM_UNIT_DIRECTORY 0xd1
#define CONFIG_ROM_LOGICAL_UNIT_DIRECTORY 0xd4
#define CONFIG_ROM_SPECIFIER_ID 0x12
#define CONFIG_ROM_UNIT_SW_VERSION 0x13
#define CONFIG_ROM_DESCRIPTOR_LEAF 0x81
#define CONFIG_ROM_DESCRIPTOR_DIRECTORY 0xc1
/* '1' '3' '9' '4' in ASCII */
#define IEEE1394_BUSID_MAGIC 0x31333934
#define IEEE1394_BUSID_MAGIC __constant_cpu_to_be32(0x31333934)
/* This is the start of a Node entry structure. It should be a stable API
* for which to gather info from the Node Manager about devices attached
......@@ -76,6 +38,7 @@ struct bus_options {
u8 bmc; /* Bus Master Capable */
u8 pmc; /* Power Manager Capable (PNP spec) */
u8 cyc_clk_acc; /* Cycle clock accuracy */
u8 max_rom; /* Maximum block read supported in the CSR */
u8 generation; /* Incremented when configrom changes */
u8 lnkspd; /* Link speed */
u16 max_rec; /* Maximum packet size node can receive */
......@@ -86,10 +49,8 @@ struct bus_options {
#define UNIT_DIRECTORY_MODEL_ID 0x02
#define UNIT_DIRECTORY_SPECIFIER_ID 0x04
#define UNIT_DIRECTORY_VERSION 0x08
#define UNIT_DIRECTORY_VENDOR_TEXT 0x10
#define UNIT_DIRECTORY_MODEL_TEXT 0x20
#define UNIT_DIRECTORY_HAS_LUN_DIRECTORY 0x40
#define UNIT_DIRECTORY_LUN_DIRECTORY 0x80
#define UNIT_DIRECTORY_HAS_LUN_DIRECTORY 0x10
#define UNIT_DIRECTORY_LUN_DIRECTORY 0x20
/*
* A unit directory corresponds to a protocol supported by the
......@@ -98,28 +59,27 @@ struct bus_options {
*/
struct unit_directory {
struct node_entry *ne; /* The node which this directory belongs to */
octlet_t address; /* Address of the unit directory on the node */
octlet_t address; /* Address of the unit directory on the node */
u8 flags; /* Indicates which entries were read */
quadlet_t vendor_id;
const char *vendor_name;
struct csr1212_keyval *vendor_name_kv;
const char *vendor_oui;
int vendor_name_size;
quadlet_t model_id;
const char *model_name;
int model_name_size;
struct csr1212_keyval *model_name_kv;
quadlet_t specifier_id;
quadlet_t version;
unsigned int id;
int ignore_driver;
int length; /* Number of quadlets */
struct device device;
/* XXX Must be last in the struct! */
quadlet_t quadlets[0];
struct csr1212_keyval *ud_kv;
};
struct node_entry {
......@@ -135,7 +95,7 @@ struct node_entry {
/* The following is read from the config rom */
u32 vendor_id;
const char *vendor_name;
struct csr1212_keyval *vendor_name_kv;
const char *vendor_oui;
u32 capabilities;
......@@ -143,8 +103,12 @@ struct node_entry {
struct device device;
/* XXX Must be last in the struct! */
quadlet_t quadlets[0];
struct class_device class_dev;
/* Means this node is not attached anymore */
int in_limbo;
struct csr1212_csr *csr;
};
struct hpsb_protocol_driver {
......@@ -231,4 +195,7 @@ void cleanup_ieee1394_nodemgr(void);
/* The template for a host device */
extern struct device nodemgr_dev_template_host;
/* Bus attributes we export */
extern struct bus_attribute *const fw_bus_attrs[];
#endif /* _IEEE1394_NODEMGR_H */
This diff is collapsed.
......@@ -49,6 +49,7 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include "csr1212.h"
#include "ieee1394.h"
#include "ieee1394_types.h"
#include "hosts.h"
......@@ -1515,6 +1516,11 @@ static int __devinit add_card(struct pci_dev *dev,
return error; \
} while (0)
struct csr1212_keyval *root;
struct csr1212_keyval *vend_id = NULL;
struct csr1212_keyval *text = NULL;
int ret;
char irq_buf[16];
struct hpsb_host *host;
struct ti_lynx *lynx; /* shortcut to currently handled device */
......@@ -1527,8 +1533,6 @@ static int __devinit add_card(struct pci_dev *dev,
struct i2c_adapter i2c_adapter;
struct i2c_algo_bit_data i2c_adapter_data;
int got_valid_bus_info_block = 0; /* set to 1, if we were able to get a valid bus info block from serial eeprom */
error = -ENXIO;
if (pci_set_dma_mask(dev, 0xffffffff))
......@@ -1814,14 +1818,15 @@ static int __devinit add_card(struct pci_dev *dev,
if (i2c_bit_add_bus(&i2c_adapter) < 0)
{
PRINT(KERN_ERR, lynx->id, "unable to register i2c");
error = -ENXIO;
FAIL("unable to register i2c");
}
else
{
/* do i2c stuff */
unsigned char i2c_cmd = 0x10;
struct i2c_msg msg[2] = { { 0x50, 0, 1, &i2c_cmd },
{ 0x50, I2C_M_RD, 20, (unsigned char*) lynx->config_rom }
{ 0x50, I2C_M_RD, 20, (unsigned char*) lynx->bus_info_block }
};
......@@ -1858,16 +1863,16 @@ static int __devinit add_card(struct pci_dev *dev,
for (i = 0; i < 5 ; i++)
PRINTD(KERN_DEBUG, lynx->id, "Businfo block quadlet %i: %08x",
i, be32_to_cpu(lynx->config_rom[i]));
i, be32_to_cpu(lynx->bus_info_block[i]));
/* info_length, crc_length and 1394 magic number to check, if it is really a bus info block */
if (((be32_to_cpu(lynx->config_rom[0]) & 0xffff0000) == 0x04040000) &&
(lynx->config_rom[1] == __constant_cpu_to_be32(0x31333934)))
if (((be32_to_cpu(lynx->bus_info_block[0]) & 0xffff0000) == 0x04040000) &&
(lynx->bus_info_block[1] == __constant_cpu_to_be32(0x31333934)))
{
PRINT(KERN_DEBUG, lynx->id, "read a valid bus info block from");
got_valid_bus_info_block = 1;
} else {
PRINT(KERN_WARNING, lynx->id, "read something from serial eeprom, but it does not seem to be a valid bus info block");
error = -ENXIO;
FAIL("read something from serial eeprom, but it does not seem to be a valid bus info block");
}
}
......@@ -1876,29 +1881,55 @@ static int __devinit add_card(struct pci_dev *dev,
}
}
if (got_valid_bus_info_block) {
memcpy(lynx->config_rom+5,lynx_csr_rom+5,sizeof(lynx_csr_rom)-20);
} else {
PRINT(KERN_INFO, lynx->id, "since we did not get a bus info block from serial eeprom, we use a generic one with a hard coded GUID");
memcpy(lynx->config_rom,lynx_csr_rom,sizeof(lynx_csr_rom));
}
hpsb_add_host(host);
lynx->state = is_host;
host->csr.guid_hi = be32_to_cpu(lynx->bus_info_block[3]);
host->csr.guid_lo = be32_to_cpu(lynx->bus_info_block[4]);
host->csr.cyc_clk_acc = (be32_to_cpu(lynx->bus_info_block[2]) >> 16) & 0xff;
host->csr.max_rec = (be32_to_cpu(lynx->bus_info_block[2]) >> 12) & 0xf;
if (!lynx->phyic.reg_1394a)
host->csr.lnk_spd = (get_phy_reg(lynx, 2) & 0xc0) >> 6;
else
host->csr.lnk_spd = be32_to_cpu(lynx->bus_info_block[2]) & 0x7;
/* Setup initial root directory entries */
root = host->csr.rom->root_kv;
vend_id = csr1212_new_immediate(CSR1212_KV_ID_VENDOR,
be32_to_cpu(lynx->bus_info_block[3]) >> 8);
text = csr1212_new_string_descriptor_leaf("Linux 1394 - PCI-Lynx");
if (!vend_id || !text) {
if (vend_id)
csr1212_release_keyval(vend_id);
if (text)
csr1212_release_keyval(text);
error = -ENOMEM;
FAIL("Failed to allocate memory for mandatory ConfigROM entries!");
}
return 0;
#undef FAIL
}
ret = csr1212_associate_keyval(vend_id, text);
csr1212_release_keyval(text); /* no longer needed locally. */
if(ret != CSR1212_SUCCESS) {
csr1212_release_keyval(vend_id);
error = ret;
FAIL("Failed to associate text descriptor to vendor id");
}
ret = csr1212_attach_keyval_to_directory(root, vend_id);
csr1212_release_keyval(vend_id); /* no longer needed locally. */
if(ret != CSR1212_SUCCESS) {
error = ret;
FAIL("Failed to attach vendor id to root directory");
}
host->update_config_rom = 1;
hpsb_add_host(host);
lynx->state = is_host;
static size_t get_lynx_rom(struct hpsb_host *host, quadlet_t **ptr)
{
struct ti_lynx *lynx = host->hostdata;
*ptr = lynx->config_rom;
return sizeof(lynx_csr_rom);
return ret;
#undef FAIL
}
static struct pci_device_id pci_table[] = {
{
.vendor = PCI_VENDOR_ID_TI,
......@@ -1919,7 +1950,7 @@ static struct pci_driver lynx_pci_driver = {
static struct hpsb_host_driver lynx_driver = {
.owner = THIS_MODULE,
.name = PCILYNX_DRIVER_NAME,
.get_rom = get_lynx_rom,
.set_hw_config_rom = NULL,
.transmit_packet = lynx_transmit,
.devctl = lynx_devctl,
.isoctl = NULL,
......
This diff is collapsed.
......@@ -7,6 +7,8 @@
#define RAW1394_DEVICE_MAJOR 171
#define RAW1394_DEVICE_NAME "raw1394"
#define RAW1394_MAX_USER_CSR_DIRS 16
struct iso_block_store {
atomic_t refcount;
size_t data_size;
......@@ -45,6 +47,12 @@ struct file_info {
/* new rawiso API */
enum raw1394_iso_state iso_state;
struct hpsb_iso *iso_handle;
/* User space's CSR1212 dynamic ConfigROM directories */
struct csr1212_keyval *csr1212_dirs[RAW1394_MAX_USER_CSR_DIRS];
/* Legacy ConfigROM update flag */
u8 cfgrom_upd;
};
struct arm_addr {
......
This diff is collapsed.
......@@ -27,6 +27,7 @@
#define RAW1394_REQ_GET_ROM 203
#define RAW1394_REQ_UPDATE_ROM 204
#define RAW1394_REQ_ECHO 205
#define RAW1394_REQ_MODIFY_ROM 206
#define RAW1394_REQ_ARM_REGISTER 300
#define RAW1394_REQ_ARM_UNREGISTER 301
......
This diff is collapsed.
This diff is collapsed.
......@@ -476,11 +476,9 @@ static void initialize_dma_ir_ctx(struct dma_iso_ctx *d, int tag, int flags)
static struct dma_iso_ctx *
find_ctx(struct list_head *list, int type, int channel)
{
struct list_head *lh;
struct dma_iso_ctx *ctx;
list_for_each(lh, list) {
struct dma_iso_ctx *ctx;
ctx = list_entry(lh, struct dma_iso_ctx, link);
list_for_each_entry(ctx, list, link) {
if (ctx->type == type && ctx->channel == channel)
return ctx;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment