Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
16eadb50
Commit
16eadb50
authored
Feb 19, 2004
by
Ben Collins
Browse files
Options
Browse Files
Download
Plain Diff
Merge
parents
70b19320
c1b2007c
Changes
27
Hide whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
4360 additions
and
1699 deletions
+4360
-1699
drivers/ieee1394/Kconfig
drivers/ieee1394/Kconfig
+6
-2
drivers/ieee1394/Makefile
drivers/ieee1394/Makefile
+2
-1
drivers/ieee1394/amdtp.c
drivers/ieee1394/amdtp.c
+5
-5
drivers/ieee1394/csr.c
drivers/ieee1394/csr.c
+145
-37
drivers/ieee1394/csr.h
drivers/ieee1394/csr.h
+35
-4
drivers/ieee1394/csr1212.c
drivers/ieee1394/csr1212.c
+1566
-0
drivers/ieee1394/csr1212.h
drivers/ieee1394/csr1212.h
+724
-0
drivers/ieee1394/dv1394.c
drivers/ieee1394/dv1394.c
+2
-7
drivers/ieee1394/eth1394.c
drivers/ieee1394/eth1394.c
+476
-247
drivers/ieee1394/eth1394.h
drivers/ieee1394/eth1394.h
+13
-20
drivers/ieee1394/highlevel.c
drivers/ieee1394/highlevel.c
+167
-89
drivers/ieee1394/highlevel.h
drivers/ieee1394/highlevel.h
+7
-2
drivers/ieee1394/hosts.c
drivers/ieee1394/hosts.c
+84
-1
drivers/ieee1394/hosts.h
drivers/ieee1394/hosts.h
+17
-29
drivers/ieee1394/ieee1394_core.c
drivers/ieee1394/ieee1394_core.c
+54
-16
drivers/ieee1394/ieee1394_core.h
drivers/ieee1394/ieee1394_core.h
+1
-0
drivers/ieee1394/nodemgr.c
drivers/ieee1394/nodemgr.c
+624
-746
drivers/ieee1394/nodemgr.h
drivers/ieee1394/nodemgr.h
+21
-54
drivers/ieee1394/ohci1394.c
drivers/ieee1394/ohci1394.c
+53
-158
drivers/ieee1394/pcilynx.c
drivers/ieee1394/pcilynx.c
+58
-27
drivers/ieee1394/pcilynx.h
drivers/ieee1394/pcilynx.h
+5
-74
drivers/ieee1394/raw1394-private.h
drivers/ieee1394/raw1394-private.h
+8
-0
drivers/ieee1394/raw1394.c
drivers/ieee1394/raw1394.c
+179
-99
drivers/ieee1394/raw1394.h
drivers/ieee1394/raw1394.h
+1
-0
drivers/ieee1394/sbp2.c
drivers/ieee1394/sbp2.c
+101
-76
drivers/ieee1394/sbp2.h
drivers/ieee1394/sbp2.h
+4
-1
drivers/ieee1394/video1394.c
drivers/ieee1394/video1394.c
+2
-4
No files found.
drivers/ieee1394/Kconfig
View file @
16eadb50
...
...
@@ -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"
...
...
drivers/ieee1394/Makefile
View file @
16eadb50
...
...
@@ -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
...
...
drivers/ieee1394/amdtp.c
View file @
16eadb50
...
...
@@ -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
);
...
...
drivers/ieee1394/csr.c
View file @
16eadb50
...
...
@@ -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
);
}
drivers/ieee1394/csr.h
View file @
16eadb50
...
...
@@ -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 */
drivers/ieee1394/csr1212.c
0 → 100644
View file @
16eadb50
/*
* csr1212.c -- IEEE 1212 Control and Status Register support for Linux
*
* Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
* Steve Kinneberg <kinnebergsteve@acmsystems.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* TODO List:
* - Verify interface consistency: i.e., public functions that take a size
* parameter expect size to be in bytes.
* - Convenience functions for reading a block of data from a given offset.
*/
#ifndef __KERNEL__
#include <string.h>
#endif
#include "csr1212.h"
/* Permitted key type for each key id */
#define __I (1 << CSR1212_KV_TYPE_IMMEDIATE)
#define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET)
#define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
#define __L (1 << CSR1212_KV_TYPE_LEAF)
static
const
u_int8_t
csr1212_key_id_type_map
[
0x30
]
=
{
0
,
/* Reserved */
__D
|
__L
,
/* Descriptor */
__I
|
__D
|
__L
,
/* Bus_Dependent_Info */
__I
|
__D
|
__L
,
/* Vendor */
__I
,
/* Hardware_Version */
0
,
0
,
/* Reserved */
__D
|
__L
,
/* Module */
0
,
0
,
0
,
0
,
/* Reserved */
__I
,
/* Node_Capabilities */
__L
,
/* EUI_64 */
0
,
0
,
0
,
/* Reserved */
__D
,
/* Unit */
__I
,
/* Specifier_ID */
__I
,
/* Version */
__I
|
__C
|
__D
|
__L
,
/* Dependent_Info */
__L
,
/* Unit_Location */
0
,
/* Reserved */
__I
,
/* Model */
__D
,
/* Instance */
__L
,
/* Keyword */
__D
,
/* Feature */
__L
,
/* Extended_ROM */
__I
,
/* Extended_Key_Specifier_ID */
__I
,
/* Extended_Key */
__I
|
__C
|
__D
|
__L
,
/* Extended_Data */
__L
,
/* Modifiable_Descriptor */
__I
,
/* Directory_ID */
__I
,
/* Revision */
};
#undef __I
#undef __C
#undef __D
#undef __L
#define quads_to_bytes(_q) ((_q) * sizeof(u_int32_t))
#define bytes_to_quads(_b) (((_b) + sizeof(u_int32_t) - 1) / sizeof(u_int32_t))
static
inline
void
free_keyval
(
struct
csr1212_keyval
*
kv
)
{
if
(
kv
->
key
.
type
==
CSR1212_KV_TYPE_LEAF
)
CSR1212_FREE
(
kv
->
value
.
leaf
.
data
);
CSR1212_FREE
(
kv
);
}
static
u_int16_t
csr1212_crc16
(
const
u_int32_t
*
buffer
,
size_t
length
)
{
int
shift
;
u_int32_t
data
;
u_int16_t
sum
,
crc
=
0
;
for
(;
length
;
length
--
)
{
data
=
CSR1212_BE32_TO_CPU
(
*
buffer
);
buffer
++
;
for
(
shift
=
28
;
shift
>=
0
;
shift
-=
4
)
{
sum
=
((
crc
>>
12
)
^
(
data
>>
shift
))
&
0xf
;
crc
=
(
crc
<<
4
)
^
(
sum
<<
12
)
^
(
sum
<<
5
)
^
(
sum
);
}
crc
&=
0xffff
;
}
return
CSR1212_CPU_TO_BE16
(
crc
);
}
#if 0
/* Microsoft computes the CRC with the bytes in reverse order. Therefore we
* have a special version of the CRC algorithm to account for their buggy
* software. */
static u_int16_t csr1212_msft_crc16(const u_int32_t *buffer, size_t length)
{
int shift;
u_int32_t data;
u_int16_t sum, crc = 0;
for (; length; length--) {
data = CSR1212_LE32_TO_CPU(*buffer);
buffer++;
for (shift = 28; shift >= 0; shift -= 4 ) {
sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
}
crc &= 0xffff;
}
return CSR1212_CPU_TO_BE16(crc);
}
#endif
static
inline
struct
csr1212_dentry
*
csr1212_find_keyval
(
struct
csr1212_keyval
*
dir
,
struct
csr1212_keyval
*
kv
)
{
struct
csr1212_dentry
*
pos
;
for
(
pos
=
dir
->
value
.
directory
.
dentries_head
;
pos
!=
NULL
;
pos
=
pos
->
next
)
{
if
(
pos
->
kv
==
kv
)
return
pos
;
}
return
NULL
;
}
static
inline
struct
csr1212_keyval
*
csr1212_find_keyval_offset
(
struct
csr1212_keyval
*
kv_list
,
u_int32_t
offset
)
{
struct
csr1212_keyval
*
kv
;
for
(
kv
=
kv_list
;
kv
!=
NULL
;
kv
=
kv
->
next
)
{
if
(
kv
->
offset
==
offset
)
return
kv
;
}
return
NULL
;
}
/* Creation Routines */
struct
csr1212_csr
*
csr1212_create_csr
(
struct
csr1212_bus_ops
*
ops
,
size_t
bus_info_size
,
void
*
private
)
{
struct
csr1212_csr
*
csr
;
csr
=
CSR1212_MALLOC
(
sizeof
(
*
csr
));
if
(
!
csr
)
return
NULL
;
csr
->
cache_head
=
csr1212_rom_cache_malloc
(
CSR1212_CONFIG_ROM_SPACE_OFFSET
,
CSR1212_CONFIG_ROM_SPACE_SIZE
);
if
(
!
csr
->
cache_head
)
{
CSR1212_FREE
(
csr
);
return
NULL
;
}
/* The keyval key id is not used for the root node, but a valid key id
* that can be used for a directory needs to be passed to
* csr1212_new_directory(). */
csr
->
root_kv
=
csr1212_new_directory
(
CSR1212_KV_ID_VENDOR
);
if
(
!
csr
->
root_kv
)
{
CSR1212_FREE
(
csr
->
cache_head
);
CSR1212_FREE
(
csr
);
return
NULL
;
}
csr
->
bus_info_data
=
csr
->
cache_head
->
data
;
csr
->
bus_info_len
=
bus_info_size
;
csr
->
crc_len
=
bus_info_size
;
csr
->
ops
=
ops
;
csr
->
private
=
private
;
csr
->
cache_tail
=
csr
->
cache_head
;
return
csr
;
}
void
csr1212_init_local_csr
(
struct
csr1212_csr
*
csr
,
const
u_int32_t
*
bus_info_data
,
int
max_rom
)
{
csr
->
max_rom
=
max_rom
;
memcpy
(
csr
->
bus_info_data
,
bus_info_data
,
csr
->
bus_info_len
);
}
static
struct
csr1212_keyval
*
csr1212_new_keyval
(
u_int8_t
type
,
u_int8_t
key
)
{
struct
csr1212_keyval
*
kv
;
if
(
key
<
0x30
&&
((
csr1212_key_id_type_map
[
key
]
&
(
1
<<
type
))
==
0
))
return
NULL
;
kv
=
CSR1212_MALLOC
(
sizeof
(
*
kv
));
if
(
!
kv
)
return
NULL
;
kv
->
key
.
type
=
type
;
kv
->
key
.
id
=
key
;
kv
->
associate
=
NULL
;
kv
->
refcnt
=
1
;
kv
->
next
=
NULL
;
kv
->
prev
=
NULL
;
kv
->
offset
=
0
;
kv
->
valid
=
0
;
return
kv
;
}
struct
csr1212_keyval
*
csr1212_new_immediate
(
u_int8_t
key
,
u_int32_t
value
)
{
struct
csr1212_keyval
*
kv
=
csr1212_new_keyval
(
CSR1212_KV_TYPE_IMMEDIATE
,
key
);
if
(
!
kv
)
return
NULL
;
kv
->
value
.
immediate
=
value
;
kv
->
valid
=
1
;
return
kv
;
}
struct
csr1212_keyval
*
csr1212_new_leaf
(
u_int8_t
key
,
const
void
*
data
,
size_t
data_len
)
{
struct
csr1212_keyval
*
kv
=
csr1212_new_keyval
(
CSR1212_KV_TYPE_LEAF
,
key
);
if
(
!
kv
)
return
NULL
;
if
(
data_len
>
0
)
{
kv
->
value
.
leaf
.
data
=
CSR1212_MALLOC
(
data_len
);
if
(
!
kv
->
value
.
leaf
.
data
)
{
CSR1212_FREE
(
kv
);
return
NULL
;
}
if
(
data
)
memcpy
(
kv
->
value
.
leaf
.
data
,
data
,
data_len
);
}
else
{
kv
->
value
.
leaf
.
data
=
NULL
;
}
kv
->
value
.
leaf
.
len
=
bytes_to_quads
(
data_len
);
kv
->
offset
=
0
;
kv
->
valid
=
1
;
return
kv
;
}
struct
csr1212_keyval
*
csr1212_new_csr_offset
(
u_int8_t
key
,
u_int32_t
csr_offset
)
{
struct
csr1212_keyval
*
kv
=
csr1212_new_keyval
(
CSR1212_KV_TYPE_CSR_OFFSET
,
key
);
if
(
!
kv
)
return
NULL
;
kv
->
value
.
csr_offset
=
csr_offset
;
kv
->
offset
=
0
;
kv
->
valid
=
1
;
return
kv
;
}
struct
csr1212_keyval
*
csr1212_new_directory
(
u_int8_t
key
)
{
struct
csr1212_keyval
*
kv
=
csr1212_new_keyval
(
CSR1212_KV_TYPE_DIRECTORY
,
key
);
if
(
!
kv
)
return
NULL
;
kv
->
value
.
directory
.
len
=
0
;
kv
->
offset
=
0
;
kv
->
value
.
directory
.
dentries_head
=
NULL
;
kv
->
value
.
directory
.
dentries_tail
=
NULL
;
kv
->
valid
=
1
;
return
kv
;
}
int
csr1212_associate_keyval
(
struct
csr1212_keyval
*
kv
,
struct
csr1212_keyval
*
associate
)
{
if
(
!
kv
||
!
associate
)
return
CSR1212_EINVAL
;
if
(
kv
->
key
.
id
==
CSR1212_KV_ID_DESCRIPTOR
||
(
associate
->
key
.
id
!=
CSR1212_KV_ID_DESCRIPTOR
&&
associate
->
key
.
id
!=
CSR1212_KV_ID_DEPENDENT_INFO
&&
associate
->
key
.
id
!=
CSR1212_KV_ID_EXTENDED_KEY
&&
associate
->
key
.
id
!=
CSR1212_KV_ID_EXTENDED_DATA
&&
associate
->
key
.
id
<
0x30
))
return
CSR1212_EINVAL
;
if
(
kv
->
key
.
id
==
CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID
&&
associate
->
key
.
id
!=
CSR1212_KV_ID_EXTENDED_KEY
)
return
CSR1212_EINVAL
;
if
(
kv
->
key
.
id
==
CSR1212_KV_ID_EXTENDED_KEY
&&
associate
->
key
.
id
!=
CSR1212_KV_ID_EXTENDED_DATA
)
return
CSR1212_EINVAL
;
if
(
associate
->
key
.
id
==
CSR1212_KV_ID_EXTENDED_KEY
&&
kv
->
key
.
id
!=
CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID
)
return
CSR1212_EINVAL
;
if
(
associate
->
key
.
id
==
CSR1212_KV_ID_EXTENDED_DATA
&&
kv
->
key
.
id
!=
CSR1212_KV_ID_EXTENDED_KEY
)
return
CSR1212_EINVAL
;
if
(
kv
->
associate
)
csr1212_release_keyval
(
kv
->
associate
);
associate
->
refcnt
++
;
kv
->
associate
=
associate
;
return
CSR1212_SUCCESS
;
}
int
csr1212_attach_keyval_to_directory
(
struct
csr1212_keyval
*
dir
,
struct
csr1212_keyval
*
kv
)
{
struct
csr1212_dentry
*
dentry
;
if
(
!
kv
||
!
dir
||
dir
->
key
.
type
!=
CSR1212_KV_TYPE_DIRECTORY
)
return
CSR1212_EINVAL
;
dentry
=
CSR1212_MALLOC
(
sizeof
(
*
dentry
));
if
(
!
dentry
)
return
CSR1212_ENOMEM
;
dentry
->
kv
=
kv
;
kv
->
refcnt
++
;
dentry
->
next
=
NULL
;
dentry
->
prev
=
dir
->
value
.
directory
.
dentries_tail
;
if
(
!
dir
->
value
.
directory
.
dentries_head
)
dir
->
value
.
directory
.
dentries_head
=
dentry
;
if
(
dir
->
value
.
directory
.
dentries_tail
)
dir
->
value
.
directory
.
dentries_tail
->
next
=
dentry
;
dir
->
value
.
directory
.
dentries_tail
=
dentry
;
return
CSR1212_SUCCESS
;
}
struct
csr1212_keyval
*
csr1212_new_extended_immediate
(
u_int32_t
spec
,
u_int32_t
key
,
u_int32_t
value
)
{
struct
csr1212_keyval
*
kvs
,
*
kvk
,
*
kvv
;
kvs
=
csr1212_new_immediate
(
CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID
,
spec
);
kvk
=
csr1212_new_immediate
(
CSR1212_KV_ID_EXTENDED_KEY
,
key
);
kvv
=
csr1212_new_immediate
(
CSR1212_KV_ID_EXTENDED_DATA
,
value
);
if
(
!
kvs
||
!
kvk
||
!
kvv
)
{
if
(
kvs
)
free_keyval
(
kvs
);
if
(
kvk
)
free_keyval
(
kvk
);
if
(
kvv
)
free_keyval
(
kvv
);
return
NULL
;
}
/* Don't keep a local reference to the extended key or value. */
kvk
->
refcnt
=
0
;
kvv
->
refcnt
=
0
;
csr1212_associate_keyval
(
kvk
,
kvv
);
csr1212_associate_keyval
(
kvs
,
kvk
);
return
kvs
;
}
struct
csr1212_keyval
*
csr1212_new_extended_leaf
(
u_int32_t
spec
,
u_int32_t
key
,
const
void
*
data
,
size_t
data_len
)
{
struct
csr1212_keyval
*
kvs
,
*
kvk
,
*
kvv
;
kvs
=
csr1212_new_immediate
(
CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID
,
spec
);
kvk
=
csr1212_new_immediate
(
CSR1212_KV_ID_EXTENDED_KEY
,
key
);
kvv
=
csr1212_new_leaf
(
CSR1212_KV_ID_EXTENDED_DATA
,
data
,
data_len
);
if
(
!
kvs
||
!
kvk
||
!
kvv
)
{
if
(
kvs
)
free_keyval
(
kvs
);
if
(
kvk
)
free_keyval
(
kvk
);
if
(
kvv
)
free_keyval
(
kvv
);
return
NULL
;
}
/* Don't keep a local reference to the extended key or value. */
kvk
->
refcnt
=
0
;
kvv
->
refcnt
=
0
;
csr1212_associate_keyval
(
kvk
,
kvv
);
csr1212_associate_keyval
(
kvs
,
kvk
);
return
kvs
;
}
struct
csr1212_keyval
*
csr1212_new_descriptor_leaf
(
u_int8_t
dtype
,
u_int32_t
specifier_id
,
const
void
*
data
,
size_t
data_len
)
{
struct
csr1212_keyval
*
kv
;
kv
=
csr1212_new_leaf
(
CSR1212_KV_ID_DESCRIPTOR
,
NULL
,
data_len
+
CSR1212_DESCRIPTOR_LEAF_OVERHEAD
);
if
(
!
kv
)
return
NULL
;
CSR1212_DESCRIPTOR_LEAF_SET_TYPE
(
kv
,
dtype
);
CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID
(
kv
,
specifier_id
);
if
(
data
)
{
memcpy
(
CSR1212_DESCRIPTOR_LEAF_DATA
(
kv
),
data
,
data_len
);
}
return
kv
;
}
struct
csr1212_keyval
*
csr1212_new_textual_descriptor_leaf
(
u_int8_t
cwidth
,
u_int16_t
cset
,
u_int16_t
language
,
const
void
*
data
,
size_t
data_len
)
{
struct
csr1212_keyval
*
kv
;
char
*
lstr
;
kv
=
csr1212_new_descriptor_leaf
(
0
,
0
,
NULL
,
data_len
+
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD
);
if
(
!
kv
)
return
NULL
;
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH
(
kv
,
cwidth
);
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET
(
kv
,
cset
);
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE
(
kv
,
language
);
lstr
=
(
char
*
)
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA
(
kv
);
/* make sure last quadlet is zeroed out */
*
((
u_int32_t
*
)
&
(
lstr
[(
data_len
-
1
)
&
~
0x3
]))
=
0
;
/* don't copy the NUL terminator */
memcpy
(
lstr
,
data
,
data_len
);
return
kv
;
}
static
int
csr1212_check_minimal_ascii
(
const
char
*
s
)
{
static
const
char
minimal_ascii_table
[]
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x07
,
0x00
,
0x00
,
0x0a
,
0x00
,
0x0C
,
0x0D
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x20
,
0x21
,
0x22
,
0x00
,
0x00
,
0x25
,
0x26
,
0x27
,
0x28
,
0x29
,
0x2a
,
0x2b
,
0x2c
,
0x2d
,
0x2e
,
0x2f
,
0x30
,
0x31
,
0x32
,
0x33
,
0x34
,
0x35
,
0x36
,
0x37
,
0x38
,
0x39
,
0x3a
,
0x3b
,
0x3c
,
0x3d
,
0x3e
,
0x3f
,
0x40
,
0x41
,
0x42
,
0x43
,
0x44
,
0x45
,
0x46
,
0x47
,
0x48
,
0x49
,
0x4a
,
0x4b
,
0x4c
,
0x4d
,
0x4e
,
0x4f
,
0x50
,
0x51
,
0x52
,
0x53
,
0x54
,
0x55
,
0x56
,
0x57
,
0x58
,
0x59
,
0x5a
,
0x00
,
0x00
,
0x00
,
0x00
,
0x5f
,
0x00
,
0x61
,
0x62
,
0x63
,
0x64
,
0x65
,
0x66
,
0x67
,
0x68
,
0x69
,
0x6a
,
0x6b
,
0x6c
,
0x6d
,
0x6e
,
0x6f
,
0x70
,
0x71
,
0x72
,
0x73
,
0x74
,
0x75
,
0x76
,
0x77
,
0x78
,
0x79
,
0x7a
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
};
for
(;
*
s
;
s
++
)
{
if
(
minimal_ascii_table
[
*
s
&
0x7F
]
!=
*
s
)
return
-
1
;
/* failed */
}
/* String conforms to minimal-ascii, as specified by IEEE 1212,
* par. 7.4 */
return
0
;
}
struct
csr1212_keyval
*
csr1212_new_string_descriptor_leaf
(
const
char
*
s
)
{
/* Check if string conform to minimal_ascii format */
if
(
csr1212_check_minimal_ascii
(
s
))
return
NULL
;
/* IEEE 1212, par. 7.5.4.1 Textual descriptors (minimal ASCII) */
return
csr1212_new_textual_descriptor_leaf
(
0
,
0
,
0
,
s
,
strlen
(
s
));
}
struct
csr1212_keyval
*
csr1212_new_icon_descriptor_leaf
(
u_int32_t
version
,
u_int8_t
palette_depth
,
u_int8_t
color_space
,
u_int16_t
language
,
u_int16_t
hscan
,
u_int16_t
vscan
,
u_int32_t
*
palette
,
u_int32_t
*
pixels
)
{
static
const
int
pd
[
4
]
=
{
0
,
4
,
16
,
256
};
static
const
int
cs
[
16
]
=
{
4
,
2
};
struct
csr1212_keyval
*
kv
;
int
palette_size
=
pd
[
palette_depth
]
*
cs
[
color_space
];
int
pixel_size
=
(
hscan
*
vscan
+
3
)
&
~
0x3
;
if
((
palette_depth
&&
!
palette
)
||
!
pixels
)
return
NULL
;
kv
=
csr1212_new_descriptor_leaf
(
1
,
0
,
NULL
,
palette_size
+
pixel_size
+
CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD
);
if
(
!
kv
)
return
NULL
;
CSR1212_ICON_DESCRIPTOR_LEAF_SET_VERSION
(
kv
,
version
);
CSR1212_ICON_DESCRIPTOR_LEAF_SET_PALETTE_DEPTH
(
kv
,
palette_depth
);
CSR1212_ICON_DESCRIPTOR_LEAF_SET_COLOR_SPACE
(
kv
,
color_space
);
CSR1212_ICON_DESCRIPTOR_LEAF_SET_LANGUAGE
(
kv
,
language
);
CSR1212_ICON_DESCRIPTOR_LEAF_SET_HSCAN
(
kv
,
hscan
);
CSR1212_ICON_DESCRIPTOR_LEAF_SET_VSCAN
(
kv
,
vscan
);
if
(
palette_size
)
memcpy
(
CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE
(
kv
),
palette
,
palette_size
);
memcpy
(
CSR1212_ICON_DESCRIPTOR_LEAF_PIXELS
(
kv
),
pixels
,
pixel_size
);
return
kv
;
}
struct
csr1212_keyval
*
csr1212_new_modifiable_descriptor_leaf
(
u_int16_t
max_size
,
u_int64_t
address
)
{
struct
csr1212_keyval
*
kv
;
/* IEEE 1212, par. 7.5.4.3 Modifiable descriptors */
kv
=
csr1212_new_leaf
(
CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR
,
NULL
,
sizeof
(
u_int64_t
));
if
(
!
kv
)
return
NULL
;
CSR1212_MODIFIABLE_DESCRIPTOR_SET_MAX_SIZE
(
kv
,
max_size
);
CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_HI
(
kv
,
address
);
CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_LO
(
kv
,
address
);
return
kv
;
}
static
int
csr1212_check_keyword
(
const
char
*
s
)
{
for
(;
*
s
;
s
++
)
{
if
((
'A'
<=
*
s
)
&&
(
*
s
<=
'Z'
))
continue
;
if
((
'0'
<=
*
s
)
&&
(
*
s
<=
'9'
))
continue
;
if
(
*
s
==
'-'
)
continue
;
return
-
1
;
/* failed */
}
/* String conforms to keyword, as specified by IEEE 1212,
* par. 7.6.5 */
return
CSR1212_SUCCESS
;
}
struct
csr1212_keyval
*
csr1212_new_keyword_leaf
(
int
strc
,
const
char
*
strv
[])
{
struct
csr1212_keyval
*
kv
;
char
*
buffer
;
int
i
,
data_len
=
0
;
/* Check all keywords to see if they conform to restrictions:
* Only the following characters is allowed ['A'..'Z','0'..'9','-']
* Each word is zero-terminated.
* Also calculate the total length of the keywords.
*/
for
(
i
=
0
;
i
<
strc
;
i
++
)
{
if
(
!
strv
[
i
]
||
csr1212_check_keyword
(
strv
[
i
]))
{
return
NULL
;
}
data_len
+=
strlen
(
strv
[
i
])
+
1
;
/* Add zero-termination char. */
}
/* IEEE 1212, par. 7.6.5 Keyword leaves */
kv
=
csr1212_new_leaf
(
CSR1212_KV_ID_KEYWORD
,
NULL
,
data_len
);
if
(
!
kv
)
return
NULL
;
buffer
=
(
char
*
)
kv
->
value
.
leaf
.
data
;
/* make sure last quadlet is zeroed out */
*
((
u_int32_t
*
)
&
(
buffer
[(
data_len
-
1
)
&
~
0x3
]))
=
0
;
/* Copy keyword(s) into leaf data buffer */
for
(
i
=
0
;
i
<
strc
;
i
++
)
{
int
len
=
strlen
(
strv
[
i
])
+
1
;
memcpy
(
buffer
,
strv
[
i
],
len
);
buffer
+=
len
;
}
return
kv
;
}
/* Destruction Routines */
void
csr1212_detach_keyval_from_directory
(
struct
csr1212_keyval
*
dir
,
struct
csr1212_keyval
*
kv
)
{
struct
csr1212_dentry
*
dentry
;
if
(
!
kv
||
!
dir
||
dir
->
key
.
type
!=
CSR1212_KV_TYPE_DIRECTORY
)
return
;
dentry
=
csr1212_find_keyval
(
dir
,
kv
);
if
(
!
dentry
)
return
;
if
(
dentry
->
prev
)
dentry
->
prev
->
next
=
dentry
->
next
;
if
(
dentry
->
next
)
dentry
->
next
->
prev
=
dentry
->
prev
;
if
(
dir
->
value
.
directory
.
dentries_head
==
dentry
)
dir
->
value
.
directory
.
dentries_head
=
dentry
->
next
;
if
(
dir
->
value
.
directory
.
dentries_tail
==
dentry
)
dir
->
value
.
directory
.
dentries_tail
=
dentry
->
prev
;
CSR1212_FREE
(
dentry
);
csr1212_release_keyval
(
kv
);
}
void
csr1212_disassociate_keyval
(
struct
csr1212_keyval
*
kv
)
{
if
(
kv
->
associate
)
{
csr1212_release_keyval
(
kv
->
associate
);
}
kv
->
associate
=
NULL
;
}
/* This function is used to free the memory taken by a keyval. If the given
* keyval is a directory type, then any keyvals contained in that directory
* will be destroyed as well if their respective refcnts are 0. By means of
* list manipulation, this routine will descend a directory structure in a
* non-recursive manner. */
void
_csr1212_destroy_keyval
(
struct
csr1212_keyval
*
kv
)
{
struct
csr1212_keyval
*
k
,
*
a
;
struct
csr1212_dentry
dentry
;
struct
csr1212_dentry
*
head
,
*
tail
;
dentry
.
kv
=
kv
;
dentry
.
next
=
NULL
;
dentry
.
prev
=
NULL
;
head
=
&
dentry
;
tail
=
head
;
while
(
head
)
{
k
=
head
->
kv
;
while
(
k
)
{
k
->
refcnt
--
;
if
(
k
->
refcnt
>
0
)
break
;
a
=
k
->
associate
;
if
(
k
->
key
.
type
==
CSR1212_KV_TYPE_DIRECTORY
)
{
/* If the current entry is a directory, then move all
* the entries to the destruction list. */
tail
->
next
=
k
->
value
.
directory
.
dentries_head
;
if
(
k
->
value
.
directory
.
dentries_head
)
k
->
value
.
directory
.
dentries_head
->
prev
=
tail
;
tail
=
k
->
value
.
directory
.
dentries_tail
;
}
free_keyval
(
k
);
k
=
a
;
}
head
=
head
->
next
;
if
(
head
)
{
if
(
head
->
prev
&&
head
->
prev
!=
&
dentry
)
{
CSR1212_FREE
(
head
->
prev
);
}
head
->
prev
=
NULL
;
}
else
if
(
tail
!=
&
dentry
)
CSR1212_FREE
(
tail
);
}
}
void
csr1212_destroy_csr
(
struct
csr1212_csr
*
csr
)
{
struct
csr1212_csr_rom_cache
*
c
,
*
oc
;
struct
csr1212_cache_region
*
cr
,
*
ocr
;
csr1212_release_keyval
(
csr
->
root_kv
);
c
=
csr
->
cache_head
;
while
(
c
)
{
oc
=
c
;
cr
=
c
->
filled_head
;
while
(
cr
)
{
ocr
=
cr
;
cr
=
cr
->
next
;
CSR1212_FREE
(
ocr
);
}
c
=
c
->
next
;
CSR1212_FREE
(
oc
);
}
CSR1212_FREE
(
csr
);
}
/* CSR Image Creation */
static
int
csr1212_append_new_cache
(
struct
csr1212_csr
*
csr
,
size_t
romsize
)
{
struct
csr1212_csr_rom_cache
*
cache
;
u_int64_t
csr_addr
;
if
(
!
csr
||
!
csr
->
ops
->
allocate_addr_range
||
!
csr
->
ops
->
release_addr
)
return
CSR1212_ENOMEM
;
/* ROM size must be a multiple of csr->max_rom */
romsize
=
(
romsize
+
(
csr
->
max_rom
-
1
))
&
~
(
csr
->
max_rom
-
1
);
csr_addr
=
csr
->
ops
->
allocate_addr_range
(
romsize
,
csr
->
max_rom
,
csr
->
private
);
if
(
csr_addr
==
~
0ULL
)
{
return
CSR1212_ENOMEM
;
}
if
(
csr_addr
<
CSR1212_REGISTER_SPACE_BASE
)
{
/* Invalid address returned from allocate_addr_range(). */
csr
->
ops
->
release_addr
(
csr_addr
,
csr
->
private
);
return
CSR1212_ENOMEM
;
}
cache
=
csr1212_rom_cache_malloc
(
csr_addr
-
CSR1212_REGISTER_SPACE_BASE
,
romsize
);
if
(
!
cache
)
{
csr
->
ops
->
release_addr
(
csr_addr
,
csr
->
private
);
return
CSR1212_ENOMEM
;
}
cache
->
ext_rom
=
csr1212_new_keyval
(
CSR1212_KV_TYPE_LEAF
,
CSR1212_KV_ID_EXTENDED_ROM
);
if
(
!
cache
->
ext_rom
)
{
csr
->
ops
->
release_addr
(
csr_addr
,
csr
->
private
);
CSR1212_FREE
(
cache
);
return
CSR1212_ENOMEM
;
}
if
(
csr1212_attach_keyval_to_directory
(
csr
->
root_kv
,
cache
->
ext_rom
)
!=
CSR1212_SUCCESS
)
{
csr1212_release_keyval
(
cache
->
ext_rom
);
csr
->
ops
->
release_addr
(
csr_addr
,
csr
->
private
);
CSR1212_FREE
(
cache
);
return
CSR1212_ENOMEM
;
}
cache
->
ext_rom
->
offset
=
csr_addr
-
CSR1212_REGISTER_SPACE_BASE
;
cache
->
ext_rom
->
value
.
leaf
.
len
=
0
;
/* Add cache to tail of cache list */
cache
->
prev
=
csr
->
cache_tail
;
csr
->
cache_tail
->
next
=
cache
;
csr
->
cache_tail
=
cache
;
return
CSR1212_SUCCESS
;
}
static
inline
void
csr1212_remove_cache
(
struct
csr1212_csr
*
csr
,
struct
csr1212_csr_rom_cache
*
cache
)
{
if
(
csr
->
cache_head
==
cache
)
csr
->
cache_head
=
cache
->
next
;
if
(
csr
->
cache_tail
==
cache
)
csr
->
cache_tail
=
cache
->
prev
;
if
(
cache
->
prev
)
cache
->
prev
->
next
=
cache
->
next
;
if
(
cache
->
next
)
cache
->
next
->
prev
=
cache
->
prev
;
if
(
cache
->
ext_rom
)
{
csr1212_detach_keyval_from_directory
(
csr
->
root_kv
,
cache
->
ext_rom
);
csr1212_release_keyval
(
cache
->
ext_rom
);
}
CSR1212_FREE
(
cache
);
}
static
int
csr1212_generate_layout_subdir
(
struct
csr1212_keyval
*
dir
,
struct
csr1212_keyval
**
layout_tail
)
{
struct
csr1212_dentry
*
dentry
;
struct
csr1212_keyval
*
dkv
;
struct
csr1212_keyval
*
last_extkey_spec
=
NULL
;
struct
csr1212_keyval
*
last_extkey
=
NULL
;
int
num_entries
=
0
;
for
(
dentry
=
dir
->
value
.
directory
.
dentries_head
;
dentry
;
dentry
=
dentry
->
next
)
{
for
(
dkv
=
dentry
->
kv
;
dkv
;
dkv
=
dkv
->
associate
)
{
/* Special Case: Extended Key Specifier_ID */
if
(
dkv
->
key
.
id
==
CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID
)
{
if
(
last_extkey_spec
==
NULL
)
{
last_extkey_spec
=
dkv
;
}
else
if
(
dkv
->
value
.
immediate
!=
last_extkey_spec
->
value
.
immediate
)
{
last_extkey_spec
=
dkv
;
}
else
{
continue
;
}
/* Special Case: Extended Key */
}
else
if
(
dkv
->
key
.
id
==
CSR1212_KV_ID_EXTENDED_KEY
)
{
if
(
last_extkey
==
NULL
)
{
last_extkey
=
dkv
;
}
else
if
(
dkv
->
value
.
immediate
!=
last_extkey
->
value
.
immediate
)
{
last_extkey
=
dkv
;
}
else
{
continue
;
}
}
num_entries
+=
1
;
switch
(
dkv
->
key
.
type
)
{
default:
case
CSR1212_KV_TYPE_IMMEDIATE
:
case
CSR1212_KV_TYPE_CSR_OFFSET
:
continue
;
case
CSR1212_KV_TYPE_LEAF
:
case
CSR1212_KV_TYPE_DIRECTORY
:
/* Remove from list */
if
(
dkv
->
prev
)
dkv
->
prev
->
next
=
dkv
->
next
;
if
(
dkv
->
next
)
dkv
->
next
->
prev
=
dkv
->
prev
;
if
(
dkv
==
*
layout_tail
)
*
layout_tail
=
dkv
->
prev
;
/* Special case: Extended ROM leafs */
if
(
dkv
->
key
.
id
==
CSR1212_KV_ID_EXTENDED_ROM
)
{
dkv
->
value
.
leaf
.
len
=
0
;
/* initialize to zero */
/* Don't add Extended ROM leafs in the layout list,
* they are handled differently. */
break
;
}
/* Add to tail of list */
dkv
->
next
=
NULL
;
dkv
->
prev
=
*
layout_tail
;
(
*
layout_tail
)
->
next
=
dkv
;
*
layout_tail
=
dkv
;
break
;
}
}
}
return
num_entries
;
}
size_t
csr1212_generate_layout_order
(
struct
csr1212_keyval
*
kv
)
{
struct
csr1212_keyval
*
ltail
=
kv
;
size_t
agg_size
=
0
;
while
(
kv
)
{
switch
(
kv
->
key
.
type
)
{
case
CSR1212_KV_TYPE_LEAF
:
/* Add 1 quadlet for crc/len field */
agg_size
+=
kv
->
value
.
leaf
.
len
+
1
;
break
;
case
CSR1212_KV_TYPE_DIRECTORY
:
kv
->
value
.
directory
.
len
=
csr1212_generate_layout_subdir
(
kv
,
&
ltail
);
/* Add 1 quadlet for crc/len field */
agg_size
+=
kv
->
value
.
directory
.
len
+
1
;
break
;
}
kv
=
kv
->
next
;
}
return
quads_to_bytes
(
agg_size
);
}
struct
csr1212_keyval
*
csr1212_generate_positions
(
struct
csr1212_csr_rom_cache
*
cache
,
struct
csr1212_keyval
*
start_kv
,
int
start_pos
)
{
struct
csr1212_keyval
*
kv
=
start_kv
;
struct
csr1212_keyval
*
okv
=
start_kv
;
int
pos
=
start_pos
;
int
kv_len
=
0
,
okv_len
=
0
;
cache
->
layout_head
=
kv
;
while
(
kv
&&
pos
<
cache
->
size
)
{
kv
->
offset
=
cache
->
offset
+
pos
;
switch
(
kv
->
key
.
type
)
{
case
CSR1212_KV_TYPE_LEAF
:
kv_len
=
kv
->
value
.
leaf
.
len
;
break
;
case
CSR1212_KV_TYPE_DIRECTORY
:
kv_len
=
kv
->
value
.
directory
.
len
;
break
;
default:
/* Should never get here */
break
;
}
pos
+=
quads_to_bytes
(
kv_len
+
1
);
if
(
pos
<=
cache
->
size
)
{
okv
=
kv
;
okv_len
=
kv_len
;
kv
=
kv
->
next
;
}
}
cache
->
layout_tail
=
okv
;
cache
->
len
=
(
okv
->
offset
-
cache
->
offset
)
+
quads_to_bytes
(
okv_len
+
1
);
return
kv
;
}
static
void
csr1212_generate_tree_subdir
(
struct
csr1212_keyval
*
dir
,
u_int32_t
*
data_buffer
)
{
struct
csr1212_dentry
*
dentry
;
struct
csr1212_keyval
*
last_extkey_spec
=
NULL
;
struct
csr1212_keyval
*
last_extkey
=
NULL
;
int
index
=
0
;
for
(
dentry
=
dir
->
value
.
directory
.
dentries_head
;
dentry
;
dentry
=
dentry
->
next
)
{
struct
csr1212_keyval
*
a
;
for
(
a
=
dentry
->
kv
;
a
;
a
=
a
->
associate
)
{
u_int32_t
value
=
0
;
/* Special Case: Extended Key Specifier_ID */
if
(
a
->
key
.
id
==
CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID
)
{
if
(
last_extkey_spec
==
NULL
)
{
last_extkey_spec
=
a
;
}
else
if
(
a
->
value
.
immediate
!=
last_extkey_spec
->
value
.
immediate
)
{
last_extkey_spec
=
a
;
}
else
{
continue
;
}
/* Special Case: Extended Key */
}
else
if
(
a
->
key
.
id
==
CSR1212_KV_ID_EXTENDED_KEY
)
{
if
(
last_extkey
==
NULL
)
{
last_extkey
=
a
;
}
else
if
(
a
->
value
.
immediate
!=
last_extkey
->
value
.
immediate
)
{
last_extkey
=
a
;
}
else
{
continue
;
}
}
switch
(
a
->
key
.
type
)
{
case
CSR1212_KV_TYPE_IMMEDIATE
:
value
=
a
->
value
.
immediate
;
break
;
case
CSR1212_KV_TYPE_CSR_OFFSET
:
value
=
a
->
value
.
csr_offset
;
break
;
case
CSR1212_KV_TYPE_LEAF
:
value
=
a
->
offset
;
value
-=
dir
->
offset
+
quads_to_bytes
(
1
+
index
);
value
=
bytes_to_quads
(
value
);
break
;
case
CSR1212_KV_TYPE_DIRECTORY
:
value
=
a
->
offset
;
value
-=
dir
->
offset
+
quads_to_bytes
(
1
+
index
);
value
=
bytes_to_quads
(
value
);
break
;
default:
/* Should never get here */
break
;
/* GDB breakpoint */
}
value
|=
(
a
->
key
.
id
&
CSR1212_KV_KEY_ID_MASK
)
<<
CSR1212_KV_KEY_SHIFT
;
value
|=
(
a
->
key
.
type
&
CSR1212_KV_KEY_TYPE_MASK
)
<<
(
CSR1212_KV_KEY_SHIFT
+
CSR1212_KV_KEY_TYPE_SHIFT
);
data_buffer
[
index
]
=
CSR1212_CPU_TO_BE32
(
value
);
index
++
;
}
}
}
void
csr1212_fill_cache
(
struct
csr1212_csr_rom_cache
*
cache
)
{
struct
csr1212_keyval
*
kv
,
*
nkv
;
struct
csr1212_keyval_img
*
kvi
;
for
(
kv
=
cache
->
layout_head
;
kv
!=
cache
->
layout_tail
->
next
;
kv
=
nkv
)
{
kvi
=
(
struct
csr1212_keyval_img
*
)
(
cache
->
data
+
bytes_to_quads
(
kv
->
offset
-
cache
->
offset
));
switch
(
kv
->
key
.
type
)
{
default:
case
CSR1212_KV_TYPE_IMMEDIATE
:
case
CSR1212_KV_TYPE_CSR_OFFSET
:
/* Should never get here */
break
;
/* GDB breakpoint */
case
CSR1212_KV_TYPE_LEAF
:
/* Don't copy over Extended ROM areas, they are
* already filled out! */
if
(
kv
->
key
.
id
!=
CSR1212_KV_ID_EXTENDED_ROM
)
memcpy
(
kvi
->
data
,
kv
->
value
.
leaf
.
data
,
quads_to_bytes
(
kv
->
value
.
leaf
.
len
));
kvi
->
length
=
CSR1212_CPU_TO_BE16
(
kv
->
value
.
leaf
.
len
);
kvi
->
crc
=
csr1212_crc16
(
kvi
->
data
,
kv
->
value
.
leaf
.
len
);
break
;
case
CSR1212_KV_TYPE_DIRECTORY
:
csr1212_generate_tree_subdir
(
kv
,
kvi
->
data
);
kvi
->
length
=
CSR1212_CPU_TO_BE16
(
kv
->
value
.
directory
.
len
);
kvi
->
crc
=
csr1212_crc16
(
kvi
->
data
,
kv
->
value
.
directory
.
len
);
break
;
}
nkv
=
kv
->
next
;
kv
->
prev
=
NULL
;
kv
->
next
=
NULL
;
}
}
int
csr1212_generate_csr_image
(
struct
csr1212_csr
*
csr
)
{
struct
csr1212_bus_info_block_img
*
bi
;
struct
csr1212_csr_rom_cache
*
cache
;
struct
csr1212_keyval
*
kv
;
size_t
agg_size
;
int
ret
;
int
init_offset
;
if
(
!
csr
)
return
CSR1212_EINVAL
;
cache
=
csr
->
cache_head
;
bi
=
(
struct
csr1212_bus_info_block_img
*
)
cache
->
data
;
bi
->
length
=
bytes_to_quads
(
csr
->
bus_info_len
)
-
1
;
bi
->
crc_length
=
bi
->
length
;
bi
->
crc
=
csr1212_crc16
(
bi
->
data
,
bi
->
crc_length
);
agg_size
=
csr1212_generate_layout_order
(
csr
->
root_kv
);
init_offset
=
csr
->
bus_info_len
;
for
(
kv
=
csr
->
root_kv
,
cache
=
csr
->
cache_head
;
kv
;
cache
=
cache
->
next
)
{
if
(
!
cache
)
{
/* Estimate approximate number of additional cache
* regions needed (it assumes that the cache holding
* the first 1K Config ROM space always exists). */
int
est_c
=
agg_size
/
(
CSR1212_EXTENDED_ROM_SIZE
-
(
2
*
sizeof
(
u_int32_t
)))
+
1
;
/* Add additional cache regions, extras will be
* removed later */
for
(;
est_c
;
est_c
--
)
{
ret
=
csr1212_append_new_cache
(
csr
,
CSR1212_EXTENDED_ROM_SIZE
);
if
(
ret
!=
CSR1212_SUCCESS
)
return
ret
;
}
/* Need to re-layout for additional cache regions */
agg_size
=
csr1212_generate_layout_order
(
csr
->
root_kv
);
kv
=
csr
->
root_kv
;
cache
=
csr
->
cache_head
;
init_offset
=
csr
->
bus_info_len
;
}
kv
=
csr1212_generate_positions
(
cache
,
kv
,
init_offset
);
agg_size
-=
cache
->
len
;
init_offset
=
sizeof
(
u_int32_t
);
}
/* Remove unused, excess cache regions */
while
(
cache
)
{
struct
csr1212_csr_rom_cache
*
oc
=
cache
;
cache
=
cache
->
next
;
csr1212_remove_cache
(
csr
,
oc
);
}
/* Go through the list backward so that when done, the correct CRC
* will be calculated for the Extended ROM areas. */
for
(
cache
=
csr
->
cache_tail
;
cache
;
cache
=
cache
->
prev
)
{
/* Only Extended ROM caches should have this set. */
if
(
cache
->
ext_rom
)
{
int
leaf_size
;
/* Make sure the Extended ROM leaf is a multiple of
* max_rom in size. */
leaf_size
=
(
cache
->
len
+
(
csr
->
max_rom
-
1
))
&
(
csr
->
max_rom
-
1
);
/* Zero out the unused ROM region */
memset
(
cache
->
data
+
bytes_to_quads
(
cache
->
len
),
0x00
,
leaf_size
-
cache
->
len
);
/* Subtract leaf header */
leaf_size
-=
sizeof
(
u_int32_t
);
/* Update the Extended ROM leaf length */
cache
->
ext_rom
->
value
.
leaf
.
len
=
bytes_to_quads
(
leaf_size
);
}
else
{
/* Zero out the unused ROM region */
memset
(
cache
->
data
+
bytes_to_quads
(
cache
->
len
),
0x00
,
cache
->
size
-
cache
->
len
);
}
/* Copy the data into the cache buffer */
csr1212_fill_cache
(
cache
);
}
return
CSR1212_SUCCESS
;
}
int
csr1212_read
(
struct
csr1212_csr
*
csr
,
u_int32_t
offset
,
void
*
buffer
,
u_int32_t
len
)
{
struct
csr1212_csr_rom_cache
*
cache
;
for
(
cache
=
csr
->
cache_head
;
cache
;
cache
=
cache
->
next
)
{
if
(
offset
>=
cache
->
offset
&&
(
offset
+
len
)
<=
(
cache
->
offset
+
cache
->
size
))
{
memcpy
(
buffer
,
&
cache
->
data
[
bytes_to_quads
(
offset
-
cache
->
offset
)],
len
);
return
CSR1212_SUCCESS
;
}
else
if
(((
offset
<
cache
->
offset
)
&&
((
offset
+
len
)
>=
cache
->
offset
))
||
((
offset
>=
cache
->
offset
)
&&
((
offset
+
len
)
>
(
cache
->
offset
+
cache
->
size
))))
{
return
CSR1212_EINVAL
;
}
}
return
CSR1212_ENOENT
;
}
/* Parse a chunk of data as a Config ROM */
static
int
csr1212_parse_bus_info_block
(
struct
csr1212_csr
*
csr
)
{
struct
csr1212_bus_info_block_img
*
bi
;
struct
csr1212_cache_region
*
cr
;
int
i
;
int
ret
;
/* IEEE 1212 says that the entire bus info block should be readable in
* a single transaction regardless of the max_rom value.
* Unfortunately, many IEEE 1394 devices do not abide by that, so the
* bus info block will be read 1 quadlet at a time. The rest of the
* ConfigROM will be read according to the max_rom field. */
for
(
i
=
0
;
i
<
csr
->
bus_info_len
;
i
+=
sizeof
(
csr1212_quad_t
))
{
ret
=
csr
->
ops
->
bus_read
(
csr
,
CSR1212_CONFIG_ROM_SPACE_BASE
+
i
,
sizeof
(
csr1212_quad_t
),
&
csr
->
cache_head
->
data
[
bytes_to_quads
(
i
)],
csr
->
private
);
if
(
ret
!=
CSR1212_SUCCESS
)
return
ret
;
}
bi
=
(
struct
csr1212_bus_info_block_img
*
)
csr
->
cache_head
->
data
;
csr
->
crc_len
=
quads_to_bytes
(
bi
->
crc_length
);
/* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that is not
* always the case, so read the rest of the crc area 1 quadlet at a time. */
for
(
i
=
csr
->
bus_info_len
;
i
<=
csr
->
crc_len
;
i
+=
sizeof
(
csr1212_quad_t
))
{
ret
=
csr
->
ops
->
bus_read
(
csr
,
CSR1212_CONFIG_ROM_SPACE_BASE
+
i
,
sizeof
(
csr1212_quad_t
),
&
csr
->
cache_head
->
data
[
bytes_to_quads
(
i
)],
csr
->
private
);
if
(
ret
!=
CSR1212_SUCCESS
)
return
ret
;
}
if
(
bytes_to_quads
(
csr
->
bus_info_len
-
sizeof
(
csr1212_quad_t
))
!=
bi
->
length
)
return
CSR1212_EINVAL
;
#if 0
/* Apparently there are too many differnt wrong implementations of the
* CRC algorithm that verifying them is moot. */
if ((csr1212_crc16(bi->data, bi->crc_length) != bi->crc) &&
(csr1212_msft_crc16(bi->data, bi->crc_length) != bi->crc))
return CSR1212_EINVAL;
#endif
cr
=
CSR1212_MALLOC
(
sizeof
(
struct
csr1212_cache_region
));
if
(
!
cr
)
return
CSR1212_ENOMEM
;
cr
->
next
=
NULL
;
cr
->
prev
=
NULL
;
cr
->
offset_start
=
0
;
cr
->
offset_end
=
csr
->
crc_len
+
4
;
csr
->
cache_head
->
filled_head
=
cr
;
csr
->
cache_head
->
filled_tail
=
cr
;
return
CSR1212_SUCCESS
;
}
static
inline
int
csr1212_parse_dir_entry
(
struct
csr1212_keyval
*
dir
,
csr1212_quad_t
ki
,
u_int32_t
kv_pos
,
struct
csr1212_csr_rom_cache
*
cache
)
{
int
ret
=
CSR1212_SUCCESS
;
struct
csr1212_keyval
*
k
=
NULL
;
u_int32_t
offset
;
switch
(
CSR1212_KV_KEY_TYPE
(
ki
))
{
case
CSR1212_KV_TYPE_IMMEDIATE
:
k
=
csr1212_new_immediate
(
CSR1212_KV_KEY_ID
(
ki
),
CSR1212_KV_VAL
(
ki
));
if
(
!
k
)
{
ret
=
CSR1212_ENOMEM
;
goto
fail
;
}
k
->
refcnt
=
0
;
/* Don't keep local reference when parsing. */
break
;
case
CSR1212_KV_TYPE_CSR_OFFSET
:
k
=
csr1212_new_csr_offset
(
CSR1212_KV_KEY_ID
(
ki
),
CSR1212_KV_VAL
(
ki
));
if
(
!
k
)
{
ret
=
CSR1212_ENOMEM
;
goto
fail
;
}
k
->
refcnt
=
0
;
/* Don't keep local reference when parsing. */
break
;
default:
/* Compute the offset from 0xffff f000 0000. */
offset
=
quads_to_bytes
(
CSR1212_KV_VAL
(
ki
))
+
kv_pos
;
if
(
offset
==
kv_pos
)
{
/* Uh-oh. Can't have a relative offset of 0 for Leaves
* or Directories. The Config ROM image is most likely
* messed up, so we'll just abort here. */
ret
=
CSR1212_EIO
;
goto
fail
;
}
k
=
csr1212_find_keyval_offset
(
cache
->
layout_head
,
offset
);
if
(
k
)
break
;
/* Found it. */
if
(
CSR1212_KV_KEY_TYPE
(
ki
)
==
CSR1212_KV_TYPE_DIRECTORY
)
{
k
=
csr1212_new_directory
(
CSR1212_KV_KEY_ID
(
ki
));
}
else
{
k
=
csr1212_new_leaf
(
CSR1212_KV_KEY_ID
(
ki
),
NULL
,
0
);
}
if
(
!
k
)
{
ret
=
CSR1212_ENOMEM
;
goto
fail
;
}
k
->
refcnt
=
0
;
/* Don't keep local reference when parsing. */
k
->
valid
=
0
;
/* Contents not read yet so it's not valid. */
k
->
offset
=
offset
;
k
->
prev
=
cache
->
layout_tail
;
k
->
next
=
NULL
;
if
(
cache
->
layout_tail
)
cache
->
layout_tail
->
next
=
k
;
cache
->
layout_tail
=
k
;
}
ret
=
csr1212_attach_keyval_to_directory
(
dir
,
k
);
fail:
if
(
ret
!=
CSR1212_SUCCESS
)
{
if
(
k
)
free_keyval
(
k
);
}
return
ret
;
}
int
csr1212_parse_keyval
(
struct
csr1212_keyval
*
kv
,
struct
csr1212_csr_rom_cache
*
cache
)
{
struct
csr1212_keyval_img
*
kvi
;
int
i
;
int
ret
=
CSR1212_SUCCESS
;
int
kvi_len
;
kvi
=
(
struct
csr1212_keyval_img
*
)
&
cache
->
data
[
bytes_to_quads
(
kv
->
offset
-
cache
->
offset
)];
kvi_len
=
CSR1212_BE16_TO_CPU
(
kvi
->
length
);
#if 0
/* Apparently there are too many differnt wrong implementations of the
* CRC algorithm that verifying them is moot. */
if ((csr1212_crc16(kvi->data, kvi_len) != kvi->crc) &&
(csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc)) {
ret = CSR1212_EINVAL;
goto fail;
}
#endif
switch
(
kv
->
key
.
type
)
{
case
CSR1212_KV_TYPE_DIRECTORY
:
for
(
i
=
0
;
i
<
kvi_len
;
i
++
)
{
csr1212_quad_t
ki
=
kvi
->
data
[
i
];
ret
=
csr1212_parse_dir_entry
(
kv
,
ki
,
(
kv
->
offset
+
quads_to_bytes
(
i
+
1
)),
cache
);
}
kv
->
value
.
directory
.
len
=
kvi_len
;
break
;
case
CSR1212_KV_TYPE_LEAF
:
if
(
kv
->
key
.
id
==
CSR1212_KV_ID_EXTENDED_ROM
)
{
kv
->
value
.
leaf
.
data
=
cache
->
data
;
}
else
{
kv
->
value
.
leaf
.
data
=
CSR1212_MALLOC
(
quads_to_bytes
(
kvi_len
));
if
(
!
kv
->
value
.
leaf
.
data
)
{
ret
=
CSR1212_ENOMEM
;
goto
fail
;
}
kv
->
value
.
leaf
.
len
=
kvi_len
;
memcpy
(
kv
->
value
.
leaf
.
data
,
kvi
->
data
,
quads_to_bytes
(
kvi_len
));
}
break
;
}
kv
->
valid
=
1
;
fail:
return
ret
;
}
int
_csr1212_read_keyval
(
struct
csr1212_csr
*
csr
,
struct
csr1212_keyval
*
kv
)
{
struct
csr1212_cache_region
*
cr
,
*
ncr
,
*
newcr
=
NULL
;
struct
csr1212_keyval_img
*
kvi
=
NULL
;
struct
csr1212_csr_rom_cache
*
cache
;
int
cache_index
;
u_int64_t
addr
;
u_int32_t
*
cache_ptr
;
u_int16_t
kv_len
=
0
;
if
(
!
csr
||
!
kv
)
return
CSR1212_EINVAL
;
/* First find which cache the data should be in (or go in if not read
* yet). */
for
(
cache
=
csr
->
cache_head
;
cache
;
cache
=
cache
->
next
)
{
if
(
kv
->
offset
>=
cache
->
offset
&&
kv
->
offset
<
(
cache
->
offset
+
cache
->
size
))
break
;
}
if
(
!
cache
)
{
csr1212_quad_t
q
;
struct
csr1212_csr_rom_cache
*
nc
;
/* Only create a new cache for Extended ROM leaves. */
if
(
kv
->
key
.
id
!=
CSR1212_KV_ID_EXTENDED_ROM
)
return
CSR1212_EINVAL
;
if
(
csr
->
ops
->
bus_read
(
csr
,
CSR1212_REGISTER_SPACE_BASE
+
kv
->
offset
,
sizeof
(
csr1212_quad_t
),
&
q
,
csr
->
private
))
{
return
CSR1212_EIO
;
}
kv
->
value
.
leaf
.
len
=
quads_to_bytes
(
CSR1212_BE32_TO_CPU
(
q
)
>>
16
);
nc
=
csr1212_rom_cache_malloc
(
kv
->
offset
,
kv
->
value
.
leaf
.
len
);
cache
->
next
=
nc
;
nc
->
prev
=
cache
;
csr
->
cache_tail
=
nc
;
cache
->
filled_head
=
CSR1212_MALLOC
(
sizeof
(
struct
csr1212_cache_region
));
if
(
!
cache
->
filled_head
)
{
return
CSR1212_ENOMEM
;
}
cache
->
filled_head
->
offset_start
=
0
;
cache
->
filled_head
->
offset_end
=
sizeof
(
csr1212_quad_t
);
cache
->
filled_tail
=
cache
->
filled_head
;
cache
->
filled_head
->
next
=
NULL
;
cache
->
filled_head
->
prev
=
NULL
;
cache
->
data
[
0
]
=
q
;
}
cache_index
=
kv
->
offset
-
cache
->
offset
;
/* Now seach read portions of the cache to see if it is there. */
for
(
cr
=
cache
->
filled_head
;
cr
;
cr
=
cr
->
next
)
{
if
(
cache_index
<
cr
->
offset_start
)
{
newcr
=
CSR1212_MALLOC
(
sizeof
(
struct
csr1212_cache_region
));
if
(
!
newcr
)
return
CSR1212_ENOMEM
;
newcr
->
offset_start
=
cache_index
&
~
(
csr
->
max_rom
-
1
);
newcr
->
offset_end
=
newcr
->
offset_start
;
newcr
->
next
=
cr
;
newcr
->
prev
=
cr
->
prev
;
cr
->
prev
=
newcr
;
cr
=
newcr
;
break
;
}
else
if
((
cache_index
>=
cr
->
offset_start
)
&&
(
cache_index
<
cr
->
offset_end
))
{
kvi
=
(
struct
csr1212_keyval_img
*
)
(
&
cache
->
data
[
bytes_to_quads
(
cache_index
)]);
kv_len
=
quads_to_bytes
(
CSR1212_BE16_TO_CPU
(
kvi
->
length
)
+
1
);
break
;
}
else
if
(
cache_index
==
cr
->
offset_end
)
break
;
}
if
(
!
cr
)
{
cr
=
cache
->
filled_tail
;
newcr
=
CSR1212_MALLOC
(
sizeof
(
struct
csr1212_cache_region
));
if
(
!
newcr
)
return
CSR1212_ENOMEM
;
newcr
->
offset_start
=
cache_index
&
~
(
csr
->
max_rom
-
1
);
newcr
->
offset_end
=
newcr
->
offset_start
;
newcr
->
prev
=
cr
;
newcr
->
next
=
cr
->
next
;
cr
->
next
=
newcr
;
cr
=
newcr
;
cache
->
filled_tail
=
newcr
;
}
while
(
!
kvi
||
cr
->
offset_end
<
cache_index
+
kv_len
)
{
cache_ptr
=
&
cache
->
data
[
bytes_to_quads
(
cr
->
offset_end
&
~
(
csr
->
max_rom
-
1
))];
addr
=
(
CSR1212_CSR_ARCH_REG_SPACE_BASE
+
cache
->
offset
+
cr
->
offset_end
)
&
~
(
csr
->
max_rom
-
1
);
if
(
csr
->
ops
->
bus_read
(
csr
,
addr
,
csr
->
max_rom
,
cache_ptr
,
csr
->
private
))
{
if
(
csr
->
max_rom
==
4
)
/* We've got problems! */
return
CSR1212_EIO
;
/* Apperently the max_rom value was a lie, set it to
* do quadlet reads and try again. */
csr
->
max_rom
=
4
;
continue
;
}
cr
->
offset_end
+=
csr
->
max_rom
-
(
cr
->
offset_end
&
(
csr
->
max_rom
-
1
));
if
(
!
kvi
&&
(
cr
->
offset_end
>
cache_index
))
{
kvi
=
(
struct
csr1212_keyval_img
*
)
(
&
cache
->
data
[
bytes_to_quads
(
cache_index
)]);
kv_len
=
quads_to_bytes
(
CSR1212_BE16_TO_CPU
(
kvi
->
length
)
+
1
);
}
if
((
kv_len
+
(
kv
->
offset
-
cache
->
offset
))
>
cache
->
size
)
{
/* The Leaf or Directory claims its length extends
* beyond the ConfigROM image region and thus beyond the
* end of our cache region. Therefore, we abort now
* rather than seg faulting later. */
return
CSR1212_EIO
;
}
ncr
=
cr
->
next
;
if
(
ncr
&&
(
cr
->
offset_end
>=
ncr
->
offset_start
))
{
/* consolidate region entries */
ncr
->
offset_start
=
cr
->
offset_start
;
if
(
cr
->
prev
)
cr
->
prev
->
next
=
cr
->
next
;
ncr
->
prev
=
cr
->
prev
;
if
(
cache
->
filled_head
==
cr
)
cache
->
filled_head
=
ncr
;
CSR1212_FREE
(
cr
);
cr
=
ncr
;
}
}
return
csr1212_parse_keyval
(
kv
,
cache
);
}
int
csr1212_parse_csr
(
struct
csr1212_csr
*
csr
)
{
static
const
int
mr_map
[]
=
{
4
,
64
,
1024
,
0
};
int
ret
;
if
(
!
csr
||
!
csr
->
ops
->
bus_read
)
return
CSR1212_EINVAL
;
ret
=
csr1212_parse_bus_info_block
(
csr
);
if
(
ret
!=
CSR1212_SUCCESS
)
return
ret
;
if
(
!
csr
->
ops
->
get_max_rom
)
csr
->
max_rom
=
mr_map
[
0
];
/* default value */
else
csr
->
max_rom
=
mr_map
[
csr
->
ops
->
get_max_rom
(
csr
->
bus_info_data
,
csr
->
private
)];
csr
->
cache_head
->
layout_head
=
csr
->
root_kv
;
csr
->
cache_head
->
layout_tail
=
csr
->
root_kv
;
csr
->
root_kv
->
offset
=
(
CSR1212_CONFIG_ROM_SPACE_BASE
&
0xffff
)
+
csr
->
bus_info_len
;
csr
->
root_kv
->
valid
=
0
;
csr1212_get_keyval
(
csr
,
csr
->
root_kv
);
return
CSR1212_SUCCESS
;
}
drivers/ieee1394/csr1212.h
0 → 100644
View file @
16eadb50
/*
* csr1212.h -- IEEE 1212 Control and Status Register support for Linux
*
* Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
* Steve Kinneberg <kinnebergsteve@acmsystems.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __CSR1212_H__
#define __CSR1212_H__
/* Compatibility layer */
#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#define CSR1212_MALLOC(size) kmalloc((size), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
#define CSR1212_FREE(ptr) kfree(ptr)
#define CSR1212_BE16_TO_CPU(quad) be16_to_cpu(quad)
#define CSR1212_CPU_TO_BE16(quad) cpu_to_be16(quad)
#define CSR1212_BE32_TO_CPU(quad) be32_to_cpu(quad)
#define CSR1212_CPU_TO_BE32(quad) cpu_to_be32(quad)
#define CSR1212_BE64_TO_CPU(quad) be64_to_cpu(quad)
#define CSR1212_CPU_TO_BE64(quad) cpu_to_be64(quad)
#define CSR1212_LE16_TO_CPU(quad) le16_to_cpu(quad)
#define CSR1212_CPU_TO_LE16(quad) cpu_to_le16(quad)
#define CSR1212_LE32_TO_CPU(quad) le32_to_cpu(quad)
#define CSR1212_CPU_TO_LE32(quad) cpu_to_le32(quad)
#define CSR1212_LE64_TO_CPU(quad) le64_to_cpu(quad)
#define CSR1212_CPU_TO_LE64(quad) cpu_to_le64(quad)
#include <linux/errno.h>
#define CSR1212_SUCCESS (0)
#define CSR1212_EINVAL (-EINVAL)
#define CSR1212_ENOMEM (-ENOMEM)
#define CSR1212_ENOENT (-ENOENT)
#define CSR1212_EIO (-EIO)
#define CSR1212_EBUSY (-EBUSY)
#else
/* Userspace */
#include <sys/types.h>
#include <malloc.h>
#define CSR1212_MALLOC(size) malloc(size)
#define CSR1212_FREE(ptr) free(ptr)
#include <endian.h>
#if __BYTE_ORDER == __LITTLE_ENDIAN
#include <byteswap.h>
#define CSR1212_BE16_TO_CPU(quad) bswap_16(quad)
#define CSR1212_CPU_TO_BE16(quad) bswap_16(quad)
#define CSR1212_BE32_TO_CPU(quad) bswap_32(quad)
#define CSR1212_CPU_TO_BE32(quad) bswap_32(quad)
#define CSR1212_BE64_TO_CPU(quad) bswap_64(quad)
#define CSR1212_CPU_TO_BE64(quad) bswap_64(quad)
#define CSR1212_LE16_TO_CPU(quad) (quad)
#define CSR1212_CPU_TO_LE16(quad) (quad)
#define CSR1212_LE32_TO_CPU(quad) (quad)
#define CSR1212_CPU_TO_LE32(quad) (quad)
#define CSR1212_LE64_TO_CPU(quad) (quad)
#define CSR1212_CPU_TO_LE64(quad) (quad)
#else
#define CSR1212_BE16_TO_CPU(quad) (quad)
#define CSR1212_CPU_TO_BE16(quad) (quad)
#define CSR1212_BE32_TO_CPU(quad) (quad)
#define CSR1212_CPU_TO_BE32(quad) (quad)
#define CSR1212_BE64_TO_CPU(quad) (quad)
#define CSR1212_CPU_TO_BE64(quad) (quad)
#define CSR1212_LE16_TO_CPU(quad) bswap_16(quad)
#define CSR1212_CPU_TO_LE16(quad) bswap_16(quad)
#define CSR1212_LE32_TO_CPU(quad) bswap_32(quad)
#define CSR1212_CPU_TO_LE32(quad) bswap_32(quad)
#define CSR1212_LE64_TO_CPU(quad) bswap_64(quad)
#define CSR1212_CPU_TO_LE64(quad) bswap_64(quad)
#endif
#include <errno.h>
#define CSR1212_SUCCESS (0)
#define CSR1212_EINVAL (EINVAL)
#define CSR1212_ENOMEM (ENOMEM)
#define CSR1212_ENOENT (ENOENT)
#define CSR1212_EIO (EIO)
#define CSR1212_EBUSY (EBUSY)
#endif
#define CSR1212_KV_VAL_MASK 0xffffff
#define CSR1212_KV_KEY_SHIFT 24
#define CSR1212_KV_KEY_TYPE_SHIFT 6
#define CSR1212_KV_KEY_ID_MASK 0x3f
#define CSR1212_KV_KEY_TYPE_MASK 0x3
/* After shift */
/* CSR 1212 key types */
#define CSR1212_KV_TYPE_IMMEDIATE 0
#define CSR1212_KV_TYPE_CSR_OFFSET 1
#define CSR1212_KV_TYPE_LEAF 2
#define CSR1212_KV_TYPE_DIRECTORY 3
/* CSR 1212 key ids */
#define CSR1212_KV_ID_DESCRIPTOR 0x01
#define CSR1212_KV_ID_BUS_DEPENDENT_INFO 0x02
#define CSR1212_KV_ID_VENDOR 0x03
#define CSR1212_KV_ID_HARDWARE_VERSION 0x04
#define CSR1212_KV_ID_MODULE 0x07
#define CSR1212_KV_ID_NODE_CAPABILITIES 0x0C
#define CSR1212_KV_ID_EUI_64 0x0D
#define CSR1212_KV_ID_UNIT 0x11
#define CSR1212_KV_ID_SPECIFIER_ID 0x12
#define CSR1212_KV_ID_VERSION 0x13
#define CSR1212_KV_ID_DEPENDENT_INFO 0x14
#define CSR1212_KV_ID_UNIT_LOCATION 0x15
#define CSR1212_KV_ID_MODEL 0x17
#define CSR1212_KV_ID_INSTANCE 0x18
#define CSR1212_KV_ID_KEYWORD 0x19
#define CSR1212_KV_ID_FEATURE 0x1A
#define CSR1212_KV_ID_EXTENDED_ROM 0x1B
#define CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID 0x1C
#define CSR1212_KV_ID_EXTENDED_KEY 0x1D
#define CSR1212_KV_ID_EXTENDED_DATA 0x1E
#define CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR 0x1F
#define CSR1212_KV_ID_DIRECTORY_ID 0x20
#define CSR1212_KV_ID_REVISION 0x21
/* IEEE 1212 Address space map */
#define CSR1212_ALL_SPACE_BASE (0x000000000000ULL)
#define CSR1212_ALL_SPACE_SIZE (1ULL << 48)
#define CSR1212_ALL_SPACE_END (CSR1212_ALL_SPACE_BASE + CSR1212_ALL_SPACE_SIZE)
#define CSR1212_MEMORY_SPACE_BASE (0x000000000000ULL)
#define CSR1212_MEMORY_SPACE_SIZE ((256ULL * (1ULL << 40)) - (512ULL * (1ULL << 20)))
#define CSR1212_MEMORY_SPACE_END (CSR1212_MEMORY_SPACE_BASE + CSR1212_MEMORY_SPACE_SIZE)
#define CSR1212_PRIVATE_SPACE_BASE (0xffffe0000000ULL)
#define CSR1212_PRIVATE_SPACE_SIZE (256ULL * (1ULL << 20))
#define CSR1212_PRIVATE_SPACE_END (CSR1212_PRIVATE_SPACE_BASE + CSR1212_PRIVATE_SPACE_SIZE)
#define CSR1212_REGISTER_SPACE_BASE (0xfffff0000000ULL)
#define CSR1212_REGISTER_SPACE_SIZE (256ULL * (1ULL << 20))
#define CSR1212_REGISTER_SPACE_END (CSR1212_REGISTER_SPACE_BASE + CSR1212_REGISTER_SPACE_SIZE)
#define CSR1212_CSR_ARCH_REG_SPACE_BASE (0xfffff0000000ULL)
#define CSR1212_CSR_ARCH_REG_SPACE_SIZE (512)
#define CSR1212_CSR_ARCH_REG_SPACE_END (CSR1212_CSR_ARCH_REG_SPACE_BASE + CSR1212_CSR_ARCH_REG_SPACE_SIZE)
#define CSR1212_CSR_ARCH_REG_SPACE_OFFSET (CSR1212_CSR_ARCH_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
#define CSR1212_CSR_BUS_DEP_REG_SPACE_BASE (0xfffff0000200ULL)
#define CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE (512)
#define CSR1212_CSR_BUS_DEP_REG_SPACE_END (CSR1212_CSR_BUS_DEP_REG_SPACE_BASE + CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE)
#define CSR1212_CSR_BUS_DEP_REG_SPACE_OFFSET (CSR1212_CSR_BUS_DEP_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
#define CSR1212_CONFIG_ROM_SPACE_BASE (0xfffff0000400ULL)
#define CSR1212_CONFIG_ROM_SPACE_SIZE (1024)
#define CSR1212_CONFIG_ROM_SPACE_END (CSR1212_CONFIG_ROM_SPACE_BASE + CSR1212_CONFIG_ROM_SPACE_SIZE)
#define CSR1212_CONFIG_ROM_SPACE_OFFSET (CSR1212_CONFIG_ROM_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
#define CSR1212_UNITS_SPACE_BASE (0xfffff0000800ULL)
#define CSR1212_UNITS_SPACE_SIZE ((256ULL * (1ULL << 20)) - 2048)
#define CSR1212_UNITS_SPACE_END (CSR1212_UNITS_SPACE_BASE + CSR1212_UNITS_SPACE_SIZE)
#define CSR1212_UNITS_SPACE_OFFSET (CSR1212_UNITS_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
#define CSR1212_EXTENDED_ROM_SIZE (0x10000 * sizeof(u_int32_t))
/* Config ROM image structures */
struct
csr1212_bus_info_block_img
{
u_int8_t
length
;
u_int8_t
crc_length
;
u_int16_t
crc
;
/* Must be last */
u_int32_t
data
[
0
];
/* older gcc can't handle [] which is standard */
};
#define CSR1212_KV_KEY(quad) (CSR1212_BE32_TO_CPU(quad) >> CSR1212_KV_KEY_SHIFT)
#define CSR1212_KV_KEY_TYPE(quad) (CSR1212_KV_KEY(quad) >> CSR1212_KV_KEY_TYPE_SHIFT)
#define CSR1212_KV_KEY_ID(quad) (CSR1212_KV_KEY(quad) & CSR1212_KV_KEY_ID_MASK)
#define CSR1212_KV_VAL(quad) (CSR1212_BE32_TO_CPU(quad) & CSR1212_KV_VAL_MASK)
#define CSR1212_SET_KV_KEY(quad, key) ((quad) = \
CSR1212_CPU_TO_BE32(CSR1212_KV_VAL(quad) | ((key) << CSR1212_KV_KEY_SHIFT)))
#define CSR1212_SET_KV_VAL(quad, val) ((quad) = \
CSR1212_CPU_TO_BE32((CSR1212_KV_KEY(quad) << CSR1212_KV_KEY_SHIFT) | (val)))
#define CSR1212_SET_KV_TYPEID(quad, type, id) ((quad) = \
CSR1212_CPU_TO_BE32(CSR1212_KV_VAL(quad) | \
(((((type) & CSR1212_KV_KEY_TYPE_MASK) << CSR1212_KV_KEY_TYPE_SHIFT) | \
((id) & CSR1212_KV_KEY_ID_MASK)) << CSR1212_KV_KEY_SHIFT)))
typedef
u_int32_t
csr1212_quad_t
;
struct
csr1212_keyval_img
{
u_int16_t
length
;
u_int16_t
crc
;
/* Must be last */
csr1212_quad_t
data
[
0
];
/* older gcc can't handle [] which is standard */
};
struct
csr1212_leaf
{
int
len
;
u_int32_t
*
data
;
};
struct
csr1212_dentry
{
struct
csr1212_dentry
*
next
,
*
prev
;
struct
csr1212_keyval
*
kv
;
};
struct
csr1212_directory
{
int
len
;
struct
csr1212_dentry
*
dentries_head
,
*
dentries_tail
;
};
struct
csr1212_keyval
{
struct
{
u_int8_t
type
;
u_int8_t
id
;
}
key
;
union
{
u_int32_t
immediate
;
u_int32_t
csr_offset
;
struct
csr1212_leaf
leaf
;
struct
csr1212_directory
directory
;
}
value
;
struct
csr1212_keyval
*
associate
;
int
refcnt
;
/* used in generating and/or parsing CSR image */
struct
csr1212_keyval
*
next
,
*
prev
;
/* flat list of CSR elements */
u_int32_t
offset
;
/* position in CSR from 0xffff f000 0000 */
u_int8_t
valid
;
/* flag indicating keyval has valid data*/
};
struct
csr1212_cache_region
{
struct
csr1212_cache_region
*
next
,
*
prev
;
u_int32_t
offset_start
;
/* inclusive */
u_int32_t
offset_end
;
/* exclusive */
};
struct
csr1212_csr_rom_cache
{
struct
csr1212_csr_rom_cache
*
next
,
*
prev
;
struct
csr1212_cache_region
*
filled_head
,
*
filled_tail
;
struct
csr1212_keyval
*
layout_head
,
*
layout_tail
;
size_t
size
;
u_int32_t
offset
;
struct
csr1212_keyval
*
ext_rom
;
size_t
len
;
/* Must be last */
u_int32_t
data
[
0
];
/* older gcc can't handle [] which is standard */
};
struct
csr1212_csr
{
size_t
bus_info_len
;
/* bus info block length in bytes */
size_t
crc_len
;
/* crc length in bytes */
u_int32_t
*
bus_info_data
;
/* bus info data incl bus name and EUI */
void
*
private
;
/* private, bus specific data */
struct
csr1212_bus_ops
*
ops
;
struct
csr1212_keyval
*
root_kv
;
int
max_rom
;
/* max bytes readable in Config ROM region */
/* Items below used for image parsing and generation */
struct
csr1212_csr_rom_cache
*
cache_head
,
*
cache_tail
;
};
struct
csr1212_bus_ops
{
/* This function is used by csr1212 to read additional information
* from remote nodes when parsing a Config ROM (i.e., read Config ROM
* entries located in the Units Space. Must return 0 on success
* anything else indicates an error. */
int
(
*
bus_read
)
(
struct
csr1212_csr
*
csr
,
u_int64_t
addr
,
u_int16_t
length
,
void
*
buffer
,
void
*
private
);
/* This function is used by csr1212 to allocate a region in units space
* in the event that Config ROM entries don't all fit in the predefined
* 1K region. The void *private parameter is private member of struct
* csr1212_csr. */
u_int64_t
(
*
allocate_addr_range
)
(
u_int64_t
size
,
u_int32_t
alignment
,
void
*
private
);
/* This function is used by csr1212 to release a region in units space
* that is no longer needed. */
void
(
*
release_addr
)
(
u_int64_t
addr
,
void
*
private
);
/* This function is used by csr1212 to determine the max read request
* supported by a remote node when reading the ConfigROM space. Must
* return 0, 1, or 2 per IEEE 1212. */
int
(
*
get_max_rom
)
(
u_int32_t
*
bus_info
,
void
*
private
);
};
/* Descriptor Leaf manipulation macros */
#define CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT 24
#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK 0xffffff
#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u_int32_t))
#define CSR1212_DESCRIPTOR_LEAF_TYPE(kv) \
(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[0]) >> CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)
#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) \
(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[0]) & \
CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)
#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
(&((kv)->value.leaf.data[1]))
#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \
((kv)->value.leaf.data[0] = \
CSR1212_CPU_TO_BE32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \
((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)))
#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \
((kv)->value.leaf.data[0] = \
CSR1212_CPU_TO_BE32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \
CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \
((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)))
/* Text Descriptor Leaf manipulation macros */
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT 28
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK 0xf
/* after shift */
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT 16
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK 0xfff
/* after shift */
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u_int32_t))
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) \
(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) >> \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT)
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) \
((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) >> \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK)
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) \
(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) & \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv) \
(&((kv)->value.leaf.data[2]))
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, width) \
((kv)->value.leaf.data[1] = \
((kv)->value.leaf.data[1] & \
CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK << \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))) | \
CSR1212_CPU_TO_BE32(((width) & \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK) << \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, char_set) \
((kv)->value.leaf.data[1] = \
((kv)->value.leaf.data[1] & \
CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK << \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))) | \
CSR1212_CPU_TO_BE32(((char_set) & \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK) << \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language) \
((kv)->value.leaf.data[1] = \
((kv)->value.leaf.data[1] & \
CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK))) | \
CSR1212_CPU_TO_BE32(((language) & \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)))
/* Icon Descriptor Leaf manipulation macros */
#define CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK 0xffffff
#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT 30
#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK 0x3
/* after shift */
#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT 16
#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK 0xf
/* after shift */
#define CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff
#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT 16
#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK 0xffff
/* after shift */
#define CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK 0xffff
#define CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD (3 * sizeof(u_int32_t))
#define CSR1212_ICON_DESCRIPTOR_LEAF_VERSION(kv) \
(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[2]) & \
CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK)
#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH(kv) \
(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) >> \
CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT)
#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE(kv) \
((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) >> \
CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT) & \
CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK)
#define CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE(kv) \
(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) & \
CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK)
#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN(kv) \
((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[4]) >> \
CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_HSCAN_SHIFT) & \
CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_HSCAN_MASK)
#define CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN(kv) \
(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[4]) & \
CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK)
#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE(kv) \
(&((kv)->value.leaf.data[5]))
static
inline
u_int32_t
*
CSR1212_ICON_DESCRIPTOR_LEAF_PIXELS
(
struct
csr1212_keyval
*
kv
)
{
static
const
int
pd
[
4
]
=
{
0
,
4
,
16
,
256
};
static
const
int
cs
[
16
]
=
{
4
,
2
};
int
ps
=
pd
[
CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH
(
kv
)];
return
&
kv
->
value
.
leaf
.
data
[
5
+
(
ps
*
cs
[
CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE
(
kv
)])
/
sizeof
(
u_int32_t
)];
}
#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_VERSION(kv, version) \
((kv)->value.leaf.data[2] = \
((kv)->value.leaf.data[2] & \
CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK))) | \
CSR1212_CPU_TO_BE32(((version) & \
CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK)))
#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_PALETTE_DEPTH(kv, palette_depth) \
((kv)->value.leaf.data[3] = \
((kv)->value.leaf.data[3] & \
CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK << \
CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT))) | \
CSR1212_CPU_TO_BE32(((palette_depth) & \
CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK) << \
CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT))
#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_COLOR_SPACE(kv, color_space) \
((kv)->value.leaf.data[3] = \
((kv)->value.leaf.data[3] & \
CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK << \
CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT))) | \
CSR1212_CPU_TO_BE32(((color_space) & \
CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK) << \
CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT))
#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language) \
((kv)->value.leaf.data[3] = \
((kv)->value.leaf.data[3] & \
CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK))) | \
CSR1212_CPU_TO_BE32(((language) & \
CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK)))
#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_HSCAN(kv, hscan) \
((kv)->value.leaf.data[4] = \
((kv)->value.leaf.data[4] & \
CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK << \
CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT))) | \
CSR1212_CPU_TO_BE32(((hscan) & \
CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK) << \
CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT))
#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_VSCAN(kv, vscan) \
((kv)->value.leaf.data[4] = \
(((kv)->value.leaf.data[4] & \
CSR1212_CPU_TO_BE32(~CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK))) | \
CSR1212_CPU_TO_BE32(((vscan) & \
CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK)))
/* Modifiable Descriptor Leaf manipulation macros */
#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT 16
#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK 0xffff
#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_SHIFT 32
#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK 0xffff
#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_LO_MASK 0xffffffffULL
#define CSR1212_MODIFIABLE_DESCRIPTOR_MAX_SIZE(kv) \
CSR1212_BE16_TO_CPU((kv)->value.leaf.data[0] >> CSR1212_MODIFIABLE_DESCRIPTOR_MAX_SIZE_SHIFT)
#define CSR1212_MODIFIABLE_DESCRIPTOR_ADDRESS(kv) \
(CSR1212_BE16_TO_CPU(((u_int64_t)((kv)->value.leaf.data[0])) << \
CSR1212_MODIFIABLE_DESCRIPTOR_ADDR_HI_SHIFT) | \
CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]))
#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_MAX_SIZE(kv, size) \
((kv)->value.leaf.data[0] = \
((kv)->value.leaf.data[0] & \
CSR1212_CPU_TO_BE32(~(CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK << \
CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT))) | \
CSR1212_CPU_TO_BE32(((size) & \
CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK) << \
CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT))
#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_HI(kv, addr) \
((kv)->value.leaf.data[0] = \
((kv)->value.leaf.data[0] & \
CSR1212_CPU_TO_BE32(~(CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK))) | \
CSR1212_CPU_TO_BE32(((addr) & \
CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK)))
#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_LO(kv, addr) \
((kv)->value.leaf.data[1] = \
CSR1212_CPU_TO_BE32(addr & CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_LO_MASK))
/* The following 2 function are for creating new Configuration ROM trees. The
* first function is used for both creating local trees and parsing remote
* trees. The second function adds pertinent information to local Configuration
* ROM trees - namely data for the bus information block. */
extern
struct
csr1212_csr
*
csr1212_create_csr
(
struct
csr1212_bus_ops
*
ops
,
size_t
bus_info_size
,
void
*
private
);
extern
void
csr1212_init_local_csr
(
struct
csr1212_csr
*
csr
,
const
u_int32_t
*
bus_info_data
,
int
max_rom
);
/* The following function destroys a Configuration ROM tree and release all
* memory taken by the tree. */
extern
void
csr1212_destroy_csr
(
struct
csr1212_csr
*
csr
);
/* The following set of functions are fore creating new keyvals for placement in
* a Configuration ROM tree. Code that creates new keyvals with these functions
* must release those keyvals with csr1212_release_keyval() when they are no
* longer needed. */
extern
struct
csr1212_keyval
*
csr1212_new_immediate
(
u_int8_t
key
,
u_int32_t
value
);
extern
struct
csr1212_keyval
*
csr1212_new_leaf
(
u_int8_t
key
,
const
void
*
data
,
size_t
data_len
);
extern
struct
csr1212_keyval
*
csr1212_new_csr_offset
(
u_int8_t
key
,
u_int32_t
csr_offset
);
extern
struct
csr1212_keyval
*
csr1212_new_directory
(
u_int8_t
key
);
extern
struct
csr1212_keyval
*
csr1212_new_extended_immediate
(
u_int32_t
spec
,
u_int32_t
key
,
u_int32_t
value
);
extern
struct
csr1212_keyval
*
csr1212_new_extended_leaf
(
u_int32_t
spec
,
u_int32_t
key
,
const
void
*
data
,
size_t
data_len
);
extern
struct
csr1212_keyval
*
csr1212_new_descriptor_leaf
(
u_int8_t
dtype
,
u_int32_t
specifier_id
,
const
void
*
data
,
size_t
data_len
);
extern
struct
csr1212_keyval
*
csr1212_new_textual_descriptor_leaf
(
u_int8_t
cwidth
,
u_int16_t
cset
,
u_int16_t
language
,
const
void
*
data
,
size_t
data_len
);
extern
struct
csr1212_keyval
*
csr1212_new_string_descriptor_leaf
(
const
char
*
s
);
extern
struct
csr1212_keyval
*
csr1212_new_icon_descriptor_leaf
(
u_int32_t
version
,
u_int8_t
palette_depth
,
u_int8_t
color_space
,
u_int16_t
language
,
u_int16_t
hscan
,
u_int16_t
vscan
,
u_int32_t
*
palette
,
u_int32_t
*
pixels
);
extern
struct
csr1212_keyval
*
csr1212_new_modifiable_descriptor_leaf
(
u_int16_t
max_size
,
u_int64_t
address
);
extern
struct
csr1212_keyval
*
csr1212_new_keyword_leaf
(
int
strc
,
const
char
*
strv
[]);
/* The following functions manage association between keyvals. Typically,
* Descriptor Leaves and Directories will be associated with another keyval and
* it is desirable for the Descriptor keyval to be place immediately after the
* keyval that it is associated with.*/
extern
int
csr1212_associate_keyval
(
struct
csr1212_keyval
*
kv
,
struct
csr1212_keyval
*
associate
);
extern
void
csr1212_disassociate_keyval
(
struct
csr1212_keyval
*
kv
);
/* The following functions manage the association of a keyval and directories.
* A keyval may be attached to more than one directory. */
extern
int
csr1212_attach_keyval_to_directory
(
struct
csr1212_keyval
*
dir
,
struct
csr1212_keyval
*
kv
);
extern
void
csr1212_detach_keyval_from_directory
(
struct
csr1212_keyval
*
dir
,
struct
csr1212_keyval
*
kv
);
/* The following functions create a Configuration ROM image from the tree of
* keyvals provided. csr1212_generate_csr_image() creates a complete image in
* the list of caches available via csr->cache_head. The other functions are
* provided should there be a need to create a flat image without restrictions
* placed by IEEE 1212. */
extern
struct
csr1212_keyval
*
csr1212_generate_positions
(
struct
csr1212_csr_rom_cache
*
cache
,
struct
csr1212_keyval
*
start_kv
,
int
start_pos
);
extern
size_t
csr1212_generate_layout_order
(
struct
csr1212_keyval
*
kv
);
extern
void
csr1212_fill_cache
(
struct
csr1212_csr_rom_cache
*
cache
);
extern
int
csr1212_generate_csr_image
(
struct
csr1212_csr
*
csr
);
/* This is a convience function for reading a block of data out of one of the
* caches in the csr->cache_head list. */
extern
int
csr1212_read
(
struct
csr1212_csr
*
csr
,
u_int32_t
offset
,
void
*
buffer
,
u_int32_t
len
);
/* The following functions are in place for parsing Configuration ROM images.
* csr1212_parse_keyval() is used should there be a need to directly parse a
* Configuration ROM directly. */
extern
int
csr1212_parse_keyval
(
struct
csr1212_keyval
*
kv
,
struct
csr1212_csr_rom_cache
*
cache
);
extern
int
csr1212_parse_csr
(
struct
csr1212_csr
*
csr
);
/* These are internal functions referenced by inline functions below. */
extern
int
_csr1212_read_keyval
(
struct
csr1212_csr
*
csr
,
struct
csr1212_keyval
*
kv
);
extern
void
_csr1212_destroy_keyval
(
struct
csr1212_keyval
*
kv
);
/* This function allocates a new cache which may be used for either parsing or
* generating sub-sets of Configuration ROM images. */
static
inline
struct
csr1212_csr_rom_cache
*
csr1212_rom_cache_malloc
(
u_int32_t
offset
,
size_t
size
)
{
struct
csr1212_csr_rom_cache
*
cache
;
cache
=
CSR1212_MALLOC
(
sizeof
(
struct
csr1212_csr_rom_cache
)
+
size
);
if
(
!
cache
)
return
NULL
;
cache
->
next
=
NULL
;
cache
->
prev
=
NULL
;
cache
->
filled_head
=
NULL
;
cache
->
filled_tail
=
NULL
;
cache
->
layout_head
=
NULL
;
cache
->
layout_tail
=
NULL
;
cache
->
offset
=
offset
;
cache
->
size
=
size
;
cache
->
ext_rom
=
NULL
;
return
cache
;
}
/* This function ensures that a keyval contains data when referencing a keyval
* created by parsing a Configuration ROM. */
static
inline
struct
csr1212_keyval
*
csr1212_get_keyval
(
struct
csr1212_csr
*
csr
,
struct
csr1212_keyval
*
kv
)
{
if
(
!
kv
)
return
NULL
;
if
(
!
kv
->
valid
)
if
(
_csr1212_read_keyval
(
csr
,
kv
)
!=
CSR1212_SUCCESS
)
return
NULL
;
return
kv
;
}
/* This function increments the reference count for a keyval should there be a
* need for code to retain a keyval that has been parsed. */
static
inline
void
csr1212_keep_keyval
(
struct
csr1212_keyval
*
kv
)
{
kv
->
refcnt
++
;
}
/* This function decrements a keyval's reference count and will destroy the
* keyval when there are no more users of the keyval. This should be called by
* any code that calls csr1212_keep_keyval() or any of the keyval creation
* routines csr1212_new_*(). */
static
inline
void
csr1212_release_keyval
(
struct
csr1212_keyval
*
kv
)
{
if
(
kv
->
refcnt
>
1
)
kv
->
refcnt
--
;
else
_csr1212_destroy_keyval
(
kv
);
}
/*
* This macro allows for looping over the keyval entries in a directory and it
* ensures that keyvals from remote ConfigROMs are parsed properly.
*
* _csr is a struct csr1212_csr * that points to CSR associated with dir.
* _kv is a struct csr1212_keyval * that'll point to the current keyval (loop index).
* _dir is a struct csr1212_keyval * that points to the directory to be looped.
* _pos is a struct csr1212_dentry * that is used internally for indexing.
*
* kv will be NULL upon exit of the loop.
*/
#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos) \
for (csr1212_get_keyval((_csr), (_dir)), \
_pos = (_dir)->value.directory.dentries_head, \
_kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL; \
(_kv) && (_pos); \
(_kv->associate == NULL) ? \
((_pos = _pos->next), \
(_kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : \
NULL)) : \
(_kv = csr1212_get_keyval((_csr), _kv->associate)))
#endif
/* __CSR1212_H__ */
drivers/ieee1394/dv1394.c
View file @
16eadb50
...
...
@@ -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
;
}
...
...
drivers/ieee1394/eth1394.c
View file @
16eadb50
...
...
@@ -29,7 +29,6 @@
*
* TODO:
* RFC 2734 related:
* - Add Config ROM entry
* - Add MCAP. Limited Multicast exists only to 224.0.0.1 and 224.0.0.2.
*
* Non-RFC 2734 related:
...
...
@@ -38,7 +37,6 @@
* - Convert kmalloc/kfree for link fragments to use kmem_cache_* instead
* - Stability improvements
* - Performance enhancements
* - Change hardcoded 1394 bus address region to a dynamic memory space allocation
* - Consider garbage collecting old partial datagrams after X amount of time
*/
...
...
@@ -69,6 +67,7 @@
#include <asm/semaphore.h>
#include <net/arp.h>
#include "csr1212.h"
#include "ieee1394_types.h"
#include "ieee1394_core.h"
#include "ieee1394_transactions.h"
...
...
@@ -89,7 +88,7 @@
#define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__)
static
char
version
[]
__devinitdata
=
"$Rev: 1
096
$ Ben Collins <bcollins@debian.org>"
;
"$Rev: 1
133
$ Ben Collins <bcollins@debian.org>"
;
struct
fragment_info
{
struct
list_head
list
;
...
...
@@ -107,8 +106,35 @@ struct partial_datagram {
struct
list_head
frag_info
;
};
static
struct
csr1212_keyval
*
eth1394_ud
=
NULL
;
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 */
};
struct
eth1394_host_info
{
struct
hpsb_host
*
host
;
struct
net_device
*
dev
;
};
struct
eth1394_node_ref
{
struct
unit_directory
*
ud
;
struct
list_head
list
;
};
struct
eth1394_node_info
{
u16
maxpayload
;
/* Max payload */
u8
sspd
;
/* Max speed */
u64
fifo
;
/* FIFO address */
struct
pdg_list
pdg
;
/* partial RX datagram lists */
int
dgl
;
/* Outgoing datagram label */
};
/* Our ieee1394 highlevel driver */
static
const
char
driver_name
[]
=
"eth1394"
;
#define ETH1394_DRIVER_NAME "IP/1394"
static
const
char
driver_name
[]
=
ETH1394_DRIVER_NAME
;
static
kmem_cache_t
*
packet_task_cache
;
...
...
@@ -188,94 +214,36 @@ static struct hpsb_highlevel eth1394_highlevel = {
};
static
void
eth1394_iso_shutdown
(
struct
eth1394_priv
*
priv
)
{
priv
->
bc_state
=
ETHER1394_BC_CLOSED
;
if
(
priv
->
iso
!=
NULL
)
{
if
(
!
in_interrupt
())
hpsb_iso_shutdown
(
priv
->
iso
);
priv
->
iso
=
NULL
;
}
}
static
int
ether1394_init_bc
(
struct
net_device
*
dev
)
{
struct
eth1394_priv
*
priv
=
(
struct
eth1394_priv
*
)
dev
->
priv
;
/* First time sending? Need a broadcast channel for ARP and for
* listening on */
if
(
priv
->
bc_state
==
ETHER1394_BC_CHECK
)
{
quadlet_t
bc
;
/* Get the local copy of the broadcast channel and check its
* validity (the IRM should validate it for us) */
bc
=
priv
->
host
->
csr
.
broadcast_channel
;
if
((
bc
&
0xc0000000
)
!=
0xc0000000
)
{
/* broadcast channel not validated yet */
ETH1394_PRINT
(
KERN_WARNING
,
dev
->
name
,
"Error BROADCAST_CHANNEL register valid "
"bit not set, can't send IP traffic
\n
"
);
eth1394_iso_shutdown
(
priv
);
return
-
EAGAIN
;
}
if
(
priv
->
broadcast_channel
!=
(
bc
&
0x3f
))
{
/* This really shouldn't be possible, but just in case
* the IEEE 1394 spec changes regarding broadcast
* channels in the future. */
eth1394_iso_shutdown
(
priv
);
if
(
in_interrupt
())
return
-
EAGAIN
;
priv
->
broadcast_channel
=
bc
&
0x3f
;
ETH1394_PRINT
(
KERN_INFO
,
dev
->
name
,
"Changing to broadcast channel %d...
\n
"
,
priv
->
broadcast_channel
);
priv
->
iso
=
hpsb_iso_recv_init
(
priv
->
host
,
16
*
4096
,
16
,
priv
->
broadcast_channel
,
HPSB_ISO_DMA_PACKET_PER_BUFFER
,
1
,
ether1394_iso
);
if
(
priv
->
iso
==
NULL
)
{
ETH1394_PRINT
(
KERN_ERR
,
dev
->
name
,
"failed to change broadcast "
"channel
\n
"
);
return
-
EAGAIN
;
}
}
if
(
hpsb_iso_recv_start
(
priv
->
iso
,
-
1
,
(
1
<<
3
),
-
1
)
<
0
)
{
ETH1394_PRINT
(
KERN_ERR
,
dev
->
name
,
"Could not start data stream reception
\n
"
);
eth1394_iso_shutdown
(
priv
);
return
-
EAGAIN
;
}
priv
->
bc_state
=
ETHER1394_BC_OPENED
;
}
return
0
;
}
/* This is called after an "ifup" */
static
int
ether1394_open
(
struct
net_device
*
dev
)
{
struct
eth1394_priv
*
priv
=
(
struct
eth1394_priv
*
)
dev
->
priv
;
unsigned
long
flags
;
int
ret
;
int
ret
=
0
;
/* Something bad happened, don't even try */
if
(
priv
->
bc_state
==
ETHER1394_BC_CLOSED
)
return
-
EAGAIN
;
spin_lock_irqsave
(
&
priv
->
lock
,
flags
);
ret
=
ether1394_init_bc
(
dev
);
spin_unlock_irqrestore
(
&
priv
->
lock
,
flags
);
if
(
priv
->
bc_state
==
ETHER1394_BC_ERROR
)
{
/* we'll try again */
priv
->
iso
=
hpsb_iso_recv_init
(
priv
->
host
,
ETHER1394_GASP_BUFFERS
*
2
*
(
1
<<
(
priv
->
host
->
csr
.
max_rec
+
1
)),
ETHER1394_GASP_BUFFERS
,
priv
->
broadcast_channel
,
HPSB_ISO_DMA_PACKET_PER_BUFFER
,
1
,
ether1394_iso
);
if
(
priv
->
iso
==
NULL
)
{
ETH1394_PRINT
(
KERN_ERR
,
dev
->
name
,
"Could not allocate isochronous receive "
"context for the broadcast channel
\n
"
);
priv
->
bc_state
=
ETHER1394_BC_ERROR
;
ret
=
-
EAGAIN
;
}
else
{
if
(
hpsb_iso_recv_start
(
priv
->
iso
,
-
1
,
(
1
<<
3
),
-
1
)
<
0
)
priv
->
bc_state
=
ETHER1394_BC_STOPPED
;
else
priv
->
bc_state
=
ETHER1394_BC_RUNNING
;
}
}
if
(
ret
)
return
ret
;
...
...
@@ -312,66 +280,227 @@ static void ether1394_tx_timeout (struct net_device *dev)
static
int
ether1394_change_mtu
(
struct
net_device
*
dev
,
int
new_mtu
)
{
struct
eth1394_priv
*
priv
=
(
struct
eth1394_priv
*
)
dev
->
priv
;
int
phy_id
=
NODEID_TO_NODE
(
priv
->
host
->
node_id
);
if
((
new_mtu
<
68
)
||
(
new_mtu
>
min
(
ETH1394_DATA_LEN
,
(
int
)(
priv
->
maxpayload
[
phy_id
]
-
(
sizeof
(
union
eth1394_hdr
)
+
ETHER1394_GASP_OVERHEAD
)))))
if
((
new_mtu
<
68
)
||
(
new_mtu
>
min
(
ETH1394_DATA_LEN
,
(
int
)((
1
<<
(
priv
->
host
->
csr
.
max_rec
+
1
))
-
(
sizeof
(
union
eth1394_hdr
)
+
ETHER1394_GASP_OVERHEAD
)))))
return
-
EINVAL
;
dev
->
mtu
=
new_mtu
;
return
0
;
}
static
inline
void
ether1394_register_limits
(
int
nodeid
,
u16
maxpayload
,
unsigned
char
sspd
,
u64
eui
,
u64
fifo
,
struct
eth1394_priv
*
priv
)
/******************************************
* 1394 bus activity functions
******************************************/
static
struct
eth1394_node_ref
*
eth1394_find_node
(
struct
list_head
*
inl
,
struct
unit_directory
*
ud
)
{
if
(
nodeid
<
0
||
nodeid
>=
ALL_NODES
)
{
ETH1394_PRINT_G
(
KERN_ERR
,
"Cannot register invalid nodeid %d
\n
"
,
nodeid
);
return
;
struct
eth1394_node_ref
*
node
;
list_for_each_entry
(
node
,
inl
,
list
)
if
(
node
->
ud
==
ud
)
return
node
;
return
NULL
;
}
static
struct
eth1394_node_ref
*
eth1394_find_node_guid
(
struct
list_head
*
inl
,
u64
guid
)
{
struct
eth1394_node_ref
*
node
;
list_for_each_entry
(
node
,
inl
,
list
)
if
(
node
->
ud
->
ne
->
guid
==
guid
)
return
node
;
return
NULL
;
}
static
struct
eth1394_node_ref
*
eth1394_find_node_nodeid
(
struct
list_head
*
inl
,
nodeid_t
nodeid
)
{
struct
eth1394_node_ref
*
node
;
list_for_each_entry
(
node
,
inl
,
list
)
{
if
(
node
->
ud
->
ne
->
nodeid
==
nodeid
)
return
node
;
}
priv
->
maxpayload
[
nodeid
]
=
maxpayload
;
priv
->
sspd
[
nodeid
]
=
sspd
;
priv
->
fifo
[
nodeid
]
=
fifo
;
priv
->
eui
[
nodeid
]
=
eui
;
return
NULL
;
}
priv
->
maxpayload
[
ALL_NODES
]
=
min
(
priv
->
maxpayload
[
ALL_NODES
],
maxpayload
);
priv
->
sspd
[
ALL_NODES
]
=
min
(
priv
->
sspd
[
ALL_NODES
],
sspd
);
static
int
eth1394_probe
(
struct
device
*
dev
)
{
struct
unit_directory
*
ud
;
struct
eth1394_host_info
*
hi
;
struct
eth1394_priv
*
priv
;
struct
eth1394_node_ref
*
new_node
;
struct
eth1394_node_info
*
node_info
;
return
;
ud
=
container_of
(
dev
,
struct
unit_directory
,
device
);
hi
=
hpsb_get_hostinfo
(
&
eth1394_highlevel
,
ud
->
ne
->
host
);
if
(
!
hi
)
return
-
ENOENT
;
new_node
=
kmalloc
(
sizeof
(
struct
eth1394_node_ref
),
in_interrupt
()
?
GFP_ATOMIC
:
GFP_KERNEL
);
if
(
!
new_node
)
return
-
ENOMEM
;
node_info
=
kmalloc
(
sizeof
(
struct
eth1394_node_info
),
in_interrupt
()
?
GFP_ATOMIC
:
GFP_KERNEL
);
if
(
!
node_info
)
{
kfree
(
new_node
);
return
-
ENOMEM
;
}
spin_lock_init
(
&
node_info
->
pdg
.
lock
);
INIT_LIST_HEAD
(
&
node_info
->
pdg
.
list
);
node_info
->
pdg
.
sz
=
0
;
node_info
->
fifo
=
ETHER1394_INVALID_ADDR
;
ud
->
device
.
driver_data
=
node_info
;
new_node
->
ud
=
ud
;
priv
=
(
struct
eth1394_priv
*
)
hi
->
dev
->
priv
;
list_add_tail
(
&
new_node
->
list
,
&
priv
->
ip_node_list
);
return
0
;
}
static
int
eth1394_remove
(
struct
device
*
dev
)
{
struct
unit_directory
*
ud
;
struct
eth1394_host_info
*
hi
;
struct
eth1394_priv
*
priv
;
struct
eth1394_node_ref
*
old_node
;
struct
eth1394_node_info
*
node_info
;
struct
list_head
*
lh
,
*
n
;
unsigned
long
flags
;
ud
=
container_of
(
dev
,
struct
unit_directory
,
device
);
hi
=
hpsb_get_hostinfo
(
&
eth1394_highlevel
,
ud
->
ne
->
host
);
if
(
!
hi
)
return
-
ENOENT
;
priv
=
(
struct
eth1394_priv
*
)
hi
->
dev
->
priv
;
old_node
=
eth1394_find_node
(
&
priv
->
ip_node_list
,
ud
);
if
(
old_node
)
{
list_del
(
&
old_node
->
list
);
kfree
(
old_node
);
node_info
=
(
struct
eth1394_node_info
*
)
ud
->
device
.
driver_data
;
spin_lock_irqsave
(
&
node_info
->
pdg
.
lock
,
flags
);
/* The partial datagram list should be empty, but we'll just
* make sure anyway... */
list_for_each_safe
(
lh
,
n
,
&
node_info
->
pdg
.
list
)
{
purge_partial_datagram
(
lh
);
}
spin_unlock_irqrestore
(
&
node_info
->
pdg
.
lock
,
flags
);
kfree
(
node_info
);
ud
->
device
.
driver_data
=
NULL
;
}
return
0
;
}
static
void
eth1394_update
(
struct
unit_directory
*
ud
)
{
struct
eth1394_host_info
*
hi
;
struct
eth1394_priv
*
priv
;
struct
eth1394_node_ref
*
node
;
struct
eth1394_node_info
*
node_info
;
hi
=
hpsb_get_hostinfo
(
&
eth1394_highlevel
,
ud
->
ne
->
host
);
if
(
!
hi
)
return
;
priv
=
(
struct
eth1394_priv
*
)
hi
->
dev
->
priv
;
node
=
eth1394_find_node
(
&
priv
->
ip_node_list
,
ud
);
if
(
!
node
)
{
node
=
kmalloc
(
sizeof
(
struct
eth1394_node_ref
),
in_interrupt
()
?
GFP_ATOMIC
:
GFP_KERNEL
);
if
(
!
node
)
return
;
node_info
=
kmalloc
(
sizeof
(
struct
eth1394_node_info
),
in_interrupt
()
?
GFP_ATOMIC
:
GFP_KERNEL
);
spin_lock_init
(
&
node_info
->
pdg
.
lock
);
INIT_LIST_HEAD
(
&
node_info
->
pdg
.
list
);
node_info
->
pdg
.
sz
=
0
;
ud
->
device
.
driver_data
=
node_info
;
node
->
ud
=
ud
;
priv
=
(
struct
eth1394_priv
*
)
hi
->
dev
->
priv
;
list_add_tail
(
&
node
->
list
,
&
priv
->
ip_node_list
);
}
}
static
struct
ieee1394_device_id
eth1394_id_table
[]
=
{
{
.
match_flags
=
(
IEEE1394_MATCH_SPECIFIER_ID
|
IEEE1394_MATCH_VERSION
),
.
specifier_id
=
ETHER1394_GASP_SPECIFIER_ID
,
.
version
=
ETHER1394_GASP_VERSION
,
},
{}
};
static
struct
hpsb_protocol_driver
eth1394_proto_driver
=
{
.
name
=
"IPv4 over 1394 Driver"
,
.
id_table
=
eth1394_id_table
,
.
update
=
eth1394_update
,
.
driver
=
{
.
name
=
ETH1394_DRIVER_NAME
,
.
bus
=
&
ieee1394_bus_type
,
.
probe
=
eth1394_probe
,
.
remove
=
eth1394_remove
,
},
};
static
void
ether1394_reset_priv
(
struct
net_device
*
dev
,
int
set_mtu
)
{
unsigned
long
flags
;
int
i
;
struct
eth1394_priv
*
priv
=
(
struct
eth1394_priv
*
)
dev
->
priv
;
struct
hpsb_host
*
host
=
priv
->
host
;
int
phy_id
=
NODEID_TO_NODE
(
host
->
node_id
);
u
64
guid
=
*
((
u64
*
)
&
(
host
->
csr
.
rom
[
3
])
);
u16
maxpayload
=
1
<<
(((
be32_to_cpu
(
host
->
csr
.
rom
[
2
])
>>
12
)
&
0xf
)
+
1
)
;
u64
guid
=
*
((
u64
*
)
&
(
host
->
csr
.
rom
->
bus_info_data
[
3
])
);
u
16
maxpayload
=
1
<<
(
host
->
csr
.
max_rec
+
1
);
int
max_speed
=
IEEE1394_SPEED_MAX
;
spin_lock_irqsave
(
&
priv
->
lock
,
flags
);
/* Clear the speed/payload/offset tables */
memset
(
priv
->
maxpayload
,
0
,
sizeof
(
priv
->
maxpayload
));
memset
(
priv
->
sspd
,
0
,
sizeof
(
priv
->
sspd
));
memset
(
priv
->
fifo
,
0
,
sizeof
(
priv
->
fifo
));
priv
->
sspd
[
ALL_NODES
]
=
ETH1394_SPEED_DEF
;
priv
->
maxpayload
[
ALL_NODES
]
=
eth1394_speedto_maxpayload
[
priv
->
sspd
[
ALL_NODES
]];
priv
->
bc_state
=
ETHER1394_BC_CHECK
;
memset
(
priv
->
ud_list
,
0
,
sizeof
(
struct
node_entry
*
)
*
ALL_NODES
);
priv
->
bc_maxpayload
=
512
;
/* Register our limits now */
ether1394_register_limits
(
phy_id
,
maxpayload
,
host
->
speed_map
[(
phy_id
<<
6
)
+
phy_id
],
guid
,
ETHER1394_REGION_ADDR
,
priv
);
/* Determine speed limit */
for
(
i
=
0
;
i
<
host
->
node_count
;
i
++
)
if
(
max_speed
>
host
->
speed_map
[
NODEID_TO_NODE
(
host
->
node_id
)
*
64
+
i
])
max_speed
=
host
->
speed_map
[
NODEID_TO_NODE
(
host
->
node_id
)
*
64
+
i
];
priv
->
bc_sspd
=
max_speed
;
/* We'll use our maxpayload as the default mtu */
if
(
set_mtu
)
{
dev
->
mtu
=
min
(
ETH1394_DATA_LEN
,
(
int
)(
priv
->
maxpayload
[
phy_id
]
-
(
sizeof
(
union
eth1394_hdr
)
+
ETHER1394_GASP_OVERHEAD
)));
dev
->
mtu
=
min
(
ETH1394_DATA_LEN
,
(
int
)(
maxpayload
-
(
sizeof
(
union
eth1394_hdr
)
+
ETHER1394_GASP_OVERHEAD
)));
/* Set our hardware address while we're at it */
*
(
u64
*
)
dev
->
dev_addr
=
guid
;
...
...
@@ -379,20 +508,6 @@ static void ether1394_reset_priv (struct net_device *dev, int set_mtu)
}
spin_unlock_irqrestore
(
&
priv
->
lock
,
flags
);
for
(
i
=
0
;
i
<
ALL_NODES
;
i
++
)
{
struct
list_head
*
lh
,
*
n
;
spin_lock_irqsave
(
&
priv
->
pdg
[
i
].
lock
,
flags
);
if
(
!
set_mtu
)
{
list_for_each_safe
(
lh
,
n
,
&
priv
->
pdg
[
i
].
list
)
{
purge_partial_datagram
(
lh
);
}
}
INIT_LIST_HEAD
(
&
(
priv
->
pdg
[
i
].
list
));
priv
->
pdg
[
i
].
sz
=
0
;
spin_unlock_irqrestore
(
&
priv
->
pdg
[
i
].
lock
,
flags
);
}
}
/* This function is called right before register_netdev */
...
...
@@ -432,15 +547,21 @@ static void ether1394_init_dev (struct net_device *dev)
*/
static
void
ether1394_add_host
(
struct
hpsb_host
*
host
)
{
int
i
;
struct
host_info
*
hi
=
NULL
;
struct
eth1394_host_info
*
hi
=
NULL
;
struct
net_device
*
dev
=
NULL
;
struct
eth1394_priv
*
priv
;
static
int
version_printed
=
0
;
hpsb_register_addrspace
(
&
eth1394_highlevel
,
host
,
&
addr_ops
,
ETHER1394_REGION_ADDR
,
ETHER1394_REGION_ADDR_END
);
u64
fifo_addr
;
fifo_addr
=
hpsb_allocate_and_register_addrspace
(
&
eth1394_highlevel
,
host
,
&
addr_ops
,
ETHER1394_REGION_ADDR_LEN
,
ETHER1394_REGION_ADDR_LEN
,
-
1
,
-
1
);
if
(
fifo_addr
==
~
0ULL
)
goto
out
;
if
(
version_printed
++
==
0
)
ETH1394_PRINT_G
(
KERN_INFO
,
"%s
\n
"
,
version
);
...
...
@@ -461,14 +582,11 @@ static void ether1394_add_host (struct hpsb_host *host)
priv
=
(
struct
eth1394_priv
*
)
dev
->
priv
;
INIT_LIST_HEAD
(
&
priv
->
ip_node_list
);
spin_lock_init
(
&
priv
->
lock
);
priv
->
host
=
host
;
for
(
i
=
0
;
i
<
ALL_NODES
;
i
++
)
{
spin_lock_init
(
&
priv
->
pdg
[
i
].
lock
);
INIT_LIST_HEAD
(
&
priv
->
pdg
[
i
].
list
);
priv
->
pdg
[
i
].
sz
=
0
;
}
priv
->
local_fifo
=
fifo_addr
;
hi
=
hpsb_create_hostinfo
(
&
eth1394_highlevel
,
host
,
sizeof
(
*
hi
));
...
...
@@ -496,10 +614,30 @@ static void ether1394_add_host (struct hpsb_host *host)
* be checked when the eth device is opened. */
priv
->
broadcast_channel
=
host
->
csr
.
broadcast_channel
&
0x3f
;
priv
->
iso
=
hpsb_iso_recv_init
(
host
,
16
*
4096
,
16
,
priv
->
broadcast_channel
,
HPSB_ISO_DMA_PACKET_PER_BUFFER
,
1
,
ether1394_iso
);
priv
->
iso
=
hpsb_iso_recv_init
(
host
,
(
ETHER1394_GASP_BUFFERS
*
2
*
(
1
<<
(
host
->
csr
.
max_rec
+
1
))),
ETHER1394_GASP_BUFFERS
,
priv
->
broadcast_channel
,
HPSB_ISO_DMA_PACKET_PER_BUFFER
,
1
,
ether1394_iso
);
if
(
priv
->
iso
==
NULL
)
{
priv
->
bc_state
=
ETHER1394_BC_CLOSED
;
ETH1394_PRINT
(
KERN_ERR
,
dev
->
name
,
"Could not allocate isochronous receive context "
"for the broadcast channel
\n
"
);
priv
->
bc_state
=
ETHER1394_BC_ERROR
;
}
else
{
if
(
hpsb_iso_recv_start
(
priv
->
iso
,
-
1
,
(
1
<<
3
),
-
1
)
<
0
)
priv
->
bc_state
=
ETHER1394_BC_STOPPED
;
else
priv
->
bc_state
=
ETHER1394_BC_RUNNING
;
}
if
(
csr1212_attach_keyval_to_directory
(
host
->
csr
.
rom
->
root_kv
,
eth1394_ud
)
!=
CSR1212_SUCCESS
)
{
ETH1394_PRINT
(
KERN_ERR
,
dev
->
name
,
"Cannot attach IP 1394 Unit Directory to "
"Config ROM
\n
"
);
goto
out
;
}
return
;
...
...
@@ -515,12 +653,21 @@ static void ether1394_add_host (struct hpsb_host *host)
/* Remove a card from our list */
static
void
ether1394_remove_host
(
struct
hpsb_host
*
host
)
{
struct
host_info
*
hi
=
hpsb_get_hostinfo
(
&
eth1394_highlevel
,
host
);
struct
eth1394_host_info
*
hi
;
hi
=
hpsb_get_hostinfo
(
&
eth1394_highlevel
,
host
);
if
(
hi
!=
NULL
)
{
struct
eth1394_priv
*
priv
=
(
struct
eth1394_priv
*
)
hi
->
dev
->
priv
;
eth1394_iso_shutdown
(
priv
);
hpsb_unregister_addrspace
(
&
eth1394_highlevel
,
host
,
priv
->
local_fifo
);
if
(
priv
->
iso
!=
NULL
)
hpsb_iso_shutdown
(
priv
->
iso
);
csr1212_detach_keyval_from_directory
(
hi
->
host
->
csr
.
rom
->
root_kv
,
eth1394_ud
);
hi
->
host
->
update_config_rom
=
1
;
if
(
hi
->
dev
)
{
unregister_netdev
(
hi
->
dev
);
...
...
@@ -534,18 +681,42 @@ static void ether1394_remove_host (struct hpsb_host *host)
/* A reset has just arisen */
static
void
ether1394_host_reset
(
struct
hpsb_host
*
host
)
{
struct
host_info
*
hi
=
hpsb_get_hostinfo
(
&
eth1394_highlevel
,
host
);
struct
eth1394_host_info
*
hi
;
struct
eth1394_priv
*
priv
;
struct
net_device
*
dev
;
struct
list_head
*
lh
,
*
n
;
struct
eth1394_node_ref
*
node
;
struct
eth1394_node_info
*
node_info
;
unsigned
long
flags
;
hi
=
hpsb_get_hostinfo
(
&
eth1394_highlevel
,
host
);
/* This can happen for hosts that we don't use */
if
(
hi
==
NULL
)
return
;
dev
=
hi
->
dev
;
priv
=
(
struct
eth1394_priv
*
)
dev
->
priv
;
/* Reset our private host data, but not our mtu */
netif_stop_queue
(
dev
);
ether1394_reset_priv
(
dev
,
0
);
list_for_each_entry
(
node
,
&
priv
->
ip_node_list
,
list
)
{
node_info
=
(
struct
eth1394_node_info
*
)
node
->
ud
->
device
.
driver_data
;
spin_lock_irqsave
(
&
node_info
->
pdg
.
lock
,
flags
);
list_for_each_safe
(
lh
,
n
,
&
node_info
->
pdg
.
list
)
{
purge_partial_datagram
(
lh
);
}
INIT_LIST_HEAD
(
&
(
node_info
->
pdg
.
list
));
node_info
->
pdg
.
sz
=
0
;
spin_unlock_irqrestore
(
&
node_info
->
pdg
.
lock
,
flags
);
}
netif_wake_queue
(
dev
);
}
...
...
@@ -622,7 +793,8 @@ static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr)
static
int
ether1394_header_cache
(
struct
neighbour
*
neigh
,
struct
hh_cache
*
hh
)
{
unsigned
short
type
=
hh
->
hh_type
;
struct
eth1394hdr
*
eth
=
(
struct
eth1394hdr
*
)(((
u8
*
)
hh
->
hh_data
)
+
6
);
struct
eth1394hdr
*
eth
=
(
struct
eth1394hdr
*
)(((
u8
*
)
hh
->
hh_data
)
+
(
16
-
ETH1394_HLEN
));
struct
net_device
*
dev
=
neigh
->
dev
;
if
(
type
==
__constant_htons
(
ETH_P_802_3
))
{
...
...
@@ -641,7 +813,7 @@ static void ether1394_header_cache_update(struct hh_cache *hh,
struct
net_device
*
dev
,
unsigned
char
*
haddr
)
{
memcpy
(((
u8
*
)
hh
->
hh_data
)
+
6
,
haddr
,
dev
->
addr_len
);
memcpy
(((
u8
*
)
hh
->
hh_data
)
+
(
16
-
ETH1394_HLEN
)
,
haddr
,
dev
->
addr_len
);
}
static
int
ether1394_mac_addr
(
struct
net_device
*
dev
,
void
*
p
)
...
...
@@ -650,7 +822,7 @@ static int ether1394_mac_addr(struct net_device *dev, void *p)
return
-
EBUSY
;
/* Not going to allow setting the MAC address, we really need to use
* the real one suppli
l
ed by the hardware */
* the real one supplied by the hardware */
return
-
EINVAL
;
}
...
...
@@ -710,31 +882,37 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb,
if
(
destid
==
(
LOCAL_BUS
|
ALL_NODES
))
dest_hw
=
~
0ULL
;
/* broadcast */
else
dest_hw
=
priv
->
eui
[
NODEID_TO_NODE
(
destid
)];
dest_hw
=
cpu_to_be64
((((
u64
)
priv
->
host
->
csr
.
guid_hi
)
<<
32
)
|
priv
->
host
->
csr
.
guid_lo
);
/* If this is an ARP packet, convert it. First, we want to make
* use of some of the fields, since they tell us a little bit
* about the sending machine. */
if
(
ether_type
==
__constant_htons
(
ETH_P_ARP
))
{
unsigned
long
flags
;
struct
eth1394_arp
*
arp1394
=
(
struct
eth1394_arp
*
)
skb
->
data
;
struct
arphdr
*
arp
=
(
struct
arphdr
*
)
skb
->
data
;
unsigned
char
*
arp_ptr
=
(
unsigned
char
*
)(
arp
+
1
);
u64
fifo_addr
=
(
u64
)
ntohs
(
arp1394
->
fifo_hi
)
<<
32
|
ntohl
(
arp1394
->
fifo_lo
);
u8
host_max_rec
=
(
be32_to_cpu
(
priv
->
host
->
csr
.
rom
[
2
])
>>
12
)
&
0xf
;
u8
max_rec
=
min
(
host_max_rec
,
(
u8
)(
arp1394
->
max_rec
));
u8
max_rec
=
min
(
priv
->
host
->
csr
.
max_rec
,
(
u8
)(
arp1394
->
max_rec
));
u16
maxpayload
=
min
(
eth1394_speedto_maxpayload
[
arp1394
->
sspd
],
(
u16
)(
1
<<
(
max_rec
+
1
)));
struct
eth1394_node_ref
*
node
;
struct
eth1394_node_info
*
node_info
;
node
=
eth1394_find_node_guid
(
&
priv
->
ip_node_list
,
be64_to_cpu
(
arp1394
->
s_uniq_id
));
if
(
!
node
)
{
return
0
;
}
node_info
=
(
struct
eth1394_node_info
*
)
node
->
ud
->
device
.
driver_data
;
/* Update our speed/payload/fifo_offset table */
spin_lock_irqsave
(
&
priv
->
lock
,
flags
);
ether1394_register_limits
(
NODEID_TO_NODE
(
srcid
),
maxpayload
,
arp1394
->
sspd
,
arp1394
->
s_uniq_id
,
fifo_addr
,
priv
);
spin_unlock_irqrestore
(
&
priv
->
lock
,
flags
);
node_info
->
maxpayload
=
maxpayload
;
node_info
->
sspd
=
arp1394
->
sspd
;
node_info
->
fifo
=
fifo_addr
;
/* Now that we're done with the 1394 specific stuff, we'll
* need to alter some of the data. Believe it or not, all
...
...
@@ -743,9 +921,8 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb,
* in and the hardware address length set to 8.
*
* IMPORTANT: The code below overwrites 1394 specific data
* needed above data so keep the call to
* ether1394_register_limits() before munging the data for the
* higher level IP stack. */
* needed above so keep the munging of the data for the
* higher level IP stack last. */
arp
->
ar_hln
=
8
;
arp_ptr
+=
arp
->
ar_hln
;
/* skip over sender unique id */
...
...
@@ -754,9 +931,9 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb,
if
(
arp
->
ar_op
==
1
)
/* just set ARP req target unique ID to 0 */
memset
(
arp_ptr
,
0
,
ETH1394_ALEN
)
;
*
((
u64
*
)
arp_ptr
)
=
0
;
else
memcpy
(
arp_ptr
,
dev
->
dev_addr
,
ETH1394_ALEN
);
*
((
u64
*
)
arp_ptr
)
=
*
((
u64
*
)
dev
->
dev_addr
);
}
/* Now add the ethernet header. */
...
...
@@ -769,12 +946,9 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb,
static
inline
int
fragment_overlap
(
struct
list_head
*
frag_list
,
int
offset
,
int
len
)
{
struct
list_head
*
lh
;
struct
fragment_info
*
fi
;
list_for_each
(
lh
,
frag_list
)
{
fi
=
list_entry
(
lh
,
struct
fragment_info
,
list
);
list_for_each_entry
(
fi
,
frag_list
,
list
)
{
if
(
!
((
offset
>
(
fi
->
offset
+
fi
->
len
-
1
))
||
((
offset
+
len
-
1
)
<
fi
->
offset
)))
return
1
;
...
...
@@ -784,13 +958,11 @@ static inline int fragment_overlap(struct list_head *frag_list, int offset, int
static
inline
struct
list_head
*
find_partial_datagram
(
struct
list_head
*
pdgl
,
int
dgl
)
{
struct
list_head
*
lh
;
struct
partial_datagram
*
pd
;
list_for_each
(
lh
,
pdgl
)
{
pd
=
list_entry
(
lh
,
struct
partial_datagram
,
list
);
list_for_each_entry
(
pd
,
pdgl
,
list
)
{
if
(
pd
->
dgl
==
dgl
)
return
lh
;
return
&
pd
->
list
;
}
return
NULL
;
}
...
...
@@ -939,12 +1111,29 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
{
struct
sk_buff
*
skb
;
unsigned
long
flags
;
struct
eth1394_priv
*
priv
;
struct
eth1394_priv
*
priv
=
(
struct
eth1394_priv
*
)
dev
->
priv
;
union
eth1394_hdr
*
hdr
=
(
union
eth1394_hdr
*
)
buf
;
u16
ether_type
=
0
;
/* initialized to clear warning */
int
hdr_len
;
struct
unit_directory
*
ud
=
priv
->
ud_list
[
NODEID_TO_NODE
(
srcid
)];
struct
eth1394_node_info
*
node_info
;
if
(
!
ud
)
{
struct
eth1394_node_ref
*
node
;
node
=
eth1394_find_node_nodeid
(
&
priv
->
ip_node_list
,
srcid
);
if
(
!
node
)
{
HPSB_PRINT
(
KERN_ERR
,
"ether1394 rx: sender nodeid "
"lookup failure: "
NODE_BUS_FMT
,
NODE_BUS_ARGS
(
priv
->
host
,
srcid
));
priv
->
stats
.
rx_dropped
++
;
return
-
1
;
}
ud
=
node
->
ud
;
priv
=
(
struct
eth1394_priv
*
)
dev
->
priv
;
priv
->
ud_list
[
NODEID_TO_NODE
(
srcid
)]
=
ud
;
}
node_info
=
(
struct
eth1394_node_info
*
)
ud
->
device
.
driver_data
;
/* First, did we receive a fragmented or unfragmented datagram? */
hdr
->
words
.
word1
=
ntohs
(
hdr
->
words
.
word1
);
...
...
@@ -975,8 +1164,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
int
dg_size
;
int
dgl
;
int
retval
;
int
sid
=
NODEID_TO_NODE
(
srcid
);
struct
pdg_list
*
pdg
=
&
(
priv
->
pdg
[
sid
]);
struct
pdg_list
*
pdg
=
&
(
node_info
->
pdg
);
hdr
->
words
.
word3
=
ntohs
(
hdr
->
words
.
word3
);
/* The 4th header word is reserved so no need to do ntohs() */
...
...
@@ -1110,8 +1298,9 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
static
int
ether1394_write
(
struct
hpsb_host
*
host
,
int
srcid
,
int
destid
,
quadlet_t
*
data
,
u64
addr
,
size_t
len
,
u16
flags
)
{
struct
host_info
*
hi
=
hpsb_get_hostinfo
(
&
eth1394_highlevel
,
host
)
;
struct
eth1394_host_info
*
hi
;
hi
=
hpsb_get_hostinfo
(
&
eth1394_highlevel
,
host
);
if
(
hi
==
NULL
)
{
ETH1394_PRINT_G
(
KERN_ERR
,
"Could not find net device for host %s
\n
"
,
host
->
driver
->
name
);
...
...
@@ -1128,7 +1317,7 @@ static void ether1394_iso(struct hpsb_iso *iso)
{
quadlet_t
*
data
;
char
*
buf
;
struct
host_info
*
hi
=
hpsb_get_hostinfo
(
&
eth1394_highlevel
,
iso
->
host
)
;
struct
eth1394_host_info
*
hi
;
struct
net_device
*
dev
;
struct
eth1394_priv
*
priv
;
unsigned
int
len
;
...
...
@@ -1137,6 +1326,7 @@ static void ether1394_iso(struct hpsb_iso *iso)
int
i
;
int
nready
;
hi
=
hpsb_get_hostinfo
(
&
eth1394_highlevel
,
iso
->
host
);
if
(
hi
==
NULL
)
{
ETH1394_PRINT_G
(
KERN_ERR
,
"Could not find net device for host %s
\n
"
,
iso
->
host
->
driver
->
name
);
...
...
@@ -1193,7 +1383,6 @@ static inline void ether1394_arp_to_1394arp(struct sk_buff *skb,
struct
net_device
*
dev
)
{
struct
eth1394_priv
*
priv
=
(
struct
eth1394_priv
*
)(
dev
->
priv
);
u16
phy_id
=
NODEID_TO_NODE
(
priv
->
host
->
node_id
);
struct
arphdr
*
arp
=
(
struct
arphdr
*
)
skb
->
data
;
unsigned
char
*
arp_ptr
=
(
unsigned
char
*
)(
arp
+
1
);
...
...
@@ -1203,10 +1392,10 @@ static inline void ether1394_arp_to_1394arp(struct sk_buff *skb,
* and set hw_addr_len, max_rec, sspd, fifo_hi and fifo_lo. */
arp1394
->
hw_addr_len
=
16
;
arp1394
->
sip
=
*
(
u32
*
)(
arp_ptr
+
ETH1394_ALEN
);
arp1394
->
max_rec
=
(
be32_to_cpu
(
priv
->
host
->
csr
.
rom
[
2
])
>>
12
)
&
0xf
;
arp1394
->
sspd
=
priv
->
sspd
[
phy_id
]
;
arp1394
->
fifo_hi
=
htons
(
priv
->
fifo
[
phy_id
]
>>
32
);
arp1394
->
fifo_lo
=
htonl
(
priv
->
fifo
[
phy_id
]
&
~
0x0
);
arp1394
->
max_rec
=
priv
->
host
->
csr
.
max_rec
;
arp1394
->
sspd
=
priv
->
host
->
csr
.
lnk_spd
;
arp1394
->
fifo_hi
=
htons
(
priv
->
local_fifo
>>
32
);
arp1394
->
fifo_lo
=
htonl
(
priv
->
local_fifo
&
~
0x0
);
return
;
}
...
...
@@ -1333,15 +1522,15 @@ static inline void ether1394_prep_gasp_packet(struct hpsb_packet *p,
p
->
data_size
=
length
;
p
->
data
=
((
quadlet_t
*
)
skb
->
data
)
-
2
;
p
->
data
[
0
]
=
cpu_to_be32
((
priv
->
host
->
node_id
<<
16
)
|
ETHER1394_GASP_SPECIFIER_ID_HI
);
p
->
data
[
1
]
=
cpu_to_be32
((
ETHER1394_GASP_SPECIFIER_ID_LO
<<
24
)
|
ETHER1394_GASP_VERSION
);
ETHER1394_GASP_SPECIFIER_ID_HI
);
p
->
data
[
1
]
=
__constant_
cpu_to_be32
((
ETHER1394_GASP_SPECIFIER_ID_LO
<<
24
)
|
ETHER1394_GASP_VERSION
);
/* Setting the node id to ALL_NODES (not LOCAL_BUS | ALL_NODES)
* prevents hpsb_send_packet() from setting the speed to an arbitrary
* value based on packet->node_id if packet->node_id is not set. */
p
->
node_id
=
ALL_NODES
;
p
->
speed_code
=
priv
->
sspd
[
ALL_NODES
]
;
p
->
speed_code
=
priv
->
bc_sspd
;
}
static
inline
void
ether1394_free_packet
(
struct
hpsb_packet
*
packet
)
...
...
@@ -1458,7 +1647,8 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
u16
dg_size
;
u16
dgl
;
struct
packet_task
*
ptask
;
struct
node_entry
*
ne
;
struct
eth1394_node_ref
*
node
;
struct
eth1394_node_info
*
node_info
=
NULL
;
ptask
=
kmem_cache_alloc
(
packet_task_cache
,
kmflags
);
if
(
ptask
==
NULL
)
{
...
...
@@ -1466,22 +1656,11 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
goto
fail
;
}
spin_lock_irqsave
(
&
priv
->
lock
,
flags
);
if
(
priv
->
bc_state
==
ETHER1394_BC_CLOSED
)
{
ETH1394_PRINT
(
KERN_ERR
,
dev
->
name
,
"Cannot send packet, no broadcast channel available.
\n
"
);
if
((
priv
->
host
->
csr
.
broadcast_channel
&
0xc0000000
)
!=
0xc0000000
)
{
ret
=
-
EAGAIN
;
spin_unlock_irqrestore
(
&
priv
->
lock
,
flags
);
goto
fail
;
}
if
((
ret
=
ether1394_init_bc
(
dev
)))
{
spin_unlock_irqrestore
(
&
priv
->
lock
,
flags
);
goto
fail
;
}
spin_unlock_irqrestore
(
&
priv
->
lock
,
flags
);
if
((
skb
=
skb_share_check
(
skb
,
kmflags
))
==
NULL
)
{
ret
=
-
ENOMEM
;
goto
fail
;
...
...
@@ -1491,28 +1670,8 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
eth
=
(
struct
eth1394hdr
*
)
skb
->
data
;
skb_pull
(
skb
,
ETH1394_HLEN
);
ne
=
hpsb_guid_get_entry
(
be64_to_cpu
(
*
(
u64
*
)
eth
->
h_dest
));
if
(
!
ne
)
dest_node
=
LOCAL_BUS
|
ALL_NODES
;
else
dest_node
=
ne
->
nodeid
;
proto
=
eth
->
h_proto
;
/* If this is an ARP packet, convert it */
if
(
proto
==
__constant_htons
(
ETH_P_ARP
))
ether1394_arp_to_1394arp
(
skb
,
dev
);
max_payload
=
priv
->
maxpayload
[
NODEID_TO_NODE
(
dest_node
)];
/* This check should be unnecessary, but we'll keep it for safety for
* a while longer. */
if
(
max_payload
<
512
)
{
ETH1394_PRINT
(
KERN_WARNING
,
dev
->
name
,
"max_payload too small: %d (setting to 512)
\n
"
,
max_payload
);
max_payload
=
512
;
}
dg_size
=
skb
->
len
;
/* Set the transmission type for the packet. ARP packets and IP
* broadcast packets are sent via GASP. */
...
...
@@ -1521,18 +1680,38 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
(
proto
==
__constant_htons
(
ETH_P_IP
)
&&
IN_MULTICAST
(
__constant_ntohl
(
skb
->
nh
.
iph
->
daddr
))))
{
tx_type
=
ETH1394_GASP
;
max_payload
-=
ETHER1394_GASP_OVERHEAD
;
dest_node
=
LOCAL_BUS
|
ALL_NODES
;
max_payload
=
priv
->
bc_maxpayload
-
ETHER1394_GASP_OVERHEAD
;
BUG_ON
(
max_payload
<
(
512
-
ETHER1394_GASP_OVERHEAD
));
dgl
=
priv
->
bc_dgl
;
if
(
max_payload
<
dg_size
+
hdr_type_len
[
ETH1394_HDR_LF_UF
])
priv
->
bc_dgl
++
;
}
else
{
node
=
eth1394_find_node_guid
(
&
priv
->
ip_node_list
,
be64_to_cpu
(
*
(
u64
*
)
eth
->
h_dest
));
if
(
!
node
)
{
ret
=
-
EAGAIN
;
goto
fail
;
}
node_info
=
(
struct
eth1394_node_info
*
)
node
->
ud
->
device
.
driver_data
;
if
(
node_info
->
fifo
==
ETHER1394_INVALID_ADDR
)
{
ret
=
-
EAGAIN
;
goto
fail
;
}
dest_node
=
node
->
ud
->
ne
->
nodeid
;
max_payload
=
node_info
->
maxpayload
;
BUG_ON
(
max_payload
<
(
512
-
ETHER1394_GASP_OVERHEAD
));
dgl
=
node_info
->
dgl
;
if
(
max_payload
<
dg_size
+
hdr_type_len
[
ETH1394_HDR_LF_UF
])
node_info
->
dgl
++
;
tx_type
=
ETH1394_WRREQ
;
}
dg_size
=
skb
->
len
;
spin_lock_irqsave
(
&
priv
->
lock
,
flags
);
dgl
=
priv
->
dgl
[
NODEID_TO_NODE
(
dest_node
)];
if
(
max_payload
<
dg_size
+
hdr_type_len
[
ETH1394_HDR_LF_UF
])
priv
->
dgl
[
NODEID_TO_NODE
(
dest_node
)]
++
;
spin_unlock_irqrestore
(
&
priv
->
lock
,
flags
);
/* If this is an ARP packet, convert it */
if
(
proto
==
__constant_htons
(
ETH_P_ARP
))
ether1394_arp_to_1394arp
(
skb
,
dev
);
ptask
->
hdr
.
words
.
word1
=
0
;
ptask
->
hdr
.
words
.
word2
=
0
;
...
...
@@ -1545,17 +1724,8 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
if
(
tx_type
!=
ETH1394_GASP
)
{
u64
addr
;
/* This test is just temporary until ConfigROM support has
* been added to eth1394. Until then, we need an ARP packet
* after a bus reset from the current destination node so that
* we can get FIFO information. */
if
(
priv
->
fifo
[
NODEID_TO_NODE
(
dest_node
)]
==
0ULL
)
{
ret
=
-
EAGAIN
;
goto
fail
;
}
spin_lock_irqsave
(
&
priv
->
lock
,
flags
);
addr
=
priv
->
fifo
[
NODEID_TO_NODE
(
dest_node
)]
;
addr
=
node_info
->
fifo
;
spin_unlock_irqrestore
(
&
priv
->
lock
,
flags
);
ptask
->
addr
=
addr
;
...
...
@@ -1621,7 +1791,7 @@ static int ether1394_ethtool_ioctl(struct net_device *dev, void *useraddr)
case
ETHTOOL_GDRVINFO
:
{
struct
ethtool_drvinfo
info
=
{
ETHTOOL_GDRVINFO
};
strcpy
(
info
.
driver
,
driver_name
);
strcpy
(
info
.
version
,
"$Rev: 1
096
$"
);
strcpy
(
info
.
version
,
"$Rev: 1
133
$"
);
/* FIXME XXX provide sane businfo */
strcpy
(
info
.
bus_info
,
"ieee1394"
);
if
(
copy_to_user
(
useraddr
,
&
info
,
sizeof
(
info
)))
...
...
@@ -1644,19 +1814,78 @@ static int ether1394_ethtool_ioctl(struct net_device *dev, void *useraddr)
static
int
__init
ether1394_init_module
(
void
)
{
int
ret
;
struct
csr1212_keyval
*
spec_id
=
NULL
;
struct
csr1212_keyval
*
spec_desc
=
NULL
;
struct
csr1212_keyval
*
ver
=
NULL
;
struct
csr1212_keyval
*
ver_desc
=
NULL
;
packet_task_cache
=
kmem_cache_create
(
"packet_task"
,
sizeof
(
struct
packet_task
),
0
,
0
,
NULL
,
NULL
);
eth1394_ud
=
csr1212_new_directory
(
CSR1212_KV_ID_UNIT
);
spec_id
=
csr1212_new_immediate
(
CSR1212_KV_ID_SPECIFIER_ID
,
ETHER1394_GASP_SPECIFIER_ID
);
spec_desc
=
csr1212_new_string_descriptor_leaf
(
"IANA"
);
ver
=
csr1212_new_immediate
(
CSR1212_KV_ID_VERSION
,
ETHER1394_GASP_VERSION
);
ver_desc
=
csr1212_new_string_descriptor_leaf
(
"IPv4"
);
if
((
!
eth1394_ud
)
||
(
!
spec_id
)
||
(
!
spec_desc
)
||
(
!
ver
)
||
(
!
ver_desc
))
{
ret
=
-
ENOMEM
;
goto
out
;
}
ret
=
csr1212_associate_keyval
(
spec_id
,
spec_desc
);
if
(
ret
!=
CSR1212_SUCCESS
)
goto
out
;
ret
=
csr1212_associate_keyval
(
ver
,
ver_desc
);
if
(
ret
!=
CSR1212_SUCCESS
)
goto
out
;
ret
=
csr1212_attach_keyval_to_directory
(
eth1394_ud
,
spec_id
);
if
(
ret
!=
CSR1212_SUCCESS
)
goto
out
;
ret
=
csr1212_attach_keyval_to_directory
(
eth1394_ud
,
ver
);
if
(
ret
!=
CSR1212_SUCCESS
)
goto
out
;
/* Register ourselves as a highlevel driver */
hpsb_register_highlevel
(
&
eth1394_highlevel
);
return
0
;
ret
=
hpsb_register_protocol
(
&
eth1394_proto_driver
);
out:
if
((
ret
!=
0
)
&&
eth1394_ud
)
{
csr1212_release_keyval
(
eth1394_ud
);
}
if
(
spec_id
)
csr1212_release_keyval
(
spec_id
);
if
(
spec_desc
)
csr1212_release_keyval
(
spec_desc
);
if
(
ver
)
csr1212_release_keyval
(
ver
);
if
(
ver_desc
)
csr1212_release_keyval
(
ver_desc
);
return
ret
;
}
static
void
__exit
ether1394_exit_module
(
void
)
{
hpsb_unregister_protocol
(
&
eth1394_proto_driver
);
hpsb_unregister_highlevel
(
&
eth1394_highlevel
);
kmem_cache_destroy
(
packet_task_cache
);
if
(
eth1394_ud
)
{
csr1212_release_keyval
(
eth1394_ud
);
}
}
module_init
(
ether1394_init_module
);
...
...
drivers/ieee1394/eth1394.h
View file @
16eadb50
...
...
@@ -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 */
};
...
...
drivers/ieee1394/highlevel.c
View file @
16eadb50
...
...
@@ -20,6 +20,7 @@
#include <linux/config.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/bitops.h>
#include "ieee1394.h"
#include "ieee1394_types.h"
...
...
@@ -44,7 +45,6 @@ static DECLARE_RWSEM(hl_drivers_sem);
static
LIST_HEAD
(
hl_irqs
);
static
rwlock_t
hl_irqs_lock
=
RW_LOCK_UNLOCKED
;
static
LIST_HEAD
(
addr_space
);
static
rwlock_t
addr_space_lock
=
RW_LOCK_UNLOCKED
;
/* addr_space list will have zero and max already included as bounds */
...
...
@@ -56,21 +56,20 @@ static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
struct
hpsb_host
*
host
)
{
struct
hl_host_info
*
hi
=
NULL
;
struct
list_head
*
lh
;
if
(
!
hl
||
!
host
)
return
NULL
;
read_lock
(
&
hl
->
host_info_lock
);
list_for_each
(
lh
,
&
hl
->
host_info_
list
)
{
hi
=
list_entry
(
lh
,
struct
hl_host_info
,
list
);
if
(
hi
->
host
==
host
)
break
;
hi
=
NULL
;
list_for_each
_entry
(
hi
,
&
hl
->
host_info_list
,
list
)
{
if
(
hi
->
host
==
host
)
{
read_unlock
(
&
hl
->
host_info_lock
);
return
hi
;
}
}
read_unlock
(
&
hl
->
host_info_lock
);
return
hi
;
return
NULL
;
}
...
...
@@ -188,7 +187,6 @@ unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host
void
*
hpsb_get_hostinfo_bykey
(
struct
hpsb_highlevel
*
hl
,
unsigned
long
key
)
{
struct
list_head
*
lh
;
struct
hl_host_info
*
hi
;
void
*
data
=
NULL
;
...
...
@@ -196,8 +194,7 @@ void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
return
NULL
;
read_lock
(
&
hl
->
host_info_lock
);
list_for_each
(
lh
,
&
hl
->
host_info_list
)
{
hi
=
list_entry
(
lh
,
struct
hl_host_info
,
list
);
list_for_each_entry
(
hi
,
&
hl
->
host_info_list
,
list
)
{
if
(
hi
->
key
==
key
)
{
data
=
hi
->
data
;
break
;
...
...
@@ -211,7 +208,6 @@ void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
struct
hpsb_host
*
hpsb_get_host_bykey
(
struct
hpsb_highlevel
*
hl
,
unsigned
long
key
)
{
struct
list_head
*
lh
;
struct
hl_host_info
*
hi
;
struct
hpsb_host
*
host
=
NULL
;
...
...
@@ -219,8 +215,7 @@ struct hpsb_host *hpsb_get_host_bykey(struct hpsb_highlevel *hl, unsigned long k
return
NULL
;
read_lock
(
&
hl
->
host_info_lock
);
list_for_each
(
lh
,
&
hl
->
host_info_list
)
{
hi
=
list_entry
(
lh
,
struct
hl_host_info
,
list
);
list_for_each_entry
(
hi
,
&
hl
->
host_info_list
,
list
)
{
if
(
hi
->
key
==
key
)
{
host
=
hi
->
host
;
break
;
...
...
@@ -237,6 +232,13 @@ static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data)
hl
->
add_host
(
host
);
if
(
host
->
update_config_rom
)
{
if
(
hpsb_update_config_rom_image
(
host
)
<
0
)
{
HPSB_ERR
(
"Failed to generate Configuration ROM image for host "
"%s-%d"
,
hl
->
name
,
host
->
id
);
}
}
return
0
;
}
...
...
@@ -261,12 +263,20 @@ void hpsb_register_highlevel(struct hpsb_highlevel *hl)
return
;
}
static
void
__unregister_host
(
struct
hpsb_highlevel
*
hl
,
struct
hpsb_host
*
host
)
static
void
__delete_addr
(
struct
hpsb_address_serve
*
as
)
{
list_del
(
&
as
->
host_list
);
list_del
(
&
as
->
hl_list
);
kfree
(
as
);
}
static
void
__unregister_host
(
struct
hpsb_highlevel
*
hl
,
struct
hpsb_host
*
host
,
int
update_cr
)
{
unsigned
long
flags
;
struct
list_head
*
lh
,
*
next
;
struct
hpsb_address_serve
*
as
;
/* First, let the highlevel driver unreg */
if
(
hl
->
remove_host
)
hl
->
remove_host
(
host
);
...
...
@@ -274,19 +284,24 @@ static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host)
* and this particular host. */
write_lock_irqsave
(
&
addr_space_lock
,
flags
);
list_for_each_safe
(
lh
,
next
,
&
hl
->
addr_list
)
{
as
=
list_entry
(
lh
,
struct
hpsb_address_serve
,
addr
_list
);
as
=
list_entry
(
lh
,
struct
hpsb_address_serve
,
hl
_list
);
if
(
as
->
host
!=
host
)
continue
;
if
(
as
->
host
==
host
)
__delete_addr
(
as
);
}
write_unlock_irqrestore
(
&
addr_space_lock
,
flags
);
if
(
!
list_empty
(
&
as
->
addr_list
))
{
list_del
(
&
as
->
as_list
);
list_del
(
&
as
->
addr_list
);
kfree
(
as
);
/* Now update the config-rom to reflect anything removed by the
* highlevel driver. */
if
(
update_cr
&&
host
->
update_config_rom
)
{
if
(
hpsb_update_config_rom_image
(
host
)
<
0
)
{
HPSB_ERR
(
"Failed to generate Configuration ROM image for host "
"%s-%d"
,
hl
->
name
,
host
->
id
);
}
}
write_unlock_irqrestore
(
&
addr_space_lock
,
flags
);
/* And finally, remove all the host info associated between these
* two. */
hpsb_destroy_hostinfo
(
hl
,
host
);
}
...
...
@@ -294,7 +309,7 @@ static int highlevel_for_each_host_unreg(struct hpsb_host *host, void *__data)
{
struct
hpsb_highlevel
*
hl
=
__data
;
__unregister_host
(
hl
,
host
);
__unregister_host
(
hl
,
host
,
1
);
return
0
;
}
...
...
@@ -312,11 +327,86 @@ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
nodemgr_for_each_host
(
hl
,
highlevel_for_each_host_unreg
);
}
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
)
{
struct
hpsb_address_serve
*
as
,
*
a1
,
*
a2
;
struct
list_head
*
entry
;
u64
retval
=
~
0ULL
;
unsigned
long
flags
;
u64
align_mask
=
~
(
alignment
-
1
);
if
((
alignment
&
3
)
||
(
alignment
>
0x800000000000ULL
)
||
((
hweight32
(
alignment
>>
32
)
+
hweight32
(
alignment
&
0xffffffff
)
!=
1
)))
{
HPSB_ERR
(
"%s called with invalid alignment: 0x%048llx"
,
__FUNCTION__
,
(
unsigned
long
long
)
alignment
);
return
retval
;
}
if
(
start
==
~
0ULL
&&
end
==
~
0ULL
)
{
start
=
CSR1212_ALL_SPACE_BASE
+
0xffff00000000ULL
;
/* ohci1394.c limit */
end
=
CSR1212_ALL_SPACE_END
;
}
if
(((
start
|
end
)
&
~
align_mask
)
||
(
start
>=
end
)
||
(
end
>
0x1000000000000ULL
))
{
HPSB_ERR
(
"%s called with invalid addresses (start = %012Lx end = %012Lx)"
,
__FUNCTION__
,
(
unsigned
long
long
)
start
,
(
unsigned
long
long
)
end
);
return
retval
;
}
as
=
(
struct
hpsb_address_serve
*
)
kmalloc
(
sizeof
(
struct
hpsb_address_serve
),
GFP_KERNEL
);
if
(
as
==
NULL
)
{
return
retval
;
}
INIT_LIST_HEAD
(
&
as
->
host_list
);
INIT_LIST_HEAD
(
&
as
->
hl_list
);
as
->
op
=
ops
;
as
->
host
=
host
;
write_lock_irqsave
(
&
addr_space_lock
,
flags
);
list_for_each
(
entry
,
&
host
->
addr_space
)
{
u64
a1sa
,
a1ea
;
u64
a2sa
,
a2ea
;
a1
=
list_entry
(
entry
,
struct
hpsb_address_serve
,
host_list
);
a2
=
list_entry
(
entry
->
next
,
struct
hpsb_address_serve
,
host_list
);
a1sa
=
a1
->
start
&
align_mask
;
a1ea
=
(
a1
->
end
+
alignment
-
1
)
&
align_mask
;
a2sa
=
a2
->
start
&
align_mask
;
a2ea
=
(
a2
->
end
+
alignment
-
1
)
&
align_mask
;
if
((
a2sa
-
a1ea
>=
size
)
&&
(
a2sa
-
start
>=
size
)
&&
(
end
-
a1ea
>=
size
))
{
as
->
start
=
max
(
start
,
a1ea
);
as
->
end
=
as
->
start
+
size
;
list_add
(
&
as
->
host_list
,
entry
);
list_add_tail
(
&
as
->
hl_list
,
&
hl
->
addr_list
);
retval
=
as
->
start
;
break
;
}
}
write_unlock_irqrestore
(
&
addr_space_lock
,
flags
);
if
(
retval
==
~
0ULL
)
{
kfree
(
as
);
}
return
retval
;
}
int
hpsb_register_addrspace
(
struct
hpsb_highlevel
*
hl
,
struct
hpsb_host
*
host
,
struct
hpsb_address_ops
*
ops
,
u64
start
,
u64
end
)
{
struct
hpsb_address_serve
*
as
;
struct
list_head
*
entry
;
struct
list_head
*
lh
;
int
retval
=
0
;
unsigned
long
flags
;
...
...
@@ -331,31 +421,35 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
return
0
;
}
INIT_LIST_HEAD
(
&
as
->
as
_list
);
INIT_LIST_HEAD
(
&
as
->
addr
_list
);
INIT_LIST_HEAD
(
&
as
->
host
_list
);
INIT_LIST_HEAD
(
&
as
->
hl
_list
);
as
->
op
=
ops
;
as
->
start
=
start
;
as
->
end
=
end
;
as
->
host
=
host
;
write_lock_irqsave
(
&
addr_space_lock
,
flags
);
entry
=
host
->
addr_space
.
next
;
while
(
list_entry
(
entry
,
struct
hpsb_address_serve
,
as_list
)
->
end
<=
start
)
{
if
(
list_entry
(
entry
->
next
,
struct
hpsb_address_serve
,
as_list
)
->
start
>=
end
)
{
list_add
(
&
as
->
as_list
,
entry
);
list_add_tail
(
&
as
->
addr_list
,
&
hl
->
addr_list
);
retval
=
1
;
break
;
}
entry
=
entry
->
next
;
}
write_unlock_irqrestore
(
&
addr_space_lock
,
flags
);
write_lock_irqsave
(
&
addr_space_lock
,
flags
);
if
(
retval
==
0
)
{
kfree
(
as
);
}
list_for_each
(
lh
,
&
host
->
addr_space
)
{
struct
hpsb_address_serve
*
as_this
=
list_entry
(
lh
,
struct
hpsb_address_serve
,
host_list
);
struct
hpsb_address_serve
*
as_next
=
list_entry
(
lh
->
next
,
struct
hpsb_address_serve
,
host_list
);
if
(
as_this
->
end
>
as
->
start
)
break
;
if
(
as_next
->
start
>=
as
->
end
)
{
list_add
(
&
as
->
host_list
,
lh
);
list_add_tail
(
&
as
->
hl_list
,
&
hl
->
addr_list
);
retval
=
1
;
break
;
}
}
write_unlock_irqrestore
(
&
addr_space_lock
,
flags
);
if
(
retval
==
0
)
kfree
(
as
);
return
retval
;
}
...
...
@@ -365,20 +459,15 @@ int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
{
int
retval
=
0
;
struct
hpsb_address_serve
*
as
;
struct
list_head
*
entry
;
struct
list_head
*
lh
,
*
next
;
unsigned
long
flags
;
write_lock_irqsave
(
&
addr_space_lock
,
flags
);
entry
=
hl
->
addr_list
.
next
;
while
(
entry
!=
&
hl
->
addr_list
)
{
as
=
list_entry
(
entry
,
struct
hpsb_address_serve
,
addr_list
);
entry
=
entry
->
next
;
list_for_each_safe
(
lh
,
next
,
&
hl
->
addr_list
)
{
as
=
list_entry
(
lh
,
struct
hpsb_address_serve
,
hl_list
);
if
(
as
->
start
==
start
&&
as
->
host
==
host
)
{
list_del
(
&
as
->
as_list
);
list_del
(
&
as
->
addr_list
);
kfree
(
as
);
__delete_addr
(
as
);
retval
=
1
;
break
;
}
...
...
@@ -419,18 +508,18 @@ void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
static
void
init_hpsb_highlevel
(
struct
hpsb_host
*
host
)
{
INIT_LIST_HEAD
(
&
dummy_zero_addr
.
as
_list
);
INIT_LIST_HEAD
(
&
dummy_zero_addr
.
addr
_list
);
INIT_LIST_HEAD
(
&
dummy_max_addr
.
as
_list
);
INIT_LIST_HEAD
(
&
dummy_max_addr
.
addr
_list
);
INIT_LIST_HEAD
(
&
dummy_zero_addr
.
host
_list
);
INIT_LIST_HEAD
(
&
dummy_zero_addr
.
hl
_list
);
INIT_LIST_HEAD
(
&
dummy_max_addr
.
host
_list
);
INIT_LIST_HEAD
(
&
dummy_max_addr
.
hl
_list
);
dummy_zero_addr
.
op
=
dummy_max_addr
.
op
=
&
dummy_ops
;
dummy_zero_addr
.
start
=
dummy_zero_addr
.
end
=
0
;
dummy_max_addr
.
start
=
dummy_max_addr
.
end
=
((
u64
)
1
)
<<
48
;
list_add_tail
(
&
dummy_zero_addr
.
as
_list
,
&
host
->
addr_space
);
list_add_tail
(
&
dummy_max_addr
.
as
_list
,
&
host
->
addr_space
);
list_add_tail
(
&
dummy_zero_addr
.
host
_list
,
&
host
->
addr_space
);
list_add_tail
(
&
dummy_max_addr
.
host
_list
,
&
host
->
addr_space
);
}
void
highlevel_add_host
(
struct
hpsb_host
*
host
)
...
...
@@ -445,6 +534,11 @@ void highlevel_add_host(struct hpsb_host *host)
hl
->
add_host
(
host
);
}
up_read
(
&
hl_drivers_sem
);
if
(
host
->
update_config_rom
)
{
if
(
hpsb_update_config_rom_image
(
host
)
<
0
)
HPSB_ERR
(
"Failed to generate Configuration ROM image for "
"host %s-%d"
,
hl
->
name
,
host
->
id
);
}
}
void
highlevel_remove_host
(
struct
hpsb_host
*
host
)
...
...
@@ -453,7 +547,7 @@ void highlevel_remove_host(struct hpsb_host *host)
down_read
(
&
hl_drivers_sem
);
list_for_each_entry
(
hl
,
&
hl_drivers
,
hl_list
)
__unregister_host
(
hl
,
host
);
__unregister_host
(
hl
,
host
,
0
);
up_read
(
&
hl_drivers_sem
);
}
...
...
@@ -501,16 +595,15 @@ int highlevel_read(struct hpsb_host *host, int nodeid, void *data,
u64
addr
,
unsigned
int
length
,
u16
flags
)
{
struct
hpsb_address_serve
*
as
;
struct
list_head
*
entry
;
unsigned
int
partlength
;
int
rcode
=
RCODE_ADDRESS_ERROR
;
read_lock
(
&
addr_space_lock
);
entry
=
host
->
addr_space
.
next
;
as
=
list_entry
(
entry
,
struct
hpsb_address_serve
,
as_list
);
list_for_each_entry
(
as
,
&
host
->
addr_space
,
host_list
)
{
if
(
as
->
start
>
addr
)
break
;
while
(
as
->
start
<=
addr
)
{
if
(
as
->
end
>
addr
)
{
partlength
=
min
(
as
->
end
-
addr
,
(
u64
)
length
);
...
...
@@ -529,9 +622,6 @@ int highlevel_read(struct hpsb_host *host, int nodeid, void *data,
break
;
}
}
entry
=
entry
->
next
;
as
=
list_entry
(
entry
,
struct
hpsb_address_serve
,
as_list
);
}
read_unlock
(
&
addr_space_lock
);
...
...
@@ -547,16 +637,15 @@ int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
void
*
data
,
u64
addr
,
unsigned
int
length
,
u16
flags
)
{
struct
hpsb_address_serve
*
as
;
struct
list_head
*
entry
;
unsigned
int
partlength
;
int
rcode
=
RCODE_ADDRESS_ERROR
;
read_lock
(
&
addr_space_lock
);
entry
=
host
->
addr_space
.
next
;
as
=
list_entry
(
entry
,
struct
hpsb_address_serve
,
as_list
);
list_for_each_entry
(
as
,
&
host
->
addr_space
,
host_list
)
{
if
(
as
->
start
>
addr
)
break
;
while
(
as
->
start
<=
addr
)
{
if
(
as
->
end
>
addr
)
{
partlength
=
min
(
as
->
end
-
addr
,
(
u64
)
length
);
...
...
@@ -575,9 +664,6 @@ int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
break
;
}
}
entry
=
entry
->
next
;
as
=
list_entry
(
entry
,
struct
hpsb_address_serve
,
as_list
);
}
read_unlock
(
&
addr_space_lock
);
...
...
@@ -594,15 +680,14 @@ int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
u64
addr
,
quadlet_t
data
,
quadlet_t
arg
,
int
ext_tcode
,
u16
flags
)
{
struct
hpsb_address_serve
*
as
;
struct
list_head
*
entry
;
int
rcode
=
RCODE_ADDRESS_ERROR
;
read_lock
(
&
addr_space_lock
);
entry
=
host
->
addr_space
.
next
;
as
=
list_entry
(
entry
,
struct
hpsb_address_serve
,
as_list
);
list_for_each_entry
(
as
,
&
host
->
addr_space
,
host_list
)
{
if
(
as
->
start
>
addr
)
break
;
while
(
as
->
start
<=
addr
)
{
if
(
as
->
end
>
addr
)
{
if
(
as
->
op
->
lock
)
{
rcode
=
as
->
op
->
lock
(
host
,
nodeid
,
store
,
addr
,
...
...
@@ -613,9 +698,6 @@ int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
break
;
}
entry
=
entry
->
next
;
as
=
list_entry
(
entry
,
struct
hpsb_address_serve
,
as_list
);
}
read_unlock
(
&
addr_space_lock
);
...
...
@@ -627,15 +709,14 @@ int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
u64
addr
,
octlet_t
data
,
octlet_t
arg
,
int
ext_tcode
,
u16
flags
)
{
struct
hpsb_address_serve
*
as
;
struct
list_head
*
entry
;
int
rcode
=
RCODE_ADDRESS_ERROR
;
read_lock
(
&
addr_space_lock
);
entry
=
host
->
addr_space
.
next
;
as
=
list_entry
(
entry
,
struct
hpsb_address_serve
,
as_list
);
list_for_each_entry
(
as
,
&
host
->
addr_space
,
host_list
)
{
if
(
as
->
start
>
addr
)
break
;
while
(
as
->
start
<=
addr
)
{
if
(
as
->
end
>
addr
)
{
if
(
as
->
op
->
lock64
)
{
rcode
=
as
->
op
->
lock64
(
host
,
nodeid
,
store
,
...
...
@@ -647,9 +728,6 @@ int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
break
;
}
entry
=
entry
->
next
;
as
=
list_entry
(
entry
,
struct
hpsb_address_serve
,
as_list
);
}
read_unlock
(
&
addr_space_lock
);
...
...
drivers/ieee1394/highlevel.h
View file @
16eadb50
...
...
@@ -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
);
...
...
drivers/ieee1394/hosts.c
View file @
16eadb50
...
...
@@ -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
;
}
drivers/ieee1394/hosts.h
View file @
16eadb50
...
...
@@ -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 */
drivers/ieee1394/ieee1394_core.c
View file @
16eadb50
...
...
@@ -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
);
drivers/ieee1394/ieee1394_core.h
View file @
16eadb50
...
...
@@ -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 */
drivers/ieee1394/nodemgr.c
View file @
16eadb50
...
...
@@ -18,6 +18,7 @@
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/moduleparam.h>
#include <asm/atomic.h>
#include "ieee1394_types.h"
...
...
@@ -28,6 +29,15 @@
#include "csr.h"
#include "nodemgr.h"
static
int
ignore_drivers
=
0
;
module_param
(
ignore_drivers
,
int
,
0444
);
MODULE_PARM_DESC
(
ignore_drivers
,
"Disable automatic probing for drivers."
);
struct
nodemgr_csr_info
{
struct
hpsb_host
*
host
;
nodeid_t
nodeid
;
unsigned
int
generation
;
};
static
char
*
nodemgr_find_oui_name
(
int
oui
)
...
...
@@ -47,6 +57,37 @@ static char *nodemgr_find_oui_name(int oui)
}
static
int
nodemgr_bus_read
(
struct
csr1212_csr
*
csr
,
u64
addr
,
u16
length
,
void
*
buffer
,
void
*
__ci
)
{
struct
nodemgr_csr_info
*
ci
=
(
struct
nodemgr_csr_info
*
)
__ci
;
int
i
,
ret
=
0
;
for
(
i
=
0
;
i
<
3
;
i
++
)
{
ret
=
hpsb_read
(
ci
->
host
,
ci
->
nodeid
,
ci
->
generation
,
addr
,
buffer
,
length
);
if
(
!
ret
)
break
;
set_current_state
(
TASK_INTERRUPTIBLE
);
if
(
schedule_timeout
(
HZ
/
3
))
return
-
EINTR
;
}
return
ret
;
}
static
int
nodemgr_get_max_rom
(
quadlet_t
*
bus_info_data
,
void
*
__ci
)
{
return
(
bus_info_data
[
2
]
>>
8
)
&
0x3
;
}
static
struct
csr1212_bus_ops
nodemgr_csr_ops
=
{
.
bus_read
=
nodemgr_bus_read
,
.
get_max_rom
=
nodemgr_get_max_rom
};
/*
* Basically what we do here is start off retrieving the bus_info block.
* From there will fill in some info about the node, verify it is of IEEE
...
...
@@ -69,7 +110,6 @@ static char *nodemgr_find_oui_name(int oui)
static
DECLARE_MUTEX
(
nodemgr_serialize
);
struct
host_info
{
struct
hpsb_host
*
host
;
struct
list_head
list
;
...
...
@@ -79,19 +119,108 @@ struct host_info {
char
daemon_name
[
15
];
};
static
int
nodemgr_bus_match
(
struct
device
*
dev
,
struct
device_driver
*
drv
);
static
int
nodemgr_hotplug
(
struct
device
*
dev
,
char
**
envp
,
int
num_envp
,
char
*
buffer
,
int
buffer_size
);
static
void
nodemgr_resume_ne
(
struct
node_entry
*
ne
);
static
void
nodemgr_remove_ne
(
struct
node_entry
*
ne
);
static
struct
node_entry
*
find_entry_by_guid
(
u64
guid
);
struct
bus_type
ieee1394_bus_type
=
{
.
name
=
"ieee1394"
,
.
match
=
nodemgr_bus_match
,
.
hotplug
=
nodemgr_hotplug
,
};
static
void
host_cls_release
(
struct
class_device
*
class_dev
)
{
put_device
(
&
container_of
((
class_dev
),
struct
hpsb_host
,
class_dev
)
->
device
);
}
struct
class
hpsb_host_class
=
{
.
name
=
"ieee1394_host"
,
.
release
=
host_cls_release
,
};
static
void
ne_cls_release
(
struct
class_device
*
class_dev
)
{
put_device
(
&
container_of
((
class_dev
),
struct
node_entry
,
class_dev
)
->
device
);
}
struct
class
nodemgr_ne_class
=
{
.
name
=
"ieee1394_node"
,
.
release
=
ne_cls_release
,
};
static
struct
hpsb_highlevel
nodemgr_highlevel
;
static
int
nodemgr_driverdata_ne
;
static
int
nodemgr_driverdata_host
;
static
int
nodemgr_platform_data_ud
;
static
int
nodemgr_generic_probe
(
struct
device
*
dev
)
{
return
-
ENODEV
;
}
static
struct
device_driver
nodemgr_driver_ne
=
{
.
name
=
"ieee1394_node"
,
.
bus
=
&
ieee1394_bus_type
,
.
probe
=
nodemgr_generic_probe
,
};
static
struct
device_driver
nodemgr_driver_host
=
{
.
name
=
"ieee1394_host"
,
.
bus
=
&
ieee1394_bus_type
,
.
probe
=
nodemgr_generic_probe
,
};
static
void
nodemgr_release_ud
(
struct
device
*
dev
)
{
struct
unit_directory
*
ud
=
container_of
(
dev
,
struct
unit_directory
,
device
);
if
(
ud
->
vendor_name_kv
)
csr1212_release_keyval
(
ud
->
vendor_name_kv
);
if
(
ud
->
model_name_kv
)
csr1212_release_keyval
(
ud
->
model_name_kv
);
kfree
(
ud
);
}
static
void
nodemgr_release_ne
(
struct
device
*
dev
)
{
struct
node_entry
*
ne
=
container_of
(
dev
,
struct
node_entry
,
device
);
if
(
ne
->
vendor_name_kv
)
csr1212_release_keyval
(
ne
->
vendor_name_kv
);
kfree
(
ne
);
}
static
void
nodemgr_release_host
(
struct
device
*
dev
)
{
struct
hpsb_host
*
host
=
container_of
(
dev
,
struct
hpsb_host
,
device
);
csr1212_destroy_csr
(
host
->
csr
.
rom
);
kfree
(
host
);
}
static
struct
device
nodemgr_dev_template_ud
=
{
.
bus
=
&
ieee1394_bus_type
,
.
release
=
nodemgr_release_ud
,
.
platform_data
=
&
nodemgr_platform_data_ud
,
};
static
struct
device
nodemgr_dev_template_ne
=
{
.
bus
=
&
ieee1394_bus_type
,
.
release
=
nodemgr_release_ne
,
.
driver
=
&
nodemgr_driver_ne
,
};
struct
device
nodemgr_dev_template_host
=
{
.
bus
=
&
ieee1394_bus_type
,
.
release
=
nodemgr_release_host
,
.
driver
=
&
nodemgr_driver_host
,
};
...
...
@@ -107,6 +236,26 @@ static struct device_attribute dev_attr_##class##_##field = { \
.show = fw_show_##class##_##field, \
};
#define fw_attr_td(class, class_type, td_kv) \
static ssize_t fw_show_##class##_##td_kv (struct device *dev, char *buf)\
{ \
int len; \
class_type *class = container_of(dev, class_type, device); \
len = (class->td_kv->value.leaf.len - 2) * sizeof(quadlet_t); \
memcpy(buf, \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(class->td_kv), \
len); \
while ((buf + len - 1) == '\0') \
len--; \
buf[len++] = '\n'; \
buf[len] = '\0'; \
return len; \
} \
static struct device_attribute dev_attr_##class##_##td_kv = { \
.attr = {.name = __stringify(td_kv), .mode = S_IRUGO }, \
.show = fw_show_##class##_##td_kv, \
};
#define fw_drv_attr(field, type, format_string) \
static ssize_t fw_drv_show_##field (struct device_driver *drv, char *buf) \
...
...
@@ -126,10 +275,13 @@ static ssize_t fw_show_ne_bus_options(struct device *dev, char *buf)
struct
node_entry
*
ne
=
container_of
(
dev
,
struct
node_entry
,
device
);
return
sprintf
(
buf
,
"IRMC(%d) CMC(%d) ISC(%d) BMC(%d) PMC(%d) GEN(%d) "
"LSPD(%d) MAX_REC(%d) CYC_CLK_ACC(%d)
\n
"
,
ne
->
busopt
.
irmc
,
ne
->
busopt
.
cmc
,
ne
->
busopt
.
isc
,
ne
->
busopt
.
bmc
,
ne
->
busopt
.
pmc
,
ne
->
busopt
.
generation
,
ne
->
busopt
.
lnkspd
,
ne
->
busopt
.
max_rec
,
ne
->
busopt
.
cyc_clk_acc
);
"LSPD(%d) MAX_REC(%d) MAX_ROM(%d) CYC_CLK_ACC(%d)
\n
"
,
ne
->
busopt
.
irmc
,
ne
->
busopt
.
cmc
,
ne
->
busopt
.
isc
,
ne
->
busopt
.
bmc
,
ne
->
busopt
.
pmc
,
ne
->
busopt
.
generation
,
ne
->
busopt
.
lnkspd
,
ne
->
busopt
.
max_rec
,
ne
->
busopt
.
max_rom
,
ne
->
busopt
.
cyc_clk_acc
);
}
static
DEVICE_ATTR
(
bus_options
,
S_IRUGO
,
fw_show_ne_bus_options
,
NULL
);
...
...
@@ -159,19 +311,121 @@ static ssize_t fw_show_ne_tlabels_mask(struct device *dev, char *buf)
return
sprintf
(
buf
,
"0x%016lx
\n
"
,
ne
->
tpool
->
pool
[
0
]);
#endif
}
static
DEVICE_ATTR
(
tlabels_mask
,
S_IRUGO
,
fw_show_ne_tlabels_mask
,
NULL
);
static
DEVICE_ATTR
(
tlabels_mask
,
S_IRUGO
,
fw_show_ne_tlabels_mask
,
NULL
);
static
ssize_t
fw_set_ignore_driver
(
struct
device
*
dev
,
const
char
*
buf
,
size_t
count
)
{
struct
unit_directory
*
ud
=
container_of
(
dev
,
struct
unit_directory
,
device
);
int
state
=
simple_strtoul
(
buf
,
NULL
,
10
);
if
(
state
==
1
)
{
down_write
(
&
dev
->
bus
->
subsys
.
rwsem
);
device_release_driver
(
dev
);
ud
->
ignore_driver
=
1
;
up_write
(
&
dev
->
bus
->
subsys
.
rwsem
);
}
else
if
(
!
state
)
ud
->
ignore_driver
=
0
;
return
count
;
}
static
ssize_t
fw_get_ignore_driver
(
struct
device
*
dev
,
char
*
buf
)
{
struct
unit_directory
*
ud
=
container_of
(
dev
,
struct
unit_directory
,
device
);
return
sprintf
(
buf
,
"%d
\n
"
,
ud
->
ignore_driver
);
}
static
DEVICE_ATTR
(
ignore_driver
,
S_IWUSR
|
S_IRUGO
,
fw_get_ignore_driver
,
fw_set_ignore_driver
);
static
ssize_t
fw_set_destroy_node
(
struct
bus_type
*
bus
,
const
char
*
buf
,
size_t
count
)
{
struct
node_entry
*
ne
;
u64
guid
=
(
u64
)
simple_strtoull
(
buf
,
NULL
,
16
);
ne
=
find_entry_by_guid
(
guid
);
if
(
ne
==
NULL
||
!
ne
->
in_limbo
)
return
-
EINVAL
;
nodemgr_remove_ne
(
ne
);
return
count
;
}
static
ssize_t
fw_get_destroy_node
(
struct
bus_type
*
bus
,
char
*
buf
)
{
return
sprintf
(
buf
,
"You can destroy in_limbo nodes by writing their GUID to this file
\n
"
);
}
static
BUS_ATTR
(
destroy_node
,
S_IWUSR
|
S_IRUGO
,
fw_get_destroy_node
,
fw_set_destroy_node
);
static
int
nodemgr_rescan_bus_thread
(
void
*
__unused
)
{
/* No userlevel access needed */
daemonize
(
"kfwrescan"
);
allow_signal
(
SIGTERM
);
bus_rescan_devices
(
&
ieee1394_bus_type
);
return
0
;
}
static
ssize_t
fw_set_rescan
(
struct
bus_type
*
bus
,
const
char
*
buf
,
size_t
count
)
{
int
state
=
simple_strtoul
(
buf
,
NULL
,
10
);
/* Don't wait for this, or care about errors. Root could do
* something stupid and spawn this a lot of times, but that's
* root's fault. */
if
(
state
==
1
)
kernel_thread
(
nodemgr_rescan_bus_thread
,
NULL
,
CLONE_KERNEL
);
return
count
;
}
static
ssize_t
fw_get_rescan
(
struct
bus_type
*
bus
,
char
*
buf
)
{
return
sprintf
(
buf
,
"You can force a rescan of the bus for "
"drivers by writing a 1 to this file
\n
"
);
}
static
BUS_ATTR
(
rescan
,
S_IWUSR
|
S_IRUGO
,
fw_get_rescan
,
fw_set_rescan
);
static
ssize_t
fw_set_ignore_drivers
(
struct
bus_type
*
bus
,
const
char
*
buf
,
size_t
count
)
{
int
state
=
simple_strtoul
(
buf
,
NULL
,
10
);
if
(
state
==
1
)
ignore_drivers
=
1
;
else
if
(
!
state
)
ignore_drivers
=
0
;
return
count
;
}
static
ssize_t
fw_get_ignore_drivers
(
struct
bus_type
*
bus
,
char
*
buf
)
{
return
sprintf
(
buf
,
"%d
\n
"
,
ignore_drivers
);
}
static
BUS_ATTR
(
ignore_drivers
,
S_IWUSR
|
S_IRUGO
,
fw_get_ignore_drivers
,
fw_set_ignore_drivers
);
struct
bus_attribute
*
const
fw_bus_attrs
[]
=
{
&
bus_attr_destroy_node
,
&
bus_attr_rescan
,
&
bus_attr_ignore_drivers
,
NULL
};
fw_attr
(
ne
,
struct
node_entry
,
capabilities
,
unsigned
int
,
"0x%06x
\n
"
)
fw_attr
(
ne
,
struct
node_entry
,
nodeid
,
unsigned
int
,
"0x%04x
\n
"
)
fw_attr
(
ne
,
struct
node_entry
,
vendor_id
,
unsigned
int
,
"0x%06x
\n
"
)
fw_attr
(
ne
,
struct
node_entry
,
vendor_name
,
const
char
*
,
"%s
\n
"
)
fw_attr
_td
(
ne
,
struct
node_entry
,
vendor_name_kv
)
fw_attr
(
ne
,
struct
node_entry
,
vendor_oui
,
const
char
*
,
"%s
\n
"
)
fw_attr
(
ne
,
struct
node_entry
,
guid
,
unsigned
long
long
,
"0x%016Lx
\n
"
)
fw_attr
(
ne
,
struct
node_entry
,
guid_vendor_id
,
unsigned
int
,
"0x%06x
\n
"
)
fw_attr
(
ne
,
struct
node_entry
,
guid_vendor_oui
,
const
char
*
,
"%s
\n
"
)
fw_attr
(
ne
,
struct
node_entry
,
in_limbo
,
int
,
"%d
\n
"
);
static
struct
device_attribute
*
const
fw_ne_attrs
[]
=
{
&
dev_attr_ne_guid
,
...
...
@@ -194,13 +448,14 @@ fw_attr(ud, struct unit_directory, vendor_id, unsigned int, "0x%06x\n")
fw_attr
(
ud
,
struct
unit_directory
,
model_id
,
unsigned
int
,
"0x%06x
\n
"
)
fw_attr
(
ud
,
struct
unit_directory
,
specifier_id
,
unsigned
int
,
"0x%06x
\n
"
)
fw_attr
(
ud
,
struct
unit_directory
,
version
,
unsigned
int
,
"0x%06x
\n
"
)
fw_attr
(
ud
,
struct
unit_directory
,
vendor_name
,
const
char
*
,
"%s
\n
"
)
fw_attr
_td
(
ud
,
struct
unit_directory
,
vendor_name_kv
)
fw_attr
(
ud
,
struct
unit_directory
,
vendor_oui
,
const
char
*
,
"%s
\n
"
)
fw_attr
(
ud
,
struct
unit_directory
,
model_name
,
const
char
*
,
"%s
\n
"
)
fw_attr
_td
(
ud
,
struct
unit_directory
,
model_name_kv
)
static
struct
device_attribute
*
const
fw_ud_attrs
[]
=
{
&
dev_attr_ud_address
,
&
dev_attr_ud_length
,
&
dev_attr_ignore_driver
,
};
...
...
@@ -358,14 +613,14 @@ static void nodemgr_create_ud_dev_files(struct unit_directory *ud)
if
(
ud
->
flags
&
UNIT_DIRECTORY_VENDOR_ID
)
{
device_create_file
(
dev
,
&
dev_attr_ud_vendor_id
);
if
(
ud
->
flags
&
UNIT_DIRECTORY_VENDOR_TEXT
)
device_create_file
(
dev
,
&
dev_attr_ud_vendor_name
);
if
(
ud
->
vendor_name_kv
)
device_create_file
(
dev
,
&
dev_attr_ud_vendor_name
_kv
);
}
if
(
ud
->
flags
&
UNIT_DIRECTORY_MODEL_ID
)
{
device_create_file
(
dev
,
&
dev_attr_ud_model_id
);
if
(
ud
->
flags
&
UNIT_DIRECTORY_MODEL_TEXT
)
device_create_file
(
dev
,
&
dev_attr_ud_model_name
);
if
(
ud
->
model_name_kv
)
device_create_file
(
dev
,
&
dev_attr_ud_model_name
_kv
);
}
}
...
...
@@ -376,14 +631,17 @@ static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
struct
unit_directory
*
ud
;
struct
ieee1394_device_id
*
id
;
if
(
dev
->
driver_data
==
&
nodemgr_driverdata_ne
||
dev
->
driver_data
==
&
nodemgr_driverdata_host
||
drv
==
&
nodemgr_driver_ne
||
drv
==
&
nodemgr_driver_host
)
/* We only match unit directories, and ignore our internal drivers */
if
(
dev
->
platform_data
!=
&
nodemgr_platform_data_ud
||
drv
->
probe
==
nodemgr_generic_probe
)
return
0
;
ud
=
container_of
(
dev
,
struct
unit_directory
,
device
);
driver
=
container_of
(
drv
,
struct
hpsb_protocol_driver
,
driver
);
if
(
ud
->
ne
->
in_limbo
||
ud
->
ignore_driver
)
return
0
;
for
(
id
=
driver
->
id_table
;
id
->
match_flags
!=
0
;
id
++
)
{
if
((
id
->
match_flags
&
IEEE1394_MATCH_VENDOR_ID
)
&&
id
->
vendor_id
!=
ud
->
vendor_id
)
...
...
@@ -408,24 +666,6 @@ static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
}
static
void
nodemgr_release_ud
(
struct
device
*
dev
)
{
kfree
(
container_of
(
dev
,
struct
unit_directory
,
device
));
}
static
void
nodemgr_release_ne
(
struct
device
*
dev
)
{
kfree
(
container_of
(
dev
,
struct
node_entry
,
device
));
}
static
void
nodemgr_release_host
(
struct
device
*
dev
)
{
kfree
(
container_of
(
dev
,
struct
hpsb_host
,
device
));
}
static
void
nodemgr_remove_ud
(
struct
unit_directory
*
ud
)
{
struct
device
*
dev
=
&
ud
->
device
;
...
...
@@ -444,10 +684,10 @@ static void nodemgr_remove_ud(struct unit_directory *ud)
device_remove_file
(
dev
,
&
dev_attr_ud_specifier_id
);
device_remove_file
(
dev
,
&
dev_attr_ud_version
);
device_remove_file
(
dev
,
&
dev_attr_ud_vendor_id
);
device_remove_file
(
dev
,
&
dev_attr_ud_vendor_name
);
device_remove_file
(
dev
,
&
dev_attr_ud_vendor_name
_kv
);
device_remove_file
(
dev
,
&
dev_attr_ud_vendor_oui
);
device_remove_file
(
dev
,
&
dev_attr_ud_model_id
);
device_remove_file
(
dev
,
&
dev_attr_ud_model_name
);
device_remove_file
(
dev
,
&
dev_attr_ud_model_name
_kv
);
device_unregister
(
dev
);
}
...
...
@@ -470,15 +710,20 @@ static void nodemgr_remove_ne(struct node_entry *ne)
struct
device
*
dev
=
&
ne
->
device
;
int
i
;
HPSB_DEBUG
(
"Node removed: ID:BUS["
NODE_BUS_FMT
"] GUID[%016Lx]"
,
NODE_BUS_ARGS
(
ne
->
host
,
ne
->
nodeid
),
(
unsigned
long
long
)
ne
->
guid
);
nodemgr_remove_node_uds
(
ne
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
fw_ne_attrs
);
i
++
)
device_remove_file
(
dev
,
fw_ne_attrs
[
i
]);
device_remove_file
(
dev
,
&
dev_attr_ne_guid_vendor_oui
);
device_remove_file
(
dev
,
&
dev_attr_ne_vendor_name
);
device_remove_file
(
dev
,
&
dev_attr_ne_vendor_name
_kv
);
device_remove_file
(
dev
,
&
dev_attr_ne_vendor_oui
);
device_remove_file
(
dev
,
&
dev_attr_ne_in_limbo
);
class_device_unregister
(
&
ne
->
class_dev
);
device_unregister
(
dev
);
}
...
...
@@ -503,188 +748,13 @@ static void nodemgr_remove_host_dev(struct device *dev)
}
static
struct
device
nodemgr_dev_template_ud
=
{
.
bus
=
&
ieee1394_bus_type
,
.
release
=
nodemgr_release_ud
,
};
static
struct
device
nodemgr_dev_template_ne
=
{
.
bus
=
&
ieee1394_bus_type
,
.
release
=
nodemgr_release_ne
,
.
driver
=
&
nodemgr_driver_ne
,
.
driver_data
=
&
nodemgr_driverdata_ne
,
};
struct
device
nodemgr_dev_template_host
=
{
.
bus
=
&
ieee1394_bus_type
,
.
release
=
nodemgr_release_host
,
.
driver
=
&
nodemgr_driver_host
,
.
driver_data
=
&
nodemgr_driverdata_host
,
};
static
int
nodemgr_hotplug
(
struct
device
*
dev
,
char
**
envp
,
int
num_envp
,
char
*
buffer
,
int
buffer_size
);
struct
bus_type
ieee1394_bus_type
=
{
.
name
=
"ieee1394"
,
.
match
=
nodemgr_bus_match
,
.
hotplug
=
nodemgr_hotplug
,
};
static
int
nodemgr_read_quadlet
(
struct
hpsb_host
*
host
,
nodeid_t
nodeid
,
unsigned
int
generation
,
octlet_t
address
,
quadlet_t
*
quad
)
{
int
i
;
int
ret
=
0
;
for
(
i
=
0
;
i
<
3
;
i
++
)
{
ret
=
hpsb_read
(
host
,
nodeid
,
generation
,
address
,
quad
,
4
);
if
(
!
ret
)
break
;
set_current_state
(
TASK_INTERRUPTIBLE
);
if
(
schedule_timeout
(
HZ
/
3
))
return
-
1
;
}
*
quad
=
be32_to_cpu
(
*
quad
);
return
ret
;
}
static
int
nodemgr_size_text_leaf
(
struct
hpsb_host
*
host
,
nodeid_t
nodeid
,
unsigned
int
generation
,
octlet_t
address
)
{
quadlet_t
quad
;
int
size
=
0
;
if
(
nodemgr_read_quadlet
(
host
,
nodeid
,
generation
,
address
,
&
quad
))
return
-
1
;
if
(
CONFIG_ROM_KEY
(
quad
)
==
CONFIG_ROM_DESCRIPTOR_LEAF
)
{
/* This is the offset. */
address
+=
4
*
CONFIG_ROM_VALUE
(
quad
);
if
(
nodemgr_read_quadlet
(
host
,
nodeid
,
generation
,
address
,
&
quad
))
return
-
1
;
/* Now we got the size of the text descriptor leaf. */
size
=
CONFIG_ROM_LEAF_LENGTH
(
quad
);
}
return
size
;
}
static
int
nodemgr_read_text_leaf
(
struct
node_entry
*
ne
,
octlet_t
address
,
quadlet_t
*
quadp
)
{
quadlet_t
quad
;
int
i
,
size
,
ret
;
if
(
nodemgr_read_quadlet
(
ne
->
host
,
ne
->
nodeid
,
ne
->
generation
,
address
,
&
quad
)
||
CONFIG_ROM_KEY
(
quad
)
!=
CONFIG_ROM_DESCRIPTOR_LEAF
)
return
-
1
;
/* This is the offset. */
address
+=
4
*
CONFIG_ROM_VALUE
(
quad
);
if
(
nodemgr_read_quadlet
(
ne
->
host
,
ne
->
nodeid
,
ne
->
generation
,
address
,
&
quad
))
return
-
1
;
/* Now we got the size of the text descriptor leaf. */
size
=
CONFIG_ROM_LEAF_LENGTH
(
quad
)
-
2
;
if
(
size
<=
0
)
return
-
1
;
address
+=
4
;
for
(
i
=
0
;
i
<
2
;
i
++
,
address
+=
4
,
quadp
++
)
{
if
(
nodemgr_read_quadlet
(
ne
->
host
,
ne
->
nodeid
,
ne
->
generation
,
address
,
quadp
))
return
-
1
;
}
/* Now read the text string. */
ret
=
-
ENXIO
;
for
(;
size
>
0
;
size
--
,
address
+=
4
,
quadp
++
)
{
for
(
i
=
0
;
i
<
3
;
i
++
)
{
ret
=
hpsb_node_read
(
ne
,
address
,
quadp
,
4
);
if
(
ret
!=
-
EAGAIN
)
break
;
}
if
(
ret
)
break
;
}
return
ret
;
}
static
struct
node_entry
*
nodemgr_scan_root_directory
(
struct
hpsb_host
*
host
,
nodeid_t
nodeid
,
unsigned
int
generation
)
static
void
nodemgr_update_bus_options
(
struct
node_entry
*
ne
)
{
octlet_t
address
;
quadlet_t
quad
;
int
length
;
int
code
,
size
,
total_size
;
struct
node_entry
*
ne
;
address
=
CSR_REGISTER_BASE
+
CSR_CONFIG_ROM
;
if
(
nodemgr_read_quadlet
(
host
,
nodeid
,
generation
,
address
,
&
quad
))
return
NULL
;
if
(
CONFIG_ROM_BUS_INFO_LENGTH
(
quad
)
==
1
)
/* minimal config rom */
return
NULL
;
address
+=
4
+
CONFIG_ROM_BUS_INFO_LENGTH
(
quad
)
*
4
;
if
(
nodemgr_read_quadlet
(
host
,
nodeid
,
generation
,
address
,
&
quad
))
return
NULL
;
length
=
CONFIG_ROM_ROOT_LENGTH
(
quad
);
address
+=
4
;
size
=
0
;
total_size
=
sizeof
(
struct
node_entry
);
for
(;
length
>
0
;
length
--
,
address
+=
4
)
{
if
(
nodemgr_read_quadlet
(
host
,
nodeid
,
generation
,
address
,
&
quad
))
return
NULL
;
code
=
CONFIG_ROM_KEY
(
quad
);
if
(
code
==
CONFIG_ROM_VENDOR_ID
&&
length
>
0
)
{
/* Check if there is a text descriptor leaf
immediately after this. */
size
=
nodemgr_size_text_leaf
(
host
,
nodeid
,
generation
,
address
+
4
);
if
(
size
>
0
)
{
address
+=
4
;
length
--
;
total_size
+=
(
size
+
1
)
*
sizeof
(
quadlet_t
);
}
else
if
(
size
<
0
)
return
NULL
;
}
}
ne
=
kmalloc
(
total_size
,
GFP_KERNEL
);
if
(
!
ne
)
return
NULL
;
memset
(
ne
,
0
,
total_size
);
if
(
size
!=
0
)
{
ne
->
vendor_name
=
(
const
char
*
)
&
(
ne
->
quadlets
[
2
]);
ne
->
quadlets
[
size
]
=
0
;
}
else
{
ne
->
vendor_name
=
NULL
;
}
return
ne
;
}
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
static
const
u16
mr
[]
=
{
4
,
64
,
1024
,
0
};
#endif
quadlet_t
busoptions
=
be32_to_cpu
(
ne
->
csr
->
bus_info_data
[
2
]);
static
void
nodemgr_update_bus_options
(
struct
node_entry
*
ne
,
quadlet_t
busoptions
)
{
ne
->
busopt
.
irmc
=
(
busoptions
>>
31
)
&
1
;
ne
->
busopt
.
cmc
=
(
busoptions
>>
30
)
&
1
;
ne
->
busopt
.
isc
=
(
busoptions
>>
29
)
&
1
;
...
...
@@ -692,28 +762,32 @@ static void nodemgr_update_bus_options(struct node_entry *ne,
ne
->
busopt
.
pmc
=
(
busoptions
>>
27
)
&
1
;
ne
->
busopt
.
cyc_clk_acc
=
(
busoptions
>>
16
)
&
0xff
;
ne
->
busopt
.
max_rec
=
1
<<
(((
busoptions
>>
12
)
&
0xf
)
+
1
);
ne
->
busopt
.
max_rom
=
(
busoptions
>>
8
)
&
0x3
;
ne
->
busopt
.
generation
=
(
busoptions
>>
4
)
&
0xf
;
ne
->
busopt
.
lnkspd
=
busoptions
&
0x7
;
HPSB_VERBOSE
(
"NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d "
"cyc_clk_acc=%d max_rec=%d gen=%d lspd=%d"
,
"cyc_clk_acc=%d max_rec=%d
max_rom=%d
gen=%d lspd=%d"
,
busoptions
,
ne
->
busopt
.
irmc
,
ne
->
busopt
.
cmc
,
ne
->
busopt
.
isc
,
ne
->
busopt
.
bmc
,
ne
->
busopt
.
pmc
,
ne
->
busopt
.
cyc_clk_acc
,
ne
->
busopt
.
max_rec
,
mr
[
ne
->
busopt
.
max_rom
],
ne
->
busopt
.
generation
,
ne
->
busopt
.
lnkspd
);
}
static
struct
node_entry
*
nodemgr_create_node
(
octlet_t
guid
,
quadlet_t
busoptions
,
static
struct
node_entry
*
nodemgr_create_node
(
octlet_t
guid
,
struct
csr1212_csr
*
csr
,
struct
host_info
*
hi
,
nodeid_t
nodeid
,
unsigned
int
generation
)
{
struct
hpsb_host
*
host
=
hi
->
host
;
struct
node_entry
*
ne
;
ne
=
nodemgr_scan_root_directory
(
host
,
nodeid
,
generation
);
ne
=
kmalloc
(
sizeof
(
struct
node_entry
),
GFP_KERNEL
);
if
(
!
ne
)
return
NULL
;
memset
(
ne
,
0
,
sizeof
(
struct
node_entry
));
ne
->
tpool
=
&
host
->
tpool
[
nodeid
&
NODE_MASK
];
ne
->
host
=
host
;
...
...
@@ -724,6 +798,7 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoption
ne
->
guid
=
guid
;
ne
->
guid_vendor_id
=
(
guid
>>
40
)
&
0xffffff
;
ne
->
guid_vendor_oui
=
nodemgr_find_oui_name
(
ne
->
guid_vendor_id
);
ne
->
csr
=
csr
;
memcpy
(
&
ne
->
device
,
&
nodemgr_dev_template_ne
,
sizeof
(
ne
->
device
));
...
...
@@ -731,13 +806,20 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoption
snprintf
(
ne
->
device
.
bus_id
,
BUS_ID_SIZE
,
"%016Lx"
,
(
unsigned
long
long
)(
ne
->
guid
));
ne
->
class_dev
.
dev
=
&
ne
->
device
;
ne
->
class_dev
.
class
=
&
nodemgr_ne_class
;
snprintf
(
ne
->
class_dev
.
class_id
,
BUS_ID_SIZE
,
"%016Lx"
,
(
unsigned
long
long
)(
ne
->
guid
));
device_register
(
&
ne
->
device
);
class_device_register
(
&
ne
->
class_dev
);
get_device
(
&
ne
->
device
);
if
(
ne
->
guid_vendor_oui
)
device_create_file
(
&
ne
->
device
,
&
dev_attr_ne_guid_vendor_oui
);
nodemgr_create_ne_dev_files
(
ne
);
nodemgr_update_bus_options
(
ne
,
busoptions
);
nodemgr_update_bus_options
(
ne
);
HPSB_DEBUG
(
"%s added: ID:BUS["
NODE_BUS_FMT
"] GUID[%016Lx]"
,
(
host
->
node_id
==
nodeid
)
?
"Host"
:
"Node"
,
...
...
@@ -747,319 +829,168 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoption
}
struct
guid_search_baton
{
u64
guid
;
struct
node_entry
*
ne
;
};
static
int
nodemgr_guid_search_cb
(
struct
device
*
dev
,
void
*
__data
)
{
struct
guid_search_baton
*
search
=
__data
;
struct
node_entry
*
ne
;
if
(
dev
->
driver_data
!=
&
nodemgr_driverdata_ne
)
return
0
;
ne
=
container_of
(
dev
,
struct
node_entry
,
device
);
if
(
ne
->
guid
==
search
->
guid
)
{
search
->
ne
=
ne
;
return
1
;
}
return
0
;
}
static
struct
node_entry
*
find_entry_by_guid
(
u64
guid
)
{
struct
guid_search_baton
search
;
search
.
guid
=
guid
;
search
.
ne
=
NULL
;
bus_for_each_dev
(
&
ieee1394_bus_type
,
NULL
,
&
search
,
nodemgr_guid_search_cb
);
return
search
.
ne
;
}
struct
nodeid_search_baton
{
nodeid_t
nodeid
;
struct
node_entry
*
ne
;
struct
hpsb_host
*
host
;
};
static
int
nodemgr_nodeid_search_cb
(
struct
device
*
dev
,
void
*
__data
)
{
struct
nodeid_search_baton
*
search
=
__data
;
struct
node_entry
*
ne
;
struct
class
*
class
=
&
nodemgr_ne_class
;
struct
class_device
*
cdev
;
struct
node_entry
*
ne
,
*
ret_ne
=
NULL
;
if
(
dev
->
driver_data
!=
&
nodemgr_driverdata_ne
)
return
0
;
ne
=
container_of
(
dev
,
struct
node_entry
,
device
);
down_read
(
&
class
->
subsys
.
rwsem
);
list_for_each_entry
(
cdev
,
&
class
->
children
,
node
)
{
ne
=
container_of
(
cdev
,
struct
node_entry
,
class_dev
);
if
(
ne
->
host
==
search
->
host
&&
ne
->
nodeid
==
search
->
node
id
)
{
search
->
ne
=
ne
;
/* Returning 1 stops the iteration */
return
1
;
if
(
ne
->
guid
==
gu
id
)
{
ret_
ne
=
ne
;
break
;
}
}
up_read
(
&
class
->
subsys
.
rwsem
);
return
0
;
return
ret_ne
;
}
static
struct
node_entry
*
find_entry_by_nodeid
(
struct
hpsb_host
*
host
,
nodeid_t
nodeid
)
{
struct
nodeid_search_baton
search
;
search
.
nodeid
=
nodeid
;
search
.
ne
=
NULL
;
search
.
host
=
host
;
bus_for_each_dev
(
&
ieee1394_bus_type
,
NULL
,
&
search
,
nodemgr_nodeid_search_cb
);
return
search
.
ne
;
}
static
struct
unit_directory
*
nodemgr_scan_unit_directory
(
struct
node_entry
*
ne
,
octlet_t
address
)
static
struct
node_entry
*
find_entry_by_nodeid
(
struct
hpsb_host
*
host
,
nodeid_t
nodeid
)
{
struct
unit_directory
*
ud
;
quadlet_t
quad
;
u8
flags
,
todo
;
int
length
,
size
,
total_size
,
count
;
int
vendor_name_size
,
model_name_size
;
if
(
nodemgr_read_quadlet
(
ne
->
host
,
ne
->
nodeid
,
ne
->
generation
,
address
,
&
quad
))
return
NULL
;
length
=
CONFIG_ROM_DIRECTORY_LENGTH
(
quad
)
;
address
+=
4
;
size
=
0
;
total_size
=
sizeof
(
struct
unit_directory
);
flags
=
0
;
count
=
0
;
vendor_name_size
=
0
;
model_name_size
=
0
;
for
(;
length
>
0
;
length
--
,
address
+=
4
)
{
int
code
;
quadlet_t
value
;
if
(
nodemgr_read_quadlet
(
ne
->
host
,
ne
->
nodeid
,
ne
->
generation
,
address
,
&
quad
))
return
NULL
;
code
=
CONFIG_ROM_KEY
(
quad
);
value
=
CONFIG_ROM_VALUE
(
quad
);
todo
=
0
;
switch
(
code
)
{
case
CONFIG_ROM_VENDOR_ID
:
todo
=
UNIT_DIRECTORY_VENDOR_TEXT
;
break
;
case
CONFIG_ROM_MODEL_ID
:
todo
=
UNIT_DIRECTORY_MODEL_TEXT
;
break
;
struct
class
*
class
=
&
nodemgr_ne_class
;
struct
class_device
*
cdev
;
struct
node_entry
*
ne
,
*
ret_ne
=
NULL
;
case
CONFIG_ROM_SPECIFIER_ID
:
case
CONFIG_ROM_UNIT_SW_VERSION
:
break
;
down_read
(
&
class
->
subsys
.
rwsem
);
list_for_each_entry
(
cdev
,
&
class
->
children
,
node
)
{
ne
=
container_of
(
cdev
,
struct
node_entry
,
class_dev
)
;
case
CONFIG_ROM_DESCRIPTOR_LEAF
:
case
CONFIG_ROM_DESCRIPTOR_DIRECTORY
:
/* TODO: read strings... icons? */
break
;
default:
/* Which types of quadlets do we want to
store? Only count immediate values and
CSR offsets for now. */
code
&=
CONFIG_ROM_KEY_TYPE_MASK
;
if
((
code
&
CONFIG_ROM_KEY_TYPE_LEAF
)
==
0
)
count
++
;
if
(
ne
->
host
==
host
&&
ne
->
nodeid
==
nodeid
)
{
ret_ne
=
ne
;
break
;
}
if
(
todo
&&
length
>
0
)
{
/* Check if there is a text descriptor leaf
immediately after this. */
size
=
nodemgr_size_text_leaf
(
ne
->
host
,
ne
->
nodeid
,
ne
->
generation
,
address
+
4
);
if
(
todo
==
UNIT_DIRECTORY_VENDOR_TEXT
)
vendor_name_size
=
size
;
else
model_name_size
=
size
;
if
(
size
>
0
)
{
address
+=
4
;
length
--
;
flags
|=
todo
;
total_size
+=
(
size
+
1
)
*
sizeof
(
quadlet_t
);
}
else
if
(
size
<
0
)
return
NULL
;
}
}
up_read
(
&
class
->
subsys
.
rwsem
);
total_size
+=
count
*
sizeof
(
quadlet_t
);
ud
=
kmalloc
(
total_size
,
GFP_KERNEL
);
if
(
ud
!=
NULL
)
{
memset
(
ud
,
0
,
total_size
);
ud
->
flags
=
flags
;
ud
->
length
=
count
;
ud
->
vendor_name_size
=
vendor_name_size
;
ud
->
model_name_size
=
model_name_size
;
}
return
ud
;
return
ret_ne
;
}
/* This implementation currently only scans the config rom and its
* immediate unit directories looking for software_id and
* software_version entries, in order to get driver autoloading working. */
static
struct
unit_directory
*
nodemgr_process_unit_directory
(
struct
host_info
*
hi
,
struct
node_entry
*
ne
,
octlet_t
address
,
unsigned
int
*
id
,
struct
unit_directory
*
parent
)
(
struct
host_info
*
hi
,
struct
node_entry
*
ne
,
struct
csr1212_keyval
*
ud_kv
,
unsigned
int
*
id
,
struct
unit_directory
*
parent
)
{
struct
unit_directory
*
ud
;
quadlet_t
quad
;
quadlet_t
*
infop
;
int
length
;
struct
unit_directory
*
ud_temp
=
NULL
;
struct
csr1212_dentry
*
dentry
;
struct
csr1212_keyval
*
kv
;
u8
last_key_id
=
0
;
if
(
!
(
ud
=
nodemgr_scan_unit_directory
(
ne
,
address
)))
ud
=
kmalloc
(
sizeof
(
struct
unit_directory
),
GFP_KERNEL
);
if
(
!
ud
)
goto
unit_directory_error
;
memset
(
ud
,
0
,
sizeof
(
struct
unit_directory
));
ud
->
ne
=
ne
;
ud
->
address
=
address
;
ud
->
ignore_driver
=
ignore_drivers
;
ud
->
address
=
ud_kv
->
offset
+
CSR1212_CONFIG_ROM_SPACE_BASE
;
ud
->
ud_kv
=
ud_kv
;
ud
->
id
=
(
*
id
)
++
;
if
(
nodemgr_read_quadlet
(
ne
->
host
,
ne
->
nodeid
,
ne
->
generation
,
address
,
&
quad
))
goto
unit_directory_error
;
length
=
CONFIG_ROM_DIRECTORY_LENGTH
(
quad
)
;
address
+=
4
;
infop
=
(
quadlet_t
*
)
ud
->
quadlets
;
for
(;
length
>
0
;
length
--
,
address
+=
4
)
{
int
code
;
quadlet_t
value
;
quadlet_t
*
quadp
;
if
(
nodemgr_read_quadlet
(
ne
->
host
,
ne
->
nodeid
,
ne
->
generation
,
address
,
&
quad
))
goto
unit_directory_error
;
code
=
CONFIG_ROM_KEY
(
quad
)
;
value
=
CONFIG_ROM_VALUE
(
quad
);
switch
(
code
)
{
case
CONFIG_ROM_VENDOR_ID
:
ud
->
vendor_id
=
value
;
ud
->
flags
|=
UNIT_DIRECTORY_VENDOR_ID
;
if
(
ud
->
vendor_id
)
ud
->
vendor_oui
=
nodemgr_find_oui_name
(
ud
->
vendor_id
);
if
((
ud
->
flags
&
UNIT_DIRECTORY_VENDOR_TEXT
)
!=
0
)
{
length
--
;
address
+=
4
;
quadp
=
&
(
ud
->
quadlets
[
ud
->
length
]);
if
(
nodemgr_read_text_leaf
(
ne
,
address
,
quadp
)
==
0
&&
quadp
[
0
]
==
0
&&
quadp
[
1
]
==
0
)
{
/* We only support minimal
ASCII and English. */
quadp
[
ud
->
vendor_name_size
]
=
0
;
ud
->
vendor_name
=
(
const
char
*
)
&
(
quadp
[
2
]);
}
csr1212_for_each_dir_entry
(
ne
->
csr
,
kv
,
ud_kv
,
dentry
)
{
switch
(
kv
->
key
.
id
)
{
case
CSR1212_KV_ID_VENDOR
:
if
(
kv
->
key
.
type
==
CSR1212_KV_TYPE_IMMEDIATE
)
{
ud
->
vendor_id
=
kv
->
value
.
immediate
;
ud
->
flags
|=
UNIT_DIRECTORY_VENDOR_ID
;
if
(
ud
->
vendor_id
)
ud
->
vendor_oui
=
nodemgr_find_oui_name
(
ud
->
vendor_id
);
}
break
;
case
C
ONFIG_ROM_MODEL_ID
:
ud
->
model_id
=
valu
e
;
case
C
SR1212_KV_ID_MODEL
:
ud
->
model_id
=
kv
->
value
.
immediat
e
;
ud
->
flags
|=
UNIT_DIRECTORY_MODEL_ID
;
if
((
ud
->
flags
&
UNIT_DIRECTORY_MODEL_TEXT
)
!=
0
)
{
length
--
;
address
+=
4
;
quadp
=
&
(
ud
->
quadlets
[
ud
->
length
+
ud
->
vendor_name_size
+
1
]);
if
(
nodemgr_read_text_leaf
(
ne
,
address
,
quadp
)
==
0
&&
quadp
[
0
]
==
0
&&
quadp
[
1
]
==
0
)
{
/* We only support minimal
ASCII and English. */
quadp
[
ud
->
model_name_size
]
=
0
;
ud
->
model_name
=
(
const
char
*
)
&
(
quadp
[
2
]);
}
}
break
;
case
C
ONFIG_ROM
_SPECIFIER_ID
:
ud
->
specifier_id
=
valu
e
;
case
C
SR1212_KV_ID
_SPECIFIER_ID
:
ud
->
specifier_id
=
kv
->
value
.
immediat
e
;
ud
->
flags
|=
UNIT_DIRECTORY_SPECIFIER_ID
;
break
;
case
C
ONFIG_ROM_UNIT_SW
_VERSION
:
ud
->
version
=
valu
e
;
case
C
SR1212_KV_ID
_VERSION
:
ud
->
version
=
kv
->
value
.
immediat
e
;
ud
->
flags
|=
UNIT_DIRECTORY_VERSION
;
break
;
case
CONFIG_ROM_DESCRIPTOR_LEAF
:
case
CONFIG_ROM_DESCRIPTOR_DIRECTORY
:
/* TODO: read strings... icons? */
case
CSR1212_KV_ID_DESCRIPTOR
:
if
(
kv
->
key
.
type
==
CSR1212_KV_TYPE_LEAF
&&
CSR1212_DESCRIPTOR_LEAF_TYPE
(
kv
)
==
0
&&
CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID
(
kv
)
==
0
&&
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH
(
kv
)
==
0
&&
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET
(
kv
)
==
0
&&
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE
(
kv
)
==
0
)
{
switch
(
last_key_id
)
{
case
CSR1212_KV_ID_VENDOR
:
ud
->
vendor_name_kv
=
kv
;
csr1212_keep_keyval
(
kv
);
break
;
case
CSR1212_KV_ID_MODEL
:
ud
->
model_name_kv
=
kv
;
csr1212_keep_keyval
(
kv
);
break
;
}
}
/* else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) ... */
break
;
case
CONFIG_ROM_LOGICAL_UNIT_DIRECTORY
:
ud
->
flags
|=
UNIT_DIRECTORY_HAS_LUN_DIRECTORY
;
ud_temp
=
nodemgr_process_unit_directory
(
hi
,
ne
,
address
+
value
*
4
,
id
,
parent
);
if
(
ud_temp
==
NULL
)
break
;
/* inherit unspecified values */
if
((
ud
->
flags
&
UNIT_DIRECTORY_VENDOR_ID
)
&&
!
(
ud_temp
->
flags
&
UNIT_DIRECTORY_VENDOR_ID
))
{
ud_temp
->
flags
|=
UNIT_DIRECTORY_VENDOR_ID
;
ud_temp
->
vendor_id
=
ud
->
vendor_id
;
ud_temp
->
vendor_oui
=
ud
->
vendor_oui
;
}
if
((
ud
->
flags
&
UNIT_DIRECTORY_MODEL_ID
)
&&
!
(
ud_temp
->
flags
&
UNIT_DIRECTORY_MODEL_ID
))
{
ud_temp
->
flags
|=
UNIT_DIRECTORY_MODEL_ID
;
ud_temp
->
model_id
=
ud
->
model_id
;
}
if
((
ud
->
flags
&
UNIT_DIRECTORY_SPECIFIER_ID
)
&&
!
(
ud_temp
->
flags
&
UNIT_DIRECTORY_SPECIFIER_ID
))
{
ud_temp
->
flags
|=
UNIT_DIRECTORY_SPECIFIER_ID
;
ud_temp
->
specifier_id
=
ud
->
specifier_id
;
}
if
((
ud
->
flags
&
UNIT_DIRECTORY_VERSION
)
&&
!
(
ud_temp
->
flags
&
UNIT_DIRECTORY_VERSION
))
{
ud_temp
->
flags
|=
UNIT_DIRECTORY_VERSION
;
ud_temp
->
version
=
ud
->
version
;
case
CSR1212_KV_ID_DEPENDENT_INFO
:
if
(
kv
->
key
.
type
==
CSR1212_KV_TYPE_DIRECTORY
)
{
/* This should really be done in SBP2 as this is
* doing SBP2 specific parsing. */
ud
->
flags
|=
UNIT_DIRECTORY_HAS_LUN_DIRECTORY
;
ud_temp
=
nodemgr_process_unit_directory
(
hi
,
ne
,
kv
,
id
,
parent
);
if
(
ud_temp
==
NULL
)
break
;
/* inherit unspecified values */
if
((
ud
->
flags
&
UNIT_DIRECTORY_VENDOR_ID
)
&&
!
(
ud_temp
->
flags
&
UNIT_DIRECTORY_VENDOR_ID
))
{
ud_temp
->
flags
|=
UNIT_DIRECTORY_VENDOR_ID
;
ud_temp
->
vendor_id
=
ud
->
vendor_id
;
ud_temp
->
vendor_oui
=
ud
->
vendor_oui
;
}
if
((
ud
->
flags
&
UNIT_DIRECTORY_MODEL_ID
)
&&
!
(
ud_temp
->
flags
&
UNIT_DIRECTORY_MODEL_ID
))
{
ud_temp
->
flags
|=
UNIT_DIRECTORY_MODEL_ID
;
ud_temp
->
model_id
=
ud
->
model_id
;
}
if
((
ud
->
flags
&
UNIT_DIRECTORY_SPECIFIER_ID
)
&&
!
(
ud_temp
->
flags
&
UNIT_DIRECTORY_SPECIFIER_ID
))
{
ud_temp
->
flags
|=
UNIT_DIRECTORY_SPECIFIER_ID
;
ud_temp
->
specifier_id
=
ud
->
specifier_id
;
}
if
((
ud
->
flags
&
UNIT_DIRECTORY_VERSION
)
&&
!
(
ud_temp
->
flags
&
UNIT_DIRECTORY_VERSION
))
{
ud_temp
->
flags
|=
UNIT_DIRECTORY_VERSION
;
ud_temp
->
version
=
ud
->
version
;
}
}
break
;
default:
/* Which types of quadlets do we want to
store? Only count immediate values and
CSR offsets for now. */
code
&=
CONFIG_ROM_KEY_TYPE_MASK
;
if
((
code
&
CONFIG_ROM_KEY_TYPE_LEAF
)
==
0
)
*
infop
++
=
quad
;
break
;
}
last_key_id
=
kv
->
key
.
id
;
}
memcpy
(
&
ud
->
device
,
&
nodemgr_dev_template_ud
,
...
...
@@ -1091,76 +1022,51 @@ static struct unit_directory *nodemgr_process_unit_directory
static
void
nodemgr_process_root_directory
(
struct
host_info
*
hi
,
struct
node_entry
*
ne
)
{
octlet_t
address
;
quadlet_t
quad
;
int
length
;
unsigned
int
ud_id
=
0
;
struct
csr1212_dentry
*
dentry
;
struct
csr1212_keyval
*
kv
;
u8
last_key_id
=
0
;
device_remove_file
(
&
ne
->
device
,
&
dev_attr_ne_vendor_oui
);
address
=
CSR_REGISTER_BASE
+
CSR_CONFIG_ROM
;
if
(
nodemgr_read_quadlet
(
ne
->
host
,
ne
->
nodeid
,
ne
->
generation
,
address
,
&
quad
))
return
;
address
+=
4
+
CONFIG_ROM_BUS_INFO_LENGTH
(
quad
)
*
4
;
if
(
nodemgr_read_quadlet
(
ne
->
host
,
ne
->
nodeid
,
ne
->
generation
,
address
,
&
quad
))
return
;
length
=
CONFIG_ROM_ROOT_LENGTH
(
quad
);
address
+=
4
;
for
(;
length
>
0
;
length
--
,
address
+=
4
)
{
int
code
,
value
;
if
(
nodemgr_read_quadlet
(
ne
->
host
,
ne
->
nodeid
,
ne
->
generation
,
address
,
&
quad
))
return
;
code
=
CONFIG_ROM_KEY
(
quad
);
value
=
CONFIG_ROM_VALUE
(
quad
);
ne
->
needs_probe
=
0
;
switch
(
code
)
{
case
CONFIG_ROM_VENDOR_ID
:
ne
->
vendor_id
=
value
;
csr1212_for_each_dir_entry
(
ne
->
csr
,
kv
,
ne
->
csr
->
root_kv
,
dentry
)
{
switch
(
kv
->
key
.
id
)
{
case
CSR1212_KV_ID_VENDOR
:
ne
->
vendor_id
=
kv
->
value
.
immediate
;
if
(
ne
->
vendor_id
)
ne
->
vendor_oui
=
nodemgr_find_oui_name
(
ne
->
vendor_id
);
/* Now check if there is a vendor name text
string. */
if
(
ne
->
vendor_name
!=
NULL
)
{
length
--
;
address
+=
4
;
if
(
nodemgr_read_text_leaf
(
ne
,
address
,
ne
->
quadlets
)
!=
0
||
ne
->
quadlets
[
0
]
!=
0
||
ne
->
quadlets
[
1
]
!=
0
)
/* We only support minimal
ASCII and English. */
ne
->
vendor_name
=
NULL
;
else
device_create_file
(
&
ne
->
device
,
&
dev_attr_ne_vendor_name
);
}
break
;
case
C
ONFIG_ROM_NODE_CAPABILIT
ES
:
ne
->
capabilities
=
valu
e
;
case
C
SR1212_KV_ID_NODE_CAPABILITI
ES
:
ne
->
capabilities
=
kv
->
value
.
immediat
e
;
break
;
case
CONFIG_ROM_UNIT_DIRECTORY
:
nodemgr_process_unit_directory
(
hi
,
ne
,
address
+
value
*
4
,
&
ud_id
,
NULL
);
case
CSR1212_KV_ID_UNIT
:
nodemgr_process_unit_directory
(
hi
,
ne
,
kv
,
&
ud_id
,
NULL
);
break
;
case
CONFIG_ROM_DESCRIPTOR_LEAF
:
case
CONFIG_ROM_DESCRIPTOR_DIRECTORY
:
/* TODO: read strings... icons? */
case
CSR1212_KV_ID_DESCRIPTOR
:
if
(
last_key_id
==
CSR1212_KV_ID_VENDOR
)
{
if
(
kv
->
key
.
type
==
CSR1212_KV_TYPE_LEAF
&&
CSR1212_DESCRIPTOR_LEAF_TYPE
(
kv
)
==
0
&&
CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID
(
kv
)
==
0
&&
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH
(
kv
)
==
0
&&
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET
(
kv
)
==
0
&&
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE
(
kv
)
==
0
)
{
ne
->
vendor_name_kv
=
kv
;
csr1212_keep_keyval
(
kv
);
}
}
break
;
}
last_key_id
=
kv
->
key
.
id
;
}
if
(
ne
->
vendor_oui
)
device_create_file
(
&
ne
->
device
,
&
dev_attr_ne_vendor_oui
);
if
(
ne
->
vendor_name_kv
)
device_create_file
(
&
ne
->
device
,
&
dev_attr_ne_vendor_name_kv
);
}
#ifdef CONFIG_HOTPLUG
...
...
@@ -1176,13 +1082,14 @@ static int nodemgr_hotplug(struct device *dev, char **envp, int num_envp,
if
(
!
dev
)
return
-
ENODEV
;
/* Have to check driver_data, since on remove, driver == NULL */
if
(
dev
->
driver_data
==
&
nodemgr_driverdata_ne
||
dev
->
driver_data
==
&
nodemgr_driverdata_host
)
if
(
dev
->
platform_data
!=
&
nodemgr_platform_data_ud
)
return
-
ENODEV
;
ud
=
container_of
(
dev
,
struct
unit_directory
,
device
);
if
(
ud
->
ne
->
in_limbo
||
ud
->
ignore_driver
)
return
-
ENODEV
;
scratch
=
buffer
;
#define PUT_ENVP(fmt,val) \
...
...
@@ -1261,7 +1168,7 @@ void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver)
* informed that this device just went through a bus reset, to allow
* the to take whatever actions required.
*/
static
void
nodemgr_update_node
(
struct
node_entry
*
ne
,
quadlet_t
busoptions
,
static
void
nodemgr_update_node
(
struct
node_entry
*
ne
,
struct
csr1212_csr
*
csr
,
struct
host_info
*
hi
,
nodeid_t
nodeid
,
unsigned
int
generation
)
{
...
...
@@ -1272,87 +1179,29 @@ static void nodemgr_update_node(struct node_entry *ne, quadlet_t busoptions,
ne
->
nodeid
=
nodeid
;
}
if
(
ne
->
busopt
.
generation
!=
((
busoptions
>>
4
)
&
0xf
))
{
if
(
ne
->
busopt
.
generation
!=
((
be32_to_cpu
(
csr
->
bus_info_data
[
2
])
>>
4
)
&
0xf
))
{
kfree
(
ne
->
csr
->
private
);
csr1212_destroy_csr
(
ne
->
csr
);
ne
->
csr
=
csr
;
/* If the node's configrom generation has changed, we
* unregister all the unit directories. */
nodemgr_remove_node_uds
(
ne
);
nodemgr_update_bus_options
(
ne
,
busoptions
);
nodemgr_update_bus_options
(
ne
);
/* Mark the node as new, so it gets re-probed */
ne
->
needs_probe
=
1
;
}
if
(
ne
->
in_limbo
)
nodemgr_resume_ne
(
ne
);
/* Mark the node current */
ne
->
generation
=
generation
;
}
static
int
read_businfo_block
(
struct
hpsb_host
*
host
,
nodeid_t
nodeid
,
unsigned
int
generation
,
quadlet_t
*
buffer
,
int
buffer_length
)
{
octlet_t
addr
=
CSR_REGISTER_BASE
+
CSR_CONFIG_ROM
;
unsigned
header_size
;
int
i
;
/* IEEE P1212 says that devices should support 64byte block
* reads, aligned on 64byte boundaries. That doesn't seem to
* work though, and we are forced to doing quadlet sized
* reads. */
HPSB_VERBOSE
(
"Initiating ConfigROM request for node "
NODE_BUS_FMT
,
NODE_BUS_ARGS
(
host
,
nodeid
));
/*
* Must retry a few times if config rom read returns zero (how long?). Will
* not normally occur, but we should do the right thing. For example, with
* some sbp2 devices, the bridge chipset cannot return valid config rom reads
* immediately after power-on, since they need to detect the type of
* device attached (disk or CD-ROM).
*/
for
(
i
=
0
;
i
<
4
;
i
++
)
{
if
(
nodemgr_read_quadlet
(
host
,
nodeid
,
generation
,
addr
,
&
buffer
[
0
])
<
0
)
{
HPSB_ERR
(
"ConfigROM quadlet transaction error for node "
NODE_BUS_FMT
,
NODE_BUS_ARGS
(
host
,
nodeid
));
return
-
1
;
}
if
(
buffer
[
0
])
break
;
set_current_state
(
TASK_INTERRUPTIBLE
);
if
(
schedule_timeout
(
HZ
/
4
))
return
-
1
;
}
header_size
=
buffer
[
0
]
>>
24
;
addr
+=
4
;
if
(
header_size
==
1
)
{
HPSB_INFO
(
"Node "
NODE_BUS_FMT
" has a minimal ROM. "
"Vendor is %08x"
,
NODE_BUS_ARGS
(
host
,
nodeid
),
buffer
[
0
]
&
0x00ffffff
);
return
-
1
;
}
if
(
header_size
<
4
)
{
HPSB_INFO
(
"Node "
NODE_BUS_FMT
" has non-standard ROM "
"format (%d quads), cannot parse"
,
NODE_BUS_ARGS
(
host
,
nodeid
),
header_size
);
return
-
1
;
}
for
(
i
=
1
;
i
<
buffer_length
;
i
++
,
addr
+=
4
)
{
if
(
nodemgr_read_quadlet
(
host
,
nodeid
,
generation
,
addr
,
&
buffer
[
i
])
<
0
)
{
HPSB_ERR
(
"ConfigROM quadlet transaction "
"error for node "
NODE_BUS_FMT
,
NODE_BUS_ARGS
(
host
,
nodeid
));
return
-
1
;
}
}
return
0
;
}
static
void
nodemgr_node_scan_one
(
struct
host_info
*
hi
,
...
...
@@ -1360,17 +1209,32 @@ static void nodemgr_node_scan_one(struct host_info *hi,
{
struct
hpsb_host
*
host
=
hi
->
host
;
struct
node_entry
*
ne
;
quadlet_t
buffer
[
5
];
octlet_t
guid
;
struct
csr1212_csr
*
csr
;
struct
nodemgr_csr_info
*
ci
;
ci
=
kmalloc
(
sizeof
(
struct
nodemgr_csr_info
),
GFP_KERNEL
);
if
(
!
ci
)
return
;
ci
->
host
=
host
;
ci
->
nodeid
=
nodeid
;
ci
->
generation
=
generation
;
/* We need to detect when the ConfigROM's generation has changed,
* so we only update the node's info when it needs to be. */
if
(
read_businfo_block
(
host
,
nodeid
,
generation
,
buffer
,
sizeof
(
buffer
)
>>
2
))
csr
=
csr1212_create_csr
(
&
nodemgr_csr_ops
,
5
*
sizeof
(
quadlet_t
),
ci
);
if
(
!
csr
||
csr1212_parse_csr
(
csr
)
!=
CSR1212_SUCCESS
)
{
HPSB_ERR
(
"Error parsing configrom for node "
NODE_BUS_FMT
,
NODE_BUS_ARGS
(
host
,
nodeid
));
if
(
csr
)
csr1212_destroy_csr
(
csr
);
kfree
(
ci
);
return
;
}
if
(
buffer
[
1
]
!=
IEEE1394_BUSID_MAGIC
)
{
if
(
csr
->
bus_info_data
[
1
]
!=
IEEE1394_BUSID_MAGIC
)
{
/* This isn't a 1394 device, but we let it slide. There
* was a report of a device with broken firmware which
* reported '2394' instead of '1394', which is obviously a
...
...
@@ -1379,176 +1243,196 @@ static void nodemgr_node_scan_one(struct host_info *hi,
* shouldn't be held responsible, so we'll allow it with a
* warning. */
HPSB_WARN
(
"Node "
NODE_BUS_FMT
" has invalid busID magic [0x%08x]"
,
NODE_BUS_ARGS
(
host
,
nodeid
),
buffer
[
1
]);
NODE_BUS_ARGS
(
host
,
nodeid
),
csr
->
bus_info_data
[
1
]);
}
guid
=
((
u64
)
b
uffer
[
3
]
<<
32
)
|
buffer
[
4
]
;
guid
=
((
u64
)
b
e32_to_cpu
(
csr
->
bus_info_data
[
3
])
<<
32
)
|
be32_to_cpu
(
csr
->
bus_info_data
[
4
])
;
ne
=
find_entry_by_guid
(
guid
);
if
(
ne
&&
ne
->
host
!=
host
&&
ne
->
in_limbo
)
{
/* Must have moved this device from one host to another */
nodemgr_remove_ne
(
ne
);
ne
=
NULL
;
}
if
(
!
ne
)
nodemgr_create_node
(
guid
,
buffer
[
2
]
,
hi
,
nodeid
,
generation
);
nodemgr_create_node
(
guid
,
csr
,
hi
,
nodeid
,
generation
);
else
nodemgr_update_node
(
ne
,
buffer
[
2
]
,
hi
,
nodeid
,
generation
);
nodemgr_update_node
(
ne
,
csr
,
hi
,
nodeid
,
generation
);
return
;
}
struct
cleanup_baton
{
unsigned
int
generation
;
struct
hpsb_host
*
host
;
struct
node_entry
*
ne
;
};
static
void
nodemgr_node_scan
(
struct
host_info
*
hi
,
int
generation
)
{
int
count
;
struct
hpsb_host
*
host
=
hi
->
host
;
struct
selfid
*
sid
=
(
struct
selfid
*
)
host
->
topology_map
;
nodeid_t
nodeid
=
LOCAL_BUS
;
/* Scan each node on the bus */
for
(
count
=
host
->
selfid_count
;
count
;
count
--
,
sid
++
)
{
if
(
sid
->
extended
)
continue
;
if
(
!
sid
->
link_active
)
{
nodeid
++
;
continue
;
}
nodemgr_node_scan_one
(
hi
,
nodeid
++
,
generation
);
}
}
static
int
nodemgr_remove_node
(
struct
device
*
dev
,
void
*
__data
)
static
void
nodemgr_suspend_ud
(
struct
unit_directory
*
ud
)
{
struct
cleanup_baton
*
cleanup
=
__data
;
struct
node_entry
*
ne
;
struct
device
*
dev
;
if
(
dev
->
driver_data
!=
&
nodemgr_driverdata_n
e
)
return
0
;
list_for_each_entry
(
dev
,
&
ud
->
device
.
children
,
nod
e
)
nodemgr_suspend_ud
(
container_of
(
dev
,
struct
unit_directory
,
device
))
;
ne
=
container_of
(
dev
,
struct
node_entry
,
device
);
if
(
ud
->
device
.
driver
)
{
int
ret
=
-
1
;
if
(
ne
->
host
!=
cleanup
->
host
)
return
0
;
if
(
ud
->
device
.
driver
->
suspend
)
ret
=
ud
->
device
.
driver
->
suspend
(
&
ud
->
device
,
0
,
0
)
;
if
(
ne
->
generation
!=
cleanup
->
generation
)
{
cleanup
->
ne
=
ne
;
return
1
;
}
if
(
ret
)
{
dev
=
&
ud
->
device
;
down_write
(
&
dev
->
bus
->
subsys
.
rwsem
);
device_release_driver
(
dev
);
up_write
(
&
dev
->
bus
->
subsys
.
rwsem
);
}
}
}
return
0
;
static
void
nodemgr_suspend_ne
(
struct
node_entry
*
ne
)
{
struct
device
*
dev
;
HPSB_DEBUG
(
"Node suspended: ID:BUS["
NODE_BUS_FMT
"] GUID[%016Lx]"
,
NODE_BUS_ARGS
(
ne
->
host
,
ne
->
nodeid
),
(
unsigned
long
long
)
ne
->
guid
);
ne
->
in_limbo
=
1
;
device_create_file
(
&
ne
->
device
,
&
dev_attr_ne_in_limbo
);
list_for_each_entry
(
dev
,
&
ne
->
device
.
children
,
node
)
nodemgr_suspend_ud
(
container_of
(
dev
,
struct
unit_directory
,
device
));
}
struct
ne_cb_data_struct
{
struct
host_info
*
hi
;
struct
node_entry
*
ne
;
};
static
int
nodemgr_probe_ne_cb
(
struct
device
*
dev
,
void
*
__data
)
static
void
nodemgr_resume_ud
(
struct
unit_directory
*
ud
)
{
struct
ne_cb_data_struct
*
ne_cb_data
=
__data
;
struct
host_info
*
hi
=
ne_cb_data
->
hi
;
struct
node_entry
*
ne
;
struct
device
*
dev
;
if
(
dev
->
driver_data
!=
&
nodemgr_driverdata_n
e
)
return
0
;
list_for_each_entry
(
dev
,
&
ud
->
device
.
children
,
nod
e
)
nodemgr_resume_ud
(
container_of
(
dev
,
struct
unit_directory
,
device
))
;
ne
=
ne_cb_data
->
ne
=
container_of
(
dev
,
struct
node_entry
,
device
);
if
(
ud
->
device
.
driver
&&
ud
->
device
.
driver
->
resume
)
ud
->
device
.
driver
->
resume
(
&
ud
->
device
,
0
);
}
if
(
ne
->
host
!=
hi
->
host
)
return
0
;
/* We can't call nodemgr_process_root_directory() here because
* that can call device_register. Since this callback is under a
* rwsem, the device_register would deadlock. So, we signal back
* to the callback, and process things there. */
static
void
nodemgr_resume_ne
(
struct
node_entry
*
ne
)
{
struct
device
*
dev
;
if
(
ne
->
needs_probe
)
{
ne
->
needs_probe
=
0
;
return
1
;
}
else
{
struct
list_head
*
lh
;
ne
->
in_limbo
=
0
;
device_remove_file
(
&
ne
->
device
,
&
dev_attr_ne_in_limbo
);
/* Update unit_dirs with attached drivers */
list_for_each
(
lh
,
&
dev
->
children
)
{
struct
unit_directory
*
ud
;
ud
=
container_of
(
list_to_dev
(
lh
),
struct
unit_directory
,
device
);
list_for_each_entry
(
dev
,
&
ne
->
device
.
children
,
node
)
nodemgr_resume_ud
(
container_of
(
dev
,
struct
unit_directory
,
device
));
if
(
ud
->
device
.
driver
)
{
struct
hpsb_protocol_driver
*
pdrv
;
HPSB_DEBUG
(
"Node resumed: ID:BUS["
NODE_BUS_FMT
"] GUID[%016Lx]"
,
NODE_BUS_ARGS
(
ne
->
host
,
ne
->
nodeid
),
(
unsigned
long
long
)
ne
->
guid
);
}
pdrv
=
container_of
(
ud
->
device
.
driver
,
struct
hpsb_protocol_driver
,
driver
);
if
(
pdrv
->
update
)
pdrv
->
update
(
ud
);
}
}
static
void
nodemgr_ud_update_pdrv
(
struct
unit_directory
*
ud
)
{
struct
device
*
dev
;
struct
hpsb_protocol_driver
*
pdrv
;
if
(
!
get_device
(
&
ud
->
device
))
return
;
list_for_each_entry
(
dev
,
&
ud
->
device
.
children
,
node
)
nodemgr_ud_update_pdrv
(
container_of
(
dev
,
struct
unit_directory
,
device
));
if
(
ud
->
device
.
driver
)
{
pdrv
=
container_of
(
ud
->
device
.
driver
,
struct
hpsb_protocol_driver
,
driver
);
if
(
pdrv
->
update
)
pdrv
->
update
(
ud
);
}
return
0
;
put_device
(
&
ud
->
device
);
}
static
void
nodemgr_
node_scan
(
struct
host_info
*
hi
,
int
generation
)
static
void
nodemgr_
probe_ne
(
struct
host_info
*
hi
,
struct
node_entry
*
ne
,
int
generation
)
{
int
count
;
struct
hpsb_host
*
host
=
hi
->
host
;
struct
selfid
*
sid
=
(
struct
selfid
*
)
host
->
topology_map
;
nodeid_t
nodeid
=
LOCAL_BUS
;
struct
device
*
dev
,
*
udev
;
/* Scan each node on the bus */
for
(
count
=
host
->
selfid_count
;
count
;
count
--
,
sid
++
)
{
if
(
sid
->
extended
)
continue
;
if
(
ne
->
host
!=
hi
->
host
||
ne
->
in_limbo
)
return
;
if
(
!
sid
->
link_active
)
{
nodeid
++
;
continue
;
}
nodemgr_node_scan_one
(
hi
,
nodeid
++
,
generation
);
}
dev
=
get_device
(
&
ne
->
device
);
if
(
!
dev
)
return
;
/* If "needs_probe", then this is either a new or changed node we
* rescan totally. If the generation matches for an existing node
* (one that existed prior to the bus reset) we send update calls
* down to the drivers. Otherwise, this is a dead node and we
* suspend it. */
if
(
ne
->
needs_probe
)
nodemgr_process_root_directory
(
hi
,
ne
);
else
if
(
ne
->
generation
==
generation
)
list_for_each_entry
(
udev
,
&
dev
->
children
,
node
)
nodemgr_ud_update_pdrv
(
container_of
(
udev
,
struct
unit_directory
,
device
));
else
nodemgr_suspend_ne
(
ne
);
put_device
(
dev
);
}
static
void
nodemgr_node_probe
(
struct
host_info
*
hi
,
int
generation
)
{
struct
hpsb_host
*
host
=
hi
->
host
;
struct
ne_cb_data_struct
ne_cb_data
;
ne_cb_data
.
hi
=
hi
;
ne_cb_data
.
ne
=
NULL
;
struct
class
*
class
=
&
nodemgr_ne_class
;
struct
class_device
*
cdev
;
/* Do some processing of the nodes we've probed. This pulls them
* into the sysfs layer if needed, and can result in processing of
* unit-directories, or just updating the node and it's
* unit-directories. */
while
(
bus_for_each_dev
(
&
ieee1394_bus_type
,
ne_cb_data
.
ne
?
&
ne_cb_data
.
ne
->
device
:
NULL
,
&
ne_cb_data
,
nodemgr_probe_ne_cb
))
{
/* If we get in here, we've got a node that needs it's
* unit directories processed. */
struct
device
*
dev
=
get_device
(
&
ne_cb_data
.
ne
->
device
);
if
(
dev
)
{
nodemgr_process_root_directory
(
hi
,
ne_cb_data
.
ne
);
put_device
(
dev
);
}
}
down_read
(
&
class
->
subsys
.
rwsem
);
list_for_each_entry
(
cdev
,
&
class
->
children
,
node
)
nodemgr_probe_ne
(
hi
,
container_of
(
cdev
,
struct
node_entry
,
class_dev
),
generation
);
up_read
(
&
class
->
subsys
.
rwsem
);
/* If we had a bus reset while we were scanning the bus, it is
* possible that we did not probe all nodes. In that case, we
* skip the clean up for now, since we could remove nodes that
* were still on the bus. The bus reset increased hi->reset_sem,
* so there's a bus scan pending which will do the clean up
* eventually. */
if
(
generation
==
get_hpsb_generation
(
host
))
{
struct
cleanup_baton
cleanup
;
cleanup
.
generation
=
generation
;
cleanup
.
host
=
host
;
/* This will iterate until all devices that do not match
* the generation are removed. */
while
(
bus_for_each_dev
(
&
ieee1394_bus_type
,
NULL
,
&
cleanup
,
nodemgr_remove_node
))
{
struct
node_entry
*
ne
=
cleanup
.
ne
;
HPSB_DEBUG
(
"Node removed: ID:BUS["
NODE_BUS_FMT
"] GUID[%016Lx]"
,
NODE_BUS_ARGS
(
host
,
ne
->
nodeid
),
(
unsigned
long
long
)
ne
->
guid
);
nodemgr_remove_ne
(
ne
);
}
/* Now let's tell the bus to rescan our devices. This may
* seem like overhead, but the driver-model core will only
* scan a device for a driver when either the device is
* added, or when a new driver is added. A bus reset is a
* good reason to rescan devices that were there before.
* For example, an sbp2 device may become available for
* login, if the host that held it was just removed. */
* eventually.
*
* Now let's tell the bus to rescan our devices. This may seem
* like overhead, but the driver-model core will only scan a
* device for a driver when either the device is added, or when a
* new driver is added. A bus reset is a good reason to rescan
* devices that were there before. For example, an sbp2 device
* may become available for login, if the host that held it was
* just removed. */
if
(
generation
==
get_hpsb_generation
(
host
))
bus_rescan_devices
(
&
ieee1394_bus_type
);
}
return
;
}
...
...
@@ -1736,32 +1620,24 @@ struct node_entry *hpsb_nodeid_get_entry(struct hpsb_host *host, nodeid_t nodeid
return
ne
;
}
struct
for_each_host_struct
{
int
(
*
cb
)(
struct
hpsb_host
*
,
void
*
);
void
*
data
;
};
static
int
nodemgr_for_each_host_cb
(
struct
device
*
dev
,
void
*
__data
)
int
nodemgr_for_each_host
(
void
*
__data
,
int
(
*
cb
)(
struct
hpsb_host
*
,
void
*
)
)
{
struct
for_each_host_struct
*
host_data
=
__data
;
struct
class
*
class
=
&
hpsb_host_class
;
struct
class_device
*
cdev
;
struct
hpsb_host
*
host
;
int
error
=
0
;
if
(
dev
->
driver_data
!=
&
nodemgr_driverdata_host
)
return
0
;
host
=
container_of
(
dev
,
struct
hpsb_host
,
device
);
down_read
(
&
class
->
subsys
.
rwsem
);
list_for_each_entry
(
cdev
,
&
class
->
children
,
node
)
{
host
=
container_of
(
cdev
,
struct
hpsb_host
,
class_dev
);
return
host_data
->
cb
(
host
,
host_data
->
data
);
}
int
nodemgr_for_each_host
(
void
*
__data
,
int
(
*
cb
)(
struct
hpsb_host
*
,
void
*
))
{
struct
for_each_host_struct
host_data
;
host_data
.
cb
=
cb
;
host_data
.
data
=
__data
;
if
((
error
=
cb
(
host
,
__data
)))
break
;
}
up_read
(
&
class
->
subsys
.
rwsem
);
return
bus_for_each_dev
(
&
ieee1394_bus_type
,
NULL
,
&
host_data
,
nodemgr_for_each_host_cb
)
;
return
error
;
}
/* The following four convenience functions use a struct node_entry
...
...
@@ -1887,6 +1763,7 @@ void init_ieee1394_nodemgr(void)
{
driver_register
(
&
nodemgr_driver_host
);
driver_register
(
&
nodemgr_driver_ne
);
class_register
(
&
nodemgr_ne_class
);
hpsb_register_highlevel
(
&
nodemgr_highlevel
);
}
...
...
@@ -1895,6 +1772,7 @@ void cleanup_ieee1394_nodemgr(void)
{
hpsb_unregister_highlevel
(
&
nodemgr_highlevel
);
class_unregister
(
&
nodemgr_ne_class
);
driver_unregister
(
&
nodemgr_driver_ne
);
driver_unregister
(
&
nodemgr_driver_host
);
}
drivers/ieee1394/nodemgr.h
View file @
16eadb50
...
...
@@ -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 */
drivers/ieee1394/ohci1394.c
View file @
16eadb50
...
...
@@ -115,6 +115,7 @@
#include <asm/pci-bridge.h>
#endif
#include "csr1212.h"
#include "ieee1394.h"
#include "ieee1394_types.h"
#include "hosts.h"
...
...
@@ -161,7 +162,7 @@ printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)
printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
static
char
version
[]
__devinitdata
=
"$Rev: 1
097
$ Ben Collins <bcollins@debian.org>"
;
"$Rev: 1
131
$ Ben Collins <bcollins@debian.org>"
;
/* Module Parameters */
static
int
phys_dma
=
1
;
...
...
@@ -495,8 +496,6 @@ static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg)
return
ctx
;
}
static
void
ohci_init_config_rom
(
struct
ti_ohci
*
ohci
);
/* Global initialization */
static
void
ohci_initialize
(
struct
ti_ohci
*
ohci
)
{
...
...
@@ -540,9 +539,6 @@ static void ohci_initialize(struct ti_ohci *ohci)
/* Set the Config ROM mapping register */
reg_write
(
ohci
,
OHCI1394_ConfigROMmap
,
ohci
->
csr_config_rom_bus
);
/* Initialize the Config ROM */
ohci_init_config_rom
(
ohci
);
/* Now get our max packet size */
ohci
->
max_packet_size
=
1
<<
(((
reg_read
(
ohci
,
OHCI1394_BusOptions
)
>>
12
)
&
0xf
)
+
1
);
...
...
@@ -2211,14 +2207,12 @@ static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci,
quadlet_t
rx_event
,
quadlet_t
tx_event
)
{
struct
list_head
*
lh
;
struct
ohci1394_iso_tasklet
*
t
;
unsigned
long
mask
;
spin_lock
(
&
ohci
->
iso_tasklet_list_lock
);
list_for_each
(
lh
,
&
ohci
->
iso_tasklet_list
)
{
t
=
list_entry
(
lh
,
struct
ohci1394_iso_tasklet
,
link
);
list_for_each_entry
(
t
,
&
ohci
->
iso_tasklet_list
,
link
)
{
mask
=
1
<<
t
->
context
;
if
(
t
->
type
==
OHCI_ISO_TRANSMIT
&&
tx_event
&
mask
)
...
...
@@ -3085,154 +3079,16 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
return
0
;
}
static
u16
ohci_crc16
(
u32
*
ptr
,
int
length
)
{
int
shift
;
u32
crc
,
sum
,
data
;
crc
=
0
;
for
(;
length
>
0
;
length
--
)
{
data
=
be32_to_cpu
(
*
ptr
++
);
for
(
shift
=
28
;
shift
>=
0
;
shift
-=
4
)
{
sum
=
((
crc
>>
12
)
^
(
data
>>
shift
))
&
0x000f
;
crc
=
(
crc
<<
4
)
^
(
sum
<<
12
)
^
(
sum
<<
5
)
^
sum
;
}
crc
&=
0xffff
;
}
return
crc
;
}
/* Config ROM macro implementation influenced by NetBSD OHCI driver */
struct
config_rom_unit
{
u32
*
start
;
u32
*
refer
;
int
length
;
int
refunit
;
};
struct
config_rom_ptr
{
u32
*
data
;
int
unitnum
;
struct
config_rom_unit
unitdir
[
10
];
};
#define cf_put_1quad(cr, q) (((cr)->data++)[0] = cpu_to_be32(q))
#define cf_put_4bytes(cr, b1, b2, b3, b4) \
(((cr)->data++)[0] = cpu_to_be32(((b1) << 24) | ((b2) << 16) | ((b3) << 8) | (b4)))
#define cf_put_keyval(cr, key, val) (((cr)->data++)[0] = cpu_to_be32(((key) << 24) | (val)))
static
inline
void
cf_put_str
(
struct
config_rom_ptr
*
cr
,
const
char
*
str
)
{
int
t
;
char
fourb
[
4
];
while
(
str
[
0
])
{
memset
(
fourb
,
0
,
4
);
for
(
t
=
0
;
t
<
4
&&
str
[
t
];
t
++
)
fourb
[
t
]
=
str
[
t
];
cf_put_4bytes
(
cr
,
fourb
[
0
],
fourb
[
1
],
fourb
[
2
],
fourb
[
3
]);
str
+=
strlen
(
str
)
<
4
?
strlen
(
str
)
:
4
;
}
return
;
}
static
inline
void
cf_put_crc16
(
struct
config_rom_ptr
*
cr
,
int
unit
)
{
*
cr
->
unitdir
[
unit
].
start
=
cpu_to_be32
((
cr
->
unitdir
[
unit
].
length
<<
16
)
|
ohci_crc16
(
cr
->
unitdir
[
unit
].
start
+
1
,
cr
->
unitdir
[
unit
].
length
));
}
static
inline
void
cf_unit_begin
(
struct
config_rom_ptr
*
cr
,
int
unit
)
{
if
(
cr
->
unitdir
[
unit
].
refer
!=
NULL
)
{
*
cr
->
unitdir
[
unit
].
refer
|=
cpu_to_be32
(
cr
->
data
-
cr
->
unitdir
[
unit
].
refer
);
cf_put_crc16
(
cr
,
cr
->
unitdir
[
unit
].
refunit
);
}
cr
->
unitnum
=
unit
;
cr
->
unitdir
[
unit
].
start
=
cr
->
data
++
;
}
static
inline
void
cf_put_refer
(
struct
config_rom_ptr
*
cr
,
char
key
,
int
unit
)
{
cr
->
unitdir
[
unit
].
refer
=
cr
->
data
;
cr
->
unitdir
[
unit
].
refunit
=
cr
->
unitnum
;
(
cr
->
data
++
)[
0
]
=
cpu_to_be32
(
key
<<
24
);
}
static
inline
void
cf_unit_end
(
struct
config_rom_ptr
*
cr
)
static
void
ohci_set_hw_config_rom
(
struct
hpsb_host
*
host
,
quadlet_t
*
config_rom
)
{
cr
->
unitdir
[
cr
->
unitnum
].
length
=
cr
->
data
-
(
cr
->
unitdir
[
cr
->
unitnum
].
start
+
1
);
cf_put_crc16
(
cr
,
cr
->
unitnum
);
}
struct
ti_ohci
*
ohci
=
host
->
hostdata
;
/* End of NetBSD derived code. */
reg_write
(
ohci
,
OHCI1394_ConfigROMhdr
,
be32_to_cpu
(
config_rom
[
0
]));
reg_write
(
ohci
,
OHCI1394_BusOptions
,
be32_to_cpu
(
config_rom
[
2
]));
static
void
ohci_init_config_rom
(
struct
ti_ohci
*
ohci
)
{
struct
config_rom_ptr
cr
;
memset
(
&
cr
,
0
,
sizeof
(
cr
));
memset
(
ohci
->
csr_config_rom_cpu
,
0
,
OHCI_CONFIG_ROM_LEN
);
cr
.
data
=
ohci
->
csr_config_rom_cpu
;
/* Bus info block */
cf_unit_begin
(
&
cr
,
0
);
cf_put_1quad
(
&
cr
,
reg_read
(
ohci
,
OHCI1394_BusID
));
cf_put_1quad
(
&
cr
,
reg_read
(
ohci
,
OHCI1394_BusOptions
));
cf_put_1quad
(
&
cr
,
reg_read
(
ohci
,
OHCI1394_GUIDHi
));
cf_put_1quad
(
&
cr
,
reg_read
(
ohci
,
OHCI1394_GUIDLo
));
cf_unit_end
(
&
cr
);
DBGMSG
(
ohci
->
id
,
"GUID: %08x:%08x"
,
reg_read
(
ohci
,
OHCI1394_GUIDHi
),
reg_read
(
ohci
,
OHCI1394_GUIDLo
));
/* IEEE P1212 suggests the initial ROM header CRC should only
* cover the header itself (and not the entire ROM). Since we do
* this, then we can make our bus_info_len the same as the CRC
* length. */
ohci
->
csr_config_rom_cpu
[
0
]
|=
cpu_to_be32
(
(
be32_to_cpu
(
ohci
->
csr_config_rom_cpu
[
0
])
&
0x00ff0000
)
<<
8
);
reg_write
(
ohci
,
OHCI1394_ConfigROMhdr
,
be32_to_cpu
(
ohci
->
csr_config_rom_cpu
[
0
]));
/* Root directory */
cf_unit_begin
(
&
cr
,
1
);
/* Vendor ID */
cf_put_keyval
(
&
cr
,
0x03
,
reg_read
(
ohci
,
OHCI1394_VendorID
)
&
0xFFFFFF
);
cf_put_refer
(
&
cr
,
0x81
,
2
);
/* Textual description unit */
cf_put_keyval
(
&
cr
,
0x0c
,
0x0083c0
);
/* Node capabilities */
/* NOTE: Add other unit referers here, and append at bottom */
cf_unit_end
(
&
cr
);
/* Textual description - "Linux 1394" */
cf_unit_begin
(
&
cr
,
2
);
cf_put_keyval
(
&
cr
,
0
,
0
);
cf_put_1quad
(
&
cr
,
0
);
cf_put_str
(
&
cr
,
"Linux OHCI-1394"
);
cf_unit_end
(
&
cr
);
ohci
->
csr_config_rom_length
=
cr
.
data
-
ohci
->
csr_config_rom_cpu
;
memcpy
(
ohci
->
csr_config_rom_cpu
,
config_rom
,
OHCI_CONFIG_ROM_LEN
);
}
static
size_t
ohci_get_rom
(
struct
hpsb_host
*
host
,
quadlet_t
**
ptr
)
{
struct
ti_ohci
*
ohci
=
host
->
hostdata
;
DBGMSG
(
ohci
->
id
,
"request csr_rom address: %p"
,
ohci
->
csr_config_rom_cpu
);
*
ptr
=
ohci
->
csr_config_rom_cpu
;
return
ohci
->
csr_config_rom_length
*
4
;
}
static
quadlet_t
ohci_hw_csr_reg
(
struct
hpsb_host
*
host
,
int
reg
,
quadlet_t
data
,
quadlet_t
compare
)
...
...
@@ -3257,7 +3113,7 @@ static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,
static
struct
hpsb_host_driver
ohci1394_driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
OHCI1394_DRIVER_NAME
,
.
get_rom
=
ohci_get
_rom
,
.
set_hw_config_rom
=
ohci_set_hw_config
_rom
,
.
transmit_packet
=
ohci_transmit
,
.
devctl
=
ohci_devctl
,
.
isoctl
=
ohci_isoctl
,
...
...
@@ -3280,6 +3136,11 @@ do { \
static
int
__devinit
ohci1394_pci_probe
(
struct
pci_dev
*
dev
,
const
struct
pci_device_id
*
ent
)
{
struct
csr1212_keyval
*
root
;
struct
csr1212_keyval
*
vend_id
=
NULL
;
struct
csr1212_keyval
*
text
=
NULL
;
int
ret
;
static
int
version_printed
=
0
;
struct
hpsb_host
*
host
;
...
...
@@ -3458,6 +3319,45 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
ohci
->
init_state
=
OHCI_INIT_HAVE_IRQ
;
ohci_initialize
(
ohci
);
/* Setup initial root directory entries */
root
=
host
->
csr
.
rom
->
root_kv
;
vend_id
=
csr1212_new_immediate
(
CSR1212_KV_ID_VENDOR
,
reg_read
(
ohci
,
OHCI1394_GUIDHi
)
>>
8
);
text
=
csr1212_new_string_descriptor_leaf
(
"Linux 1394 - OHCI"
);
if
(
!
vend_id
||
!
text
)
{
if
(
vend_id
)
{
csr1212_release_keyval
(
vend_id
);
}
if
(
text
)
{
csr1212_release_keyval
(
text
);
}
FAIL
(
-
ENOMEM
,
"Failed to allocate memory for mandatory ConfigROM entries!"
);
}
ret
=
csr1212_associate_keyval
(
vend_id
,
text
);
csr1212_release_keyval
(
text
);
if
(
ret
!=
CSR1212_SUCCESS
)
{
csr1212_release_keyval
(
vend_id
);
FAIL
(
ret
,
"Failed to associate text descriptor to vendor id"
);
}
ret
=
csr1212_attach_keyval_to_directory
(
root
,
vend_id
);
if
(
ret
!=
CSR1212_SUCCESS
)
{
csr1212_release_keyval
(
vend_id
);
FAIL
(
ret
,
"Failed to attach vendor id to root directory"
);
}
host
->
update_config_rom
=
1
;
/* Set certain csr values */
host
->
csr
.
guid_hi
=
reg_read
(
ohci
,
OHCI1394_GUIDHi
);
host
->
csr
.
guid_lo
=
reg_read
(
ohci
,
OHCI1394_GUIDLo
);
host
->
csr
.
cyc_clk_acc
=
100
;
/* how do we determine clk accuracy? */
host
->
csr
.
max_rec
=
(
reg_read
(
ohci
,
OHCI1394_BusOptions
)
>>
12
)
&
0xf
;
host
->
csr
.
lnk_spd
=
reg_read
(
ohci
,
OHCI1394_BusOptions
)
&
0x7
;
/* Tell the highlevel this host is ready */
hpsb_add_host
(
host
);
ohci
->
init_state
=
OHCI_INIT_DONE
;
...
...
@@ -3574,13 +3474,11 @@ static void ohci1394_pci_remove(struct pci_dev *pdev)
}
#ifdef CONFIG_PM
static
int
ohci1394_pci_resume
(
struct
pci_dev
*
dev
)
{
pci_enable_device
(
dev
);
return
0
;
}
#endif
#define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
...
...
@@ -3604,10 +3502,7 @@ static struct pci_driver ohci1394_pci_driver = {
.
id_table
=
ohci1394_pci_tbl
,
.
probe
=
ohci1394_pci_probe
,
.
remove
=
ohci1394_pci_remove
,
#ifdef CONFIG_PM
.
resume
=
ohci1394_pci_resume
,
#endif
/* PM */
};
...
...
drivers/ieee1394/pcilynx.c
View file @
16eadb50
...
...
@@ -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
,
...
...
drivers/ieee1394/pcilynx.h
View file @
16eadb50
#ifndef __PCILYNX_H__
#define __PCILYNX_H__
#include <linux/config.h>
#define PCILYNX_DRIVER_NAME "pcilynx"
...
...
@@ -50,7 +53,7 @@ struct ti_lynx {
void
*
local_rom
;
void
*
local_ram
;
void
*
aux_port
;
quadlet_t
config_rom
[
PCILYNX_CONFIG_ROM_LENGTH
/
4
];
quadlet_t
bus_info_block
[
5
];
#ifdef CONFIG_IEEE1394_PCILYNX_PORTS
atomic_t
aux_intr_seen
;
...
...
@@ -510,76 +513,4 @@ static inline void run_pcl(const struct ti_lynx *lynx, pcl_t pclid, int dmachan)
#define PCL_BIGENDIAN (1<<16)
#define PCL_ISOMODE (1<<12)
#define _(x) (__constant_cpu_to_be32(x))
static
quadlet_t
lynx_csr_rom
[]
=
{
/* bus info block offset (hex) */
_
(
0x04046aaf
),
/* info/CRC length, CRC 400 */
_
(
0x31333934
),
/* 1394 magic number 404 */
_
(
0xf064a000
),
/* misc. settings 408 */
_
(
0x08002850
),
/* vendor ID, chip ID high 40c */
_
(
0x0000ffff
),
/* chip ID low 410 */
/* root directory */
_
(
0x00095778
),
/* directory length, CRC 414 */
_
(
0x03080028
),
/* vendor ID (Texas Instr.) 418 */
_
(
0x81000008
),
/* offset to textual ID 41c */
_
(
0x0c000200
),
/* node capabilities 420 */
_
(
0x8d00000e
),
/* offset to unique ID 424 */
_
(
0xc7000010
),
/* offset to module independent info 428 */
_
(
0x04000000
),
/* module hardware version 42c */
_
(
0x81000014
),
/* offset to textual ID 430 */
_
(
0x09000000
),
/* node hardware version 434 */
_
(
0x81000018
),
/* offset to textual ID 438 */
/* module vendor ID textual */
_
(
0x00070812
),
/* CRC length, CRC 43c */
_
(
0x00000000
),
/* 440 */
_
(
0x00000000
),
/* 444 */
_
(
0x54455841
),
/* "Texas Instruments" 448 */
_
(
0x5320494e
),
/* 44c */
_
(
0x53545255
),
/* 450 */
_
(
0x4d454e54
),
/* 454 */
_
(
0x53000000
),
/* 458 */
/* node unique ID leaf */
_
(
0x00022ead
),
/* CRC length, CRC 45c */
_
(
0x08002850
),
/* vendor ID, chip ID high 460 */
_
(
0x0000ffff
),
/* chip ID low 464 */
/* module dependent info */
_
(
0x0005d837
),
/* CRC length, CRC 468 */
_
(
0x81000012
),
/* offset to module textual ID 46c */
_
(
0x81000017
),
/* textual descriptor 470 */
_
(
0x39010000
),
/* SRAM size 474 */
_
(
0x3a010000
),
/* AUXRAM size 478 */
_
(
0x3b000000
),
/* AUX device 47c */
/* module textual ID */
_
(
0x000594df
),
/* CRC length, CRC 480 */
_
(
0x00000000
),
/* 484 */
_
(
0x00000000
),
/* 488 */
_
(
0x54534231
),
/* "TSB12LV21" 48c */
_
(
0x324c5632
),
/* 490 */
_
(
0x31000000
),
/* 494 */
/* part number */
_
(
0x00068405
),
/* CRC length, CRC 498 */
_
(
0x00000000
),
/* 49c */
_
(
0x00000000
),
/* 4a0 */
_
(
0x39383036
),
/* "9806000-0001" 4a4 */
_
(
0x3030302d
),
/* 4a8 */
_
(
0x30303031
),
/* 4ac */
_
(
0x20000001
),
/* 4b0 */
/* module hardware version textual */
_
(
0x00056501
),
/* CRC length, CRC 4b4 */
_
(
0x00000000
),
/* 4b8 */
_
(
0x00000000
),
/* 4bc */
_
(
0x5453424b
),
/* "TSBKPCITST" 4c0 */
_
(
0x50434954
),
/* 4c4 */
_
(
0x53540000
),
/* 4c8 */
/* node hardware version textual */
_
(
0x0005d805
),
/* CRC length, CRC 4d0 */
_
(
0x00000000
),
/* 4d4 */
_
(
0x00000000
),
/* 4d8 */
_
(
0x54534232
),
/* "TSB21LV03" 4dc */
_
(
0x314c5630
),
/* 4e0 */
_
(
0x33000000
)
/* 4e4 */
};
#undef _
#endif
drivers/ieee1394/raw1394-private.h
View file @
16eadb50
...
...
@@ -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
{
...
...
drivers/ieee1394/raw1394.c
View file @
16eadb50
...
...
@@ -43,6 +43,7 @@
#include <asm/atomic.h>
#include <linux/devfs_fs_kernel.h>
#include "csr1212.h"
#include "ieee1394.h"
#include "ieee1394_types.h"
#include "ieee1394_core.h"
...
...
@@ -214,15 +215,11 @@ static void add_host(struct hpsb_host *host)
static
struct
host_info
*
find_host_info
(
struct
hpsb_host
*
host
)
{
struct
list_head
*
lh
;
struct
host_info
*
hi
;
list_for_each
(
lh
,
&
host_info_list
)
{
hi
=
list_entry
(
lh
,
struct
host_info
,
list
);
if
(
hi
->
host
==
host
)
{
list_for_each_entry
(
hi
,
&
host_info_list
,
list
)
if
(
hi
->
host
==
host
)
return
hi
;
}
}
return
NULL
;
}
...
...
@@ -261,7 +258,6 @@ static void remove_host(struct hpsb_host *host)
static
void
host_reset
(
struct
hpsb_host
*
host
)
{
unsigned
long
flags
;
struct
list_head
*
lh
;
struct
host_info
*
hi
;
struct
file_info
*
fi
;
struct
pending_request
*
req
;
...
...
@@ -270,8 +266,7 @@ static void host_reset(struct hpsb_host *host)
hi
=
find_host_info
(
host
);
if
(
hi
!=
NULL
)
{
list_for_each
(
lh
,
&
hi
->
file_info_list
)
{
fi
=
list_entry
(
lh
,
struct
file_info
,
list
);
list_for_each_entry
(
fi
,
&
hi
->
file_info_list
,
list
)
{
if
(
fi
->
notification
==
RAW1394_NOTIFY_ON
)
{
req
=
__alloc_pending_request
(
SLAB_ATOMIC
);
...
...
@@ -298,7 +293,6 @@ static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
size_t
length
)
{
unsigned
long
flags
;
struct
list_head
*
lh
;
struct
host_info
*
hi
;
struct
file_info
*
fi
;
struct
pending_request
*
req
;
...
...
@@ -314,12 +308,9 @@ static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
hi
=
find_host_info
(
host
);
if
(
hi
!=
NULL
)
{
list_for_each
(
lh
,
&
hi
->
file_info_list
)
{
fi
=
list_entry
(
lh
,
struct
file_info
,
list
);
if
(
!
(
fi
->
listen_channels
&
(
1ULL
<<
channel
)))
{
list_for_each_entry
(
fi
,
&
hi
->
file_info_list
,
list
)
{
if
(
!
(
fi
->
listen_channels
&
(
1ULL
<<
channel
)))
continue
;
}
req
=
__alloc_pending_request
(
SLAB_ATOMIC
);
if
(
!
req
)
break
;
...
...
@@ -354,20 +345,14 @@ static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,
}
spin_unlock_irqrestore
(
&
host_info_lock
,
flags
);
lh
=
reqs
.
next
;
while
(
lh
!=
&
reqs
)
{
req
=
list_entry
(
lh
,
struct
pending_request
,
list
);
lh
=
lh
->
next
;
list_for_each_entry
(
req
,
&
reqs
,
list
)
queue_complete_req
(
req
);
}
}
static
void
fcp_request
(
struct
hpsb_host
*
host
,
int
nodeid
,
int
direction
,
int
cts
,
u8
*
data
,
size_t
length
)
{
unsigned
long
flags
;
struct
list_head
*
lh
;
struct
host_info
*
hi
;
struct
file_info
*
fi
;
struct
pending_request
*
req
;
...
...
@@ -383,12 +368,9 @@ static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
hi
=
find_host_info
(
host
);
if
(
hi
!=
NULL
)
{
list_for_each
(
lh
,
&
hi
->
file_info_list
)
{
fi
=
list_entry
(
lh
,
struct
file_info
,
list
);
if
(
!
fi
->
fcp_buffer
)
{
list_for_each_entry
(
fi
,
&
hi
->
file_info_list
,
list
)
{
if
(
!
fi
->
fcp_buffer
)
continue
;
}
req
=
__alloc_pending_request
(
SLAB_ATOMIC
);
if
(
!
req
)
break
;
...
...
@@ -423,13 +405,8 @@ static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
}
spin_unlock_irqrestore
(
&
host_info_lock
,
flags
);
lh
=
reqs
.
next
;
while
(
lh
!=
&
reqs
)
{
req
=
list_entry
(
lh
,
struct
pending_request
,
list
);
lh
=
lh
->
next
;
list_for_each_entry
(
req
,
&
reqs
,
list
)
queue_complete_req
(
req
);
}
}
...
...
@@ -505,7 +482,6 @@ static int state_opened(struct file_info *fi, struct pending_request *req)
static
int
state_initialized
(
struct
file_info
*
fi
,
struct
pending_request
*
req
)
{
struct
list_head
*
lh
;
struct
host_info
*
hi
;
struct
raw1394_khost_list
*
khl
;
...
...
@@ -527,12 +503,9 @@ static int state_initialized(struct file_info *fi, struct pending_request *req)
req
->
req
.
misc
=
host_count
;
req
->
data
=
(
quadlet_t
*
)
khl
;
list_for_each
(
lh
,
&
host_info_list
)
{
hi
=
list_entry
(
lh
,
struct
host_info
,
list
);
list_for_each_entry
(
hi
,
&
host_info_list
,
list
)
{
khl
->
nodes
=
hi
->
host
->
node_count
;
strcpy
(
khl
->
name
,
hi
->
host
->
driver
->
name
);
khl
++
;
}
}
...
...
@@ -550,23 +523,17 @@ static int state_initialized(struct file_info *fi, struct pending_request *req)
break
;
case
RAW1394_REQ_SET_CARD
:
lh
=
NULL
;
spin_lock_irq
(
&
host_info_lock
);
if
(
req
->
req
.
misc
<
host_count
)
{
lh
=
host_info_list
.
next
;
while
(
req
->
req
.
misc
--
)
{
lh
=
lh
->
next
;
}
hi
=
list_entry
(
lh
,
struct
host_info
,
list
);
list_for_each_entry
(
hi
,
&
host_info_list
,
list
)
{
if
(
!
req
->
req
.
misc
--
)
break
;
}
get_device
(
&
hi
->
host
->
device
);
// XXX Need to handle failure case
list_add_tail
(
&
fi
->
list
,
&
hi
->
file_info_list
);
fi
->
host
=
hi
->
host
;
fi
->
state
=
connected
;
}
spin_unlock_irq
(
&
host_info_lock
);
if
(
lh
!=
NULL
)
{
req
->
req
.
error
=
RAW1394_ERROR_NONE
;
req
->
req
.
generation
=
get_hpsb_generation
(
fi
->
host
);
req
->
req
.
misc
=
(
fi
->
host
->
node_id
<<
16
)
...
...
@@ -577,6 +544,7 @@ static int state_initialized(struct file_info *fi, struct pending_request *req)
}
else
{
req
->
req
.
error
=
RAW1394_ERROR_INVALID_ARG
;
}
spin_unlock_irq
(
&
host_info_lock
);
req
->
req
.
length
=
0
;
break
;
...
...
@@ -898,7 +866,6 @@ static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
u64
addr
,
size_t
length
,
u16
flags
)
{
struct
pending_request
*
req
;
struct
list_head
*
lh
;
struct
host_info
*
hi
;
struct
file_info
*
fi
=
NULL
;
struct
list_head
*
entry
;
...
...
@@ -915,8 +882,7 @@ static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
spin_lock
(
&
host_info_lock
);
hi
=
find_host_info
(
host
);
/* search address-entry */
if
(
hi
!=
NULL
)
{
list_for_each
(
lh
,
&
hi
->
file_info_list
)
{
fi
=
list_entry
(
lh
,
struct
file_info
,
list
);
list_for_each_entry
(
fi
,
&
hi
->
file_info_list
,
list
)
{
entry
=
fi
->
addr_list
.
next
;
while
(
entry
!=
&
(
fi
->
addr_list
))
{
arm_addr
=
list_entry
(
entry
,
struct
arm_addr
,
addr_list
);
...
...
@@ -1034,7 +1000,6 @@ static int arm_write (struct hpsb_host *host, int nodeid, int destid,
quadlet_t
*
data
,
u64
addr
,
size_t
length
,
u16
flags
)
{
struct
pending_request
*
req
;
struct
list_head
*
lh
;
struct
host_info
*
hi
;
struct
file_info
*
fi
=
NULL
;
struct
list_head
*
entry
;
...
...
@@ -1051,8 +1016,7 @@ static int arm_write (struct hpsb_host *host, int nodeid, int destid,
spin_lock
(
&
host_info_lock
);
hi
=
find_host_info
(
host
);
/* search address-entry */
if
(
hi
!=
NULL
)
{
list_for_each
(
lh
,
&
hi
->
file_info_list
)
{
fi
=
list_entry
(
lh
,
struct
file_info
,
list
);
list_for_each_entry
(
fi
,
&
hi
->
file_info_list
,
list
)
{
entry
=
fi
->
addr_list
.
next
;
while
(
entry
!=
&
(
fi
->
addr_list
))
{
arm_addr
=
list_entry
(
entry
,
struct
arm_addr
,
addr_list
);
...
...
@@ -1161,7 +1125,6 @@ static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store,
u64
addr
,
quadlet_t
data
,
quadlet_t
arg
,
int
ext_tcode
,
u16
flags
)
{
struct
pending_request
*
req
;
struct
list_head
*
lh
;
struct
host_info
*
hi
;
struct
file_info
*
fi
=
NULL
;
struct
list_head
*
entry
;
...
...
@@ -1187,8 +1150,7 @@ static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store,
spin_lock
(
&
host_info_lock
);
hi
=
find_host_info
(
host
);
/* search address-entry */
if
(
hi
!=
NULL
)
{
list_for_each
(
lh
,
&
hi
->
file_info_list
)
{
fi
=
list_entry
(
lh
,
struct
file_info
,
list
);
list_for_each_entry
(
fi
,
&
hi
->
file_info_list
,
list
)
{
entry
=
fi
->
addr_list
.
next
;
while
(
entry
!=
&
(
fi
->
addr_list
))
{
arm_addr
=
list_entry
(
entry
,
struct
arm_addr
,
addr_list
);
...
...
@@ -1359,7 +1321,6 @@ static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store,
u64
addr
,
octlet_t
data
,
octlet_t
arg
,
int
ext_tcode
,
u16
flags
)
{
struct
pending_request
*
req
;
struct
list_head
*
lh
;
struct
host_info
*
hi
;
struct
file_info
*
fi
=
NULL
;
struct
list_head
*
entry
;
...
...
@@ -1394,8 +1355,7 @@ static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store,
spin_lock
(
&
host_info_lock
);
hi
=
find_host_info
(
host
);
/* search addressentry in file_info's for host */
if
(
hi
!=
NULL
)
{
list_for_each
(
lh
,
&
hi
->
file_info_list
)
{
fi
=
list_entry
(
lh
,
struct
file_info
,
list
);
list_for_each_entry
(
fi
,
&
hi
->
file_info_list
,
list
)
{
entry
=
fi
->
addr_list
.
next
;
while
(
entry
!=
&
(
fi
->
addr_list
))
{
arm_addr
=
list_entry
(
entry
,
struct
arm_addr
,
addr_list
);
...
...
@@ -1566,7 +1526,6 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
{
int
retval
;
struct
arm_addr
*
addr
;
struct
list_head
*
lh
,
*
lh_1
,
*
lh_2
;
struct
host_info
*
hi
;
struct
file_info
*
fi_hlp
=
NULL
;
struct
list_head
*
entry
;
...
...
@@ -1630,8 +1589,7 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
same_host
=
0
;
another_host
=
0
;
/* same host with address-entry containing same addressrange ? */
list_for_each
(
lh
,
&
hi
->
file_info_list
)
{
fi_hlp
=
list_entry
(
lh
,
struct
file_info
,
list
);
list_for_each_entry
(
fi_hlp
,
&
hi
->
file_info_list
,
list
)
{
entry
=
fi_hlp
->
addr_list
.
next
;
while
(
entry
!=
&
(
fi_hlp
->
addr_list
))
{
arm_addr
=
list_entry
(
entry
,
struct
arm_addr
,
addr_list
);
...
...
@@ -1656,11 +1614,9 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
return
(
-
EALREADY
);
}
/* another host with valid address-entry containing same addressrange */
list_for_each
(
lh_1
,
&
host_info_list
)
{
hi
=
list_entry
(
lh_1
,
struct
host_info
,
list
);
list_for_each_entry
(
hi
,
&
host_info_list
,
list
)
{
if
(
hi
->
host
!=
fi
->
host
)
{
list_for_each
(
lh_2
,
&
hi
->
file_info_list
)
{
fi_hlp
=
list_entry
(
lh_2
,
struct
file_info
,
list
);
list_for_each_entry
(
fi_hlp
,
&
hi
->
file_info_list
,
list
)
{
entry
=
fi_hlp
->
addr_list
.
next
;
while
(
entry
!=
&
(
fi_hlp
->
addr_list
))
{
arm_addr
=
list_entry
(
entry
,
struct
arm_addr
,
addr_list
);
...
...
@@ -1719,7 +1675,6 @@ static int arm_unregister(struct file_info *fi, struct pending_request *req)
int
retval
=
0
;
struct
list_head
*
entry
;
struct
arm_addr
*
addr
=
NULL
;
struct
list_head
*
lh_1
,
*
lh_2
;
struct
host_info
*
hi
;
struct
file_info
*
fi_hlp
=
NULL
;
struct
arm_addr
*
arm_addr
=
NULL
;
...
...
@@ -1750,11 +1705,9 @@ static int arm_unregister(struct file_info *fi, struct pending_request *req)
another_host
=
0
;
/* another host with valid address-entry containing
same addressrange */
list_for_each
(
lh_1
,
&
host_info_list
)
{
hi
=
list_entry
(
lh_1
,
struct
host_info
,
list
);
list_for_each_entry
(
hi
,
&
host_info_list
,
list
)
{
if
(
hi
->
host
!=
fi
->
host
)
{
list_for_each
(
lh_2
,
&
hi
->
file_info_list
)
{
fi_hlp
=
list_entry
(
lh_2
,
struct
file_info
,
list
);
list_for_each_entry
(
fi_hlp
,
&
hi
->
file_info_list
,
list
)
{
entry
=
fi_hlp
->
addr_list
.
next
;
while
(
entry
!=
&
(
fi_hlp
->
addr_list
))
{
arm_addr
=
list_entry
(
entry
,
...
...
@@ -1822,9 +1775,9 @@ static int arm_get_buf(struct file_info *fi, struct pending_request *req)
if
(
req
->
req
.
address
+
req
->
req
.
length
<=
arm_addr
->
end
)
{
offset
=
req
->
req
.
address
-
arm_addr
->
start
;
DBGMSG
(
"arm_get_buf copy_to_user( %08X, %
08X
, %u )"
,
DBGMSG
(
"arm_get_buf copy_to_user( %08X, %
p
, %u )"
,
(
u32
)
req
->
req
.
recvb
,
(
u32
)
(
arm_addr
->
addr_space_buffer
+
offset
)
,
arm_addr
->
addr_space_buffer
+
offset
,
(
u32
)
req
->
req
.
length
);
if
(
copy_to_user
(
int2ptr
(
req
->
req
.
recvb
),
arm_addr
->
addr_space_buffer
+
offset
,
req
->
req
.
length
))
{
...
...
@@ -1833,7 +1786,10 @@ static int arm_get_buf(struct file_info *fi, struct pending_request *req)
}
spin_unlock_irqrestore
(
&
host_info_lock
,
flags
);
free_pending_request
(
req
);
/* we have to free the request, because we queue no response, and therefore nobody will free it */
/* We have to free the request, because we
* queue no response, and therefore nobody
* will free it. */
free_pending_request
(
req
);
return
sizeof
(
struct
raw1394_request
);
}
else
{
DBGMSG
(
"arm_get_buf request exceeded mapping"
);
...
...
@@ -1873,8 +1829,8 @@ static int arm_set_buf(struct file_info *fi, struct pending_request *req)
if
(
req
->
req
.
address
+
req
->
req
.
length
<=
arm_addr
->
end
)
{
offset
=
req
->
req
.
address
-
arm_addr
->
start
;
DBGMSG
(
"arm_set_buf copy_from_user( %
08X
, %08X, %u )"
,
(
u32
)
(
arm_addr
->
addr_space_buffer
+
offset
)
,
DBGMSG
(
"arm_set_buf copy_from_user( %
p
, %08X, %u )"
,
arm_addr
->
addr_space_buffer
+
offset
,
(
u32
)
req
->
req
.
sendb
,
(
u32
)
req
->
req
.
length
);
...
...
@@ -1941,22 +1897,22 @@ static int write_phypacket(struct file_info *fi, struct pending_request *req)
static
int
get_config_rom
(
struct
file_info
*
fi
,
struct
pending_request
*
req
)
{
size_t
return_size
;
unsigned
char
rom_version
;
int
ret
=
sizeof
(
struct
raw1394_request
);
quadlet_t
*
data
=
kmalloc
(
req
->
req
.
length
,
SLAB_KERNEL
);
int
status
;
if
(
!
data
)
return
-
ENOMEM
;
status
=
hpsb_get_config_rom
(
fi
->
host
,
data
,
req
->
req
.
length
,
&
return_size
,
&
rom_version
);
status
=
csr1212_read
(
fi
->
host
->
csr
.
rom
,
CSR1212_CONFIG_ROM_SPACE_OFFSET
,
data
,
req
->
req
.
length
);
if
(
copy_to_user
(
int2ptr
(
req
->
req
.
recvb
),
data
,
req
->
req
.
length
))
ret
=
-
EFAULT
;
if
(
copy_to_user
(
int2ptr
(
req
->
req
.
tag
),
&
return_size
,
sizeof
(
return_size
)))
if
(
copy_to_user
(
int2ptr
(
req
->
req
.
tag
),
&
fi
->
host
->
csr
.
rom
->
cache_head
->
len
,
sizeof
(
fi
->
host
->
csr
.
rom
->
cache_head
->
len
)))
ret
=
-
EFAULT
;
if
(
copy_to_user
(
int2ptr
(
req
->
req
.
address
),
&
rom_version
,
sizeof
(
rom_vers
ion
)))
if
(
copy_to_user
(
int2ptr
(
req
->
req
.
address
),
&
fi
->
host
->
csr
.
generation
,
sizeof
(
fi
->
host
->
csr
.
generat
ion
)))
ret
=
-
EFAULT
;
if
(
copy_to_user
(
int2ptr
(
req
->
req
.
sendb
),
&
status
,
sizeof
(
status
)))
...
...
@@ -1987,10 +1943,122 @@ static int update_config_rom(struct file_info *fi, struct pending_request *req)
kfree
(
data
);
if
(
ret
>=
0
)
{
free_pending_request
(
req
);
/* we have to free the request, because we queue no response, and therefore nobody will free it */
fi
->
cfgrom_upd
=
1
;
}
return
ret
;
}
static
int
modify_config_rom
(
struct
file_info
*
fi
,
struct
pending_request
*
req
)
{
struct
csr1212_keyval
*
kv
;
struct
csr1212_csr_rom_cache
*
cache
;
struct
csr1212_dentry
*
dentry
;
u32
dr
;
int
ret
=
0
;
if
(
req
->
req
.
misc
==
~
0
)
{
if
(
req
->
req
.
length
==
0
)
return
-
EINVAL
;
/* Find an unused slot */
for
(
dr
=
0
;
dr
<
RAW1394_MAX_USER_CSR_DIRS
&&
fi
->
csr1212_dirs
[
dr
];
dr
++
);
if
(
dr
==
RAW1394_MAX_USER_CSR_DIRS
)
return
-
ENOMEM
;
fi
->
csr1212_dirs
[
dr
]
=
csr1212_new_directory
(
CSR1212_KV_ID_VENDOR
);
if
(
!
fi
->
csr1212_dirs
[
dr
])
return
-
ENOMEM
;
}
else
{
dr
=
req
->
req
.
misc
;
if
(
!
fi
->
csr1212_dirs
[
dr
])
return
-
EINVAL
;
/* Delete old stuff */
for
(
dentry
=
fi
->
csr1212_dirs
[
dr
]
->
value
.
directory
.
dentries_head
;
dentry
;
dentry
=
dentry
->
next
)
{
csr1212_detach_keyval_from_directory
(
fi
->
host
->
csr
.
rom
->
root_kv
,
dentry
->
kv
);
}
if
(
req
->
req
.
length
==
0
)
{
csr1212_release_keyval
(
fi
->
csr1212_dirs
[
dr
]);
fi
->
csr1212_dirs
[
dr
]
=
NULL
;
hpsb_update_config_rom_image
(
fi
->
host
);
free_pending_request
(
req
);
return
sizeof
(
struct
raw1394_request
);
}
}
cache
=
csr1212_rom_cache_malloc
(
0
,
req
->
req
.
length
);
if
(
!
cache
)
{
csr1212_release_keyval
(
fi
->
csr1212_dirs
[
dr
]);
fi
->
csr1212_dirs
[
dr
]
=
NULL
;
return
-
ENOMEM
;
}
cache
->
filled_head
=
kmalloc
(
sizeof
(
struct
csr1212_cache_region
),
GFP_KERNEL
);
if
(
!
cache
->
filled_head
)
{
csr1212_release_keyval
(
fi
->
csr1212_dirs
[
dr
]);
fi
->
csr1212_dirs
[
dr
]
=
NULL
;
CSR1212_FREE
(
cache
);
return
-
ENOMEM
;
}
cache
->
filled_tail
=
cache
->
filled_head
;
if
(
copy_from_user
(
cache
->
data
,
int2ptr
(
req
->
req
.
sendb
),
req
->
req
.
length
))
{
csr1212_release_keyval
(
fi
->
csr1212_dirs
[
dr
]);
fi
->
csr1212_dirs
[
dr
]
=
NULL
;
CSR1212_FREE
(
cache
);
ret
=
-
EFAULT
;
}
else
{
cache
->
len
=
req
->
req
.
length
;
cache
->
filled_head
->
offset_start
=
0
;
cache
->
filled_head
->
offset_end
=
cache
->
size
-
1
;
cache
->
layout_head
=
cache
->
layout_tail
=
fi
->
csr1212_dirs
[
dr
];
ret
=
CSR1212_SUCCESS
;
/* parse all the items */
for
(
kv
=
cache
->
layout_head
;
ret
==
CSR1212_SUCCESS
&&
kv
;
kv
=
kv
->
next
)
{
ret
=
csr1212_parse_keyval
(
kv
,
cache
);
}
/* attach top level items to the root directory */
for
(
dentry
=
fi
->
csr1212_dirs
[
dr
]
->
value
.
directory
.
dentries_head
;
ret
==
CSR1212_SUCCESS
&&
dentry
;
dentry
=
dentry
->
next
)
{
ret
=
csr1212_attach_keyval_to_directory
(
fi
->
host
->
csr
.
rom
->
root_kv
,
dentry
->
kv
);
}
if
(
ret
==
CSR1212_SUCCESS
)
{
ret
=
hpsb_update_config_rom_image
(
fi
->
host
);
if
(
ret
>=
0
&&
copy_to_user
(
int2ptr
(
req
->
req
.
recvb
),
&
dr
,
sizeof
(
dr
)))
{
ret
=
-
ENOMEM
;
}
}
}
kfree
(
cache
->
filled_head
);
kfree
(
cache
);
if
(
ret
>=
0
)
{
/* we have to free the request, because we queue no response,
* and therefore nobody will free it */
free_pending_request
(
req
);
return
sizeof
(
struct
raw1394_request
);
}
else
{
for
(
dentry
=
fi
->
csr1212_dirs
[
dr
]
->
value
.
directory
.
dentries_head
;
dentry
;
dentry
=
dentry
->
next
)
{
csr1212_detach_keyval_from_directory
(
fi
->
host
->
csr
.
rom
->
root_kv
,
dentry
->
kv
);
}
csr1212_release_keyval
(
fi
->
csr1212_dirs
[
dr
]);
fi
->
csr1212_dirs
[
dr
]
=
NULL
;
return
ret
;
}
}
static
int
state_connected
(
struct
file_info
*
fi
,
struct
pending_request
*
req
)
{
int
node
=
req
->
req
.
address
>>
48
;
...
...
@@ -2049,6 +2117,9 @@ static int state_connected(struct file_info *fi, struct pending_request *req)
case
RAW1394_REQ_UPDATE_ROM
:
return
update_config_rom
(
fi
,
req
);
case
RAW1394_REQ_MODIFY_ROM
:
return
modify_config_rom
(
fi
,
req
);
}
if
(
req
->
req
.
generation
!=
get_hpsb_generation
(
fi
->
host
))
{
...
...
@@ -2125,15 +2196,11 @@ static ssize_t raw1394_write(struct file *file, const char *buffer, size_t count
* completion queue (reqlists_lock must be taken) */
static
inline
int
__rawiso_event_in_queue
(
struct
file_info
*
fi
)
{
struct
list_head
*
lh
;
struct
pending_request
*
req
;
list_for_each
(
lh
,
&
fi
->
req_complete
)
{
req
=
list_entry
(
lh
,
struct
pending_request
,
list
);
if
(
req
->
req
.
type
==
RAW1394_REQ_RAWISO_ACTIVITY
)
{
list_for_each_entry
(
req
,
&
fi
->
req_complete
,
list
)
if
(
req
->
req
.
type
==
RAW1394_REQ_RAWISO_ACTIVITY
)
return
1
;
}
}
return
0
;
}
...
...
@@ -2167,15 +2234,14 @@ static void queue_rawiso_event(struct file_info *fi)
static
void
rawiso_activity_cb
(
struct
hpsb_iso
*
iso
)
{
unsigned
long
flags
;
struct
list_head
*
lh
;
struct
host_info
*
hi
;
struct
file_info
*
fi
;
spin_lock_irqsave
(
&
host_info_lock
,
flags
);
hi
=
find_host_info
(
iso
->
host
);
if
(
hi
!=
NULL
)
{
list_for_each
(
lh
,
&
hi
->
file_info_list
)
{
struct
file_info
*
fi
=
list_entry
(
lh
,
struct
file_info
,
list
);
list_for_each_entry
(
fi
,
&
hi
->
file_info_list
,
list
)
{
if
(
fi
->
iso_handle
==
iso
)
queue_rawiso_event
(
fi
);
}
...
...
@@ -2495,11 +2561,11 @@ static int raw1394_release(struct inode *inode, struct file *file)
int
retval
=
0
;
struct
list_head
*
entry
;
struct
arm_addr
*
addr
=
NULL
;
struct
list_head
*
lh_1
,
*
lh_2
;
struct
host_info
*
hi
;
struct
file_info
*
fi_hlp
=
NULL
;
struct
arm_addr
*
arm_addr
=
NULL
;
int
another_host
;
int
csr_mod
=
0
;
if
(
fi
->
iso_state
!=
RAW1394_ISO_INACTIVE
)
raw1394_iso_shutdown
(
fi
);
...
...
@@ -2524,11 +2590,9 @@ static int raw1394_release(struct inode *inode, struct file *file)
addr
=
list_entry
(
lh
,
struct
arm_addr
,
addr_list
);
/* another host with valid address-entry containing
same addressrange? */
list_for_each
(
lh_1
,
&
host_info_list
)
{
hi
=
list_entry
(
lh_1
,
struct
host_info
,
list
);
list_for_each_entry
(
hi
,
&
host_info_list
,
list
)
{
if
(
hi
->
host
!=
fi
->
host
)
{
list_for_each
(
lh_2
,
&
hi
->
file_info_list
)
{
fi_hlp
=
list_entry
(
lh_2
,
struct
file_info
,
list
);
list_for_each_entry
(
fi_hlp
,
&
hi
->
file_info_list
,
list
)
{
entry
=
fi_hlp
->
addr_list
.
next
;
while
(
entry
!=
&
(
fi_hlp
->
addr_list
))
{
arm_addr
=
list_entry
(
entry
,
...
...
@@ -2587,6 +2651,22 @@ static int raw1394_release(struct inode *inode, struct file *file)
if
(
!
done
)
down_interruptible
(
&
fi
->
complete_sem
);
}
/* Remove any sub-trees left by user space programs */
for
(
i
=
0
;
i
<
RAW1394_MAX_USER_CSR_DIRS
;
i
++
)
{
struct
csr1212_dentry
*
dentry
;
if
(
!
fi
->
csr1212_dirs
[
i
])
continue
;
for
(
dentry
=
fi
->
csr1212_dirs
[
i
]
->
value
.
directory
.
dentries_head
;
dentry
;
dentry
=
dentry
->
next
)
{
csr1212_detach_keyval_from_directory
(
fi
->
host
->
csr
.
rom
->
root_kv
,
dentry
->
kv
);
}
csr1212_release_keyval
(
fi
->
csr1212_dirs
[
i
]);
fi
->
csr1212_dirs
[
i
]
=
NULL
;
csr_mod
=
1
;
}
if
((
csr_mod
||
fi
->
cfgrom_upd
)
&&
hpsb_update_config_rom_image
(
fi
->
host
)
<
0
)
HPSB_ERR
(
"Failed to generate Configuration ROM image for host %d"
,
fi
->
host
->
id
);
if
(
fi
->
state
==
connected
)
{
spin_lock_irq
(
&
host_info_lock
);
list_del
(
&
fi
->
list
);
...
...
drivers/ieee1394/raw1394.h
View file @
16eadb50
...
...
@@ -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
...
...
drivers/ieee1394/sbp2.c
View file @
16eadb50
...
...
@@ -67,6 +67,7 @@
#include "../scsi/scsi.h"
#include "../scsi/hosts.h"
#include "csr1212.h"
#include "ieee1394.h"
#include "ieee1394_types.h"
#include "ieee1394_core.h"
...
...
@@ -77,7 +78,7 @@
#include "sbp2.h"
static
char
version
[]
__devinitdata
=
"$Rev: 1
096
$ Ben Collins <bcollins@debian.org>"
;
"$Rev: 1
130
$ Ben Collins <bcollins@debian.org>"
;
/*
* Module load parameter definitions
...
...
@@ -233,6 +234,7 @@ const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xA, 0xB, 0xC };
static
struct
hpsb_highlevel
sbp2_highlevel
=
{
.
name
=
SBP2_DEVICE_NAME
,
.
remove_host
=
sbp2_remove_host
,
.
host_reset
=
sbp2_host_reset
,
};
static
struct
hpsb_address_ops
sbp2_ops
=
{
...
...
@@ -468,14 +470,12 @@ static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_
static
struct
sbp2_command_info
*
sbp2util_find_command_for_orb
(
struct
scsi_id_instance_data
*
scsi_id
,
dma_addr_t
orb
)
{
struct
list_head
*
lh
;
struct
sbp2_command_info
*
command
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
scsi_id
->
sbp2_command_orb_lock
,
flags
);
if
(
!
list_empty
(
&
scsi_id
->
sbp2_command_orb_inuse
))
{
list_for_each
(
lh
,
&
scsi_id
->
sbp2_command_orb_inuse
)
{
command
=
list_entry
(
lh
,
struct
sbp2_command_info
,
list
);
list_for_each_entry
(
command
,
&
scsi_id
->
sbp2_command_orb_inuse
,
list
)
{
if
(
command
->
command_orb_dma
==
orb
)
{
spin_unlock_irqrestore
(
&
scsi_id
->
sbp2_command_orb_lock
,
flags
);
return
(
command
);
...
...
@@ -495,14 +495,12 @@ static struct sbp2_command_info *sbp2util_find_command_for_orb(
*/
static
struct
sbp2_command_info
*
sbp2util_find_command_for_SCpnt
(
struct
scsi_id_instance_data
*
scsi_id
,
void
*
SCpnt
)
{
struct
list_head
*
lh
;
struct
sbp2_command_info
*
command
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
scsi_id
->
sbp2_command_orb_lock
,
flags
);
if
(
!
list_empty
(
&
scsi_id
->
sbp2_command_orb_inuse
))
{
list_for_each
(
lh
,
&
scsi_id
->
sbp2_command_orb_inuse
)
{
command
=
list_entry
(
lh
,
struct
sbp2_command_info
,
list
);
list_for_each_entry
(
command
,
&
scsi_id
->
sbp2_command_orb_inuse
,
list
)
{
if
(
command
->
Current_SCpnt
==
SCpnt
)
{
spin_unlock_irqrestore
(
&
scsi_id
->
sbp2_command_orb_lock
,
flags
);
return
(
command
);
...
...
@@ -665,6 +663,8 @@ static void sbp2_update(struct unit_directory *ud)
* Ok, reconnect has failed. Perhaps we didn't
* reconnect fast enough. Try doing a regular login.
*/
sbp2_logout_device
(
scsi_id
);
if
(
sbp2_login_device
(
scsi_id
))
{
/* Login failed too, just remove the device. */
SBP2_ERR
(
"sbp2_reconnect_device failed!"
);
...
...
@@ -771,9 +771,8 @@ static void sbp2_remove_host(struct hpsb_host *host)
static
int
sbp2_start_ud
(
struct
sbp2scsi_host_info
*
hi
,
struct
unit_directory
*
ud
)
{
struct
scsi_id_instance_data
*
scsi_id
;
struct
scsi_id_instance_data
*
scsi_id
,
*
scsi_id_tmp
;
struct
scsi_id_group
*
scsi_group
;
struct
list_head
*
lh
,
*
next
;
SBP2_DEBUG
(
"sbp2_start_ud"
);
...
...
@@ -785,22 +784,13 @@ static int sbp2_start_ud(struct sbp2scsi_host_info *hi, struct unit_directory *u
INIT_LIST_HEAD
(
&
scsi_group
->
scsi_id_list
);
ud
->
device
.
driver_data
=
scsi_group
;
sbp2_parse_unit_directory
(
scsi_group
,
ud
);
list_for_each_safe
(
lh
,
next
,
&
scsi_group
->
scsi_id_list
)
{
scsi_id
=
list_entry
(
lh
,
struct
scsi_id_instance_data
,
list
);
sbp2_parse_unit_directory
(
scsi_group
,
ud
,
hi
);
scsi_id
->
ne
=
ud
->
ne
;
scsi_id
->
hi
=
hi
;
scsi_id
->
speed_code
=
IEEE1394_SPEED_100
;
scsi_id
->
max_payload_size
=
sbp2_speedto_max_payload
[
IEEE1394_SPEED_100
];
atomic_set
(
&
scsi_id
->
sbp2_login_complete
,
0
);
INIT_LIST_HEAD
(
&
scsi_id
->
sbp2_command_orb_inuse
);
INIT_LIST_HEAD
(
&
scsi_id
->
sbp2_command_orb_completed
);
scsi_id
->
sbp2_command_orb_lock
=
SPIN_LOCK_UNLOCKED
;
/* Make sure the scsi_host is ready for this */
scsi_unblock_requests
(
hi
->
scsi_host
);
list_for_each_entry_safe
(
scsi_id
,
scsi_id_tmp
,
&
scsi_group
->
scsi_id_list
,
list
)
sbp2_start_device
(
scsi_id
);
}
/* Check to see if any of our devices survived the ordeal */
if
(
list_empty
(
&
scsi_group
->
scsi_id_list
))
{
...
...
@@ -812,6 +802,17 @@ static int sbp2_start_ud(struct sbp2scsi_host_info *hi, struct unit_directory *u
}
static
void
sbp2_host_reset
(
struct
hpsb_host
*
host
)
{
struct
sbp2scsi_host_info
*
hi
;
hi
=
hpsb_get_hostinfo
(
&
sbp2_highlevel
,
host
);
if
(
hi
)
scsi_block_requests
(
hi
->
scsi_host
);
}
/*
* This function is where we first pull the node unique ids, and then
* allocate memory and register a SBP-2 device.
...
...
@@ -1012,7 +1013,7 @@ static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id)
/* Remove it from the scsi layer now */
if
(
scsi_id
->
sdev
)
{
scsi_remove_device
(
scsi_id
->
sdev
);
scsi_device_put
(
scsi_id
->
sdev
);
//
scsi_device_put(scsi_id->sdev);
}
sbp2util_remove_command_orb_pool
(
scsi_id
);
...
...
@@ -1530,16 +1531,46 @@ static int sbp2_set_busy_timeout(struct scsi_id_instance_data *scsi_id)
return
(
0
);
}
static
struct
scsi_id_instance_data
*
sbp2_alloc_scsi_id
(
struct
scsi_id_group
*
scsi_group
,
struct
unit_directory
*
ud
,
struct
sbp2scsi_host_info
*
hi
)
{
struct
scsi_id_instance_data
*
scsi_id
=
kmalloc
(
sizeof
(
*
scsi_id
),
GFP_KERNEL
);
if
(
!
scsi_id
)
return
NULL
;
memset
(
scsi_id
,
0
,
sizeof
(
*
scsi_id
));
scsi_id
->
ne
=
ud
->
ne
;
scsi_id
->
hi
=
hi
;
scsi_id
->
ud
=
ud
;
scsi_id
->
speed_code
=
IEEE1394_SPEED_100
;
scsi_id
->
max_payload_size
=
sbp2_speedto_max_payload
[
IEEE1394_SPEED_100
];
atomic_set
(
&
scsi_id
->
sbp2_login_complete
,
0
);
INIT_LIST_HEAD
(
&
scsi_id
->
sbp2_command_orb_inuse
);
INIT_LIST_HEAD
(
&
scsi_id
->
sbp2_command_orb_completed
);
scsi_id
->
sbp2_command_orb_lock
=
SPIN_LOCK_UNLOCKED
;
scsi_id
->
sbp2_device_type_and_lun
=
SBP2_DEVICE_TYPE_LUN_UNINITIALIZED
;
list_add_tail
(
&
scsi_id
->
list
,
&
scsi_group
->
scsi_id_list
);
return
scsi_id
;
}
/*
* This function is called to parse sbp2 device's config rom unit
* directory. Used to determine things like sbp2 management agent offset,
* and command set used (SCSI or RBC).
*/
static
void
sbp2_parse_unit_directory
(
struct
scsi_id_group
*
scsi_group
,
struct
unit_directory
*
ud
)
struct
unit_directory
*
ud
,
struct
sbp2scsi_host_info
*
hi
)
{
struct
csr1212_keyval
*
kv
;
struct
csr1212_dentry
*
dentry
;
struct
scsi_id_instance_data
*
scsi_id
;
struct
list_head
*
lh
;
u64
management_agent_addr
;
u32
command_set_spec_id
,
command_set
,
unit_characteristics
,
firmware_revision
,
workarounds
;
...
...
@@ -1554,29 +1585,42 @@ static void sbp2_parse_unit_directory(struct scsi_id_group *scsi_group,
firmware_revision
=
0x0
;
/* Handle different fields in the unit directory, based on keys */
for
(
i
=
0
;
i
<
ud
->
length
;
i
++
)
{
switch
(
CONFIG_ROM_KEY
(
ud
->
quadlets
[
i
]))
{
case
SBP2_CSR_OFFSET_KEY
:
/* Save off the management agent address */
management_agent_addr
=
CSR_REGISTER_BASE
+
(
CONFIG_ROM_VALUE
(
ud
->
quadlets
[
i
])
<<
2
);
SBP2_DEBUG
(
"sbp2_management_agent_addr = %x"
,
(
unsigned
int
)
management_agent_addr
);
csr1212_for_each_dir_entry
(
ud
->
ne
->
csr
,
kv
,
ud
->
ud_kv
,
dentry
)
{
switch
(
kv
->
key
.
id
)
{
case
CSR1212_KV_ID_DEPENDENT_INFO
:
if
(
kv
->
key
.
type
==
CSR1212_KV_TYPE_CSR_OFFSET
)
{
/* Save off the management agent address */
management_agent_addr
=
CSR1212_REGISTER_SPACE_BASE
+
(
kv
->
value
.
csr_offset
<<
2
);
SBP2_DEBUG
(
"sbp2_management_agent_addr = %x"
,
(
unsigned
int
)
management_agent_addr
);
}
else
{
/*
* Device type and lun (used for
* detemining type of sbp2 device)
*/
scsi_id
=
sbp2_alloc_scsi_id
(
scsi_group
,
ud
,
hi
);
if
(
!
scsi_id
)
{
SBP2_ERR
(
"Out of memory adding scsi_id, not all LUN's will be added"
);
break
;
}
scsi_id
->
sbp2_device_type_and_lun
=
kv
->
value
.
immediate
;
}
break
;
case
SBP2_COMMAND_SET_SPEC_ID_KEY
:
/* Command spec organization */
command_set_spec_id
=
CONFIG_ROM_VALUE
(
ud
->
quadlets
[
i
]);
command_set_spec_id
=
kv
->
value
.
immediate
;
SBP2_DEBUG
(
"sbp2_command_set_spec_id = %x"
,
(
unsigned
int
)
command_set_spec_id
);
break
;
case
SBP2_COMMAND_SET_KEY
:
/* Command set used by sbp2 device */
command_set
=
CONFIG_ROM_VALUE
(
ud
->
quadlets
[
i
])
;
command_set
=
kv
->
value
.
immediate
;
SBP2_DEBUG
(
"sbp2_command_set = %x"
,
(
unsigned
int
)
command_set
);
break
;
...
...
@@ -1586,35 +1630,14 @@ static void sbp2_parse_unit_directory(struct scsi_id_group *scsi_group,
* Unit characterisitcs (orb related stuff
* that I'm not yet paying attention to)
*/
unit_characteristics
=
CONFIG_ROM_VALUE
(
ud
->
quadlets
[
i
]);
unit_characteristics
=
kv
->
value
.
immediate
;
SBP2_DEBUG
(
"sbp2_unit_characteristics = %x"
,
(
unsigned
int
)
unit_characteristics
);
break
;
case
SBP2_DEVICE_TYPE_AND_LUN_KEY
:
/*
* Device type and lun (used for
* detemining type of sbp2 device)
*/
scsi_id
=
kmalloc
(
sizeof
(
*
scsi_id
),
GFP_KERNEL
);
if
(
!
scsi_id
)
{
SBP2_ERR
(
"Out of memory adding scsi_id, not all LUN's will be added"
);
break
;
}
memset
(
scsi_id
,
0
,
sizeof
(
*
scsi_id
));
scsi_id
->
sbp2_device_type_and_lun
=
CONFIG_ROM_VALUE
(
ud
->
quadlets
[
i
]);
SBP2_DEBUG
(
"sbp2_device_type_and_lun = %x"
,
(
unsigned
int
)
scsi_id
->
sbp2_device_type_and_lun
);
list_add_tail
(
&
scsi_id
->
list
,
&
scsi_group
->
scsi_id_list
);
break
;
case
SBP2_FIRMWARE_REVISION_KEY
:
/* Firmware revision */
firmware_revision
=
CONFIG_ROM_VALUE
(
ud
->
quadlets
[
i
]);
firmware_revision
=
kv
->
value
.
immediate
;
if
(
force_inquiry_hack
)
SBP2_INFO
(
"sbp2_firmware_revision = %x"
,
(
unsigned
int
)
firmware_revision
);
...
...
@@ -1668,26 +1691,20 @@ static void sbp2_parse_unit_directory(struct scsi_id_group *scsi_group,
if
(
ud
->
flags
&
UNIT_DIRECTORY_LUN_DIRECTORY
)
{
struct
unit_directory
*
parent_ud
=
container_of
(
ud
->
device
.
parent
,
struct
unit_directory
,
device
);
sbp2_parse_unit_directory
(
scsi_group
,
parent_ud
);
sbp2_parse_unit_directory
(
scsi_group
,
parent_ud
,
hi
);
}
else
{
/* If our list is empty, add a base scsi_id (happens in a normal
* case where there is no logical_unit_number entry */
if
(
list_empty
(
&
scsi_group
->
scsi_id_list
))
{
scsi_id
=
kmalloc
(
sizeof
(
*
scsi_id
),
GFP_KERNEL
);
scsi_id
=
sbp2_alloc_scsi_id
(
scsi_group
,
ud
,
hi
);
if
(
!
scsi_id
)
{
SBP2_ERR
(
"Out of memory adding scsi_id"
);
return
;
}
memset
(
scsi_id
,
0
,
sizeof
(
*
scsi_id
));
scsi_id
->
sbp2_device_type_and_lun
=
SBP2_DEVICE_TYPE_LUN_UNINITIALIZED
;
list_add_tail
(
&
scsi_id
->
list
,
&
scsi_group
->
scsi_id_list
);
}
/* Update the generic fields in all the LUN's */
list_for_each
(
lh
,
&
scsi_group
->
scsi_id_list
)
{
scsi_id
=
list_entry
(
lh
,
struct
scsi_id_instance_data
,
list
);
list_for_each_entry
(
scsi_id
,
&
scsi_group
->
scsi_id_list
,
list
)
{
scsi_id
->
sbp2_management_agent_addr
=
management_agent_addr
;
scsi_id
->
sbp2_command_set_spec_id
=
command_set_spec_id
;
scsi_id
->
sbp2_command_set
=
command_set
;
...
...
@@ -1727,7 +1744,7 @@ static int sbp2_max_speed_and_size(struct scsi_id_instance_data *scsi_id)
/* Payload size is the lesser of what our speed supports and what
* our host supports. */
scsi_id
->
max_payload_size
=
min
(
sbp2_speedto_max_payload
[
scsi_id
->
speed_code
],
(
u8
)(
((
be32_to_cpu
(
hi
->
host
->
csr
.
rom
[
2
])
>>
12
)
&
0xf
)
-
1
));
(
u8
)(
hi
->
host
->
csr
.
max_rec
-
1
));
SBP2_ERR
(
"Node "
NODE_BUS_FMT
": Max speed [%s] - Max payload [%u]"
,
NODE_BUS_ARGS
(
hi
->
host
,
scsi_id
->
ne
->
nodeid
),
...
...
@@ -2654,6 +2671,8 @@ static void sbp2scsi_complete_all_commands(struct scsi_id_instance_data *scsi_id
}
}
scsi_unblock_requests
(
hi
->
scsi_host
);
return
;
}
...
...
@@ -2849,10 +2868,11 @@ static const char *sbp2scsi_info (struct Scsi_Host *host)
return
"SCSI emulation for IEEE-1394 SBP-2 Devices"
;
}
static
ssize_t
sbp2_sysfs_ieee1394_
gu
id_show
(
struct
device
*
dev
,
char
*
buf
)
static
ssize_t
sbp2_sysfs_ieee1394_id_show
(
struct
device
*
dev
,
char
*
buf
)
{
struct
scsi_device
*
sdev
;
struct
scsi_id_instance_data
*
scsi_id
;
int
lun
;
if
(
!
(
sdev
=
to_scsi_device
(
dev
)))
return
0
;
...
...
@@ -2860,13 +2880,18 @@ static ssize_t sbp2_sysfs_ieee1394_guid_show(struct device *dev, char *buf)
if
(
!
(
scsi_id
=
sdev
->
hostdata
))
return
0
;
return
sprintf
(
buf
,
"%016Lx
\n
"
,
(
unsigned
long
long
)
scsi_id
->
ne
->
guid
);
}
if
(
scsi_id
->
sbp2_device_type_and_lun
==
SBP2_DEVICE_TYPE_LUN_UNINITIALIZED
)
lun
=
0
;
else
lun
=
ORB_SET_LUN
(
scsi_id
->
sbp2_device_type_and_lun
);
static
DEVICE_ATTR
(
ieee1394_guid
,
S_IRUGO
,
sbp2_sysfs_ieee1394_guid_show
,
NULL
);
return
sprintf
(
buf
,
"%016Lx:%d:%d
\n
"
,
(
unsigned
long
long
)
scsi_id
->
ne
->
guid
,
scsi_id
->
ud
->
id
,
lun
);
}
static
DEVICE_ATTR
(
ieee1394_id
,
S_IRUGO
,
sbp2_sysfs_ieee1394_id_show
,
NULL
);
static
struct
device_attribute
*
sbp2_sysfs_sdev_attrs
[]
=
{
&
dev_attr_ieee1394_
gu
id
,
&
dev_attr_ieee1394_id
,
NULL
};
...
...
drivers/ieee1394/sbp2.h
View file @
16eadb50
...
...
@@ -406,6 +406,7 @@ struct scsi_id_instance_data {
/* Node entry, as retrieved from NodeMgr entries */
struct
node_entry
*
ne
;
struct
unit_directory
*
ud
;
/* A backlink to our host_info */
struct
sbp2scsi_host_info
*
hi
;
...
...
@@ -470,6 +471,7 @@ static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_i
*/
static
struct
sbp2scsi_host_info
*
sbp2_add_host
(
struct
hpsb_host
*
host
);
static
void
sbp2_remove_host
(
struct
hpsb_host
*
host
);
static
void
sbp2_host_reset
(
struct
hpsb_host
*
host
);
static
int
sbp2_probe
(
struct
device
*
dev
);
static
int
sbp2_remove
(
struct
device
*
dev
);
...
...
@@ -512,7 +514,8 @@ static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense
static
void
sbp2_check_sbp2_command
(
struct
scsi_id_instance_data
*
scsi_id
,
unchar
*
cmd
);
static
void
sbp2_check_sbp2_response
(
struct
scsi_id_instance_data
*
scsi_id
,
Scsi_Cmnd
*
SCpnt
);
static
void
sbp2_parse_unit_directory
(
struct
scsi_id_group
*
scsi_group
,
struct
unit_directory
*
ud
);
struct
unit_directory
*
ud
,
struct
sbp2scsi_host_info
*
hi
);
static
int
sbp2_set_busy_timeout
(
struct
scsi_id_instance_data
*
scsi_id
);
static
int
sbp2_max_speed_and_size
(
struct
scsi_id_instance_data
*
scsi_id
);
...
...
drivers/ieee1394/video1394.c
View file @
16eadb50
...
...
@@ -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
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment