Commit 40caf5ea authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6: (56 commits)
  ieee1394: remove garbage from Kconfig
  ieee1394: more help in Kconfig
  ieee1394: ohci1394: Fix mistake in printk message.
  ieee1394: ohci1394: remove unnecessary rcvPhyPkt bit flipping in LinkControl register
  ieee1394: ohci1394: fix cosmetic problem in error logging
  ieee1394: eth1394: send async streams at S100 on 1394b buses
  ieee1394: eth1394: fix error path in module_init
  ieee1394: eth1394: correct return codes in hard_start_xmit
  ieee1394: eth1394: hard_start_xmit is called in atomic context
  ieee1394: eth1394: some conditions are unlikely
  ieee1394: eth1394: clean up fragment_overlap
  ieee1394: eth1394: don't use alloc_etherdev
  ieee1394: eth1394: omit useless set_mac_address callback
  ieee1394: eth1394: CONFIG_INET is always defined
  ieee1394: eth1394: allow MTU bigger than 1500
  ieee1394: unexport highlevel_host_reset
  ieee1394: eth1394: contain host reset
  ieee1394: eth1394: shorter error messages
  ieee1394: eth1394: correct a memset argument
  ieee1394: eth1394: refactor .probe and .update
  ...
parents d6454706 bcfd09ee
# -*- shell-script -*-
menu "IEEE 1394 (FireWire) support" menu "IEEE 1394 (FireWire) support"
config IEEE1394 config IEEE1394
tristate "IEEE 1394 (FireWire) support" tristate "IEEE 1394 (FireWire) support"
depends on PCI || BROKEN depends on PCI || BROKEN
select NET
help help
IEEE 1394 describes a high performance serial bus, which is also IEEE 1394 describes a high performance serial bus, which is also
known as FireWire(tm) or i.Link(tm) and is used for connecting all known as FireWire(tm) or i.Link(tm) and is used for connecting all
...@@ -35,24 +32,7 @@ config IEEE1394_VERBOSEDEBUG ...@@ -35,24 +32,7 @@ config IEEE1394_VERBOSEDEBUG
Say Y if you really want or need the debugging output, everyone Say Y if you really want or need the debugging output, everyone
else says N. else says N.
config IEEE1394_EXTRA_CONFIG_ROMS comment "Controllers"
bool "Build in extra config rom entries for certain functionality"
depends on IEEE1394
help
Some IEEE1394 functionality depends on extra config rom entries
being available in the host adapters CSR. These options will
allow you to choose which ones.
config IEEE1394_CONFIG_ROM_IP1394
bool "IP-1394 Entry"
depends on IEEE1394_EXTRA_CONFIG_ROMS && IEEE1394
help
Adds an entry for using IP-over-1394. If you want to use your
IEEE1394 bus as a network for IP systems (including interacting
with MacOSX and WinXP IP-over-1394), enable this option and the
eth1394 option below.
comment "Device Drivers"
depends on IEEE1394 depends on IEEE1394
comment "Texas Instruments PCILynx requires I2C" comment "Texas Instruments PCILynx requires I2C"
...@@ -70,6 +50,10 @@ config IEEE1394_PCILYNX ...@@ -70,6 +50,10 @@ config IEEE1394_PCILYNX
To compile this driver as a module, say M here: the To compile this driver as a module, say M here: the
module will be called pcilynx. module will be called pcilynx.
Only some old and now very rare PCI and CardBus cards and
PowerMacs G3 B&W contain the PCILynx controller. Therefore
almost everybody can say N here.
config IEEE1394_OHCI1394 config IEEE1394_OHCI1394
tristate "OHCI-1394 support" tristate "OHCI-1394 support"
depends on PCI && IEEE1394 depends on PCI && IEEE1394
...@@ -83,7 +67,7 @@ config IEEE1394_OHCI1394 ...@@ -83,7 +67,7 @@ config IEEE1394_OHCI1394
To compile this driver as a module, say M here: the To compile this driver as a module, say M here: the
module will be called ohci1394. module will be called ohci1394.
comment "Protocol Drivers" comment "Protocols"
depends on IEEE1394 depends on IEEE1394
config IEEE1394_VIDEO1394 config IEEE1394_VIDEO1394
...@@ -121,11 +105,15 @@ config IEEE1394_SBP2_PHYS_DMA ...@@ -121,11 +105,15 @@ config IEEE1394_SBP2_PHYS_DMA
This option is buggy and currently broken on some architectures. This option is buggy and currently broken on some architectures.
If unsure, say N. If unsure, say N.
config IEEE1394_ETH1394_ROM_ENTRY
depends on IEEE1394
bool
default n
config IEEE1394_ETH1394 config IEEE1394_ETH1394
tristate "Ethernet over 1394" tristate "IP over 1394"
depends on IEEE1394 && EXPERIMENTAL && INET depends on IEEE1394 && EXPERIMENTAL && INET
select IEEE1394_CONFIG_ROM_IP1394 select IEEE1394_ETH1394_ROM_ENTRY
select IEEE1394_EXTRA_CONFIG_ROMS
help help
This driver implements a functional majority of RFC 2734: IPv4 over This driver implements a functional majority of RFC 2734: IPv4 over
1394. It will provide IP connectivity with implementations of RFC 1394. It will provide IP connectivity with implementations of RFC
...@@ -134,6 +122,8 @@ config IEEE1394_ETH1394 ...@@ -134,6 +122,8 @@ config IEEE1394_ETH1394
This driver is still considered experimental. It does not yet support This driver is still considered experimental. It does not yet support
MCAP, therefore multicast support is significantly limited. MCAP, therefore multicast support is significantly limited.
The module is called eth1394 although it does not emulate Ethernet.
config IEEE1394_DV1394 config IEEE1394_DV1394
tristate "OHCI-DV I/O support (deprecated)" tristate "OHCI-DV I/O support (deprecated)"
depends on IEEE1394 && IEEE1394_OHCI1394 depends on IEEE1394 && IEEE1394_OHCI1394
...@@ -146,12 +136,12 @@ config IEEE1394_RAWIO ...@@ -146,12 +136,12 @@ config IEEE1394_RAWIO
tristate "Raw IEEE1394 I/O support" tristate "Raw IEEE1394 I/O support"
depends on IEEE1394 depends on IEEE1394
help help
Say Y here if you want support for the raw device. This is generally This option adds support for the raw1394 device file which enables
a good idea, so you should say Y here. The raw device enables direct communication of user programs with the IEEE 1394 bus and thus
direct communication of user programs with the IEEE 1394 bus and with the attached peripherals. Almost all application programs which
thus with the attached peripherals. access FireWire require this option.
To compile this driver as a module, say M here: the To compile this driver as a module, say M here: the module will be
module will be called raw1394. called raw1394.
endmenu endmenu
...@@ -26,12 +26,6 @@ struct hpsb_config_rom_entry { ...@@ -26,12 +26,6 @@ struct hpsb_config_rom_entry {
/* Base initialization, called at module load */ /* Base initialization, called at module load */
int (*init)(void); int (*init)(void);
/* Add entry to specified host */
int (*add)(struct hpsb_host *host);
/* Remove entry from specified host */
void (*remove)(struct hpsb_host *host);
/* Cleanup called at module exit */ /* Cleanup called at module exit */
void (*cleanup)(void); void (*cleanup)(void);
...@@ -39,7 +33,7 @@ struct hpsb_config_rom_entry { ...@@ -39,7 +33,7 @@ struct hpsb_config_rom_entry {
unsigned int flag; unsigned int flag;
}; };
/* The default host entry. This must succeed. */
int hpsb_default_host_entry(struct hpsb_host *host) int hpsb_default_host_entry(struct hpsb_host *host)
{ {
struct csr1212_keyval *root; struct csr1212_keyval *root;
...@@ -63,9 +57,9 @@ int hpsb_default_host_entry(struct hpsb_host *host) ...@@ -63,9 +57,9 @@ int hpsb_default_host_entry(struct hpsb_host *host)
return -ENOMEM; return -ENOMEM;
} }
ret = csr1212_associate_keyval(vend_id, text); csr1212_associate_keyval(vend_id, text);
csr1212_release_keyval(text); csr1212_release_keyval(text);
ret |= csr1212_attach_keyval_to_directory(root, vend_id); ret = csr1212_attach_keyval_to_directory(root, vend_id);
csr1212_release_keyval(vend_id); csr1212_release_keyval(vend_id);
if (ret != CSR1212_SUCCESS) { if (ret != CSR1212_SUCCESS) {
csr1212_destroy_csr(host->csr.rom); csr1212_destroy_csr(host->csr.rom);
...@@ -78,7 +72,7 @@ int hpsb_default_host_entry(struct hpsb_host *host) ...@@ -78,7 +72,7 @@ int hpsb_default_host_entry(struct hpsb_host *host)
} }
#ifdef CONFIG_IEEE1394_CONFIG_ROM_IP1394 #ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
#include "eth1394.h" #include "eth1394.h"
static struct csr1212_keyval *ip1394_ud; static struct csr1212_keyval *ip1394_ud;
...@@ -103,10 +97,12 @@ static int config_rom_ip1394_init(void) ...@@ -103,10 +97,12 @@ static int config_rom_ip1394_init(void)
if (!ip1394_ud || !spec_id || !spec_desc || !ver || !ver_desc) if (!ip1394_ud || !spec_id || !spec_desc || !ver || !ver_desc)
goto ip1394_fail; goto ip1394_fail;
if (csr1212_associate_keyval(spec_id, spec_desc) == CSR1212_SUCCESS && csr1212_associate_keyval(spec_id, spec_desc);
csr1212_associate_keyval(ver, ver_desc) == CSR1212_SUCCESS && csr1212_associate_keyval(ver, ver_desc);
csr1212_attach_keyval_to_directory(ip1394_ud, spec_id) == CSR1212_SUCCESS && if (csr1212_attach_keyval_to_directory(ip1394_ud, spec_id)
csr1212_attach_keyval_to_directory(ip1394_ud, ver) == CSR1212_SUCCESS) == CSR1212_SUCCESS &&
csr1212_attach_keyval_to_directory(ip1394_ud, ver)
== CSR1212_SUCCESS)
ret = 0; ret = 0;
ip1394_fail: ip1394_fail:
...@@ -135,7 +131,7 @@ static void config_rom_ip1394_cleanup(void) ...@@ -135,7 +131,7 @@ static void config_rom_ip1394_cleanup(void)
} }
} }
static int config_rom_ip1394_add(struct hpsb_host *host) int hpsb_config_rom_ip1394_add(struct hpsb_host *host)
{ {
if (!ip1394_ud) if (!ip1394_ud)
return -ENODEV; return -ENODEV;
...@@ -144,92 +140,55 @@ static int config_rom_ip1394_add(struct hpsb_host *host) ...@@ -144,92 +140,55 @@ static int config_rom_ip1394_add(struct hpsb_host *host)
ip1394_ud) != CSR1212_SUCCESS) ip1394_ud) != CSR1212_SUCCESS)
return -ENOMEM; return -ENOMEM;
host->config_roms |= HPSB_CONFIG_ROM_ENTRY_IP1394;
host->update_config_rom = 1;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_add);
static void config_rom_ip1394_remove(struct hpsb_host *host) void hpsb_config_rom_ip1394_remove(struct hpsb_host *host)
{ {
csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, ip1394_ud); csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, ip1394_ud);
host->config_roms &= ~HPSB_CONFIG_ROM_ENTRY_IP1394;
host->update_config_rom = 1;
} }
EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_remove);
static struct hpsb_config_rom_entry ip1394_entry = { static struct hpsb_config_rom_entry ip1394_entry = {
.name = "ip1394", .name = "ip1394",
.init = config_rom_ip1394_init, .init = config_rom_ip1394_init,
.add = config_rom_ip1394_add,
.remove = config_rom_ip1394_remove,
.cleanup = config_rom_ip1394_cleanup, .cleanup = config_rom_ip1394_cleanup,
.flag = HPSB_CONFIG_ROM_ENTRY_IP1394, .flag = HPSB_CONFIG_ROM_ENTRY_IP1394,
}; };
#endif /* CONFIG_IEEE1394_CONFIG_ROM_IP1394 */
#endif /* CONFIG_IEEE1394_ETH1394_ROM_ENTRY */
static struct hpsb_config_rom_entry *const config_rom_entries[] = { static struct hpsb_config_rom_entry *const config_rom_entries[] = {
#ifdef CONFIG_IEEE1394_CONFIG_ROM_IP1394 #ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
&ip1394_entry, &ip1394_entry,
#endif #endif
NULL,
}; };
/* Initialize all config roms */
int hpsb_init_config_roms(void) int hpsb_init_config_roms(void)
{ {
int i, error = 0; int i, error = 0;
for (i = 0; config_rom_entries[i]; i++) { for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
if (!config_rom_entries[i]->init)
continue;
if (config_rom_entries[i]->init()) { if (config_rom_entries[i]->init()) {
HPSB_ERR("Failed to initialize config rom entry `%s'", HPSB_ERR("Failed to initialize config rom entry `%s'",
config_rom_entries[i]->name); config_rom_entries[i]->name);
error = -1; error = -1;
} else
HPSB_DEBUG("Initialized config rom entry `%s'",
config_rom_entries[i]->name);
}
return error;
}
void hpsb_cleanup_config_roms(void)
{
int i;
for (i = 0; config_rom_entries[i]; i++) {
if (config_rom_entries[i]->cleanup)
config_rom_entries[i]->cleanup();
}
}
int hpsb_add_extra_config_roms(struct hpsb_host *host)
{
int i, error = 0;
for (i = 0; config_rom_entries[i]; i++) {
if (config_rom_entries[i]->add(host)) {
HPSB_ERR("fw-host%d: Failed to attach config rom entry `%s'",
host->id, config_rom_entries[i]->name);
error = -1;
} else {
host->config_roms |= config_rom_entries[i]->flag;
host->update_config_rom = 1;
} }
}
return error; return error;
} }
void hpsb_remove_extra_config_roms(struct hpsb_host *host) /* Cleanup all config roms */
void hpsb_cleanup_config_roms(void)
{ {
int i; int i;
for (i = 0; config_rom_entries[i]; i++) { for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
if (!(host->config_roms & config_rom_entries[i]->flag)) config_rom_entries[i]->cleanup();
continue;
config_rom_entries[i]->remove(host);
host->config_roms &= ~config_rom_entries[i]->flag;
host->update_config_rom = 1;
}
} }
#ifndef _IEEE1394_CONFIG_ROMS_H #ifndef _IEEE1394_CONFIG_ROMS_H
#define _IEEE1394_CONFIG_ROMS_H #define _IEEE1394_CONFIG_ROMS_H
#include "ieee1394_types.h" struct hpsb_host;
#include "hosts.h"
/* The default host entry. This must succeed. */
int hpsb_default_host_entry(struct hpsb_host *host); int hpsb_default_host_entry(struct hpsb_host *host);
/* Initialize all config roms */
int hpsb_init_config_roms(void); int hpsb_init_config_roms(void);
/* Cleanup all config roms */
void hpsb_cleanup_config_roms(void); void hpsb_cleanup_config_roms(void);
/* Add extra config roms to specified host */
int hpsb_add_extra_config_roms(struct hpsb_host *host);
/* Remove extra config roms from specified host */
void hpsb_remove_extra_config_roms(struct hpsb_host *host);
/* List of flags to check if a host contains a certain extra config rom /* List of flags to check if a host contains a certain extra config rom
* entry. Available in the host->config_roms member. */ * entry. Available in the host->config_roms member. */
#define HPSB_CONFIG_ROM_ENTRY_IP1394 0x00000001 #define HPSB_CONFIG_ROM_ENTRY_IP1394 0x00000001
#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
int hpsb_config_rom_ip1394_add(struct hpsb_host *host);
void hpsb_config_rom_ip1394_remove(struct hpsb_host *host);
#endif
#endif /* _IEEE1394_CONFIG_ROMS_H */ #endif /* _IEEE1394_CONFIG_ROMS_H */
...@@ -31,12 +31,13 @@ ...@@ -31,12 +31,13 @@
/* TODO List: /* TODO List:
* - Verify interface consistency: i.e., public functions that take a size * - Verify interface consistency: i.e., public functions that take a size
* parameter expect size to be in bytes. * parameter expect size to be in bytes.
* - Convenience functions for reading a block of data from a given offset.
*/ */
#ifndef __KERNEL__ #include <linux/errno.h>
#include <string.h> #include <linux/kernel.h>
#endif #include <linux/string.h>
#include <asm/bug.h>
#include <asm/byteorder.h>
#include "csr1212.h" #include "csr1212.h"
...@@ -46,7 +47,7 @@ ...@@ -46,7 +47,7 @@
#define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET) #define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET)
#define __D (1 << CSR1212_KV_TYPE_DIRECTORY) #define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
#define __L (1 << CSR1212_KV_TYPE_LEAF) #define __L (1 << CSR1212_KV_TYPE_LEAF)
static const u_int8_t csr1212_key_id_type_map[0x30] = { static const u8 csr1212_key_id_type_map[0x30] = {
__C, /* used by Apple iSight */ __C, /* used by Apple iSight */
__D | __L, /* Descriptor */ __D | __L, /* Descriptor */
__I | __D | __L, /* Bus_Dependent_Info */ __I | __D | __L, /* Bus_Dependent_Info */
...@@ -82,10 +83,10 @@ static const u_int8_t csr1212_key_id_type_map[0x30] = { ...@@ -82,10 +83,10 @@ static const u_int8_t csr1212_key_id_type_map[0x30] = {
#undef __L #undef __L
#define quads_to_bytes(_q) ((_q) * sizeof(u_int32_t)) #define quads_to_bytes(_q) ((_q) * sizeof(u32))
#define bytes_to_quads(_b) (((_b) + sizeof(u_int32_t) - 1) / sizeof(u_int32_t)) #define bytes_to_quads(_b) (((_b) + sizeof(u32) - 1) / sizeof(u32))
static inline void free_keyval(struct csr1212_keyval *kv) static void free_keyval(struct csr1212_keyval *kv)
{ {
if ((kv->key.type == CSR1212_KV_TYPE_LEAF) && if ((kv->key.type == CSR1212_KV_TYPE_LEAF) &&
(kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)) (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM))
...@@ -94,14 +95,14 @@ static inline void free_keyval(struct csr1212_keyval *kv) ...@@ -94,14 +95,14 @@ static inline void free_keyval(struct csr1212_keyval *kv)
CSR1212_FREE(kv); CSR1212_FREE(kv);
} }
static u_int16_t csr1212_crc16(const u_int32_t *buffer, size_t length) static u16 csr1212_crc16(const u32 *buffer, size_t length)
{ {
int shift; int shift;
u_int32_t data; u32 data;
u_int16_t sum, crc = 0; u16 sum, crc = 0;
for (; length; length--) { for (; length; length--) {
data = CSR1212_BE32_TO_CPU(*buffer); data = be32_to_cpu(*buffer);
buffer++; buffer++;
for (shift = 28; shift >= 0; shift -= 4 ) { for (shift = 28; shift >= 0; shift -= 4 ) {
sum = ((crc >> 12) ^ (data >> shift)) & 0xf; sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
...@@ -110,21 +111,18 @@ static u_int16_t csr1212_crc16(const u_int32_t *buffer, size_t length) ...@@ -110,21 +111,18 @@ static u_int16_t csr1212_crc16(const u_int32_t *buffer, size_t length)
crc &= 0xffff; crc &= 0xffff;
} }
return CSR1212_CPU_TO_BE16(crc); return cpu_to_be16(crc);
} }
#if 0 /* Microsoft computes the CRC with the bytes in reverse order. */
/* Microsoft computes the CRC with the bytes in reverse order. Therefore we static u16 csr1212_msft_crc16(const u32 *buffer, size_t length)
* 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; int shift;
u_int32_t data; u32 data;
u_int16_t sum, crc = 0; u16 sum, crc = 0;
for (; length; length--) { for (; length; length--) {
data = CSR1212_LE32_TO_CPU(*buffer); data = le32_to_cpu(*buffer);
buffer++; buffer++;
for (shift = 28; shift >= 0; shift -= 4 ) { for (shift = 28; shift >= 0; shift -= 4 ) {
sum = ((crc >> 12) ^ (data >> shift)) & 0xf; sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
...@@ -133,38 +131,35 @@ static u_int16_t csr1212_msft_crc16(const u_int32_t *buffer, size_t length) ...@@ -133,38 +131,35 @@ static u_int16_t csr1212_msft_crc16(const u_int32_t *buffer, size_t length)
crc &= 0xffff; crc &= 0xffff;
} }
return CSR1212_CPU_TO_BE16(crc); return cpu_to_be16(crc);
} }
#endif
static inline struct csr1212_dentry *csr1212_find_keyval(struct csr1212_keyval *dir, static struct csr1212_dentry *
struct csr1212_keyval *kv) csr1212_find_keyval(struct csr1212_keyval *dir, struct csr1212_keyval *kv)
{ {
struct csr1212_dentry *pos; struct csr1212_dentry *pos;
for (pos = dir->value.directory.dentries_head; for (pos = dir->value.directory.dentries_head;
pos != NULL; pos = pos->next) { pos != NULL; pos = pos->next)
if (pos->kv == kv) if (pos->kv == kv)
return pos; return pos;
}
return NULL; return NULL;
} }
static struct csr1212_keyval *
static inline struct csr1212_keyval *csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, u32 offset)
u_int32_t offset)
{ {
struct csr1212_keyval *kv; struct csr1212_keyval *kv;
for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next) { for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next)
if (kv->offset == offset) if (kv->offset == offset)
return kv; return kv;
}
return NULL; return NULL;
} }
/* Creation Routines */ /* Creation Routines */
struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops, struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
size_t bus_info_size, void *private) size_t bus_info_size, void *private)
{ {
...@@ -202,27 +197,17 @@ struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops, ...@@ -202,27 +197,17 @@ struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
return csr; return csr;
} }
void csr1212_init_local_csr(struct csr1212_csr *csr, void csr1212_init_local_csr(struct csr1212_csr *csr,
const u_int32_t *bus_info_data, int max_rom) const u32 *bus_info_data, int max_rom)
{ {
static const int mr_map[] = { 4, 64, 1024, 0 }; static const int mr_map[] = { 4, 64, 1024, 0 };
#ifdef __KERNEL__
BUG_ON(max_rom & ~0x3); BUG_ON(max_rom & ~0x3);
csr->max_rom = mr_map[max_rom]; csr->max_rom = mr_map[max_rom];
#else
if (max_rom & ~0x3) /* caller supplied invalid argument */
csr->max_rom = 0;
else
csr->max_rom = mr_map[max_rom];
#endif
memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len); memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len);
} }
static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key)
static struct csr1212_keyval *csr1212_new_keyval(u_int8_t type, u_int8_t key)
{ {
struct csr1212_keyval *kv; struct csr1212_keyval *kv;
...@@ -246,10 +231,11 @@ static struct csr1212_keyval *csr1212_new_keyval(u_int8_t type, u_int8_t key) ...@@ -246,10 +231,11 @@ static struct csr1212_keyval *csr1212_new_keyval(u_int8_t type, u_int8_t key)
return kv; return kv;
} }
struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value) struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value)
{ {
struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key); struct csr1212_keyval *kv;
kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key);
if (!kv) if (!kv)
return NULL; return NULL;
...@@ -258,10 +244,12 @@ struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value) ...@@ -258,10 +244,12 @@ struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value)
return kv; return kv;
} }
struct csr1212_keyval *csr1212_new_leaf(u_int8_t key, const void *data, size_t data_len) static struct csr1212_keyval *
csr1212_new_leaf(u8 key, const void *data, size_t data_len)
{ {
struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key); struct csr1212_keyval *kv;
kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key);
if (!kv) if (!kv)
return NULL; return NULL;
...@@ -285,10 +273,12 @@ struct csr1212_keyval *csr1212_new_leaf(u_int8_t key, const void *data, size_t d ...@@ -285,10 +273,12 @@ struct csr1212_keyval *csr1212_new_leaf(u_int8_t key, const void *data, size_t d
return kv; return kv;
} }
struct csr1212_keyval *csr1212_new_csr_offset(u_int8_t key, u_int32_t csr_offset) static struct csr1212_keyval *
csr1212_new_csr_offset(u8 key, u32 csr_offset)
{ {
struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key); struct csr1212_keyval *kv;
kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key);
if (!kv) if (!kv)
return NULL; return NULL;
...@@ -299,10 +289,11 @@ struct csr1212_keyval *csr1212_new_csr_offset(u_int8_t key, u_int32_t csr_offset ...@@ -299,10 +289,11 @@ struct csr1212_keyval *csr1212_new_csr_offset(u_int8_t key, u_int32_t csr_offset
return kv; return kv;
} }
struct csr1212_keyval *csr1212_new_directory(u_int8_t key) struct csr1212_keyval *csr1212_new_directory(u8 key)
{ {
struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key); struct csr1212_keyval *kv;
kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key);
if (!kv) if (!kv)
return NULL; return NULL;
...@@ -314,43 +305,29 @@ struct csr1212_keyval *csr1212_new_directory(u_int8_t key) ...@@ -314,43 +305,29 @@ struct csr1212_keyval *csr1212_new_directory(u_int8_t key)
return kv; return kv;
} }
int csr1212_associate_keyval(struct csr1212_keyval *kv, void csr1212_associate_keyval(struct csr1212_keyval *kv,
struct csr1212_keyval *associate) struct csr1212_keyval *associate)
{ {
if (!kv || !associate) BUG_ON(!kv || !associate || kv->key.id == CSR1212_KV_ID_DESCRIPTOR ||
return CSR1212_EINVAL; (associate->key.id != CSR1212_KV_ID_DESCRIPTOR &&
associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO &&
if (kv->key.id == CSR1212_KV_ID_DESCRIPTOR || associate->key.id != CSR1212_KV_ID_EXTENDED_KEY &&
(associate->key.id != CSR1212_KV_ID_DESCRIPTOR && associate->key.id != CSR1212_KV_ID_EXTENDED_DATA &&
associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO && associate->key.id < 0x30) ||
associate->key.id != CSR1212_KV_ID_EXTENDED_KEY && (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID &&
associate->key.id != CSR1212_KV_ID_EXTENDED_DATA && associate->key.id != CSR1212_KV_ID_EXTENDED_KEY) ||
associate->key.id < 0x30)) (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
return CSR1212_EINVAL; associate->key.id != CSR1212_KV_ID_EXTENDED_DATA) ||
(associate->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
if (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID && kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) ||
associate->key.id != CSR1212_KV_ID_EXTENDED_KEY) (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA &&
return CSR1212_EINVAL; kv->key.id != CSR1212_KV_ID_EXTENDED_KEY));
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) if (kv->associate)
csr1212_release_keyval(kv->associate); csr1212_release_keyval(kv->associate);
associate->refcnt++; associate->refcnt++;
kv->associate = associate; kv->associate = associate;
return CSR1212_SUCCESS;
} }
int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir, int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
...@@ -358,12 +335,11 @@ int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir, ...@@ -358,12 +335,11 @@ int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
{ {
struct csr1212_dentry *dentry; struct csr1212_dentry *dentry;
if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY) BUG_ON(!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY);
return CSR1212_EINVAL;
dentry = CSR1212_MALLOC(sizeof(*dentry)); dentry = CSR1212_MALLOC(sizeof(*dentry));
if (!dentry) if (!dentry)
return CSR1212_ENOMEM; return -ENOMEM;
dentry->kv = kv; dentry->kv = kv;
...@@ -382,66 +358,22 @@ int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir, ...@@ -382,66 +358,22 @@ int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
return CSR1212_SUCCESS; return CSR1212_SUCCESS;
} }
struct csr1212_keyval *csr1212_new_extended_immediate(u_int32_t spec, u_int32_t key, #define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
u_int32_t value) (&((kv)->value.leaf.data[1]))
{
struct csr1212_keyval *kvs, *kvk, *kvv; #define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \
((kv)->value.leaf.data[0] = \
kvs = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID, spec); cpu_to_be32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \
kvk = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY, key); ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)))
kvv = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_DATA, value); #define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \
((kv)->value.leaf.data[0] = \
if (!kvs || !kvk || !kvv) { cpu_to_be32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \
if (kvs) CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \
free_keyval(kvs); ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)))
if (kvk)
free_keyval(kvk); static struct csr1212_keyval *
if (kvv) csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id,
free_keyval(kvv); const void *data, size_t data_len)
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; struct csr1212_keyval *kv;
...@@ -453,197 +385,72 @@ struct csr1212_keyval *csr1212_new_descriptor_leaf(u_int8_t dtype, u_int32_t spe ...@@ -453,197 +385,72 @@ struct csr1212_keyval *csr1212_new_descriptor_leaf(u_int8_t dtype, u_int32_t spe
CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype); CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype);
CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id); CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id);
if (data) { if (data)
memcpy(CSR1212_DESCRIPTOR_LEAF_DATA(kv), data, data_len); 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; return kv;
} }
/* Check if string conforms to minimal ASCII as per IEEE 1212 clause 7.4 */
static int csr1212_check_minimal_ascii(const char *s) static int csr1212_check_minimal_ascii(const char *s)
{ {
static const char minimal_ascii_table[] = { static const char minimal_ascii_table[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, /* 1 2 4 8 16 32 64 128 */
0x00, 0x00, 0x0a, 0x00, 0x0C, 0x0D, 0x00, 0x00, 128, /* --, --, --, --, --, --, --, 07, */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 4 + 16 + 32, /* --, --, 0a, --, 0C, 0D, --, --, */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0, /* --, --, --, --, --, --, --, --, */
0x20, 0x21, 0x22, 0x00, 0x00, 0x25, 0x26, 0x27, 0, /* --, --, --, --, --, --, --, --, */
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 255 - 8 - 16, /* 20, 21, 22, --, --, 25, 26, 27, */
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 255, /* 28, 29, 2a, 2b, 2c, 2d, 2e, 2f, */
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 255, /* 30, 31, 32, 33, 34, 35, 36, 37, */
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 255, /* 38, 39, 3a, 3b, 3c, 3d, 3e, 3f, */
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 255, /* 40, 41, 42, 43, 44, 45, 46, 47, */
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 255, /* 48, 49, 4a, 4b, 4c, 4d, 4e, 4f, */
0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x5f, 255, /* 50, 51, 52, 53, 54, 55, 56, 57, */
0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 1 + 2 + 4 + 128, /* 58, 59, 5a, --, --, --, --, 5f, */
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 255 - 1, /* --, 61, 62, 63, 64, 65, 66, 67, */
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 255, /* 68, 69, 6a, 6b, 6c, 6d, 6e, 6f, */
0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 255, /* 70, 71, 72, 73, 74, 75, 76, 77, */
1 + 2 + 4, /* 78, 79, 7a, --, --, --, --, --, */
}; };
int i, j;
for (; *s; s++) { for (; *s; s++) {
if (minimal_ascii_table[*s & 0x7F] != *s) i = *s >> 3; /* i = *s / 8; */
return -1; /* failed */ j = 1 << (*s & 3); /* j = 1 << (*s % 8); */
if (i >= ARRAY_SIZE(minimal_ascii_table) ||
!(minimal_ascii_table[i] & j))
return -EINVAL;
} }
/* String conforms to minimal-ascii, as specified by IEEE 1212,
* par. 7.4 */
return 0; return 0;
} }
/* IEEE 1212 clause 7.5.4.1 textual descriptors (English, minimal ASCII) */
struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s) 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; struct csr1212_keyval *kv;
int palette_size; u32 *text;
int pixel_size = (hscan * vscan + 3) & ~0x3; size_t str_len, quads;
if (!pixels || (!palette && palette_depth) || if (!s || !*s || csr1212_check_minimal_ascii(s))
(palette_depth & ~0x3) || (color_space & ~0xf))
return NULL; return NULL;
palette_size = pd[palette_depth] * cs[color_space]; str_len = strlen(s);
quads = bytes_to_quads(str_len);
kv = csr1212_new_descriptor_leaf(1, 0, NULL, kv = csr1212_new_descriptor_leaf(0, 0, NULL, quads_to_bytes(quads) +
palette_size + pixel_size + CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD);
CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD);
if (!kv) if (!kv)
return NULL; return NULL;
CSR1212_ICON_DESCRIPTOR_LEAF_SET_VERSION(kv, version); kv->value.leaf.data[1] = 0; /* width, character_set, language */
CSR1212_ICON_DESCRIPTOR_LEAF_SET_PALETTE_DEPTH(kv, palette_depth); text = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv);
CSR1212_ICON_DESCRIPTOR_LEAF_SET_COLOR_SPACE(kv, color_space); text[quads - 1] = 0; /* padding */
CSR1212_ICON_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language); memcpy(text, s, str_len);
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; 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 */ /* Destruction Routines */
...@@ -674,23 +481,12 @@ void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir, ...@@ -674,23 +481,12 @@ void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
csr1212_release_keyval(kv); 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 /* 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 * 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 * 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 * list manipulation, this routine will descend a directory structure in a
* non-recursive manner. */ * non-recursive manner. */
void _csr1212_destroy_keyval(struct csr1212_keyval *kv) static void csr1212_destroy_keyval(struct csr1212_keyval *kv)
{ {
struct csr1212_keyval *k, *a; struct csr1212_keyval *k, *a;
struct csr1212_dentry dentry; struct csr1212_dentry dentry;
...@@ -715,11 +511,13 @@ void _csr1212_destroy_keyval(struct csr1212_keyval *kv) ...@@ -715,11 +511,13 @@ void _csr1212_destroy_keyval(struct csr1212_keyval *kv)
a = k->associate; a = k->associate;
if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) { if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) {
/* If the current entry is a directory, then move all /* If the current entry is a directory, move all
* the entries to the destruction list. */ * the entries to the destruction list. */
if (k->value.directory.dentries_head) { if (k->value.directory.dentries_head) {
tail->next = k->value.directory.dentries_head; tail->next =
k->value.directory.dentries_head->prev = tail; k->value.directory.dentries_head;
k->value.directory.dentries_head->prev =
tail;
tail = k->value.directory.dentries_tail; tail = k->value.directory.dentries_tail;
} }
} }
...@@ -729,15 +527,22 @@ void _csr1212_destroy_keyval(struct csr1212_keyval *kv) ...@@ -729,15 +527,22 @@ void _csr1212_destroy_keyval(struct csr1212_keyval *kv)
head = head->next; head = head->next;
if (head) { if (head) {
if (head->prev && head->prev != &dentry) { if (head->prev && head->prev != &dentry)
CSR1212_FREE(head->prev); CSR1212_FREE(head->prev);
}
head->prev = NULL; head->prev = NULL;
} else if (tail != &dentry) } else if (tail != &dentry) {
CSR1212_FREE(tail); CSR1212_FREE(tail);
}
} }
} }
void csr1212_release_keyval(struct csr1212_keyval *kv)
{
if (kv->refcnt > 1)
kv->refcnt--;
else
csr1212_destroy_keyval(kv);
}
void csr1212_destroy_csr(struct csr1212_csr *csr) void csr1212_destroy_csr(struct csr1212_csr *csr)
{ {
...@@ -763,49 +568,51 @@ void csr1212_destroy_csr(struct csr1212_csr *csr) ...@@ -763,49 +568,51 @@ void csr1212_destroy_csr(struct csr1212_csr *csr)
} }
/* CSR Image Creation */ /* CSR Image Creation */
static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize) static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
{ {
struct csr1212_csr_rom_cache *cache; struct csr1212_csr_rom_cache *cache;
u_int64_t csr_addr; u64 csr_addr;
if (!csr || !csr->ops || !csr->ops->allocate_addr_range || BUG_ON(!csr || !csr->ops || !csr->ops->allocate_addr_range ||
!csr->ops->release_addr || csr->max_rom < 1) !csr->ops->release_addr || csr->max_rom < 1);
return CSR1212_EINVAL;
/* ROM size must be a multiple of csr->max_rom */ /* ROM size must be a multiple of csr->max_rom */
romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1); romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1);
csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom, csr->private); csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom,
if (csr_addr == CSR1212_INVALID_ADDR_SPACE) { csr->private);
return CSR1212_ENOMEM; if (csr_addr == CSR1212_INVALID_ADDR_SPACE)
} return -ENOMEM;
if (csr_addr < CSR1212_REGISTER_SPACE_BASE) { if (csr_addr < CSR1212_REGISTER_SPACE_BASE) {
/* Invalid address returned from allocate_addr_range(). */ /* Invalid address returned from allocate_addr_range(). */
csr->ops->release_addr(csr_addr, csr->private); csr->ops->release_addr(csr_addr, csr->private);
return CSR1212_ENOMEM; return -ENOMEM;
} }
cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE, romsize); cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE,
romsize);
if (!cache) { if (!cache) {
csr->ops->release_addr(csr_addr, csr->private); csr->ops->release_addr(csr_addr, csr->private);
return CSR1212_ENOMEM; return -ENOMEM;
} }
cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, CSR1212_KV_ID_EXTENDED_ROM); cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF,
CSR1212_KV_ID_EXTENDED_ROM);
if (!cache->ext_rom) { if (!cache->ext_rom) {
csr->ops->release_addr(csr_addr, csr->private); csr->ops->release_addr(csr_addr, csr->private);
CSR1212_FREE(cache); CSR1212_FREE(cache);
return CSR1212_ENOMEM; return -ENOMEM;
} }
if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) != CSR1212_SUCCESS) { if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) !=
CSR1212_SUCCESS) {
csr1212_release_keyval(cache->ext_rom); csr1212_release_keyval(cache->ext_rom);
csr->ops->release_addr(csr_addr, csr->private); csr->ops->release_addr(csr_addr, csr->private);
CSR1212_FREE(cache); CSR1212_FREE(cache);
return CSR1212_ENOMEM; return -ENOMEM;
} }
cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE; cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE;
cache->ext_rom->value.leaf.len = -1; cache->ext_rom->value.leaf.len = -1;
...@@ -818,8 +625,8 @@ static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize) ...@@ -818,8 +625,8 @@ static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
return CSR1212_SUCCESS; return CSR1212_SUCCESS;
} }
static inline void csr1212_remove_cache(struct csr1212_csr *csr, static void csr1212_remove_cache(struct csr1212_csr *csr,
struct csr1212_csr_rom_cache *cache) struct csr1212_csr_rom_cache *cache)
{ {
if (csr->cache_head == cache) if (csr->cache_head == cache)
csr->cache_head = cache->next; csr->cache_head = cache->next;
...@@ -832,7 +639,8 @@ static inline void csr1212_remove_cache(struct csr1212_csr *csr, ...@@ -832,7 +639,8 @@ static inline void csr1212_remove_cache(struct csr1212_csr *csr,
cache->next->prev = cache->prev; cache->next->prev = cache->prev;
if (cache->ext_rom) { if (cache->ext_rom) {
csr1212_detach_keyval_from_directory(csr->root_kv, cache->ext_rom); csr1212_detach_keyval_from_directory(csr->root_kv,
cache->ext_rom);
csr1212_release_keyval(cache->ext_rom); csr1212_release_keyval(cache->ext_rom);
} }
...@@ -852,28 +660,29 @@ static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir, ...@@ -852,28 +660,29 @@ static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
dentry = dentry->next) { dentry = dentry->next) {
for (dkv = dentry->kv; dkv; dkv = dkv->associate) { for (dkv = dentry->kv; dkv; dkv = dkv->associate) {
/* Special Case: Extended Key Specifier_ID */ /* Special Case: Extended Key Specifier_ID */
if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) { if (dkv->key.id ==
if (last_extkey_spec == NULL) { CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
if (last_extkey_spec == NULL)
last_extkey_spec = dkv; last_extkey_spec = dkv;
} else if (dkv->value.immediate != last_extkey_spec->value.immediate) { else if (dkv->value.immediate !=
last_extkey_spec->value.immediate)
last_extkey_spec = dkv; last_extkey_spec = dkv;
} else { else
continue; continue;
}
/* Special Case: Extended Key */ /* Special Case: Extended Key */
} else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) { } else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
if (last_extkey == NULL) { if (last_extkey == NULL)
last_extkey = dkv; last_extkey = dkv;
} else if (dkv->value.immediate != last_extkey->value.immediate) { else if (dkv->value.immediate !=
last_extkey->value.immediate)
last_extkey = dkv; last_extkey = dkv;
} else { else
continue; continue;
}
} }
num_entries += 1; num_entries += 1;
switch(dkv->key.type) { switch (dkv->key.type) {
default: default:
case CSR1212_KV_TYPE_IMMEDIATE: case CSR1212_KV_TYPE_IMMEDIATE:
case CSR1212_KV_TYPE_CSR_OFFSET: case CSR1212_KV_TYPE_CSR_OFFSET:
...@@ -891,8 +700,9 @@ static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir, ...@@ -891,8 +700,9 @@ static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
/* Special case: Extended ROM leafs */ /* Special case: Extended ROM leafs */
if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) { if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
dkv->value.leaf.len = -1; dkv->value.leaf.len = -1;
/* Don't add Extended ROM leafs in the layout list, /* Don't add Extended ROM leafs in the
* they are handled differently. */ * layout list, they are handled
* differently. */
break; break;
} }
...@@ -908,20 +718,21 @@ static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir, ...@@ -908,20 +718,21 @@ static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
return num_entries; return num_entries;
} }
size_t csr1212_generate_layout_order(struct csr1212_keyval *kv) static size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
{ {
struct csr1212_keyval *ltail = kv; struct csr1212_keyval *ltail = kv;
size_t agg_size = 0; size_t agg_size = 0;
while(kv) { while (kv) {
switch(kv->key.type) { switch (kv->key.type) {
case CSR1212_KV_TYPE_LEAF: case CSR1212_KV_TYPE_LEAF:
/* Add 1 quadlet for crc/len field */ /* Add 1 quadlet for crc/len field */
agg_size += kv->value.leaf.len + 1; agg_size += kv->value.leaf.len + 1;
break; break;
case CSR1212_KV_TYPE_DIRECTORY: case CSR1212_KV_TYPE_DIRECTORY:
kv->value.directory.len = csr1212_generate_layout_subdir(kv, &ltail); kv->value.directory.len =
csr1212_generate_layout_subdir(kv, &ltail);
/* Add 1 quadlet for crc/len field */ /* Add 1 quadlet for crc/len field */
agg_size += kv->value.directory.len + 1; agg_size += kv->value.directory.len + 1;
break; break;
...@@ -931,9 +742,9 @@ size_t csr1212_generate_layout_order(struct csr1212_keyval *kv) ...@@ -931,9 +742,9 @@ size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
return quads_to_bytes(agg_size); return quads_to_bytes(agg_size);
} }
struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *cache, static struct csr1212_keyval *
struct csr1212_keyval *start_kv, csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
int start_pos) struct csr1212_keyval *start_kv, int start_pos)
{ {
struct csr1212_keyval *kv = start_kv; struct csr1212_keyval *kv = start_kv;
struct csr1212_keyval *okv = start_kv; struct csr1212_keyval *okv = start_kv;
...@@ -942,13 +753,12 @@ struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache * ...@@ -942,13 +753,12 @@ struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *
cache->layout_head = kv; cache->layout_head = kv;
while(kv && pos < cache->size) { while (kv && pos < cache->size) {
/* Special case: Extended ROM leafs */ /* Special case: Extended ROM leafs */
if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) { if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
kv->offset = cache->offset + pos; kv->offset = cache->offset + pos;
}
switch(kv->key.type) { switch (kv->key.type) {
case CSR1212_KV_TYPE_LEAF: case CSR1212_KV_TYPE_LEAF:
kv_len = kv->value.leaf.len; kv_len = kv->value.leaf.len;
break; break;
...@@ -959,6 +769,7 @@ struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache * ...@@ -959,6 +769,7 @@ struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *
default: default:
/* Should never get here */ /* Should never get here */
WARN_ON(1);
break; break;
} }
...@@ -972,46 +783,55 @@ struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache * ...@@ -972,46 +783,55 @@ struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *
} }
cache->layout_tail = okv; cache->layout_tail = okv;
cache->len = (okv->offset - cache->offset) + quads_to_bytes(okv_len + 1); cache->len = okv->offset - cache->offset + quads_to_bytes(okv_len + 1);
return kv; return kv;
} }
static void csr1212_generate_tree_subdir(struct csr1212_keyval *dir, #define CSR1212_KV_KEY_SHIFT 24
u_int32_t *data_buffer) #define CSR1212_KV_KEY_TYPE_SHIFT 6
#define CSR1212_KV_KEY_ID_MASK 0x3f
#define CSR1212_KV_KEY_TYPE_MASK 0x3 /* after shift */
static void
csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u32 *data_buffer)
{ {
struct csr1212_dentry *dentry; struct csr1212_dentry *dentry;
struct csr1212_keyval *last_extkey_spec = NULL; struct csr1212_keyval *last_extkey_spec = NULL;
struct csr1212_keyval *last_extkey = NULL; struct csr1212_keyval *last_extkey = NULL;
int index = 0; int index = 0;
for (dentry = dir->value.directory.dentries_head; dentry; dentry = dentry->next) { for (dentry = dir->value.directory.dentries_head;
dentry;
dentry = dentry->next) {
struct csr1212_keyval *a; struct csr1212_keyval *a;
for (a = dentry->kv; a; a = a->associate) { for (a = dentry->kv; a; a = a->associate) {
u_int32_t value = 0; u32 value = 0;
/* Special Case: Extended Key Specifier_ID */ /* Special Case: Extended Key Specifier_ID */
if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) { if (a->key.id ==
if (last_extkey_spec == NULL) { CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
if (last_extkey_spec == NULL)
last_extkey_spec = a; last_extkey_spec = a;
} else if (a->value.immediate != last_extkey_spec->value.immediate) { else if (a->value.immediate !=
last_extkey_spec->value.immediate)
last_extkey_spec = a; last_extkey_spec = a;
} else { else
continue; continue;
}
/* Special Case: Extended Key */ /* Special Case: Extended Key */
} else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) { } else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
if (last_extkey == NULL) { if (last_extkey == NULL)
last_extkey = a; last_extkey = a;
} else if (a->value.immediate != last_extkey->value.immediate) { else if (a->value.immediate !=
last_extkey->value.immediate)
last_extkey = a; last_extkey = a;
} else { else
continue; continue;
}
} }
switch(a->key.type) { switch (a->key.type) {
case CSR1212_KV_TYPE_IMMEDIATE: case CSR1212_KV_TYPE_IMMEDIATE:
value = a->value.immediate; value = a->value.immediate;
break; break;
...@@ -1030,32 +850,46 @@ static void csr1212_generate_tree_subdir(struct csr1212_keyval *dir, ...@@ -1030,32 +850,46 @@ static void csr1212_generate_tree_subdir(struct csr1212_keyval *dir,
break; break;
default: default:
/* Should never get here */ /* Should never get here */
break; /* GDB breakpoint */ WARN_ON(1);
break;
} }
value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) << CSR1212_KV_KEY_SHIFT; value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) <<
CSR1212_KV_KEY_SHIFT;
value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) << value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) <<
(CSR1212_KV_KEY_SHIFT + CSR1212_KV_KEY_TYPE_SHIFT); (CSR1212_KV_KEY_SHIFT +
data_buffer[index] = CSR1212_CPU_TO_BE32(value); CSR1212_KV_KEY_TYPE_SHIFT);
data_buffer[index] = cpu_to_be32(value);
index++; index++;
} }
} }
} }
void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache) struct csr1212_keyval_img {
u16 length;
u16 crc;
/* Must be last */
u32 data[0]; /* older gcc can't handle [] which is standard */
};
static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
{ {
struct csr1212_keyval *kv, *nkv; struct csr1212_keyval *kv, *nkv;
struct csr1212_keyval_img *kvi; struct csr1212_keyval_img *kvi;
for (kv = cache->layout_head; kv != cache->layout_tail->next; kv = nkv) { for (kv = cache->layout_head;
kvi = (struct csr1212_keyval_img *) kv != cache->layout_tail->next;
(cache->data + bytes_to_quads(kv->offset - cache->offset)); kv = nkv) {
switch(kv->key.type) { kvi = (struct csr1212_keyval_img *)(cache->data +
bytes_to_quads(kv->offset - cache->offset));
switch (kv->key.type) {
default: default:
case CSR1212_KV_TYPE_IMMEDIATE: case CSR1212_KV_TYPE_IMMEDIATE:
case CSR1212_KV_TYPE_CSR_OFFSET: case CSR1212_KV_TYPE_CSR_OFFSET:
/* Should never get here */ /* Should never get here */
break; /* GDB breakpoint */ WARN_ON(1);
break;
case CSR1212_KV_TYPE_LEAF: case CSR1212_KV_TYPE_LEAF:
/* Don't copy over Extended ROM areas, they are /* Don't copy over Extended ROM areas, they are
...@@ -1064,15 +898,16 @@ void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache) ...@@ -1064,15 +898,16 @@ void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
memcpy(kvi->data, kv->value.leaf.data, memcpy(kvi->data, kv->value.leaf.data,
quads_to_bytes(kv->value.leaf.len)); quads_to_bytes(kv->value.leaf.len));
kvi->length = CSR1212_CPU_TO_BE16(kv->value.leaf.len); kvi->length = cpu_to_be16(kv->value.leaf.len);
kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len); kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len);
break; break;
case CSR1212_KV_TYPE_DIRECTORY: case CSR1212_KV_TYPE_DIRECTORY:
csr1212_generate_tree_subdir(kv, kvi->data); csr1212_generate_tree_subdir(kv, kvi->data);
kvi->length = CSR1212_CPU_TO_BE16(kv->value.directory.len); kvi->length = cpu_to_be16(kv->value.directory.len);
kvi->crc = csr1212_crc16(kvi->data, kv->value.directory.len); kvi->crc = csr1212_crc16(kvi->data,
kv->value.directory.len);
break; break;
} }
...@@ -1086,6 +921,10 @@ void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache) ...@@ -1086,6 +921,10 @@ void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
} }
} }
/* This size is arbitrarily chosen.
* The struct overhead is subtracted for more economic allocations. */
#define CSR1212_EXTENDED_ROM_SIZE (2048 - sizeof(struct csr1212_csr_rom_cache))
int csr1212_generate_csr_image(struct csr1212_csr *csr) int csr1212_generate_csr_image(struct csr1212_csr *csr)
{ {
struct csr1212_bus_info_block_img *bi; struct csr1212_bus_info_block_img *bi;
...@@ -1095,8 +934,7 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr) ...@@ -1095,8 +934,7 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr)
int ret; int ret;
int init_offset; int init_offset;
if (!csr) BUG_ON(!csr);
return CSR1212_EINVAL;
cache = csr->cache_head; cache = csr->cache_head;
...@@ -1113,18 +951,21 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr) ...@@ -1113,18 +951,21 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr)
init_offset = csr->bus_info_len; init_offset = csr->bus_info_len;
for (kv = csr->root_kv, cache = csr->cache_head; kv; cache = cache->next) { for (kv = csr->root_kv, cache = csr->cache_head;
kv;
cache = cache->next) {
if (!cache) { if (!cache) {
/* Estimate approximate number of additional cache /* Estimate approximate number of additional cache
* regions needed (it assumes that the cache holding * regions needed (it assumes that the cache holding
* the first 1K Config ROM space always exists). */ * the first 1K Config ROM space always exists). */
int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE - int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE -
(2 * sizeof(u_int32_t))) + 1; (2 * sizeof(u32))) + 1;
/* Add additional cache regions, extras will be /* Add additional cache regions, extras will be
* removed later */ * removed later */
for (; est_c; est_c--) { for (; est_c; est_c--) {
ret = csr1212_append_new_cache(csr, CSR1212_EXTENDED_ROM_SIZE); ret = csr1212_append_new_cache(csr,
CSR1212_EXTENDED_ROM_SIZE);
if (ret != CSR1212_SUCCESS) if (ret != CSR1212_SUCCESS)
return ret; return ret;
} }
...@@ -1136,7 +977,7 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr) ...@@ -1136,7 +977,7 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr)
} }
kv = csr1212_generate_positions(cache, kv, init_offset); kv = csr1212_generate_positions(cache, kv, init_offset);
agg_size -= cache->len; agg_size -= cache->len;
init_offset = sizeof(u_int32_t); init_offset = sizeof(u32);
} }
/* Remove unused, excess cache regions */ /* Remove unused, excess cache regions */
...@@ -1149,15 +990,14 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr) ...@@ -1149,15 +990,14 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr)
/* Go through the list backward so that when done, the correct CRC /* Go through the list backward so that when done, the correct CRC
* will be calculated for the Extended ROM areas. */ * will be calculated for the Extended ROM areas. */
for(cache = csr->cache_tail; cache; cache = cache->prev) { for (cache = csr->cache_tail; cache; cache = cache->prev) {
/* Only Extended ROM caches should have this set. */ /* Only Extended ROM caches should have this set. */
if (cache->ext_rom) { if (cache->ext_rom) {
int leaf_size; int leaf_size;
/* Make sure the Extended ROM leaf is a multiple of /* Make sure the Extended ROM leaf is a multiple of
* max_rom in size. */ * max_rom in size. */
if (csr->max_rom < 1) BUG_ON(csr->max_rom < 1);
return CSR1212_EINVAL;
leaf_size = (cache->len + (csr->max_rom - 1)) & leaf_size = (cache->len + (csr->max_rom - 1)) &
~(csr->max_rom - 1); ~(csr->max_rom - 1);
...@@ -1166,7 +1006,7 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr) ...@@ -1166,7 +1006,7 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr)
leaf_size - cache->len); leaf_size - cache->len);
/* Subtract leaf header */ /* Subtract leaf header */
leaf_size -= sizeof(u_int32_t); leaf_size -= sizeof(u32);
/* Update the Extended ROM leaf length */ /* Update the Extended ROM leaf length */
cache->ext_rom->value.leaf.len = cache->ext_rom->value.leaf.len =
...@@ -1184,33 +1024,31 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr) ...@@ -1184,33 +1024,31 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr)
/* Set the length and CRC of the extended ROM. */ /* Set the length and CRC of the extended ROM. */
struct csr1212_keyval_img *kvi = struct csr1212_keyval_img *kvi =
(struct csr1212_keyval_img*)cache->data; (struct csr1212_keyval_img*)cache->data;
u16 len = bytes_to_quads(cache->len) - 1;
kvi->length = CSR1212_CPU_TO_BE16(bytes_to_quads(cache->len) - 1); kvi->length = cpu_to_be16(len);
kvi->crc = csr1212_crc16(kvi->data, kvi->crc = csr1212_crc16(kvi->data, len);
bytes_to_quads(cache->len) - 1);
} }
} }
return CSR1212_SUCCESS; return CSR1212_SUCCESS;
} }
int csr1212_read(struct csr1212_csr *csr, u_int32_t offset, void *buffer, u_int32_t len) int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer, u32 len)
{ {
struct csr1212_csr_rom_cache *cache; struct csr1212_csr_rom_cache *cache;
for (cache = csr->cache_head; cache; cache = cache->next) { for (cache = csr->cache_head; cache; cache = cache->next)
if (offset >= cache->offset && if (offset >= cache->offset &&
(offset + len) <= (cache->offset + cache->size)) { (offset + len) <= (cache->offset + cache->size)) {
memcpy(buffer, memcpy(buffer, &cache->data[
&cache->data[bytes_to_quads(offset - cache->offset)], bytes_to_quads(offset - cache->offset)],
len); len);
return CSR1212_SUCCESS; return CSR1212_SUCCESS;
} }
}
return CSR1212_ENOENT;
}
return -ENOENT;
}
/* Parse a chunk of data as a Config ROM */ /* Parse a chunk of data as a Config ROM */
...@@ -1227,46 +1065,43 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr) ...@@ -1227,46 +1065,43 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
* Unfortunately, many IEEE 1394 devices do not abide by that, so the * 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 * 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. */ * ConfigROM will be read according to the max_rom field. */
for (i = 0; i < csr->bus_info_len; i += sizeof(csr1212_quad_t)) { for (i = 0; i < csr->bus_info_len; i += sizeof(u32)) {
ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i, ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
sizeof(csr1212_quad_t), sizeof(u32), &csr->cache_head->data[bytes_to_quads(i)],
&csr->cache_head->data[bytes_to_quads(i)], csr->private);
csr->private);
if (ret != CSR1212_SUCCESS) if (ret != CSR1212_SUCCESS)
return ret; return ret;
/* check ROM header's info_length */ /* check ROM header's info_length */
if (i == 0 && if (i == 0 &&
CSR1212_BE32_TO_CPU(csr->cache_head->data[0]) >> 24 != be32_to_cpu(csr->cache_head->data[0]) >> 24 !=
bytes_to_quads(csr->bus_info_len) - 1) bytes_to_quads(csr->bus_info_len) - 1)
return CSR1212_EINVAL; return -EINVAL;
} }
bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data; bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
csr->crc_len = quads_to_bytes(bi->crc_length); 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 /* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that
* always the case, so read the rest of the crc area 1 quadlet at a time. */ * is not always the case, so read the rest of the crc area 1 quadlet at
for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(csr1212_quad_t)) { * a time. */
for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(u32)) {
ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i, ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
sizeof(csr1212_quad_t), sizeof(u32), &csr->cache_head->data[bytes_to_quads(i)],
&csr->cache_head->data[bytes_to_quads(i)], csr->private);
csr->private);
if (ret != CSR1212_SUCCESS) if (ret != CSR1212_SUCCESS)
return ret; return ret;
} }
#if 0 /* Apparently there are many different wrong implementations of the CRC
/* Apparently there are too many differnt wrong implementations of the * algorithm. We don't fail, we just warn. */
* CRC algorithm that verifying them is moot. */
if ((csr1212_crc16(bi->data, bi->crc_length) != bi->crc) && if ((csr1212_crc16(bi->data, bi->crc_length) != bi->crc) &&
(csr1212_msft_crc16(bi->data, bi->crc_length) != bi->crc)) (csr1212_msft_crc16(bi->data, bi->crc_length) != bi->crc))
return CSR1212_EINVAL; printk(KERN_DEBUG "IEEE 1394 device has ROM CRC error\n");
#endif
cr = CSR1212_MALLOC(sizeof(*cr)); cr = CSR1212_MALLOC(sizeof(*cr));
if (!cr) if (!cr)
return CSR1212_ENOMEM; return -ENOMEM;
cr->next = NULL; cr->next = NULL;
cr->prev = NULL; cr->prev = NULL;
...@@ -1279,21 +1114,26 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr) ...@@ -1279,21 +1114,26 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
return CSR1212_SUCCESS; return CSR1212_SUCCESS;
} }
static int csr1212_parse_dir_entry(struct csr1212_keyval *dir, #define CSR1212_KV_KEY(q) (be32_to_cpu(q) >> CSR1212_KV_KEY_SHIFT)
csr1212_quad_t ki, #define CSR1212_KV_KEY_TYPE(q) (CSR1212_KV_KEY(q) >> CSR1212_KV_KEY_TYPE_SHIFT)
u_int32_t kv_pos) #define CSR1212_KV_KEY_ID(q) (CSR1212_KV_KEY(q) & CSR1212_KV_KEY_ID_MASK)
#define CSR1212_KV_VAL_MASK 0xffffff
#define CSR1212_KV_VAL(q) (be32_to_cpu(q) & CSR1212_KV_VAL_MASK)
static int
csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
{ {
int ret = CSR1212_SUCCESS; int ret = CSR1212_SUCCESS;
struct csr1212_keyval *k = NULL; struct csr1212_keyval *k = NULL;
u_int32_t offset; u32 offset;
switch(CSR1212_KV_KEY_TYPE(ki)) { switch (CSR1212_KV_KEY_TYPE(ki)) {
case CSR1212_KV_TYPE_IMMEDIATE: case CSR1212_KV_TYPE_IMMEDIATE:
k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki), k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki),
CSR1212_KV_VAL(ki)); CSR1212_KV_VAL(ki));
if (!k) { if (!k) {
ret = CSR1212_ENOMEM; ret = -ENOMEM;
goto fail; goto out;
} }
k->refcnt = 0; /* Don't keep local reference when parsing. */ k->refcnt = 0; /* Don't keep local reference when parsing. */
...@@ -1303,8 +1143,8 @@ static int csr1212_parse_dir_entry(struct csr1212_keyval *dir, ...@@ -1303,8 +1143,8 @@ static int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki), k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki),
CSR1212_KV_VAL(ki)); CSR1212_KV_VAL(ki));
if (!k) { if (!k) {
ret = CSR1212_ENOMEM; ret = -ENOMEM;
goto fail; goto out;
} }
k->refcnt = 0; /* Don't keep local reference when parsing. */ k->refcnt = 0; /* Don't keep local reference when parsing. */
break; break;
...@@ -1316,8 +1156,8 @@ static int csr1212_parse_dir_entry(struct csr1212_keyval *dir, ...@@ -1316,8 +1156,8 @@ static int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
/* Uh-oh. Can't have a relative offset of 0 for Leaves /* Uh-oh. Can't have a relative offset of 0 for Leaves
* or Directories. The Config ROM image is most likely * or Directories. The Config ROM image is most likely
* messed up, so we'll just abort here. */ * messed up, so we'll just abort here. */
ret = CSR1212_EIO; ret = -EIO;
goto fail; goto out;
} }
k = csr1212_find_keyval_offset(dir, offset); k = csr1212_find_keyval_offset(dir, offset);
...@@ -1325,14 +1165,14 @@ static int csr1212_parse_dir_entry(struct csr1212_keyval *dir, ...@@ -1325,14 +1165,14 @@ static int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
if (k) if (k)
break; /* Found it. */ break; /* Found it. */
if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY) { if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY)
k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki)); k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki));
} else { else
k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0); k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0);
}
if (!k) { if (!k) {
ret = CSR1212_ENOMEM; ret = -ENOMEM;
goto fail; goto out;
} }
k->refcnt = 0; /* Don't keep local reference when parsing. */ k->refcnt = 0; /* Don't keep local reference when parsing. */
k->valid = 0; /* Contents not read yet so it's not valid. */ k->valid = 0; /* Contents not read yet so it's not valid. */
...@@ -1344,16 +1184,12 @@ static int csr1212_parse_dir_entry(struct csr1212_keyval *dir, ...@@ -1344,16 +1184,12 @@ static int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
dir->next = k; dir->next = k;
} }
ret = csr1212_attach_keyval_to_directory(dir, k); ret = csr1212_attach_keyval_to_directory(dir, k);
out:
fail: if (ret != CSR1212_SUCCESS && k != NULL)
if (ret != CSR1212_SUCCESS) { free_keyval(k);
if (k)
free_keyval(k);
}
return ret; return ret;
} }
int csr1212_parse_keyval(struct csr1212_keyval *kv, int csr1212_parse_keyval(struct csr1212_keyval *kv,
struct csr1212_csr_rom_cache *cache) struct csr1212_csr_rom_cache *cache)
{ {
...@@ -1362,24 +1198,20 @@ int csr1212_parse_keyval(struct csr1212_keyval *kv, ...@@ -1362,24 +1198,20 @@ int csr1212_parse_keyval(struct csr1212_keyval *kv,
int ret = CSR1212_SUCCESS; int ret = CSR1212_SUCCESS;
int kvi_len; int kvi_len;
kvi = (struct csr1212_keyval_img*)&cache->data[bytes_to_quads(kv->offset - kvi = (struct csr1212_keyval_img*)
cache->offset)]; &cache->data[bytes_to_quads(kv->offset - cache->offset)];
kvi_len = CSR1212_BE16_TO_CPU(kvi->length); kvi_len = be16_to_cpu(kvi->length);
#if 0 /* Apparently there are many different wrong implementations of the CRC
/* Apparently there are too many differnt wrong implementations of the * algorithm. We don't fail, we just warn. */
* CRC algorithm that verifying them is moot. */
if ((csr1212_crc16(kvi->data, kvi_len) != kvi->crc) && if ((csr1212_crc16(kvi->data, kvi_len) != kvi->crc) &&
(csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc)) { (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc))
ret = CSR1212_EINVAL; printk(KERN_DEBUG "IEEE 1394 device has ROM CRC error\n");
goto fail;
}
#endif
switch(kv->key.type) { switch (kv->key.type) {
case CSR1212_KV_TYPE_DIRECTORY: case CSR1212_KV_TYPE_DIRECTORY:
for (i = 0; i < kvi_len; i++) { for (i = 0; i < kvi_len; i++) {
csr1212_quad_t ki = kvi->data[i]; u32 ki = kvi->data[i];
/* Some devices put null entries in their unit /* Some devices put null entries in their unit
* directories. If we come across such an entry, * directories. If we come across such an entry,
...@@ -1387,76 +1219,72 @@ int csr1212_parse_keyval(struct csr1212_keyval *kv, ...@@ -1387,76 +1219,72 @@ int csr1212_parse_keyval(struct csr1212_keyval *kv,
if (ki == 0x0) if (ki == 0x0)
continue; continue;
ret = csr1212_parse_dir_entry(kv, ki, ret = csr1212_parse_dir_entry(kv, ki,
(kv->offset + kv->offset + quads_to_bytes(i + 1));
quads_to_bytes(i + 1)));
} }
kv->value.directory.len = kvi_len; kv->value.directory.len = kvi_len;
break; break;
case CSR1212_KV_TYPE_LEAF: case CSR1212_KV_TYPE_LEAF:
if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) { if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
kv->value.leaf.data = CSR1212_MALLOC(quads_to_bytes(kvi_len)); size_t size = quads_to_bytes(kvi_len);
kv->value.leaf.data = CSR1212_MALLOC(size);
if (!kv->value.leaf.data) { if (!kv->value.leaf.data) {
ret = CSR1212_ENOMEM; ret = -ENOMEM;
goto fail; goto out;
} }
kv->value.leaf.len = kvi_len; kv->value.leaf.len = kvi_len;
memcpy(kv->value.leaf.data, kvi->data, quads_to_bytes(kvi_len)); memcpy(kv->value.leaf.data, kvi->data, size);
} }
break; break;
} }
kv->valid = 1; kv->valid = 1;
out:
fail:
return ret; return ret;
} }
static int
int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
{ {
struct csr1212_cache_region *cr, *ncr, *newcr = NULL; struct csr1212_cache_region *cr, *ncr, *newcr = NULL;
struct csr1212_keyval_img *kvi = NULL; struct csr1212_keyval_img *kvi = NULL;
struct csr1212_csr_rom_cache *cache; struct csr1212_csr_rom_cache *cache;
int cache_index; int cache_index;
u_int64_t addr; u64 addr;
u_int32_t *cache_ptr; u32 *cache_ptr;
u_int16_t kv_len = 0; u16 kv_len = 0;
if (!csr || !kv || csr->max_rom < 1) BUG_ON(!csr || !kv || csr->max_rom < 1);
return CSR1212_EINVAL;
/* First find which cache the data should be in (or go in if not read /* First find which cache the data should be in (or go in if not read
* yet). */ * yet). */
for (cache = csr->cache_head; cache; cache = cache->next) { for (cache = csr->cache_head; cache; cache = cache->next)
if (kv->offset >= cache->offset && if (kv->offset >= cache->offset &&
kv->offset < (cache->offset + cache->size)) kv->offset < (cache->offset + cache->size))
break; break;
}
if (!cache) { if (!cache) {
csr1212_quad_t q; u32 q, cache_size;
u_int32_t cache_size;
/* Only create a new cache for Extended ROM leaves. */ /* Only create a new cache for Extended ROM leaves. */
if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
return CSR1212_EINVAL; return -EINVAL;
if (csr->ops->bus_read(csr, if (csr->ops->bus_read(csr,
CSR1212_REGISTER_SPACE_BASE + kv->offset, CSR1212_REGISTER_SPACE_BASE + kv->offset,
sizeof(csr1212_quad_t), &q, csr->private)) { sizeof(u32), &q, csr->private))
return CSR1212_EIO; return -EIO;
}
kv->value.leaf.len = CSR1212_BE32_TO_CPU(q) >> 16; kv->value.leaf.len = be32_to_cpu(q) >> 16;
cache_size = (quads_to_bytes(kv->value.leaf.len + 1) + cache_size = (quads_to_bytes(kv->value.leaf.len + 1) +
(csr->max_rom - 1)) & ~(csr->max_rom - 1); (csr->max_rom - 1)) & ~(csr->max_rom - 1);
cache = csr1212_rom_cache_malloc(kv->offset, cache_size); cache = csr1212_rom_cache_malloc(kv->offset, cache_size);
if (!cache) if (!cache)
return CSR1212_ENOMEM; return -ENOMEM;
kv->value.leaf.data = &cache->data[1]; kv->value.leaf.data = &cache->data[1];
csr->cache_tail->next = cache; csr->cache_tail->next = cache;
...@@ -1465,12 +1293,11 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) ...@@ -1465,12 +1293,11 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
csr->cache_tail = cache; csr->cache_tail = cache;
cache->filled_head = cache->filled_head =
CSR1212_MALLOC(sizeof(*cache->filled_head)); CSR1212_MALLOC(sizeof(*cache->filled_head));
if (!cache->filled_head) { if (!cache->filled_head)
return CSR1212_ENOMEM; return -ENOMEM;
}
cache->filled_head->offset_start = 0; cache->filled_head->offset_start = 0;
cache->filled_head->offset_end = sizeof(csr1212_quad_t); cache->filled_head->offset_end = sizeof(u32);
cache->filled_tail = cache->filled_head; cache->filled_tail = cache->filled_head;
cache->filled_head->next = NULL; cache->filled_head->next = NULL;
cache->filled_head->prev = NULL; cache->filled_head->prev = NULL;
...@@ -1488,7 +1315,7 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) ...@@ -1488,7 +1315,7 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
if (cache_index < cr->offset_start) { if (cache_index < cr->offset_start) {
newcr = CSR1212_MALLOC(sizeof(*newcr)); newcr = CSR1212_MALLOC(sizeof(*newcr));
if (!newcr) if (!newcr)
return CSR1212_ENOMEM; return -ENOMEM;
newcr->offset_start = cache_index & ~(csr->max_rom - 1); newcr->offset_start = cache_index & ~(csr->max_rom - 1);
newcr->offset_end = newcr->offset_start; newcr->offset_end = newcr->offset_start;
...@@ -1501,18 +1328,18 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) ...@@ -1501,18 +1328,18 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
(cache_index < cr->offset_end)) { (cache_index < cr->offset_end)) {
kvi = (struct csr1212_keyval_img*) kvi = (struct csr1212_keyval_img*)
(&cache->data[bytes_to_quads(cache_index)]); (&cache->data[bytes_to_quads(cache_index)]);
kv_len = quads_to_bytes(CSR1212_BE16_TO_CPU(kvi->length) + kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
1);
break; break;
} else if (cache_index == cr->offset_end) } else if (cache_index == cr->offset_end) {
break; break;
}
} }
if (!cr) { if (!cr) {
cr = cache->filled_tail; cr = cache->filled_tail;
newcr = CSR1212_MALLOC(sizeof(*newcr)); newcr = CSR1212_MALLOC(sizeof(*newcr));
if (!newcr) if (!newcr)
return CSR1212_ENOMEM; return -ENOMEM;
newcr->offset_start = cache_index & ~(csr->max_rom - 1); newcr->offset_start = cache_index & ~(csr->max_rom - 1);
newcr->offset_end = newcr->offset_start; newcr->offset_end = newcr->offset_start;
...@@ -1534,7 +1361,7 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) ...@@ -1534,7 +1361,7 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
csr->private)) { csr->private)) {
if (csr->max_rom == 4) if (csr->max_rom == 4)
/* We've got problems! */ /* We've got problems! */
return CSR1212_EIO; return -EIO;
/* Apperently the max_rom value was a lie, set it to /* Apperently the max_rom value was a lie, set it to
* do quadlet reads and try again. */ * do quadlet reads and try again. */
...@@ -1548,8 +1375,7 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) ...@@ -1548,8 +1375,7 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
if (!kvi && (cr->offset_end > cache_index)) { if (!kvi && (cr->offset_end > cache_index)) {
kvi = (struct csr1212_keyval_img*) kvi = (struct csr1212_keyval_img*)
(&cache->data[bytes_to_quads(cache_index)]); (&cache->data[bytes_to_quads(cache_index)]);
kv_len = quads_to_bytes(CSR1212_BE16_TO_CPU(kvi->length) + kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
1);
} }
if ((kv_len + (kv->offset - cache->offset)) > cache->size) { if ((kv_len + (kv->offset - cache->offset)) > cache->size) {
...@@ -1557,7 +1383,7 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) ...@@ -1557,7 +1383,7 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
* beyond the ConfigROM image region and thus beyond the * beyond the ConfigROM image region and thus beyond the
* end of our cache region. Therefore, we abort now * end of our cache region. Therefore, we abort now
* rather than seg faulting later. */ * rather than seg faulting later. */
return CSR1212_EIO; return -EIO;
} }
ncr = cr->next; ncr = cr->next;
...@@ -1579,7 +1405,16 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv) ...@@ -1579,7 +1405,16 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
return csr1212_parse_keyval(kv, cache); return csr1212_parse_keyval(kv, cache);
} }
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;
}
int csr1212_parse_csr(struct csr1212_csr *csr) int csr1212_parse_csr(struct csr1212_csr *csr)
{ {
...@@ -1587,20 +1422,19 @@ int csr1212_parse_csr(struct csr1212_csr *csr) ...@@ -1587,20 +1422,19 @@ int csr1212_parse_csr(struct csr1212_csr *csr)
struct csr1212_dentry *dentry; struct csr1212_dentry *dentry;
int ret; int ret;
if (!csr || !csr->ops || !csr->ops->bus_read) BUG_ON(!csr || !csr->ops || !csr->ops->bus_read);
return CSR1212_EINVAL;
ret = csr1212_parse_bus_info_block(csr); ret = csr1212_parse_bus_info_block(csr);
if (ret != CSR1212_SUCCESS) if (ret != CSR1212_SUCCESS)
return ret; return ret;
if (!csr->ops->get_max_rom) if (!csr->ops->get_max_rom) {
csr->max_rom = mr_map[0]; /* default value */ csr->max_rom = mr_map[0]; /* default value */
else { } else {
int i = csr->ops->get_max_rom(csr->bus_info_data, int i = csr->ops->get_max_rom(csr->bus_info_data,
csr->private); csr->private);
if (i & ~0x3) if (i & ~0x3)
return CSR1212_EINVAL; return -EINVAL;
csr->max_rom = mr_map[i]; csr->max_rom = mr_map[i];
} }
...@@ -1613,7 +1447,7 @@ int csr1212_parse_csr(struct csr1212_csr *csr) ...@@ -1613,7 +1447,7 @@ int csr1212_parse_csr(struct csr1212_csr *csr)
csr->root_kv->valid = 0; csr->root_kv->valid = 0;
csr->root_kv->next = csr->root_kv; csr->root_kv->next = csr->root_kv;
csr->root_kv->prev = csr->root_kv; csr->root_kv->prev = csr->root_kv;
ret = _csr1212_read_keyval(csr, csr->root_kv); ret = csr1212_read_keyval(csr, csr->root_kv);
if (ret != CSR1212_SUCCESS) if (ret != CSR1212_SUCCESS)
return ret; return ret;
...@@ -1623,7 +1457,7 @@ int csr1212_parse_csr(struct csr1212_csr *csr) ...@@ -1623,7 +1457,7 @@ int csr1212_parse_csr(struct csr1212_csr *csr)
dentry; dentry = dentry->next) { dentry; dentry = dentry->next) {
if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM && if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM &&
!dentry->kv->valid) { !dentry->kv->valid) {
ret = _csr1212_read_keyval(csr, dentry->kv); ret = csr1212_read_keyval(csr, dentry->kv);
if (ret != CSR1212_SUCCESS) if (ret != CSR1212_SUCCESS)
return ret; return ret;
} }
......
...@@ -30,94 +30,13 @@ ...@@ -30,94 +30,13 @@
#ifndef __CSR1212_H__ #ifndef __CSR1212_H__
#define __CSR1212_H__ #define __CSR1212_H__
/* Compatibility layer */
#ifdef __KERNEL__
#include <linux/types.h> #include <linux/types.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
#include <asm/pgalloc.h>
#define CSR1212_MALLOC(size) vmalloc((size))
#define CSR1212_FREE(ptr) vfree(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_MALLOC(size) kmalloc((size), GFP_KERNEL)
#define CSR1212_FREE(ptr) kfree(ptr)
#define CSR1212_KV_VAL_MASK 0xffffff #define CSR1212_SUCCESS (0)
#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 */ /* CSR 1212 key types */
...@@ -190,48 +109,22 @@ ...@@ -190,48 +109,22 @@
#define CSR1212_UNITS_SPACE_END (CSR1212_UNITS_SPACE_BASE + CSR1212_UNITS_SPACE_SIZE) #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_UNITS_SPACE_OFFSET (CSR1212_UNITS_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
#define CSR1212_EXTENDED_ROM_SIZE (0x10000 * sizeof(u_int32_t))
#define CSR1212_INVALID_ADDR_SPACE -1 #define CSR1212_INVALID_ADDR_SPACE -1
/* Config ROM image structures */ /* Config ROM image structures */
struct csr1212_bus_info_block_img { struct csr1212_bus_info_block_img {
u_int8_t length; u8 length;
u_int8_t crc_length; u8 crc_length;
u_int16_t crc; u16 crc;
/* Must be last */ /* Must be last */
u_int32_t data[0]; /* older gcc can't handle [] which is standard */ u32 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 { struct csr1212_leaf {
int len; int len;
u_int32_t *data; u32 *data;
}; };
struct csr1212_dentry { struct csr1212_dentry {
...@@ -246,12 +139,12 @@ struct csr1212_directory { ...@@ -246,12 +139,12 @@ struct csr1212_directory {
struct csr1212_keyval { struct csr1212_keyval {
struct { struct {
u_int8_t type; u8 type;
u_int8_t id; u8 id;
} key; } key;
union { union {
u_int32_t immediate; u32 immediate;
u_int32_t csr_offset; u32 csr_offset;
struct csr1212_leaf leaf; struct csr1212_leaf leaf;
struct csr1212_directory directory; struct csr1212_directory directory;
} value; } value;
...@@ -260,15 +153,15 @@ struct csr1212_keyval { ...@@ -260,15 +153,15 @@ struct csr1212_keyval {
/* used in generating and/or parsing CSR image */ /* used in generating and/or parsing CSR image */
struct csr1212_keyval *next, *prev; /* flat list of CSR elements */ struct csr1212_keyval *next, *prev; /* flat list of CSR elements */
u_int32_t offset; /* position in CSR from 0xffff f000 0000 */ u32 offset; /* position in CSR from 0xffff f000 0000 */
u_int8_t valid; /* flag indicating keyval has valid data*/ u8 valid; /* flag indicating keyval has valid data*/
}; };
struct csr1212_cache_region { struct csr1212_cache_region {
struct csr1212_cache_region *next, *prev; struct csr1212_cache_region *next, *prev;
u_int32_t offset_start; /* inclusive */ u32 offset_start; /* inclusive */
u_int32_t offset_end; /* exclusive */ u32 offset_end; /* exclusive */
}; };
struct csr1212_csr_rom_cache { struct csr1212_csr_rom_cache {
...@@ -276,18 +169,18 @@ struct csr1212_csr_rom_cache { ...@@ -276,18 +169,18 @@ struct csr1212_csr_rom_cache {
struct csr1212_cache_region *filled_head, *filled_tail; struct csr1212_cache_region *filled_head, *filled_tail;
struct csr1212_keyval *layout_head, *layout_tail; struct csr1212_keyval *layout_head, *layout_tail;
size_t size; size_t size;
u_int32_t offset; u32 offset;
struct csr1212_keyval *ext_rom; struct csr1212_keyval *ext_rom;
size_t len; size_t len;
/* Must be last */ /* Must be last */
u_int32_t data[0]; /* older gcc can't handle [] which is standard */ u32 data[0]; /* older gcc can't handle [] which is standard */
}; };
struct csr1212_csr { struct csr1212_csr {
size_t bus_info_len; /* bus info block length in bytes */ size_t bus_info_len; /* bus info block length in bytes */
size_t crc_len; /* crc 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 */ u32 *bus_info_data; /* bus info data incl bus name and EUI */
void *private; /* private, bus specific data */ void *private; /* private, bus specific data */
struct csr1212_bus_ops *ops; struct csr1212_bus_ops *ops;
...@@ -305,52 +198,38 @@ struct csr1212_bus_ops { ...@@ -305,52 +198,38 @@ struct csr1212_bus_ops {
* from remote nodes when parsing a Config ROM (i.e., read Config ROM * from remote nodes when parsing a Config ROM (i.e., read Config ROM
* entries located in the Units Space. Must return 0 on success * entries located in the Units Space. Must return 0 on success
* anything else indicates an error. */ * anything else indicates an error. */
int (*bus_read) (struct csr1212_csr *csr, u_int64_t addr, int (*bus_read) (struct csr1212_csr *csr, u64 addr,
u_int16_t length, void *buffer, void *private); u16 length, void *buffer, void *private);
/* This function is used by csr1212 to allocate a region in units space /* 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 * 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 * 1K region. The void *private parameter is private member of struct
* csr1212_csr. */ * csr1212_csr. */
u_int64_t (*allocate_addr_range) (u_int64_t size, u_int32_t alignment, u64 (*allocate_addr_range) (u64 size, u32 alignment, void *private);
void *private);
/* This function is used by csr1212 to release a region in units space /* This function is used by csr1212 to release a region in units space
* that is no longer needed. */ * that is no longer needed. */
void (*release_addr) (u_int64_t addr, void *private); void (*release_addr) (u64 addr, void *private);
/* This function is used by csr1212 to determine the max read request /* This function is used by csr1212 to determine the max read request
* supported by a remote node when reading the ConfigROM space. Must * supported by a remote node when reading the ConfigROM space. Must
* return 0, 1, or 2 per IEEE 1212. */ * return 0, 1, or 2 per IEEE 1212. */
int (*get_max_rom) (u_int32_t *bus_info, void *private); int (*get_max_rom) (u32 *bus_info, void *private);
}; };
/* Descriptor Leaf manipulation macros */ /* Descriptor Leaf manipulation macros */
#define CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT 24 #define CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT 24
#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK 0xffffff #define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK 0xffffff
#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u_int32_t)) #define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
#define CSR1212_DESCRIPTOR_LEAF_TYPE(kv) \ #define CSR1212_DESCRIPTOR_LEAF_TYPE(kv) \
(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[0]) >> CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) (be32_to_cpu((kv)->value.leaf.data[0]) >> \
CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)
#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) \ #define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) \
(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[0]) & \ (be32_to_cpu((kv)->value.leaf.data[0]) & \
CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK) 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 */ /* Text Descriptor Leaf manipulation macros */
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT 28 #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT 28
...@@ -358,182 +237,21 @@ struct csr1212_bus_ops { ...@@ -358,182 +237,21 @@ struct csr1212_bus_ops {
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT 16 #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_CHAR_SET_MASK 0xfff /* after shift */
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u_int32_t)) #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) \ #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) \
(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) >> \ (be32_to_cpu((kv)->value.leaf.data[1]) >> \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT) CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT)
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) \ #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) \
((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) >> \ ((be32_to_cpu((kv)->value.leaf.data[1]) >> \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \ CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK) CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK)
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) \ #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) \
(CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) & \ (be32_to_cpu((kv)->value.leaf.data[1]) & \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK) CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv) \ #define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv) \
(&((kv)->value.leaf.data[2])) (&((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 /* The following 2 function are for creating new Configuration ROM trees. The
* first function is used for both creating local trees and parsing remote * first function is used for both creating local trees and parsing remote
...@@ -543,11 +261,10 @@ extern struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops, ...@@ -543,11 +261,10 @@ extern struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
size_t bus_info_size, size_t bus_info_size,
void *private); void *private);
extern void csr1212_init_local_csr(struct csr1212_csr *csr, extern void csr1212_init_local_csr(struct csr1212_csr *csr,
const u_int32_t *bus_info_data, int max_rom); const u32 *bus_info_data, int max_rom);
/* The following function destroys a Configuration ROM tree and release all /* Destroy a Configuration ROM tree and release all memory taken by the tree. */
* memory taken by the tree. */
extern void csr1212_destroy_csr(struct csr1212_csr *csr); extern void csr1212_destroy_csr(struct csr1212_csr *csr);
...@@ -555,50 +272,20 @@ extern void csr1212_destroy_csr(struct csr1212_csr *csr); ...@@ -555,50 +272,20 @@ extern void csr1212_destroy_csr(struct csr1212_csr *csr);
* a Configuration ROM tree. Code that creates new keyvals with these functions * a Configuration ROM tree. Code that creates new keyvals with these functions
* must release those keyvals with csr1212_release_keyval() when they are no * must release those keyvals with csr1212_release_keyval() when they are no
* longer needed. */ * longer needed. */
extern struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value); extern struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value);
extern struct csr1212_keyval *csr1212_new_leaf(u_int8_t key, const void *data, extern struct csr1212_keyval *csr1212_new_directory(u8 key);
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_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, /* The following function manages association between keyvals. Typically,
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 * Descriptor Leaves and Directories will be associated with another keyval and
* it is desirable for the Descriptor keyval to be place immediately after the * it is desirable for the Descriptor keyval to be place immediately after the
* keyval that it is associated with.*/ * keyval that it is associated with.
extern int csr1212_associate_keyval(struct csr1212_keyval *kv, * Take care with subsequent ROM modifications: There is no function to remove
struct csr1212_keyval *associate); * previously specified associations.
extern void csr1212_disassociate_keyval(struct csr1212_keyval *kv); */
extern void csr1212_associate_keyval(struct csr1212_keyval *kv,
struct csr1212_keyval *associate);
/* The following functions manage the association of a keyval and directories. /* The following functions manage the association of a keyval and directories.
...@@ -609,23 +296,15 @@ extern void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir, ...@@ -609,23 +296,15 @@ extern void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
struct csr1212_keyval *kv); struct csr1212_keyval *kv);
/* The following functions create a Configuration ROM image from the tree of /* Creates a complete Configuration ROM image in the list of caches available
* keyvals provided. csr1212_generate_csr_image() creates a complete image in * via csr->cache_head. */
* 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); 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 /* This is a convience function for reading a block of data out of one of the
* caches in the csr->cache_head list. */ * caches in the csr->cache_head list. */
extern int csr1212_read(struct csr1212_csr *csr, u_int32_t offset, void *buffer, extern int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer,
u_int32_t len); u32 len);
/* The following functions are in place for parsing Configuration ROM images. /* The following functions are in place for parsing Configuration ROM images.
...@@ -635,15 +314,11 @@ extern int csr1212_parse_keyval(struct csr1212_keyval *kv, ...@@ -635,15 +314,11 @@ extern int csr1212_parse_keyval(struct csr1212_keyval *kv,
struct csr1212_csr_rom_cache *cache); struct csr1212_csr_rom_cache *cache);
extern int csr1212_parse_csr(struct csr1212_csr *csr); 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 /* This function allocates a new cache which may be used for either parsing or
* generating sub-sets of Configuration ROM images. */ * generating sub-sets of Configuration ROM images. */
static inline struct csr1212_csr_rom_cache *csr1212_rom_cache_malloc(u_int32_t offset, static inline struct csr1212_csr_rom_cache *
size_t size) csr1212_rom_cache_malloc(u32 offset, size_t size)
{ {
struct csr1212_csr_rom_cache *cache; struct csr1212_csr_rom_cache *cache;
...@@ -667,16 +342,8 @@ static inline struct csr1212_csr_rom_cache *csr1212_rom_cache_malloc(u_int32_t o ...@@ -667,16 +342,8 @@ static inline struct csr1212_csr_rom_cache *csr1212_rom_cache_malloc(u_int32_t o
/* This function ensures that a keyval contains data when referencing a keyval /* This function ensures that a keyval contains data when referencing a keyval
* created by parsing a Configuration ROM. */ * created by parsing a Configuration ROM. */
static inline struct csr1212_keyval *csr1212_get_keyval(struct csr1212_csr *csr, extern struct csr1212_keyval *
struct csr1212_keyval *kv) 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 /* This function increments the reference count for a keyval should there be a
...@@ -691,37 +358,29 @@ static inline void csr1212_keep_keyval(struct csr1212_keyval *kv) ...@@ -691,37 +358,29 @@ static inline void csr1212_keep_keyval(struct csr1212_keyval *kv)
* keyval when there are no more users of the keyval. This should be called by * 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 * any code that calls csr1212_keep_keyval() or any of the keyval creation
* routines csr1212_new_*(). */ * routines csr1212_new_*(). */
static inline void csr1212_release_keyval(struct csr1212_keyval *kv) extern 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 * This macro allows for looping over the keyval entries in a directory and it
* ensures that keyvals from remote ConfigROMs are parsed properly. * ensures that keyvals from remote ConfigROMs are parsed properly.
* *
* _csr is a struct csr1212_csr * that points to CSR associated with dir. * struct csr1212_csr *_csr points to the CSR associated with dir.
* _kv is a struct csr1212_keyval * that'll point to the current keyval (loop index). * struct csr1212_keyval *_kv points to the current keyval (loop index).
* _dir is a struct csr1212_keyval * that points to the directory to be looped. * struct csr1212_keyval *_dir points to the directory to be looped.
* _pos is a struct csr1212_dentry * that is used internally for indexing. * struct csr1212_dentry *_pos is used internally for indexing.
* *
* kv will be NULL upon exit of the loop. * kv will be NULL upon exit of the loop.
*/ */
#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos) \ #define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos) \
for (csr1212_get_keyval((_csr), (_dir)), \ for (csr1212_get_keyval((_csr), (_dir)), \
_pos = (_dir)->value.directory.dentries_head, \ _pos = (_dir)->value.directory.dentries_head, \
_kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL; \ _kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL;\
(_kv) && (_pos); \ (_kv) && (_pos); \
(_kv->associate == NULL) ? \ (_kv->associate == NULL) ? \
((_pos = _pos->next), \ ((_pos = _pos->next), (_kv = (_pos) ? \
(_kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : \ csr1212_get_keyval((_csr), _pos->kv) : \
NULL)) : \ NULL)) : \
(_kv = csr1212_get_keyval((_csr), _kv->associate))) (_kv = csr1212_get_keyval((_csr), _kv->associate)))
#endif /* __CSR1212_H__ */ #endif /* __CSR1212_H__ */
...@@ -62,6 +62,9 @@ void dma_prog_region_free(struct dma_prog_region *prog) ...@@ -62,6 +62,9 @@ void dma_prog_region_free(struct dma_prog_region *prog)
/* dma_region */ /* dma_region */
/**
* dma_region_init - clear out all fields but do not allocate anything
*/
void dma_region_init(struct dma_region *dma) void dma_region_init(struct dma_region *dma)
{ {
dma->kvirt = NULL; dma->kvirt = NULL;
...@@ -71,6 +74,9 @@ void dma_region_init(struct dma_region *dma) ...@@ -71,6 +74,9 @@ void dma_region_init(struct dma_region *dma)
dma->sglist = NULL; dma->sglist = NULL;
} }
/**
* dma_region_alloc - allocate the buffer and map it to the IOMMU
*/
int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
struct pci_dev *dev, int direction) struct pci_dev *dev, int direction)
{ {
...@@ -128,6 +134,9 @@ int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, ...@@ -128,6 +134,9 @@ int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
return -ENOMEM; return -ENOMEM;
} }
/**
* dma_region_free - unmap and free the buffer
*/
void dma_region_free(struct dma_region *dma) void dma_region_free(struct dma_region *dma)
{ {
if (dma->n_dma_pages) { if (dma->n_dma_pages) {
...@@ -167,6 +176,12 @@ static inline int dma_region_find(struct dma_region *dma, unsigned long offset, ...@@ -167,6 +176,12 @@ static inline int dma_region_find(struct dma_region *dma, unsigned long offset,
return i; return i;
} }
/**
* dma_region_offset_to_bus - get bus address of an offset within a DMA region
*
* Returns the DMA bus address of the byte with the given @offset relative to
* the beginning of the @dma.
*/
dma_addr_t dma_region_offset_to_bus(struct dma_region * dma, dma_addr_t dma_region_offset_to_bus(struct dma_region * dma,
unsigned long offset) unsigned long offset)
{ {
...@@ -177,6 +192,9 @@ dma_addr_t dma_region_offset_to_bus(struct dma_region * dma, ...@@ -177,6 +192,9 @@ dma_addr_t dma_region_offset_to_bus(struct dma_region * dma,
return sg_dma_address(sg) + rem; return sg_dma_address(sg) + rem;
} }
/**
* dma_region_sync_for_cpu - sync the CPU's view of the buffer
*/
void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset, void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
unsigned long len) unsigned long len)
{ {
...@@ -193,6 +211,9 @@ void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset, ...@@ -193,6 +211,9 @@ void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
dma->direction); dma->direction);
} }
/**
* dma_region_sync_for_device - sync the IO bus' view of the buffer
*/
void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset, void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
unsigned long len) unsigned long len)
{ {
...@@ -244,6 +265,9 @@ static struct vm_operations_struct dma_region_vm_ops = { ...@@ -244,6 +265,9 @@ static struct vm_operations_struct dma_region_vm_ops = {
.nopage = dma_region_pagefault, .nopage = dma_region_pagefault,
}; };
/**
* dma_region_mmap - map the buffer into a user space process
*/
int dma_region_mmap(struct dma_region *dma, struct file *file, int dma_region_mmap(struct dma_region *dma, struct file *file,
struct vm_area_struct *vma) struct vm_area_struct *vma)
{ {
......
...@@ -66,35 +66,23 @@ struct dma_region { ...@@ -66,35 +66,23 @@ struct dma_region {
int direction; int direction;
}; };
/* clear out all fields but do not allocate anything */
void dma_region_init(struct dma_region *dma); void dma_region_init(struct dma_region *dma);
/* allocate the buffer and map it to the IOMMU */
int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
struct pci_dev *dev, int direction); struct pci_dev *dev, int direction);
/* unmap and free the buffer */
void dma_region_free(struct dma_region *dma); void dma_region_free(struct dma_region *dma);
/* sync the CPU's view of the buffer */
void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset, void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
unsigned long len); unsigned long len);
/* sync the IO bus' view of the buffer */
void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset, void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
unsigned long len); unsigned long len);
/* map the buffer into a user space process */
int dma_region_mmap(struct dma_region *dma, struct file *file, int dma_region_mmap(struct dma_region *dma, struct file *file,
struct vm_area_struct *vma); struct vm_area_struct *vma);
dma_addr_t dma_region_offset_to_bus(struct dma_region *dma,
unsigned long offset);
/* macro to index into a DMA region (or dma_prog_region) */ /**
* dma_region_i - macro to index into a DMA region (or dma_prog_region)
*/
#define dma_region_i(_dma, _type, _index) \ #define dma_region_i(_dma, _type, _index) \
( ((_type*) ((_dma)->kvirt)) + (_index) ) ( ((_type*) ((_dma)->kvirt)) + (_index) )
/* return the DMA bus address of the byte with the given offset
* relative to the beginning of the dma_region */
dma_addr_t dma_region_offset_to_bus(struct dma_region *dma,
unsigned long offset);
#endif /* IEEE1394_DMA_H */ #endif /* IEEE1394_DMA_H */
/* /*
* eth1394.c -- Ethernet driver for Linux IEEE-1394 Subsystem * eth1394.c -- IPv4 driver for Linux IEEE-1394 Subsystem
* *
* Copyright (C) 2001-2003 Ben Collins <bcollins@debian.org> * Copyright (C) 2001-2003 Ben Collins <bcollins@debian.org>
* 2000 Bonin Franck <boninf@free.fr> * 2000 Bonin Franck <boninf@free.fr>
...@@ -22,10 +22,9 @@ ...@@ -22,10 +22,9 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
/* This driver intends to support RFC 2734, which describes a method for /*
* transporting IPv4 datagrams over IEEE-1394 serial busses. This driver * This driver intends to support RFC 2734, which describes a method for
* will ultimately support that method, but currently falls short in * transporting IPv4 datagrams over IEEE-1394 serial busses.
* several areas.
* *
* TODO: * TODO:
* RFC 2734 related: * RFC 2734 related:
...@@ -40,7 +39,6 @@ ...@@ -40,7 +39,6 @@
* - Consider garbage collecting old partial datagrams after X amount of time * - Consider garbage collecting old partial datagrams after X amount of time
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -52,7 +50,6 @@ ...@@ -52,7 +50,6 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/inetdevice.h> #include <linux/inetdevice.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/ip.h> #include <linux/ip.h>
...@@ -84,10 +81,6 @@ ...@@ -84,10 +81,6 @@
#define ETH1394_PRINT(level, dev_name, fmt, args...) \ #define ETH1394_PRINT(level, dev_name, fmt, args...) \
printk(level "%s: %s: " fmt, driver_name, dev_name, ## args) printk(level "%s: %s: " fmt, driver_name, dev_name, ## args)
#define DEBUG(fmt, args...) \
printk(KERN_ERR "%s:%s[%d]: " fmt "\n", driver_name, __FUNCTION__, __LINE__, ## args)
#define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__)
struct fragment_info { struct fragment_info {
struct list_head list; struct list_head list;
int offset; int offset;
...@@ -105,9 +98,9 @@ struct partial_datagram { ...@@ -105,9 +98,9 @@ struct partial_datagram {
}; };
struct pdg_list { struct pdg_list {
struct list_head list; /* partial datagram list per node */ struct list_head list; /* partial datagram list per node */
unsigned int sz; /* partial datagram list size per node */ unsigned int sz; /* partial datagram list size per node */
spinlock_t lock; /* partial datagram lock */ spinlock_t lock; /* partial datagram lock */
}; };
struct eth1394_host_info { struct eth1394_host_info {
...@@ -121,16 +114,14 @@ struct eth1394_node_ref { ...@@ -121,16 +114,14 @@ struct eth1394_node_ref {
}; };
struct eth1394_node_info { struct eth1394_node_info {
u16 maxpayload; /* Max payload */ u16 maxpayload; /* max payload */
u8 sspd; /* Max speed */ u8 sspd; /* max speed */
u64 fifo; /* FIFO address */ u64 fifo; /* FIFO address */
struct pdg_list pdg; /* partial RX datagram lists */ struct pdg_list pdg; /* partial RX datagram lists */
int dgl; /* Outgoing datagram label */ int dgl; /* outgoing datagram label */
}; };
/* Our ieee1394 highlevel driver */ static const char driver_name[] = "eth1394";
#define ETH1394_DRIVER_NAME "eth1394"
static const char driver_name[] = ETH1394_DRIVER_NAME;
static struct kmem_cache *packet_task_cache; static struct kmem_cache *packet_task_cache;
...@@ -138,18 +129,12 @@ static struct hpsb_highlevel eth1394_highlevel; ...@@ -138,18 +129,12 @@ static struct hpsb_highlevel eth1394_highlevel;
/* Use common.lf to determine header len */ /* Use common.lf to determine header len */
static const int hdr_type_len[] = { static const int hdr_type_len[] = {
sizeof (struct eth1394_uf_hdr), sizeof(struct eth1394_uf_hdr),
sizeof (struct eth1394_ff_hdr), sizeof(struct eth1394_ff_hdr),
sizeof (struct eth1394_sf_hdr), sizeof(struct eth1394_sf_hdr),
sizeof (struct eth1394_sf_hdr) sizeof(struct eth1394_sf_hdr)
}; };
/* Change this to IEEE1394_SPEED_S100 to make testing easier */
#define ETH1394_SPEED_DEF IEEE1394_SPEED_MAX
/* For now, this needs to be 1500, so that XP works with us */
#define ETH1394_DATA_LEN ETH_DATA_LEN
static const u16 eth1394_speedto_maxpayload[] = { static const u16 eth1394_speedto_maxpayload[] = {
/* S100, S200, S400, S800, S1600, S3200 */ /* S100, S200, S400, S800, S1600, S3200 */
512, 1024, 2048, 4096, 4096, 4096 512, 1024, 2048, 4096, 4096, 4096
...@@ -159,7 +144,8 @@ MODULE_AUTHOR("Ben Collins (bcollins@debian.org)"); ...@@ -159,7 +144,8 @@ MODULE_AUTHOR("Ben Collins (bcollins@debian.org)");
MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)"); MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* The max_partial_datagrams parameter is the maximum number of fragmented /*
* The max_partial_datagrams parameter is the maximum number of fragmented
* datagrams per node that eth1394 will keep in memory. Providing an upper * datagrams per node that eth1394 will keep in memory. Providing an upper
* bound allows us to limit the amount of memory that partial datagrams * bound allows us to limit the amount of memory that partial datagrams
* consume in the event that some partial datagrams are never completed. * consume in the event that some partial datagrams are never completed.
...@@ -179,10 +165,7 @@ static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr); ...@@ -179,10 +165,7 @@ static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr);
static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh); static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh);
static void ether1394_header_cache_update(struct hh_cache *hh, static void ether1394_header_cache_update(struct hh_cache *hh,
struct net_device *dev, struct net_device *dev,
unsigned char * haddr); unsigned char *haddr);
static int ether1394_mac_addr(struct net_device *dev, void *p);
static void purge_partial_datagram(struct list_head *old);
static int ether1394_tx(struct sk_buff *skb, struct net_device *dev); static int ether1394_tx(struct sk_buff *skb, struct net_device *dev);
static void ether1394_iso(struct hpsb_iso *iso); static void ether1394_iso(struct hpsb_iso *iso);
...@@ -190,9 +173,9 @@ static struct ethtool_ops ethtool_ops; ...@@ -190,9 +173,9 @@ static struct ethtool_ops ethtool_ops;
static int ether1394_write(struct hpsb_host *host, 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); quadlet_t *data, u64 addr, size_t len, u16 flags);
static void ether1394_add_host (struct hpsb_host *host); static void ether1394_add_host(struct hpsb_host *host);
static void ether1394_remove_host (struct hpsb_host *host); static void ether1394_remove_host(struct hpsb_host *host);
static void ether1394_host_reset (struct hpsb_host *host); static void ether1394_host_reset(struct hpsb_host *host);
/* Function for incoming 1394 packets */ /* Function for incoming 1394 packets */
static struct hpsb_address_ops addr_ops = { static struct hpsb_address_ops addr_ops = {
...@@ -207,89 +190,107 @@ static struct hpsb_highlevel eth1394_highlevel = { ...@@ -207,89 +190,107 @@ static struct hpsb_highlevel eth1394_highlevel = {
.host_reset = ether1394_host_reset, .host_reset = ether1394_host_reset,
}; };
static int ether1394_recv_init(struct eth1394_priv *priv)
{
unsigned int iso_buf_size;
/* FIXME: rawiso limits us to PAGE_SIZE */
iso_buf_size = min((unsigned int)PAGE_SIZE,
2 * (1U << (priv->host->csr.max_rec + 1)));
priv->iso = hpsb_iso_recv_init(priv->host,
ETHER1394_GASP_BUFFERS * iso_buf_size,
ETHER1394_GASP_BUFFERS,
priv->broadcast_channel,
HPSB_ISO_DMA_PACKET_PER_BUFFER,
1, ether1394_iso);
if (priv->iso == NULL) {
ETH1394_PRINT_G(KERN_ERR, "Failed to allocate IR context\n");
priv->bc_state = ETHER1394_BC_ERROR;
return -EAGAIN;
}
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;
return 0;
}
/* This is called after an "ifup" */ /* This is called after an "ifup" */
static int ether1394_open (struct net_device *dev) static int ether1394_open(struct net_device *dev)
{ {
struct eth1394_priv *priv = netdev_priv(dev); struct eth1394_priv *priv = netdev_priv(dev);
int ret = 0; int ret;
/* Something bad happened, don't even try */
if (priv->bc_state == ETHER1394_BC_ERROR) { if (priv->bc_state == ETHER1394_BC_ERROR) {
/* we'll try again */ ret = ether1394_recv_init(priv);
priv->iso = hpsb_iso_recv_init(priv->host, if (ret)
ETHER1394_ISO_BUF_SIZE, return ret;
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;
}
} }
netif_start_queue(dev);
if (ret)
return ret;
netif_start_queue (dev);
return 0; return 0;
} }
/* This is called after an "ifdown" */ /* This is called after an "ifdown" */
static int ether1394_stop (struct net_device *dev) static int ether1394_stop(struct net_device *dev)
{ {
netif_stop_queue (dev); netif_stop_queue(dev);
return 0; return 0;
} }
/* Return statistics to the caller */ /* Return statistics to the caller */
static struct net_device_stats *ether1394_stats (struct net_device *dev) static struct net_device_stats *ether1394_stats(struct net_device *dev)
{ {
return &(((struct eth1394_priv *)netdev_priv(dev))->stats); return &(((struct eth1394_priv *)netdev_priv(dev))->stats);
} }
/* What to do if we timeout. I think a host reset is probably in order, so /* FIXME: What to do if we timeout? I think a host reset is probably in order,
* that's what we do. Should we increment the stat counters too? */ * so that's what we do. Should we increment the stat counters too? */
static void ether1394_tx_timeout (struct net_device *dev) static void ether1394_tx_timeout(struct net_device *dev)
{ {
ETH1394_PRINT (KERN_ERR, dev->name, "Timeout, resetting host %s\n", struct hpsb_host *host =
((struct eth1394_priv *)netdev_priv(dev))->host->driver->name); ((struct eth1394_priv *)netdev_priv(dev))->host;
highlevel_host_reset (((struct eth1394_priv *)netdev_priv(dev))->host); ETH1394_PRINT(KERN_ERR, dev->name, "Timeout, resetting host\n");
ether1394_host_reset(host);
}
netif_wake_queue (dev); static inline int ether1394_max_mtu(struct hpsb_host* host)
{
return (1 << (host->csr.max_rec + 1))
- sizeof(union eth1394_hdr) - ETHER1394_GASP_OVERHEAD;
} }
static int ether1394_change_mtu(struct net_device *dev, int new_mtu) static int ether1394_change_mtu(struct net_device *dev, int new_mtu)
{ {
struct eth1394_priv *priv = netdev_priv(dev); int max_mtu;
if ((new_mtu < 68) || 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; return -EINVAL;
max_mtu = ether1394_max_mtu(
((struct eth1394_priv *)netdev_priv(dev))->host);
if (new_mtu > max_mtu) {
ETH1394_PRINT(KERN_INFO, dev->name,
"Local node constrains MTU to %d\n", max_mtu);
return -ERANGE;
}
dev->mtu = new_mtu; dev->mtu = new_mtu;
return 0; return 0;
} }
static void purge_partial_datagram(struct list_head *old) static void purge_partial_datagram(struct list_head *old)
{ {
struct partial_datagram *pd = list_entry(old, struct partial_datagram, list); struct partial_datagram *pd;
struct list_head *lh, *n; struct list_head *lh, *n;
struct fragment_info *fi;
pd = list_entry(old, struct partial_datagram, list);
list_for_each_safe(lh, n, &pd->frag_info) { list_for_each_safe(lh, n, &pd->frag_info) {
struct fragment_info *fi = list_entry(lh, struct fragment_info, list); fi = list_entry(lh, struct fragment_info, list);
list_del(lh); list_del(lh);
kfree(fi); kfree(fi);
} }
...@@ -330,35 +331,26 @@ static struct eth1394_node_ref *eth1394_find_node_nodeid(struct list_head *inl, ...@@ -330,35 +331,26 @@ static struct eth1394_node_ref *eth1394_find_node_nodeid(struct list_head *inl,
nodeid_t nodeid) nodeid_t nodeid)
{ {
struct eth1394_node_ref *node; struct eth1394_node_ref *node;
list_for_each_entry(node, inl, list) {
list_for_each_entry(node, inl, list)
if (node->ud->ne->nodeid == nodeid) if (node->ud->ne->nodeid == nodeid)
return node; return node;
}
return NULL; return NULL;
} }
static int eth1394_probe(struct device *dev) static int eth1394_new_node(struct eth1394_host_info *hi,
struct unit_directory *ud)
{ {
struct unit_directory *ud;
struct eth1394_host_info *hi;
struct eth1394_priv *priv; struct eth1394_priv *priv;
struct eth1394_node_ref *new_node; struct eth1394_node_ref *new_node;
struct eth1394_node_info *node_info; struct eth1394_node_info *node_info;
ud = container_of(dev, struct unit_directory, device); new_node = kmalloc(sizeof(*new_node), GFP_KERNEL);
hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
if (!hi)
return -ENOENT;
new_node = kmalloc(sizeof(*new_node),
in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
if (!new_node) if (!new_node)
return -ENOMEM; return -ENOMEM;
node_info = kmalloc(sizeof(*node_info), node_info = kmalloc(sizeof(*node_info), GFP_KERNEL);
in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
if (!node_info) { if (!node_info) {
kfree(new_node); kfree(new_node);
return -ENOMEM; return -ENOMEM;
...@@ -374,10 +366,22 @@ static int eth1394_probe(struct device *dev) ...@@ -374,10 +366,22 @@ static int eth1394_probe(struct device *dev)
priv = netdev_priv(hi->dev); priv = netdev_priv(hi->dev);
list_add_tail(&new_node->list, &priv->ip_node_list); list_add_tail(&new_node->list, &priv->ip_node_list);
return 0; return 0;
} }
static int eth1394_probe(struct device *dev)
{
struct unit_directory *ud;
struct eth1394_host_info *hi;
ud = container_of(dev, struct unit_directory, device);
hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
if (!hi)
return -ENOENT;
return eth1394_new_node(hi, ud);
}
static int eth1394_remove(struct device *dev) static int eth1394_remove(struct device *dev)
{ {
struct unit_directory *ud; struct unit_directory *ud;
...@@ -396,24 +400,23 @@ static int eth1394_remove(struct device *dev) ...@@ -396,24 +400,23 @@ static int eth1394_remove(struct device *dev)
priv = netdev_priv(hi->dev); priv = netdev_priv(hi->dev);
old_node = eth1394_find_node(&priv->ip_node_list, ud); old_node = eth1394_find_node(&priv->ip_node_list, ud);
if (!old_node)
return 0;
if (old_node) { list_del(&old_node->list);
list_del(&old_node->list); kfree(old_node);
kfree(old_node);
node_info = (struct eth1394_node_info*)ud->device.driver_data; node_info = (struct eth1394_node_info*)ud->device.driver_data;
spin_lock_irqsave(&node_info->pdg.lock, flags); spin_lock_irqsave(&node_info->pdg.lock, flags);
/* The partial datagram list should be empty, but we'll just /* The partial datagram list should be empty, but we'll just
* make sure anyway... */ * make sure anyway... */
list_for_each_safe(lh, n, &node_info->pdg.list) { list_for_each_safe(lh, n, &node_info->pdg.list)
purge_partial_datagram(lh); purge_partial_datagram(lh);
} spin_unlock_irqrestore(&node_info->pdg.lock, flags);
spin_unlock_irqrestore(&node_info->pdg.lock, flags);
kfree(node_info); kfree(node_info);
ud->device.driver_data = NULL; ud->device.driver_data = NULL;
}
return 0; return 0;
} }
...@@ -422,44 +425,19 @@ static int eth1394_update(struct unit_directory *ud) ...@@ -422,44 +425,19 @@ static int eth1394_update(struct unit_directory *ud)
struct eth1394_host_info *hi; struct eth1394_host_info *hi;
struct eth1394_priv *priv; struct eth1394_priv *priv;
struct eth1394_node_ref *node; struct eth1394_node_ref *node;
struct eth1394_node_info *node_info;
hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host); hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
if (!hi) if (!hi)
return -ENOENT; return -ENOENT;
priv = netdev_priv(hi->dev); priv = netdev_priv(hi->dev);
node = eth1394_find_node(&priv->ip_node_list, ud); node = eth1394_find_node(&priv->ip_node_list, ud);
if (node)
return 0;
if (!node) { return eth1394_new_node(hi, ud);
node = kmalloc(sizeof(*node),
in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
if (!node)
return -ENOMEM;
node_info = kmalloc(sizeof(*node_info),
in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
if (!node_info) {
kfree(node);
return -ENOMEM;
}
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 = netdev_priv(hi->dev);
list_add_tail(&node->list, &priv->ip_node_list);
}
return 0;
} }
static struct ieee1394_device_id eth1394_id_table[] = { static struct ieee1394_device_id eth1394_id_table[] = {
{ {
.match_flags = (IEEE1394_MATCH_SPECIFIER_ID | .match_flags = (IEEE1394_MATCH_SPECIFIER_ID |
...@@ -473,7 +451,7 @@ static struct ieee1394_device_id eth1394_id_table[] = { ...@@ -473,7 +451,7 @@ static struct ieee1394_device_id eth1394_id_table[] = {
MODULE_DEVICE_TABLE(ieee1394, eth1394_id_table); MODULE_DEVICE_TABLE(ieee1394, eth1394_id_table);
static struct hpsb_protocol_driver eth1394_proto_driver = { static struct hpsb_protocol_driver eth1394_proto_driver = {
.name = ETH1394_DRIVER_NAME, .name = driver_name,
.id_table = eth1394_id_table, .id_table = eth1394_id_table,
.update = eth1394_update, .update = eth1394_update,
.driver = { .driver = {
...@@ -482,47 +460,50 @@ static struct hpsb_protocol_driver eth1394_proto_driver = { ...@@ -482,47 +460,50 @@ static struct hpsb_protocol_driver eth1394_proto_driver = {
}, },
}; };
static void ether1394_reset_priv(struct net_device *dev, int set_mtu)
static void ether1394_reset_priv (struct net_device *dev, int set_mtu)
{ {
unsigned long flags; unsigned long flags;
int i; int i;
struct eth1394_priv *priv = netdev_priv(dev); struct eth1394_priv *priv = netdev_priv(dev);
struct hpsb_host *host = priv->host; struct hpsb_host *host = priv->host;
u64 guid = get_unaligned((u64*)&(host->csr.rom->bus_info_data[3])); u64 guid = get_unaligned((u64 *)&(host->csr.rom->bus_info_data[3]));
u16 maxpayload = 1 << (host->csr.max_rec + 1);
int max_speed = IEEE1394_SPEED_MAX; int max_speed = IEEE1394_SPEED_MAX;
spin_lock_irqsave (&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
memset(priv->ud_list, 0, sizeof(struct node_entry*) * ALL_NODES); memset(priv->ud_list, 0, sizeof(priv->ud_list));
priv->bc_maxpayload = 512; priv->bc_maxpayload = 512;
/* Determine speed limit */ /* Determine speed limit */
for (i = 0; i < host->node_count; i++) /* FIXME: This is broken for nodes with link speed < PHY speed,
* and it is suboptimal for S200B...S800B hardware.
* The result of nodemgr's speed probe should be used somehow. */
for (i = 0; i < host->node_count; i++) {
/* take care of S100B...S400B PHY ports */
if (host->speed[i] == SELFID_SPEED_UNKNOWN) {
max_speed = IEEE1394_SPEED_100;
break;
}
if (max_speed > host->speed[i]) if (max_speed > host->speed[i])
max_speed = host->speed[i]; max_speed = host->speed[i];
}
priv->bc_sspd = max_speed; priv->bc_sspd = max_speed;
/* We'll use our maxpayload as the default mtu */
if (set_mtu) { if (set_mtu) {
dev->mtu = min(ETH1394_DATA_LEN, /* Use the RFC 2734 default 1500 octets or the maximum payload
(int)(maxpayload - * as initial MTU */
(sizeof(union eth1394_hdr) + dev->mtu = min(1500, ether1394_max_mtu(host));
ETHER1394_GASP_OVERHEAD)));
/* Set our hardware address while we're at it */ /* Set our hardware address while we're at it */
memcpy(dev->dev_addr, &guid, sizeof(u64)); memcpy(dev->dev_addr, &guid, sizeof(u64));
memset(dev->broadcast, 0xff, sizeof(u64)); memset(dev->broadcast, 0xff, sizeof(u64));
} }
spin_unlock_irqrestore (&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
} }
/* This function is called right before register_netdev */ static void ether1394_init_dev(struct net_device *dev)
static void ether1394_init_dev (struct net_device *dev)
{ {
/* Our functions */
dev->open = ether1394_open; dev->open = ether1394_open;
dev->stop = ether1394_stop; dev->stop = ether1394_stop;
dev->hard_start_xmit = ether1394_tx; dev->hard_start_xmit = ether1394_tx;
...@@ -535,10 +516,9 @@ static void ether1394_init_dev (struct net_device *dev) ...@@ -535,10 +516,9 @@ static void ether1394_init_dev (struct net_device *dev)
dev->hard_header_cache = ether1394_header_cache; dev->hard_header_cache = ether1394_header_cache;
dev->header_cache_update= ether1394_header_cache_update; dev->header_cache_update= ether1394_header_cache_update;
dev->hard_header_parse = ether1394_header_parse; dev->hard_header_parse = ether1394_header_parse;
dev->set_mac_address = ether1394_mac_addr;
SET_ETHTOOL_OPS(dev, &ethtool_ops); SET_ETHTOOL_OPS(dev, &ethtool_ops);
/* Some constants */
dev->watchdog_timeo = ETHER1394_TIMEOUT; dev->watchdog_timeo = ETHER1394_TIMEOUT;
dev->flags = IFF_BROADCAST | IFF_MULTICAST; dev->flags = IFF_BROADCAST | IFF_MULTICAST;
dev->features = NETIF_F_HIGHDMA; dev->features = NETIF_F_HIGHDMA;
...@@ -546,7 +526,8 @@ static void ether1394_init_dev (struct net_device *dev) ...@@ -546,7 +526,8 @@ static void ether1394_init_dev (struct net_device *dev)
dev->hard_header_len = ETH1394_HLEN; dev->hard_header_len = ETH1394_HLEN;
dev->type = ARPHRD_IEEE1394; dev->type = ARPHRD_IEEE1394;
ether1394_reset_priv (dev, 1); /* FIXME: This value was copied from ether_setup(). Is it too much? */
dev->tx_queue_len = 1000;
} }
/* /*
...@@ -554,34 +535,33 @@ static void ether1394_init_dev (struct net_device *dev) ...@@ -554,34 +535,33 @@ static void ether1394_init_dev (struct net_device *dev)
* when the module is installed. This is where we add all of our ethernet * when the module is installed. This is where we add all of our ethernet
* devices. One for each host. * devices. One for each host.
*/ */
static void ether1394_add_host (struct hpsb_host *host) static void ether1394_add_host(struct hpsb_host *host)
{ {
struct eth1394_host_info *hi = NULL; struct eth1394_host_info *hi = NULL;
struct net_device *dev = NULL; struct net_device *dev = NULL;
struct eth1394_priv *priv; struct eth1394_priv *priv;
u64 fifo_addr; u64 fifo_addr;
if (!(host->config_roms & HPSB_CONFIG_ROM_ENTRY_IP1394)) if (hpsb_config_rom_ip1394_add(host) != 0) {
ETH1394_PRINT_G(KERN_ERR, "Can't add IP-over-1394 ROM entry\n");
return; return;
}
fifo_addr = hpsb_allocate_and_register_addrspace( fifo_addr = hpsb_allocate_and_register_addrspace(
&eth1394_highlevel, host, &addr_ops, &eth1394_highlevel, host, &addr_ops,
ETHER1394_REGION_ADDR_LEN, ETHER1394_REGION_ADDR_LEN, ETHER1394_REGION_ADDR_LEN, ETHER1394_REGION_ADDR_LEN,
CSR1212_INVALID_ADDR_SPACE, CSR1212_INVALID_ADDR_SPACE); CSR1212_INVALID_ADDR_SPACE, CSR1212_INVALID_ADDR_SPACE);
if (fifo_addr == CSR1212_INVALID_ADDR_SPACE) if (fifo_addr == CSR1212_INVALID_ADDR_SPACE) {
goto out; ETH1394_PRINT_G(KERN_ERR, "Cannot register CSR space\n");
hpsb_config_rom_ip1394_remove(host);
/* We should really have our own alloc_hpsbdev() function in return;
* net_init.c instead of calling the one for ethernet then hijacking }
* it for ourselves. That way we'd be a real networking device. */
dev = alloc_etherdev(sizeof (struct eth1394_priv));
dev = alloc_netdev(sizeof(*priv), "eth%d", ether1394_init_dev);
if (dev == NULL) { if (dev == NULL) {
ETH1394_PRINT_G (KERN_ERR, "Out of memory trying to allocate " ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
"etherdevice for IEEE 1394 device %s-%d\n",
host->driver->name, host->id);
goto out; goto out;
} }
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
#if 0 #if 0
...@@ -590,31 +570,26 @@ static void ether1394_add_host (struct hpsb_host *host) ...@@ -590,31 +570,26 @@ static void ether1394_add_host (struct hpsb_host *host)
#endif #endif
priv = netdev_priv(dev); priv = netdev_priv(dev);
INIT_LIST_HEAD(&priv->ip_node_list); INIT_LIST_HEAD(&priv->ip_node_list);
spin_lock_init(&priv->lock); spin_lock_init(&priv->lock);
priv->host = host; priv->host = host;
priv->local_fifo = fifo_addr; priv->local_fifo = fifo_addr;
hi = hpsb_create_hostinfo(&eth1394_highlevel, host, sizeof(*hi)); hi = hpsb_create_hostinfo(&eth1394_highlevel, host, sizeof(*hi));
if (hi == NULL) { if (hi == NULL) {
ETH1394_PRINT_G (KERN_ERR, "Out of memory trying to create " ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
"hostinfo for IEEE 1394 device %s-%d\n",
host->driver->name, host->id);
goto out; goto out;
} }
ether1394_init_dev(dev); ether1394_reset_priv(dev, 1);
if (register_netdev (dev)) { if (register_netdev(dev)) {
ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n"); ETH1394_PRINT_G(KERN_ERR, "Cannot register the driver\n");
goto out; goto out;
} }
ETH1394_PRINT (KERN_INFO, dev->name, "IEEE-1394 IPv4 over 1394 Ethernet (fw-host%d)\n", ETH1394_PRINT(KERN_INFO, dev->name, "IPv4 over IEEE 1394 (fw-host%d)\n",
host->id); host->id);
hi->host = host; hi->host = host;
hi->dev = dev; hi->dev = dev;
...@@ -623,61 +598,37 @@ static void ether1394_add_host (struct hpsb_host *host) ...@@ -623,61 +598,37 @@ static void ether1394_add_host (struct hpsb_host *host)
* be checked when the eth device is opened. */ * be checked when the eth device is opened. */
priv->broadcast_channel = host->csr.broadcast_channel & 0x3f; priv->broadcast_channel = host->csr.broadcast_channel & 0x3f;
priv->iso = hpsb_iso_recv_init(host, ether1394_recv_init(priv);
ETHER1394_ISO_BUF_SIZE,
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;
} 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;
}
return; return;
out: out:
if (dev != NULL) if (dev)
free_netdev(dev); free_netdev(dev);
if (hi) if (hi)
hpsb_destroy_hostinfo(&eth1394_highlevel, host); hpsb_destroy_hostinfo(&eth1394_highlevel, host);
hpsb_unregister_addrspace(&eth1394_highlevel, host, fifo_addr);
return; hpsb_config_rom_ip1394_remove(host);
} }
/* Remove a card from our list */ /* Remove a card from our list */
static void ether1394_remove_host (struct hpsb_host *host) static void ether1394_remove_host(struct hpsb_host *host)
{ {
struct eth1394_host_info *hi; struct eth1394_host_info *hi;
struct eth1394_priv *priv;
hi = hpsb_get_hostinfo(&eth1394_highlevel, host); hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
if (hi != NULL) { if (!hi)
struct eth1394_priv *priv = netdev_priv(hi->dev); return;
priv = netdev_priv(hi->dev);
hpsb_unregister_addrspace(&eth1394_highlevel, host, hpsb_unregister_addrspace(&eth1394_highlevel, host, priv->local_fifo);
priv->local_fifo); hpsb_config_rom_ip1394_remove(host);
if (priv->iso)
if (priv->iso != NULL) hpsb_iso_shutdown(priv->iso);
hpsb_iso_shutdown(priv->iso); unregister_netdev(hi->dev);
free_netdev(hi->dev);
if (hi->dev) {
unregister_netdev (hi->dev);
free_netdev(hi->dev);
}
}
return;
} }
/* A reset has just arisen */ /* A bus reset happened */
static void ether1394_host_reset (struct hpsb_host *host) static void ether1394_host_reset(struct hpsb_host *host)
{ {
struct eth1394_host_info *hi; struct eth1394_host_info *hi;
struct eth1394_priv *priv; struct eth1394_priv *priv;
...@@ -690,24 +641,23 @@ static void ether1394_host_reset (struct hpsb_host *host) ...@@ -690,24 +641,23 @@ static void ether1394_host_reset (struct hpsb_host *host)
hi = hpsb_get_hostinfo(&eth1394_highlevel, host); hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
/* This can happen for hosts that we don't use */ /* This can happen for hosts that we don't use */
if (hi == NULL) if (!hi)
return; return;
dev = hi->dev; dev = hi->dev;
priv = (struct eth1394_priv *)netdev_priv(dev); priv = netdev_priv(dev);
/* Reset our private host data, but not our mtu */ /* Reset our private host data, but not our MTU */
netif_stop_queue (dev); netif_stop_queue(dev);
ether1394_reset_priv (dev, 0); ether1394_reset_priv(dev, 0);
list_for_each_entry(node, &priv->ip_node_list, list) { list_for_each_entry(node, &priv->ip_node_list, list) {
node_info = (struct eth1394_node_info*)node->ud->device.driver_data; node_info = node->ud->device.driver_data;
spin_lock_irqsave(&node_info->pdg.lock, flags); spin_lock_irqsave(&node_info->pdg.lock, flags);
list_for_each_safe(lh, n, &node_info->pdg.list) { list_for_each_safe(lh, n, &node_info->pdg.list)
purge_partial_datagram(lh); purge_partial_datagram(lh);
}
INIT_LIST_HEAD(&(node_info->pdg.list)); INIT_LIST_HEAD(&(node_info->pdg.list));
node_info->pdg.sz = 0; node_info->pdg.sz = 0;
...@@ -715,7 +665,7 @@ static void ether1394_host_reset (struct hpsb_host *host) ...@@ -715,7 +665,7 @@ static void ether1394_host_reset (struct hpsb_host *host)
spin_unlock_irqrestore(&node_info->pdg.lock, flags); spin_unlock_irqrestore(&node_info->pdg.lock, flags);
} }
netif_wake_queue (dev); netif_wake_queue(dev);
} }
/****************************************** /******************************************
...@@ -723,7 +673,6 @@ static void ether1394_host_reset (struct hpsb_host *host) ...@@ -723,7 +673,6 @@ static void ether1394_host_reset (struct hpsb_host *host)
******************************************/ ******************************************/
/* These functions have been adapted from net/ethernet/eth.c */ /* These functions have been adapted from net/ethernet/eth.c */
/* Create a fake MAC header for an arbitrary protocol layer. /* Create a fake MAC header for an arbitrary protocol layer.
* saddr=NULL means use device source address * saddr=NULL means use device source address
* daddr=NULL means leave destination address (eg unresolved arp). */ * daddr=NULL means leave destination address (eg unresolved arp). */
...@@ -731,25 +680,24 @@ static int ether1394_header(struct sk_buff *skb, struct net_device *dev, ...@@ -731,25 +680,24 @@ static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr, unsigned short type, void *daddr, void *saddr,
unsigned len) unsigned len)
{ {
struct eth1394hdr *eth = (struct eth1394hdr *)skb_push(skb, ETH1394_HLEN); struct eth1394hdr *eth =
(struct eth1394hdr *)skb_push(skb, ETH1394_HLEN);
eth->h_proto = htons(type); eth->h_proto = htons(type);
if (dev->flags & (IFF_LOOPBACK|IFF_NOARP)) { if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
memset(eth->h_dest, 0, dev->addr_len); memset(eth->h_dest, 0, dev->addr_len);
return(dev->hard_header_len); return dev->hard_header_len;
} }
if (daddr) { if (daddr) {
memcpy(eth->h_dest,daddr,dev->addr_len); memcpy(eth->h_dest, daddr, dev->addr_len);
return dev->hard_header_len; return dev->hard_header_len;
} }
return -dev->hard_header_len; return -dev->hard_header_len;
} }
/* Rebuild the faked MAC header. This is called after an ARP /* Rebuild the faked MAC header. This is called after an ARP
* (or in future other address resolution) has completed on this * (or in future other address resolution) has completed on this
* sk_buff. We now let ARP fill in the other fields. * sk_buff. We now let ARP fill in the other fields.
...@@ -760,38 +708,30 @@ static int ether1394_header(struct sk_buff *skb, struct net_device *dev, ...@@ -760,38 +708,30 @@ static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
static int ether1394_rebuild_header(struct sk_buff *skb) static int ether1394_rebuild_header(struct sk_buff *skb)
{ {
struct eth1394hdr *eth = (struct eth1394hdr *)skb->data; struct eth1394hdr *eth = (struct eth1394hdr *)skb->data;
struct net_device *dev = skb->dev;
switch (eth->h_proto) { if (eth->h_proto == htons(ETH_P_IP))
return arp_find((unsigned char *)&eth->h_dest, skb);
#ifdef CONFIG_INET
case __constant_htons(ETH_P_IP):
return arp_find((unsigned char*)&eth->h_dest, skb);
#endif
default:
ETH1394_PRINT(KERN_DEBUG, dev->name,
"unable to resolve type %04x addresses.\n",
ntohs(eth->h_proto));
break;
}
ETH1394_PRINT(KERN_DEBUG, skb->dev->name,
"unable to resolve type %04x addresses\n",
ntohs(eth->h_proto));
return 0; return 0;
} }
static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr) static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr)
{ {
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
memcpy(haddr, dev->dev_addr, ETH1394_ALEN); memcpy(haddr, dev->dev_addr, ETH1394_ALEN);
return ETH1394_ALEN; return ETH1394_ALEN;
} }
static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh) static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh)
{ {
unsigned short type = hh->hh_type; unsigned short type = hh->hh_type;
struct eth1394hdr *eth = (struct eth1394hdr*)(((u8*)hh->hh_data) +
(16 - ETH1394_HLEN));
struct net_device *dev = neigh->dev; struct net_device *dev = neigh->dev;
struct eth1394hdr *eth =
(struct eth1394hdr *)((u8 *)hh->hh_data + 16 - ETH1394_HLEN);
if (type == htons(ETH_P_802_3)) if (type == htons(ETH_P_802_3))
return -1; return -1;
...@@ -808,38 +748,25 @@ static void ether1394_header_cache_update(struct hh_cache *hh, ...@@ -808,38 +748,25 @@ static void ether1394_header_cache_update(struct hh_cache *hh,
struct net_device *dev, struct net_device *dev,
unsigned char * haddr) unsigned char * haddr)
{ {
memcpy(((u8*)hh->hh_data) + (16 - ETH1394_HLEN), 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)
{
if (netif_running(dev))
return -EBUSY;
/* Not going to allow setting the MAC address, we really need to use
* the real one supplied by the hardware */
return -EINVAL;
}
/****************************************** /******************************************
* Datagram reception code * Datagram reception code
******************************************/ ******************************************/
/* Copied from net/ethernet/eth.c */ /* Copied from net/ethernet/eth.c */
static inline u16 ether1394_type_trans(struct sk_buff *skb, static u16 ether1394_type_trans(struct sk_buff *skb, struct net_device *dev)
struct net_device *dev)
{ {
struct eth1394hdr *eth; struct eth1394hdr *eth;
unsigned char *rawp; unsigned char *rawp;
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
skb_pull (skb, ETH1394_HLEN); skb_pull(skb, ETH1394_HLEN);
eth = eth1394_hdr(skb); eth = eth1394_hdr(skb);
if (*eth->h_dest & 1) { if (*eth->h_dest & 1) {
if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len)==0) if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len) == 0)
skb->pkt_type = PACKET_BROADCAST; skb->pkt_type = PACKET_BROADCAST;
#if 0 #if 0
else else
...@@ -848,47 +775,45 @@ static inline u16 ether1394_type_trans(struct sk_buff *skb, ...@@ -848,47 +775,45 @@ static inline u16 ether1394_type_trans(struct sk_buff *skb,
} else { } else {
if (memcmp(eth->h_dest, dev->dev_addr, dev->addr_len)) if (memcmp(eth->h_dest, dev->dev_addr, dev->addr_len))
skb->pkt_type = PACKET_OTHERHOST; skb->pkt_type = PACKET_OTHERHOST;
} }
if (ntohs (eth->h_proto) >= 1536) if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto; return eth->h_proto;
rawp = skb->data; rawp = skb->data;
if (*(unsigned short *)rawp == 0xFFFF) if (*(unsigned short *)rawp == 0xFFFF)
return htons (ETH_P_802_3); return htons(ETH_P_802_3);
return htons (ETH_P_802_2); return htons(ETH_P_802_2);
} }
/* Parse an encapsulated IP1394 header into an ethernet frame packet. /* Parse an encapsulated IP1394 header into an ethernet frame packet.
* We also perform ARP translation here, if need be. */ * We also perform ARP translation here, if need be. */
static inline u16 ether1394_parse_encap(struct sk_buff *skb, static u16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev,
struct net_device *dev, nodeid_t srcid, nodeid_t destid,
nodeid_t srcid, nodeid_t destid, u16 ether_type)
u16 ether_type)
{ {
struct eth1394_priv *priv = netdev_priv(dev); struct eth1394_priv *priv = netdev_priv(dev);
u64 dest_hw; u64 dest_hw;
unsigned short ret = 0; unsigned short ret = 0;
/* Setup our hw addresses. We use these to build the /* Setup our hw addresses. We use these to build the ethernet header. */
* ethernet header. */
if (destid == (LOCAL_BUS | ALL_NODES)) if (destid == (LOCAL_BUS | ALL_NODES))
dest_hw = ~0ULL; /* broadcast */ dest_hw = ~0ULL; /* broadcast */
else else
dest_hw = cpu_to_be64((((u64)priv->host->csr.guid_hi) << 32) | dest_hw = cpu_to_be64((u64)priv->host->csr.guid_hi << 32 |
priv->host->csr.guid_lo); priv->host->csr.guid_lo);
/* If this is an ARP packet, convert it. First, we want to make /* 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 * use of some of the fields, since they tell us a little bit
* about the sending machine. */ * about the sending machine. */
if (ether_type == htons(ETH_P_ARP)) { if (ether_type == htons(ETH_P_ARP)) {
struct eth1394_arp *arp1394 = (struct eth1394_arp*)skb->data; struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
struct arphdr *arp = (struct arphdr *)skb->data; struct arphdr *arp = (struct arphdr *)skb->data;
unsigned char *arp_ptr = (unsigned char *)(arp + 1); unsigned char *arp_ptr = (unsigned char *)(arp + 1);
u64 fifo_addr = (u64)ntohs(arp1394->fifo_hi) << 32 | u64 fifo_addr = (u64)ntohs(arp1394->fifo_hi) << 32 |
ntohl(arp1394->fifo_lo); ntohl(arp1394->fifo_lo);
u8 max_rec = min(priv->host->csr.max_rec, u8 max_rec = min(priv->host->csr.max_rec,
(u8)(arp1394->max_rec)); (u8)(arp1394->max_rec));
int sspd = arp1394->sspd; int sspd = arp1394->sspd;
...@@ -902,16 +827,17 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb, ...@@ -902,16 +827,17 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb,
if (sspd > 5 || sspd < 0) if (sspd > 5 || sspd < 0)
sspd = 0; sspd = 0;
maxpayload = min(eth1394_speedto_maxpayload[sspd], (u16)(1 << (max_rec + 1))); maxpayload = min(eth1394_speedto_maxpayload[sspd],
(u16)(1 << (max_rec + 1)));
guid = get_unaligned(&arp1394->s_uniq_id); guid = get_unaligned(&arp1394->s_uniq_id);
node = eth1394_find_node_guid(&priv->ip_node_list, node = eth1394_find_node_guid(&priv->ip_node_list,
be64_to_cpu(guid)); be64_to_cpu(guid));
if (!node) { if (!node)
return 0; return 0;
}
node_info = (struct eth1394_node_info*)node->ud->device.driver_data; node_info =
(struct eth1394_node_info *)node->ud->device.driver_data;
/* Update our speed/payload/fifo_offset table */ /* Update our speed/payload/fifo_offset table */
node_info->maxpayload = maxpayload; node_info->maxpayload = maxpayload;
...@@ -930,7 +856,7 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb, ...@@ -930,7 +856,7 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb,
arp->ar_hln = 8; arp->ar_hln = 8;
arp_ptr += arp->ar_hln; /* skip over sender unique id */ arp_ptr += arp->ar_hln; /* skip over sender unique id */
*(u32*)arp_ptr = arp1394->sip; /* move sender IP addr */ *(u32 *)arp_ptr = arp1394->sip; /* move sender IP addr */
arp_ptr += arp->ar_pln; /* skip over sender IP addr */ arp_ptr += arp->ar_pln; /* skip over sender IP addr */
if (arp->ar_op == htons(ARPOP_REQUEST)) if (arp->ar_op == htons(ARPOP_REQUEST))
...@@ -947,65 +873,65 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb, ...@@ -947,65 +873,65 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb,
return ret; return ret;
} }
static inline int fragment_overlap(struct list_head *frag_list, int offset, int len) static int fragment_overlap(struct list_head *frag_list, int offset, int len)
{ {
struct fragment_info *fi; struct fragment_info *fi;
int end = offset + len;
list_for_each_entry(fi, frag_list, list) { list_for_each_entry(fi, frag_list, list)
if ( ! ((offset > (fi->offset + fi->len - 1)) || if (offset < fi->offset + fi->len && end > fi->offset)
((offset + len - 1) < fi->offset)))
return 1; return 1;
}
return 0; return 0;
} }
static inline struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl) static struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl)
{ {
struct partial_datagram *pd; struct partial_datagram *pd;
list_for_each_entry(pd, pdgl, list) { list_for_each_entry(pd, pdgl, list)
if (pd->dgl == dgl) if (pd->dgl == dgl)
return &pd->list; return &pd->list;
}
return NULL; return NULL;
} }
/* Assumes that new fragment does not overlap any existing fragments */ /* Assumes that new fragment does not overlap any existing fragments */
static inline int new_fragment(struct list_head *frag_info, int offset, int len) static int new_fragment(struct list_head *frag_info, int offset, int len)
{ {
struct list_head *lh; struct list_head *lh;
struct fragment_info *fi, *fi2, *new; struct fragment_info *fi, *fi2, *new;
list_for_each(lh, frag_info) { list_for_each(lh, frag_info) {
fi = list_entry(lh, struct fragment_info, list); fi = list_entry(lh, struct fragment_info, list);
if ((fi->offset + fi->len) == offset) { if (fi->offset + fi->len == offset) {
/* The new fragment can be tacked on to the end */ /* The new fragment can be tacked on to the end */
fi->len += len; fi->len += len;
/* Did the new fragment plug a hole? */ /* Did the new fragment plug a hole? */
fi2 = list_entry(lh->next, struct fragment_info, list); fi2 = list_entry(lh->next, struct fragment_info, list);
if ((fi->offset + fi->len) == fi2->offset) { if (fi->offset + fi->len == fi2->offset) {
/* glue fragments together */ /* glue fragments together */
fi->len += fi2->len; fi->len += fi2->len;
list_del(lh->next); list_del(lh->next);
kfree(fi2); kfree(fi2);
} }
return 0; return 0;
} else if ((offset + len) == fi->offset) { } else if (offset + len == fi->offset) {
/* The new fragment can be tacked on to the beginning */ /* The new fragment can be tacked on to the beginning */
fi->offset = offset; fi->offset = offset;
fi->len += len; fi->len += len;
/* Did the new fragment plug a hole? */ /* Did the new fragment plug a hole? */
fi2 = list_entry(lh->prev, struct fragment_info, list); fi2 = list_entry(lh->prev, struct fragment_info, list);
if ((fi2->offset + fi2->len) == fi->offset) { if (fi2->offset + fi2->len == fi->offset) {
/* glue fragments together */ /* glue fragments together */
fi2->len += fi->len; fi2->len += fi->len;
list_del(lh); list_del(lh);
kfree(fi); kfree(fi);
} }
return 0; return 0;
} else if (offset > (fi->offset + fi->len)) { } else if (offset > fi->offset + fi->len) {
break; break;
} else if ((offset + len) < fi->offset) { } else if (offset + len < fi->offset) {
lh = lh->prev; lh = lh->prev;
break; break;
} }
...@@ -1019,14 +945,12 @@ static inline int new_fragment(struct list_head *frag_info, int offset, int len) ...@@ -1019,14 +945,12 @@ static inline int new_fragment(struct list_head *frag_info, int offset, int len)
new->len = len; new->len = len;
list_add(&new->list, lh); list_add(&new->list, lh);
return 0; return 0;
} }
static inline int new_partial_datagram(struct net_device *dev, static int new_partial_datagram(struct net_device *dev, struct list_head *pdgl,
struct list_head *pdgl, int dgl, int dgl, int dg_size, char *frag_buf,
int dg_size, char *frag_buf, int frag_off, int frag_len)
int frag_off, int frag_len)
{ {
struct partial_datagram *new; struct partial_datagram *new;
...@@ -1059,33 +983,33 @@ static inline int new_partial_datagram(struct net_device *dev, ...@@ -1059,33 +983,33 @@ static inline int new_partial_datagram(struct net_device *dev,
memcpy(new->pbuf + frag_off, frag_buf, frag_len); memcpy(new->pbuf + frag_off, frag_buf, frag_len);
list_add(&new->list, pdgl); list_add(&new->list, pdgl);
return 0; return 0;
} }
static inline int update_partial_datagram(struct list_head *pdgl, struct list_head *lh, static int update_partial_datagram(struct list_head *pdgl, struct list_head *lh,
char *frag_buf, int frag_off, int frag_len) char *frag_buf, int frag_off, int frag_len)
{ {
struct partial_datagram *pd = list_entry(lh, struct partial_datagram, list); struct partial_datagram *pd =
list_entry(lh, struct partial_datagram, list);
if (new_fragment(&pd->frag_info, frag_off, frag_len) < 0) { if (new_fragment(&pd->frag_info, frag_off, frag_len) < 0)
return -ENOMEM; return -ENOMEM;
}
memcpy(pd->pbuf + frag_off, frag_buf, frag_len); memcpy(pd->pbuf + frag_off, frag_buf, frag_len);
/* Move list entry to beginnig of list so that oldest partial /* Move list entry to beginnig of list so that oldest partial
* datagrams percolate to the end of the list */ * datagrams percolate to the end of the list */
list_move(lh, pdgl); list_move(lh, pdgl);
return 0; return 0;
} }
static inline int is_datagram_complete(struct list_head *lh, int dg_size) static int is_datagram_complete(struct list_head *lh, int dg_size)
{ {
struct partial_datagram *pd = list_entry(lh, struct partial_datagram, list); struct partial_datagram *pd;
struct fragment_info *fi = list_entry(pd->frag_info.next, struct fragment_info *fi;
struct fragment_info, list);
pd = list_entry(lh, struct partial_datagram, list);
fi = list_entry(pd->frag_info.next, struct fragment_info, list);
return (fi->len == dg_size); return (fi->len == dg_size);
} }
...@@ -1108,7 +1032,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, ...@@ -1108,7 +1032,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
if (!ud) { if (!ud) {
struct eth1394_node_ref *node; struct eth1394_node_ref *node;
node = eth1394_find_node_nodeid(&priv->ip_node_list, srcid); node = eth1394_find_node_nodeid(&priv->ip_node_list, srcid);
if (!node) { if (unlikely(!node)) {
HPSB_PRINT(KERN_ERR, "ether1394 rx: sender nodeid " HPSB_PRINT(KERN_ERR, "ether1394 rx: sender nodeid "
"lookup failure: " NODE_BUS_FMT, "lookup failure: " NODE_BUS_FMT,
NODE_BUS_ARGS(priv->host, srcid)); NODE_BUS_ARGS(priv->host, srcid));
...@@ -1120,7 +1044,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, ...@@ -1120,7 +1044,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
priv->ud_list[NODEID_TO_NODE(srcid)] = ud; priv->ud_list[NODEID_TO_NODE(srcid)] = ud;
} }
node_info = (struct eth1394_node_info*)ud->device.driver_data; node_info = (struct eth1394_node_info *)ud->device.driver_data;
/* First, did we receive a fragmented or unfragmented datagram? */ /* First, did we receive a fragmented or unfragmented datagram? */
hdr->words.word1 = ntohs(hdr->words.word1); hdr->words.word1 = ntohs(hdr->words.word1);
...@@ -1133,13 +1057,14 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, ...@@ -1133,13 +1057,14 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
* high level network layer. */ * high level network layer. */
skb = dev_alloc_skb(len + dev->hard_header_len + 15); skb = dev_alloc_skb(len + dev->hard_header_len + 15);
if (!skb) { if (unlikely(!skb)) {
HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n"); ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
priv->stats.rx_dropped++; priv->stats.rx_dropped++;
return -1; return -1;
} }
skb_reserve(skb, (dev->hard_header_len + 15) & ~15); skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
memcpy(skb_put(skb, len - hdr_len), buf + hdr_len, len - hdr_len); memcpy(skb_put(skb, len - hdr_len), buf + hdr_len,
len - hdr_len);
ether_type = hdr->uf.ether_type; ether_type = hdr->uf.ether_type;
} else { } else {
/* A datagram fragment has been received, now the fun begins. */ /* A datagram fragment has been received, now the fun begins. */
...@@ -1224,9 +1149,8 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, ...@@ -1224,9 +1149,8 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
pd = list_entry(lh, struct partial_datagram, list); pd = list_entry(lh, struct partial_datagram, list);
if (hdr->common.lf == ETH1394_HDR_LF_FF) { if (hdr->common.lf == ETH1394_HDR_LF_FF)
pd->ether_type = ether_type; pd->ether_type = ether_type;
}
if (is_datagram_complete(lh, dg_size)) { if (is_datagram_complete(lh, dg_size)) {
ether_type = pd->ether_type; ether_type = pd->ether_type;
...@@ -1253,8 +1177,8 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, ...@@ -1253,8 +1177,8 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
skb->protocol = ether1394_parse_encap(skb, dev, srcid, destid, skb->protocol = ether1394_parse_encap(skb, dev, srcid, destid,
ether_type); ether_type);
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
if (!skb->protocol) { if (!skb->protocol) {
priv->stats.rx_errors++; priv->stats.rx_errors++;
priv->stats.rx_dropped++; priv->stats.rx_dropped++;
...@@ -1288,9 +1212,9 @@ static int ether1394_write(struct hpsb_host *host, int srcid, int destid, ...@@ -1288,9 +1212,9 @@ static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
struct eth1394_host_info *hi; struct eth1394_host_info *hi;
hi = hpsb_get_hostinfo(&eth1394_highlevel, host); hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
if (hi == NULL) { if (unlikely(!hi)) {
ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n", ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
host->driver->name); host->id);
return RCODE_ADDRESS_ERROR; return RCODE_ADDRESS_ERROR;
} }
...@@ -1314,9 +1238,9 @@ static void ether1394_iso(struct hpsb_iso *iso) ...@@ -1314,9 +1238,9 @@ static void ether1394_iso(struct hpsb_iso *iso)
int nready; int nready;
hi = hpsb_get_hostinfo(&eth1394_highlevel, iso->host); hi = hpsb_get_hostinfo(&eth1394_highlevel, iso->host);
if (hi == NULL) { if (unlikely(!hi)) {
ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n", ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
iso->host->driver->name); iso->host->id);
return; return;
} }
...@@ -1326,20 +1250,20 @@ static void ether1394_iso(struct hpsb_iso *iso) ...@@ -1326,20 +1250,20 @@ static void ether1394_iso(struct hpsb_iso *iso)
for (i = 0; i < nready; i++) { for (i = 0; i < nready; i++) {
struct hpsb_iso_packet_info *info = struct hpsb_iso_packet_info *info =
&iso->infos[(iso->first_packet + i) % iso->buf_packets]; &iso->infos[(iso->first_packet + i) % iso->buf_packets];
data = (quadlet_t*) (iso->data_buf.kvirt + info->offset); data = (quadlet_t *)(iso->data_buf.kvirt + info->offset);
/* skip over GASP header */ /* skip over GASP header */
buf = (char *)data + 8; buf = (char *)data + 8;
len = info->len - 8; len = info->len - 8;
specifier_id = (((be32_to_cpu(data[0]) & 0xffff) << 8) | specifier_id = (be32_to_cpu(data[0]) & 0xffff) << 8 |
((be32_to_cpu(data[1]) & 0xff000000) >> 24)); (be32_to_cpu(data[1]) & 0xff000000) >> 24;
source_id = be32_to_cpu(data[0]) >> 16; source_id = be32_to_cpu(data[0]) >> 16;
priv = netdev_priv(dev); priv = netdev_priv(dev);
if (info->channel != (iso->host->csr.broadcast_channel & 0x3f) || if (info->channel != (iso->host->csr.broadcast_channel & 0x3f)
specifier_id != ETHER1394_GASP_SPECIFIER_ID) { || specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
/* This packet is not for us */ /* This packet is not for us */
continue; continue;
} }
...@@ -1367,35 +1291,31 @@ static void ether1394_iso(struct hpsb_iso *iso) ...@@ -1367,35 +1291,31 @@ static void ether1394_iso(struct hpsb_iso *iso)
* speed, and unicast FIFO address information between the sender_unique_id * speed, and unicast FIFO address information between the sender_unique_id
* and the IP addresses. * and the IP addresses.
*/ */
static inline void ether1394_arp_to_1394arp(struct sk_buff *skb, static void ether1394_arp_to_1394arp(struct sk_buff *skb,
struct net_device *dev) struct net_device *dev)
{ {
struct eth1394_priv *priv = netdev_priv(dev); struct eth1394_priv *priv = netdev_priv(dev);
struct arphdr *arp = (struct arphdr *)skb->data; struct arphdr *arp = (struct arphdr *)skb->data;
unsigned char *arp_ptr = (unsigned char *)(arp + 1); unsigned char *arp_ptr = (unsigned char *)(arp + 1);
struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data; struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
/* Believe it or not, all that need to happen is sender IP get moved
* and set hw_addr_len, max_rec, sspd, fifo_hi and fifo_lo. */
arp1394->hw_addr_len = 16; arp1394->hw_addr_len = 16;
arp1394->sip = *(u32*)(arp_ptr + ETH1394_ALEN); arp1394->sip = *(u32*)(arp_ptr + ETH1394_ALEN);
arp1394->max_rec = priv->host->csr.max_rec; arp1394->max_rec = priv->host->csr.max_rec;
arp1394->sspd = priv->host->csr.lnk_spd; arp1394->sspd = priv->host->csr.lnk_spd;
arp1394->fifo_hi = htons (priv->local_fifo >> 32); arp1394->fifo_hi = htons(priv->local_fifo >> 32);
arp1394->fifo_lo = htonl (priv->local_fifo & ~0x0); arp1394->fifo_lo = htonl(priv->local_fifo & ~0x0);
return;
} }
/* We need to encapsulate the standard header with our own. We use the /* We need to encapsulate the standard header with our own. We use the
* ethernet header's proto for our own. */ * ethernet header's proto for our own. */
static inline unsigned int ether1394_encapsulate_prep(unsigned int max_payload, static unsigned int ether1394_encapsulate_prep(unsigned int max_payload,
__be16 proto, __be16 proto,
union eth1394_hdr *hdr, union eth1394_hdr *hdr,
u16 dg_size, u16 dgl) u16 dg_size, u16 dgl)
{ {
unsigned int adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_UF]; unsigned int adj_max_payload =
max_payload - hdr_type_len[ETH1394_HDR_LF_UF];
/* Does it all fit in one packet? */ /* Does it all fit in one packet? */
if (dg_size <= adj_max_payload) { if (dg_size <= adj_max_payload) {
...@@ -1408,19 +1328,19 @@ static inline unsigned int ether1394_encapsulate_prep(unsigned int max_payload, ...@@ -1408,19 +1328,19 @@ static inline unsigned int ether1394_encapsulate_prep(unsigned int max_payload,
hdr->ff.dgl = dgl; hdr->ff.dgl = dgl;
adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_FF]; adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_FF];
} }
return((dg_size + (adj_max_payload - 1)) / adj_max_payload); return (dg_size + adj_max_payload - 1) / adj_max_payload;
} }
static inline unsigned int ether1394_encapsulate(struct sk_buff *skb, static unsigned int ether1394_encapsulate(struct sk_buff *skb,
unsigned int max_payload, unsigned int max_payload,
union eth1394_hdr *hdr) union eth1394_hdr *hdr)
{ {
union eth1394_hdr *bufhdr; union eth1394_hdr *bufhdr;
int ftype = hdr->common.lf; int ftype = hdr->common.lf;
int hdrsz = hdr_type_len[ftype]; int hdrsz = hdr_type_len[ftype];
unsigned int adj_max_payload = max_payload - hdrsz; unsigned int adj_max_payload = max_payload - hdrsz;
switch(ftype) { switch (ftype) {
case ETH1394_HDR_LF_UF: case ETH1394_HDR_LF_UF:
bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz); bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz);
bufhdr->words.word1 = htons(hdr->words.word1); bufhdr->words.word1 = htons(hdr->words.word1);
...@@ -1449,11 +1369,10 @@ static inline unsigned int ether1394_encapsulate(struct sk_buff *skb, ...@@ -1449,11 +1369,10 @@ static inline unsigned int ether1394_encapsulate(struct sk_buff *skb,
bufhdr->words.word3 = htons(hdr->words.word3); bufhdr->words.word3 = htons(hdr->words.word3);
bufhdr->words.word4 = 0; bufhdr->words.word4 = 0;
} }
return min(max_payload, skb->len); return min(max_payload, skb->len);
} }
static inline struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host) static struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host)
{ {
struct hpsb_packet *p; struct hpsb_packet *p;
...@@ -1466,61 +1385,57 @@ static inline struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host ...@@ -1466,61 +1385,57 @@ static inline struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host
return p; return p;
} }
static inline int ether1394_prep_write_packet(struct hpsb_packet *p, static int ether1394_prep_write_packet(struct hpsb_packet *p,
struct hpsb_host *host, struct hpsb_host *host, nodeid_t node,
nodeid_t node, u64 addr, u64 addr, void *data, int tx_len)
void * data, int tx_len)
{ {
p->node_id = node; p->node_id = node;
p->data = NULL; p->data = NULL;
p->tcode = TCODE_WRITEB; p->tcode = TCODE_WRITEB;
p->header[1] = (host->node_id << 16) | (addr >> 32); p->header[1] = host->node_id << 16 | addr >> 32;
p->header[2] = addr & 0xffffffff; p->header[2] = addr & 0xffffffff;
p->header_size = 16; p->header_size = 16;
p->expect_response = 1; p->expect_response = 1;
if (hpsb_get_tlabel(p)) { if (hpsb_get_tlabel(p)) {
ETH1394_PRINT_G(KERN_ERR, "No more tlabels left while sending " ETH1394_PRINT_G(KERN_ERR, "Out of tlabels\n");
"to node " NODE_BUS_FMT "\n", NODE_BUS_ARGS(host, node));
return -1; return -1;
} }
p->header[0] = (p->node_id << 16) | (p->tlabel << 10) p->header[0] =
| (1 << 8) | (TCODE_WRITEB << 4); p->node_id << 16 | p->tlabel << 10 | 1 << 8 | TCODE_WRITEB << 4;
p->header[3] = tx_len << 16; p->header[3] = tx_len << 16;
p->data_size = (tx_len + 3) & ~3; p->data_size = (tx_len + 3) & ~3;
p->data = (quadlet_t*)data; p->data = data;
return 0; return 0;
} }
static inline void ether1394_prep_gasp_packet(struct hpsb_packet *p, static void ether1394_prep_gasp_packet(struct hpsb_packet *p,
struct eth1394_priv *priv, struct eth1394_priv *priv,
struct sk_buff *skb, int length) struct sk_buff *skb, int length)
{ {
p->header_size = 4; p->header_size = 4;
p->tcode = TCODE_STREAM_DATA; p->tcode = TCODE_STREAM_DATA;
p->header[0] = (length << 16) | (3 << 14) p->header[0] = length << 16 | 3 << 14 | priv->broadcast_channel << 8 |
| ((priv->broadcast_channel) << 8) TCODE_STREAM_DATA << 4;
| (TCODE_STREAM_DATA << 4);
p->data_size = length; p->data_size = length;
p->data = ((quadlet_t*)skb->data) - 2; p->data = (quadlet_t *)skb->data - 2;
p->data[0] = cpu_to_be32((priv->host->node_id << 16) | p->data[0] = cpu_to_be32(priv->host->node_id << 16 |
ETHER1394_GASP_SPECIFIER_ID_HI); ETHER1394_GASP_SPECIFIER_ID_HI);
p->data[1] = cpu_to_be32((ETHER1394_GASP_SPECIFIER_ID_LO << 24) | p->data[1] = cpu_to_be32(ETHER1394_GASP_SPECIFIER_ID_LO << 24 |
ETHER1394_GASP_VERSION); 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->bc_sspd; p->speed_code = priv->bc_sspd;
/* prevent hpsb_send_packet() from overriding our speed code */
p->node_id = LOCAL_BUS | ALL_NODES;
} }
static inline void ether1394_free_packet(struct hpsb_packet *packet) static void ether1394_free_packet(struct hpsb_packet *packet)
{ {
if (packet->tcode != TCODE_STREAM_DATA) if (packet->tcode != TCODE_STREAM_DATA)
hpsb_free_tlabel(packet); hpsb_free_tlabel(packet);
...@@ -1539,7 +1454,7 @@ static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len) ...@@ -1539,7 +1454,7 @@ static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len)
return -1; return -1;
if (ptask->tx_type == ETH1394_GASP) { if (ptask->tx_type == ETH1394_GASP) {
int length = tx_len + (2 * sizeof(quadlet_t)); int length = tx_len + 2 * sizeof(quadlet_t);
ether1394_prep_gasp_packet(packet, priv, ptask->skb, length); ether1394_prep_gasp_packet(packet, priv, ptask->skb, length);
} else if (ether1394_prep_write_packet(packet, priv->host, } else if (ether1394_prep_write_packet(packet, priv->host,
...@@ -1562,13 +1477,11 @@ static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len) ...@@ -1562,13 +1477,11 @@ static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len)
return 0; return 0;
} }
/* Task function to be run when a datagram transmission is completed */ /* Task function to be run when a datagram transmission is completed */
static inline void ether1394_dg_complete(struct packet_task *ptask, int fail) static void ether1394_dg_complete(struct packet_task *ptask, int fail)
{ {
struct sk_buff *skb = ptask->skb; struct sk_buff *skb = ptask->skb;
struct net_device *dev = skb->dev; struct eth1394_priv *priv = netdev_priv(skb->dev);
struct eth1394_priv *priv = netdev_priv(dev);
unsigned long flags; unsigned long flags;
/* Statistics */ /* Statistics */
...@@ -1586,7 +1499,6 @@ static inline void ether1394_dg_complete(struct packet_task *ptask, int fail) ...@@ -1586,7 +1499,6 @@ static inline void ether1394_dg_complete(struct packet_task *ptask, int fail)
kmem_cache_free(packet_task_cache, ptask); kmem_cache_free(packet_task_cache, ptask);
} }
/* Callback for when a packet has been sent and the status of that packet is /* Callback for when a packet has been sent and the status of that packet is
* known */ * known */
static void ether1394_complete_cb(void *__ptask) static void ether1394_complete_cb(void *__ptask)
...@@ -1614,19 +1526,15 @@ static void ether1394_complete_cb(void *__ptask) ...@@ -1614,19 +1526,15 @@ static void ether1394_complete_cb(void *__ptask)
} }
} }
/* Transmit a packet (called by kernel) */ /* Transmit a packet (called by kernel) */
static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) static int ether1394_tx(struct sk_buff *skb, struct net_device *dev)
{ {
gfp_t kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
struct eth1394hdr *eth; struct eth1394hdr *eth;
struct eth1394_priv *priv = netdev_priv(dev); struct eth1394_priv *priv = netdev_priv(dev);
__be16 proto; __be16 proto;
unsigned long flags; unsigned long flags;
nodeid_t dest_node; nodeid_t dest_node;
eth1394_tx_type tx_type; eth1394_tx_type tx_type;
int ret = 0;
unsigned int tx_len; unsigned int tx_len;
unsigned int max_payload; unsigned int max_payload;
u16 dg_size; u16 dg_size;
...@@ -1635,29 +1543,24 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) ...@@ -1635,29 +1543,24 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
struct eth1394_node_ref *node; struct eth1394_node_ref *node;
struct eth1394_node_info *node_info = NULL; struct eth1394_node_info *node_info = NULL;
ptask = kmem_cache_alloc(packet_task_cache, kmflags); ptask = kmem_cache_alloc(packet_task_cache, GFP_ATOMIC);
if (ptask == NULL) { if (ptask == NULL)
ret = -ENOMEM;
goto fail; goto fail;
}
/* XXX Ignore this for now. Noticed that when MacOSX is the IRM, /* XXX Ignore this for now. Noticed that when MacOSX is the IRM,
* it does not set our validity bit. We need to compensate for * it does not set our validity bit. We need to compensate for
* that somewhere else, but not in eth1394. */ * that somewhere else, but not in eth1394. */
#if 0 #if 0
if ((priv->host->csr.broadcast_channel & 0xc0000000) != 0xc0000000) { if ((priv->host->csr.broadcast_channel & 0xc0000000) != 0xc0000000)
ret = -EAGAIN;
goto fail; goto fail;
}
#endif #endif
if ((skb = skb_share_check (skb, kmflags)) == NULL) { skb = skb_share_check(skb, GFP_ATOMIC);
ret = -ENOMEM; if (!skb)
goto fail; goto fail;
}
/* Get rid of the fake eth1394 header, but save a pointer */ /* Get rid of the fake eth1394 header, but save a pointer */
eth = (struct eth1394hdr*)skb->data; eth = (struct eth1394hdr *)skb->data;
skb_pull(skb, ETH1394_HLEN); skb_pull(skb, ETH1394_HLEN);
proto = eth->h_proto; proto = eth->h_proto;
...@@ -1672,7 +1575,7 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) ...@@ -1672,7 +1575,7 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
tx_type = ETH1394_GASP; tx_type = ETH1394_GASP;
dest_node = LOCAL_BUS | ALL_NODES; dest_node = LOCAL_BUS | ALL_NODES;
max_payload = priv->bc_maxpayload - ETHER1394_GASP_OVERHEAD; max_payload = priv->bc_maxpayload - ETHER1394_GASP_OVERHEAD;
BUG_ON(max_payload < (512 - ETHER1394_GASP_OVERHEAD)); BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD);
dgl = priv->bc_dgl; dgl = priv->bc_dgl;
if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
priv->bc_dgl++; priv->bc_dgl++;
...@@ -1681,19 +1584,17 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) ...@@ -1681,19 +1584,17 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
node = eth1394_find_node_guid(&priv->ip_node_list, node = eth1394_find_node_guid(&priv->ip_node_list,
be64_to_cpu(guid)); be64_to_cpu(guid));
if (!node) { if (!node)
ret = -EAGAIN;
goto fail; goto fail;
}
node_info = (struct eth1394_node_info*)node->ud->device.driver_data; node_info =
if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE) { (struct eth1394_node_info *)node->ud->device.driver_data;
ret = -EAGAIN; if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE)
goto fail; goto fail;
}
dest_node = node->ud->ne->nodeid; dest_node = node->ud->ne->nodeid;
max_payload = node_info->maxpayload; max_payload = node_info->maxpayload;
BUG_ON(max_payload < (512 - ETHER1394_GASP_OVERHEAD)); BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD);
dgl = node_info->dgl; dgl = node_info->dgl;
if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
...@@ -1703,7 +1604,7 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) ...@@ -1703,7 +1604,7 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
/* If this is an ARP packet, convert it */ /* If this is an ARP packet, convert it */
if (proto == htons(ETH_P_ARP)) if (proto == htons(ETH_P_ARP))
ether1394_arp_to_1394arp (skb, dev); ether1394_arp_to_1394arp(skb, dev);
ptask->hdr.words.word1 = 0; ptask->hdr.words.word1 = 0;
ptask->hdr.words.word2 = 0; ptask->hdr.words.word2 = 0;
...@@ -1726,9 +1627,8 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) ...@@ -1726,9 +1627,8 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
ptask->tx_type = tx_type; ptask->tx_type = tx_type;
ptask->max_payload = max_payload; ptask->max_payload = max_payload;
ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload, proto, ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload,
&ptask->hdr, dg_size, proto, &ptask->hdr, dg_size, dgl);
dgl);
/* Add the encapsulation header to the fragment */ /* Add the encapsulation header to the fragment */
tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr); tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr);
...@@ -1737,7 +1637,7 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) ...@@ -1737,7 +1637,7 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
goto fail; goto fail;
netif_wake_queue(dev); netif_wake_queue(dev);
return 0; return NETDEV_TX_OK;
fail: fail:
if (ptask) if (ptask)
kmem_cache_free(packet_task_cache, ptask); kmem_cache_free(packet_task_cache, ptask);
...@@ -1745,40 +1645,56 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) ...@@ -1745,40 +1645,56 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
if (skb != NULL) if (skb != NULL)
dev_kfree_skb(skb); dev_kfree_skb(skb);
spin_lock_irqsave (&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
priv->stats.tx_dropped++; priv->stats.tx_dropped++;
priv->stats.tx_errors++; priv->stats.tx_errors++;
spin_unlock_irqrestore (&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
if (netif_queue_stopped(dev)) if (netif_queue_stopped(dev))
netif_wake_queue(dev); netif_wake_queue(dev);
return 0; /* returning non-zero causes serious problems */ /*
* FIXME: According to a patch from 2003-02-26, "returning non-zero
* causes serious problems" here, allegedly. Before that patch,
* -ERRNO was returned which is not appropriate under Linux 2.6.
* Perhaps more needs to be done? Stop the queue in serious
* conditions and restart it elsewhere?
*/
/* return NETDEV_TX_BUSY; */
return NETDEV_TX_OK;
} }
static void ether1394_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) static void ether1394_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{ {
strcpy (info->driver, driver_name); strcpy(info->driver, driver_name);
/* FIXME XXX provide sane businfo */ strcpy(info->bus_info, "ieee1394"); /* FIXME provide more detail? */
strcpy (info->bus_info, "ieee1394");
} }
static struct ethtool_ops ethtool_ops = { static struct ethtool_ops ethtool_ops = {
.get_drvinfo = ether1394_get_drvinfo .get_drvinfo = ether1394_get_drvinfo
}; };
static int __init ether1394_init_module (void) static int __init ether1394_init_module(void)
{ {
packet_task_cache = kmem_cache_create("packet_task", sizeof(struct packet_task), int err;
packet_task_cache = kmem_cache_create("packet_task",
sizeof(struct packet_task),
0, 0, NULL, NULL); 0, 0, NULL, NULL);
if (!packet_task_cache)
return -ENOMEM;
/* Register ourselves as a highlevel driver */
hpsb_register_highlevel(&eth1394_highlevel); hpsb_register_highlevel(&eth1394_highlevel);
err = hpsb_register_protocol(&eth1394_proto_driver);
return hpsb_register_protocol(&eth1394_proto_driver); if (err) {
hpsb_unregister_highlevel(&eth1394_highlevel);
kmem_cache_destroy(packet_task_cache);
}
return err;
} }
static void __exit ether1394_exit_module (void) static void __exit ether1394_exit_module(void)
{ {
hpsb_unregister_protocol(&eth1394_proto_driver); hpsb_unregister_protocol(&eth1394_proto_driver);
hpsb_unregister_highlevel(&eth1394_highlevel); hpsb_unregister_highlevel(&eth1394_highlevel);
......
...@@ -25,8 +25,11 @@ ...@@ -25,8 +25,11 @@
#define __ETH1394_H #define __ETH1394_H
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <asm/byteorder.h>
#include "ieee1394.h" #include "ieee1394.h"
#include "ieee1394_types.h"
/* Register for incoming packets. This is 4096 bytes, which supports up to /* Register for incoming packets. This is 4096 bytes, which supports up to
* S3200 (per Table 16-3 of IEEE 1394b-2002). */ * S3200 (per Table 16-3 of IEEE 1394b-2002). */
...@@ -34,22 +37,15 @@ ...@@ -34,22 +37,15 @@
/* GASP identifier numbers for IPv4 over IEEE 1394 */ /* GASP identifier numbers for IPv4 over IEEE 1394 */
#define ETHER1394_GASP_SPECIFIER_ID 0x00005E #define ETHER1394_GASP_SPECIFIER_ID 0x00005E
#define ETHER1394_GASP_SPECIFIER_ID_HI ((ETHER1394_GASP_SPECIFIER_ID >> 8) & 0xffff) #define ETHER1394_GASP_SPECIFIER_ID_HI ((0x00005E >> 8) & 0xffff)
#define ETHER1394_GASP_SPECIFIER_ID_LO (ETHER1394_GASP_SPECIFIER_ID & 0xff) #define ETHER1394_GASP_SPECIFIER_ID_LO (0x00005E & 0xff)
#define ETHER1394_GASP_VERSION 1 #define ETHER1394_GASP_VERSION 1
#define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t)) /* GASP header overhead */ #define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t)) /* for GASP header */
#define ETHER1394_GASP_BUFFERS 16 #define ETHER1394_GASP_BUFFERS 16
/* rawiso buffer size - due to a limitation in rawiso, we must limit each #define NODE_SET (ALL_NODES + 1) /* Node set == 64 */
* GASP buffer to be less than PAGE_SIZE. */
#define ETHER1394_ISO_BUF_SIZE ETHER1394_GASP_BUFFERS * \
min((unsigned int)PAGE_SIZE, \
2 * (1U << (priv->host->csr.max_rec + 1)))
/* Node set == 64 */
#define NODE_SET (ALL_NODES + 1)
enum eth1394_bc_states { ETHER1394_BC_ERROR, enum eth1394_bc_states { ETHER1394_BC_ERROR,
ETHER1394_BC_RUNNING, ETHER1394_BC_RUNNING,
...@@ -85,19 +81,14 @@ struct eth1394hdr { ...@@ -85,19 +81,14 @@ struct eth1394hdr {
unsigned short h_proto; /* packet type ID field */ unsigned short h_proto; /* packet type ID field */
} __attribute__((packed)); } __attribute__((packed));
#ifdef __KERNEL__
#include <linux/skbuff.h>
static inline struct eth1394hdr *eth1394_hdr(const struct sk_buff *skb) static inline struct eth1394hdr *eth1394_hdr(const struct sk_buff *skb)
{ {
return (struct eth1394hdr *)skb_mac_header(skb); return (struct eth1394hdr *)skb_mac_header(skb);
} }
#endif
typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type; typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type;
/* IP1394 headers */ /* IP1394 headers */
#include <asm/byteorder.h>
/* Unfragmented */ /* Unfragmented */
#if defined __BIG_ENDIAN_BITFIELD #if defined __BIG_ENDIAN_BITFIELD
......
...@@ -70,8 +70,12 @@ static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl, ...@@ -70,8 +70,12 @@ static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
return NULL; return NULL;
} }
/* Returns a per host/driver data structure that was previously stored by /**
* hpsb_create_hostinfo. */ * hpsb_get_hostinfo - retrieve a hostinfo pointer bound to this driver/host
*
* Returns a per @host and @hl driver data structure that was previously stored
* by hpsb_create_hostinfo.
*/
void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host) void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
{ {
struct hl_host_info *hi = hl_get_hostinfo(hl, host); struct hl_host_info *hi = hl_get_hostinfo(hl, host);
...@@ -79,7 +83,13 @@ void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host) ...@@ -79,7 +83,13 @@ void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
return hi ? hi->data : NULL; return hi ? hi->data : NULL;
} }
/* If size is zero, then the return here is only valid for error checking */ /**
* hpsb_create_hostinfo - allocate a hostinfo pointer bound to this driver/host
*
* Allocate a hostinfo pointer backed by memory with @data_size and bind it to
* to this @hl driver and @host. If @data_size is zero, then the return here is
* only valid for error checking.
*/
void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
size_t data_size) size_t data_size)
{ {
...@@ -113,6 +123,11 @@ void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, ...@@ -113,6 +123,11 @@ void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
return data; return data;
} }
/**
* hpsb_set_hostinfo - set the hostinfo pointer to something useful
*
* Usually follows a call to hpsb_create_hostinfo, where the size is 0.
*/
int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
void *data) void *data)
{ {
...@@ -132,6 +147,11 @@ int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, ...@@ -132,6 +147,11 @@ int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
return -EINVAL; return -EINVAL;
} }
/**
* hpsb_destroy_hostinfo - free and remove a hostinfo pointer
*
* Free and remove the hostinfo pointer bound to this @hl driver and @host.
*/
void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host) void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
{ {
struct hl_host_info *hi; struct hl_host_info *hi;
...@@ -147,6 +167,12 @@ void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host) ...@@ -147,6 +167,12 @@ void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
return; return;
} }
/**
* hpsb_set_hostinfo_key - set an alternate lookup key for an hostinfo
*
* Sets an alternate lookup key for the hostinfo bound to this @hl driver and
* @host.
*/
void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned long key) unsigned long key)
{ {
...@@ -158,6 +184,9 @@ void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, ...@@ -158,6 +184,9 @@ void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
return; return;
} }
/**
* hpsb_get_hostinfo_bykey - retrieve a hostinfo pointer by its alternate key
*/
void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key) void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
{ {
struct hl_host_info *hi; struct hl_host_info *hi;
...@@ -189,6 +218,12 @@ static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data) ...@@ -189,6 +218,12 @@ static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data)
return 0; return 0;
} }
/**
* hpsb_register_highlevel - register highlevel driver
*
* The name pointer in @hl has to stay valid at all times because the string is
* not copied.
*/
void hpsb_register_highlevel(struct hpsb_highlevel *hl) void hpsb_register_highlevel(struct hpsb_highlevel *hl)
{ {
unsigned long flags; unsigned long flags;
...@@ -258,6 +293,9 @@ static int highlevel_for_each_host_unreg(struct hpsb_host *host, void *__data) ...@@ -258,6 +293,9 @@ static int highlevel_for_each_host_unreg(struct hpsb_host *host, void *__data)
return 0; return 0;
} }
/**
* hpsb_unregister_highlevel - unregister highlevel driver
*/
void hpsb_unregister_highlevel(struct hpsb_highlevel *hl) void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
{ {
unsigned long flags; unsigned long flags;
...@@ -273,6 +311,19 @@ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl) ...@@ -273,6 +311,19 @@ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
nodemgr_for_each_host(hl, highlevel_for_each_host_unreg); nodemgr_for_each_host(hl, highlevel_for_each_host_unreg);
} }
/**
* hpsb_allocate_and_register_addrspace - alloc' and reg' a host address space
*
* @start and @end are 48 bit pointers and have to be quadlet aligned.
* @end points to the first address behind the handled addresses. This
* function can be called multiple times for a single hpsb_highlevel @hl to
* implement sparse register sets. The requested region must not overlap any
* previously allocated region, otherwise registering will fail.
*
* It returns true for successful allocation. Address spaces can be
* unregistered with hpsb_unregister_addrspace. All remaining address spaces
* are automatically deallocated together with the hpsb_highlevel @hl.
*/
u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl, u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
struct hpsb_host *host, struct hpsb_host *host,
struct hpsb_address_ops *ops, struct hpsb_address_ops *ops,
...@@ -348,6 +399,19 @@ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl, ...@@ -348,6 +399,19 @@ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
return retval; return retval;
} }
/**
* hpsb_register_addrspace - register a host address space
*
* @start and @end are 48 bit pointers and have to be quadlet aligned.
* @end points to the first address behind the handled addresses. This
* function can be called multiple times for a single hpsb_highlevel @hl to
* implement sparse register sets. The requested region must not overlap any
* previously allocated region, otherwise registering will fail.
*
* It returns true for successful allocation. Address spaces can be
* unregistered with hpsb_unregister_addrspace. All remaining address spaces
* are automatically deallocated together with the hpsb_highlevel @hl.
*/
int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host, int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
struct hpsb_address_ops *ops, u64 start, u64 end) struct hpsb_address_ops *ops, u64 start, u64 end)
{ {
...@@ -419,6 +483,11 @@ int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host, ...@@ -419,6 +483,11 @@ int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
return retval; return retval;
} }
/**
* hpsb_listen_channel - enable receving a certain isochronous channel
*
* Reception is handled through the @hl's iso_receive op.
*/
int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned int channel) unsigned int channel)
{ {
...@@ -431,6 +500,9 @@ int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, ...@@ -431,6 +500,9 @@ int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
return 0; return 0;
} }
/**
* hpsb_unlisten_channel - disable receving a certain isochronous channel
*/
void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned int channel) unsigned int channel)
{ {
...@@ -528,6 +600,17 @@ void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction, ...@@ -528,6 +600,17 @@ void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
read_unlock_irqrestore(&hl_irqs_lock, flags); read_unlock_irqrestore(&hl_irqs_lock, flags);
} }
/*
* highlevel_read, highlevel_write, highlevel_lock, highlevel_lock64:
*
* These functions are called to handle transactions. They are called when a
* packet arrives. The flags argument contains the second word of the first
* header quadlet of the incoming packet (containing transaction label, retry
* code, transaction code and priority). These functions either return a
* response code or a negative number. In the first case a response will be
* generated. In the latter case, no response will be sent and the driver which
* handled the request will send the response itself.
*/
int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr, int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
unsigned int length, u16 flags) unsigned int length, u16 flags)
{ {
......
...@@ -99,16 +99,6 @@ struct hpsb_address_ops { ...@@ -99,16 +99,6 @@ struct hpsb_address_ops {
void highlevel_add_host(struct hpsb_host *host); void highlevel_add_host(struct hpsb_host *host);
void highlevel_remove_host(struct hpsb_host *host); void highlevel_remove_host(struct hpsb_host *host);
void highlevel_host_reset(struct hpsb_host *host); void highlevel_host_reset(struct hpsb_host *host);
/*
* These functions are called to handle transactions. They are called when a
* packet arrives. The flags argument contains the second word of the first
* header quadlet of the incoming packet (containing transaction label, retry
* code, transaction code and priority). These functions either return a
* response code or a negative number. In the first case a response will be
* generated. In the latter case, no response will be sent and the driver which
* handled the request will send the response itself.
*/
int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr, int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
unsigned int length, u16 flags); unsigned int length, u16 flags);
int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data, int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
...@@ -119,30 +109,13 @@ int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store, ...@@ -119,30 +109,13 @@ int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store, int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
u16 flags); u16 flags);
void highlevel_iso_receive(struct hpsb_host *host, void *data, size_t length); void highlevel_iso_receive(struct hpsb_host *host, void *data, size_t length);
void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction, void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
void *data, size_t length); void *data, size_t length);
/*
* Register highlevel driver. The name pointer has to stay valid at all times
* because the string is not copied.
*/
void hpsb_register_highlevel(struct hpsb_highlevel *hl); void hpsb_register_highlevel(struct hpsb_highlevel *hl);
void hpsb_unregister_highlevel(struct hpsb_highlevel *hl); void hpsb_unregister_highlevel(struct hpsb_highlevel *hl);
/*
* Register handlers for host address spaces. Start and end are 48 bit pointers
* and have to be quadlet aligned. Argument "end" points to the first address
* behind the handled addresses. This function can be called multiple times for
* a single hpsb_highlevel to implement sparse register sets. The requested
* region must not overlap any previously allocated region, otherwise
* registering will fail.
*
* It returns true for successful allocation. Address spaces can be
* unregistered with hpsb_unregister_addrspace. All remaining address spaces
* are automatically deallocated together with the hpsb_highlevel.
*/
u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl, u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
struct hpsb_host *host, struct hpsb_host *host,
struct hpsb_address_ops *ops, struct hpsb_address_ops *ops,
...@@ -152,45 +125,19 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host, ...@@ -152,45 +125,19 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
struct hpsb_address_ops *ops, u64 start, u64 end); struct hpsb_address_ops *ops, u64 start, u64 end);
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host, int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
u64 start); u64 start);
/*
* Enable or disable receving a certain isochronous channel through the
* iso_receive op.
*/
int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned int channel); unsigned int channel);
void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned int channel); unsigned int channel);
/* Retrieve a hostinfo pointer bound to this driver/host */
void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host); void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
/* Allocate a hostinfo pointer of data_size bound to this driver/host */
void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
size_t data_size); size_t data_size);
/* Free and remove the hostinfo pointer bound to this driver/host */
void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host); void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
/* Set an alternate lookup key for the hostinfo bound to this driver/host */
void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned long key); unsigned long key);
/* Retrieve the alternate lookup key for the hostinfo bound to this
* driver/host */
unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl,
struct hpsb_host *host);
/* Retrieve a hostinfo pointer bound to this driver using its alternate key */
void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key); void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key);
/* Set the hostinfo pointer to something useful. Usually follows a call to
* hpsb_create_hostinfo, where the size is 0. */
int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
void *data); void *data);
/* Retrieve hpsb_host using a highlevel handle and a key */
struct hpsb_host *hpsb_get_host_bykey(struct hpsb_highlevel *hl,
unsigned long key);
#endif /* IEEE1394_HIGHLEVEL_H */ #endif /* IEEE1394_HIGHLEVEL_H */
...@@ -94,14 +94,6 @@ static int alloc_hostnum_cb(struct hpsb_host *host, void *__data) ...@@ -94,14 +94,6 @@ static int alloc_hostnum_cb(struct hpsb_host *host, void *__data)
return 0; return 0;
} }
/*
* The pending_packet_queue is special in that it's processed
* from hardirq context too (such as hpsb_bus_reset()). Hence
* split the lock class from the usual networking skb-head
* lock class by using a separate key for it:
*/
static struct lock_class_key pending_packet_queue_key;
static DEFINE_MUTEX(host_num_alloc); static DEFINE_MUTEX(host_num_alloc);
/** /**
...@@ -137,9 +129,7 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra, ...@@ -137,9 +129,7 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
h->hostdata = h + 1; h->hostdata = h + 1;
h->driver = drv; h->driver = drv;
skb_queue_head_init(&h->pending_packet_queue); INIT_LIST_HEAD(&h->pending_packets);
lockdep_set_class(&h->pending_packet_queue.lock,
&pending_packet_queue_key);
INIT_LIST_HEAD(&h->addr_space); INIT_LIST_HEAD(&h->addr_space);
for (i = 2; i < 16; i++) for (i = 2; i < 16; i++)
...@@ -190,7 +180,7 @@ int hpsb_add_host(struct hpsb_host *host) ...@@ -190,7 +180,7 @@ int hpsb_add_host(struct hpsb_host *host)
{ {
if (hpsb_default_host_entry(host)) if (hpsb_default_host_entry(host))
return -ENOMEM; return -ENOMEM;
hpsb_add_extra_config_roms(host);
highlevel_add_host(host); highlevel_add_host(host);
return 0; return 0;
} }
...@@ -212,12 +202,19 @@ void hpsb_remove_host(struct hpsb_host *host) ...@@ -212,12 +202,19 @@ void hpsb_remove_host(struct hpsb_host *host)
host->driver = &dummy_driver; host->driver = &dummy_driver;
highlevel_remove_host(host); highlevel_remove_host(host);
hpsb_remove_extra_config_roms(host);
class_device_unregister(&host->class_dev); class_device_unregister(&host->class_dev);
device_unregister(&host->device); device_unregister(&host->device);
} }
/**
* hpsb_update_config_rom_image - updates configuration ROM image of a host
*
* 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) int hpsb_update_config_rom_image(struct hpsb_host *host)
{ {
unsigned long reset_delay; unsigned long reset_delay;
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/skbuff.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
...@@ -25,8 +24,7 @@ struct hpsb_host { ...@@ -25,8 +24,7 @@ struct hpsb_host {
atomic_t generation; atomic_t generation;
struct sk_buff_head pending_packet_queue; struct list_head pending_packets;
struct timer_list timeout; struct timer_list timeout;
unsigned long timeout_interval; unsigned long timeout_interval;
...@@ -202,12 +200,6 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra, ...@@ -202,12 +200,6 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
int hpsb_add_host(struct hpsb_host *host); int hpsb_add_host(struct hpsb_host *host);
void hpsb_resume_host(struct hpsb_host *host); void hpsb_resume_host(struct hpsb_host *host);
void hpsb_remove_host(struct hpsb_host *host); void hpsb_remove_host(struct hpsb_host *host);
/* 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); int hpsb_update_config_rom_image(struct hpsb_host *host);
#endif /* _IEEE1394_HOSTS_H */ #endif /* _IEEE1394_HOSTS_H */
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/kdev_t.h> #include <linux/kdev_t.h>
#include <linux/skbuff.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/preempt.h> #include <linux/preempt.h>
...@@ -96,13 +95,15 @@ static void queue_packet_complete(struct hpsb_packet *packet); ...@@ -96,13 +95,15 @@ static void queue_packet_complete(struct hpsb_packet *packet);
/** /**
* hpsb_set_packet_complete_task - set the task that runs when a packet * hpsb_set_packet_complete_task - set task that runs when a packet completes
* completes. You cannot call this more than once on a single packet
* before it is sent.
*
* @packet: the packet whose completion we want the task added to * @packet: the packet whose completion we want the task added to
* @routine: function to call * @routine: function to call
* @data: data (if any) to pass to the above function * @data: data (if any) to pass to the above function
*
* Set the task that runs when a packet completes. You cannot call this more
* than once on a single packet before it is sent.
*
* Typically, the complete @routine is responsible to call hpsb_free_packet().
*/ */
void hpsb_set_packet_complete_task(struct hpsb_packet *packet, void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
void (*routine)(void *), void *data) void (*routine)(void *), void *data)
...@@ -115,12 +116,12 @@ void hpsb_set_packet_complete_task(struct hpsb_packet *packet, ...@@ -115,12 +116,12 @@ void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
/** /**
* hpsb_alloc_packet - allocate new packet structure * hpsb_alloc_packet - allocate new packet structure
* @data_size: size of the data block to be allocated * @data_size: size of the data block to be allocated, in bytes
* *
* This function allocates, initializes and returns a new &struct hpsb_packet. * This function allocates, initializes and returns a new &struct hpsb_packet.
* It can be used in interrupt context. A header block is always included, its * It can be used in interrupt context. A header block is always included and
* size is big enough to contain all possible 1394 headers. The data block is * initialized with zeros. Its size is big enough to contain all possible 1394
* only allocated when @data_size is not zero. * headers. The data block is only allocated if @data_size is not zero.
* *
* For packets for which responses will be received the @data_size has to be big * For packets for which responses will be received the @data_size has to be big
* enough to contain the response's data block since no further allocation * enough to contain the response's data block since no further allocation
...@@ -135,50 +136,49 @@ void hpsb_set_packet_complete_task(struct hpsb_packet *packet, ...@@ -135,50 +136,49 @@ void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
*/ */
struct hpsb_packet *hpsb_alloc_packet(size_t data_size) struct hpsb_packet *hpsb_alloc_packet(size_t data_size)
{ {
struct hpsb_packet *packet = NULL; struct hpsb_packet *packet;
struct sk_buff *skb;
data_size = ((data_size + 3) & ~3); data_size = ((data_size + 3) & ~3);
skb = alloc_skb(data_size + sizeof(*packet), GFP_ATOMIC); packet = kzalloc(sizeof(*packet) + data_size, GFP_ATOMIC);
if (skb == NULL) if (!packet)
return NULL; return NULL;
memset(skb->data, 0, data_size + sizeof(*packet));
packet = (struct hpsb_packet *)skb->data;
packet->skb = skb;
packet->header = packet->embedded_header;
packet->state = hpsb_unused; packet->state = hpsb_unused;
packet->generation = -1; packet->generation = -1;
INIT_LIST_HEAD(&packet->driver_list); INIT_LIST_HEAD(&packet->driver_list);
INIT_LIST_HEAD(&packet->queue);
atomic_set(&packet->refcnt, 1); atomic_set(&packet->refcnt, 1);
if (data_size) { if (data_size) {
packet->data = (quadlet_t *)(skb->data + sizeof(*packet)); packet->data = packet->embedded_data;
packet->data_size = data_size; packet->allocated_data_size = data_size;
} }
return packet; return packet;
} }
/** /**
* hpsb_free_packet - free packet and data associated with it * hpsb_free_packet - free packet and data associated with it
* @packet: packet to free (is NULL safe) * @packet: packet to free (is NULL safe)
* *
* This function will free packet->data and finally the packet itself. * Frees @packet->data only if it was allocated through hpsb_alloc_packet().
*/ */
void hpsb_free_packet(struct hpsb_packet *packet) void hpsb_free_packet(struct hpsb_packet *packet)
{ {
if (packet && atomic_dec_and_test(&packet->refcnt)) { if (packet && atomic_dec_and_test(&packet->refcnt)) {
BUG_ON(!list_empty(&packet->driver_list)); BUG_ON(!list_empty(&packet->driver_list) ||
kfree_skb(packet->skb); !list_empty(&packet->queue));
kfree(packet);
} }
} }
/**
* hpsb_reset_bus - initiate bus reset on the given host
* @host: host controller whose bus to reset
* @type: one of enum reset_types
*
* Returns 1 if bus reset already in progress, 0 otherwise.
*/
int hpsb_reset_bus(struct hpsb_host *host, int type) int hpsb_reset_bus(struct hpsb_host *host, int type)
{ {
if (!host->in_bus_reset) { if (!host->in_bus_reset) {
...@@ -229,6 +229,14 @@ int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer, ...@@ -229,6 +229,14 @@ int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
return 0; return 0;
} }
/**
* hpsb_bus_reset - notify a bus reset to the core
*
* For host driver module usage. Safe to use in interrupt context, although
* quite complex; so you may want to run it in the bottom rather than top half.
*
* Returns 1 if bus reset already in progress, 0 otherwise.
*/
int hpsb_bus_reset(struct hpsb_host *host) int hpsb_bus_reset(struct hpsb_host *host)
{ {
if (host->in_bus_reset) { if (host->in_bus_reset) {
...@@ -405,6 +413,14 @@ static void build_speed_map(struct hpsb_host *host, int nodecount) ...@@ -405,6 +413,14 @@ static void build_speed_map(struct hpsb_host *host, int nodecount)
} }
/**
* hpsb_selfid_received - hand over received selfid packet to the core
*
* For host driver module usage. Safe to use in interrupt context.
*
* The host driver should have done a successful complement check (second
* quadlet is complement of first) beforehand.
*/
void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid) void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
{ {
if (host->in_bus_reset) { if (host->in_bus_reset) {
...@@ -416,6 +432,15 @@ void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid) ...@@ -416,6 +432,15 @@ void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
} }
} }
/**
* hpsb_selfid_complete - notify completion of SelfID stage to the core
*
* For host driver module usage. Safe to use in interrupt context, although
* quite complex; so you may want to run it in the bottom rather than top half.
*
* Notify completion of SelfID stage to the core and report new physical ID
* and whether host is root now.
*/
void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot) void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
{ {
if (!host->in_bus_reset) if (!host->in_bus_reset)
...@@ -462,30 +487,41 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot) ...@@ -462,30 +487,41 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
highlevel_host_reset(host); highlevel_host_reset(host);
} }
static spinlock_t pending_packets_lock = SPIN_LOCK_UNLOCKED;
/**
* hpsb_packet_sent - notify core of sending a packet
*
* For host driver module usage. Safe to call from within a transmit packet
* routine.
*
* Notify core of sending a packet. Ackcode is the ack code returned for async
* transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE
* for other cases (internal errors that don't justify a panic).
*/
void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
int ackcode) int ackcode)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&host->pending_packet_queue.lock, flags); spin_lock_irqsave(&pending_packets_lock, flags);
packet->ack_code = ackcode; packet->ack_code = ackcode;
if (packet->no_waiter || packet->state == hpsb_complete) { if (packet->no_waiter || packet->state == hpsb_complete) {
/* if packet->no_waiter, must not have a tlabel allocated */ /* if packet->no_waiter, must not have a tlabel allocated */
spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags); spin_unlock_irqrestore(&pending_packets_lock, flags);
hpsb_free_packet(packet); hpsb_free_packet(packet);
return; return;
} }
atomic_dec(&packet->refcnt); /* drop HC's reference */ atomic_dec(&packet->refcnt); /* drop HC's reference */
/* here the packet must be on the host->pending_packet_queue */ /* here the packet must be on the host->pending_packets queue */
if (ackcode != ACK_PENDING || !packet->expect_response) { if (ackcode != ACK_PENDING || !packet->expect_response) {
packet->state = hpsb_complete; packet->state = hpsb_complete;
__skb_unlink(packet->skb, &host->pending_packet_queue); list_del_init(&packet->queue);
spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags); spin_unlock_irqrestore(&pending_packets_lock, flags);
queue_packet_complete(packet); queue_packet_complete(packet);
return; return;
} }
...@@ -493,7 +529,7 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, ...@@ -493,7 +529,7 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
packet->state = hpsb_pending; packet->state = hpsb_pending;
packet->sendtime = jiffies; packet->sendtime = jiffies;
spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags); spin_unlock_irqrestore(&pending_packets_lock, flags);
mod_timer(&host->timeout, jiffies + host->timeout_interval); mod_timer(&host->timeout, jiffies + host->timeout_interval);
} }
...@@ -504,9 +540,10 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, ...@@ -504,9 +540,10 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
* @rootid: root whose force_root bit should get set (-1 = don't set force_root) * @rootid: root whose force_root bit should get set (-1 = don't set force_root)
* @gapcnt: gap count value to set (-1 = don't set gap count) * @gapcnt: gap count value to set (-1 = don't set gap count)
* *
* This function sends a PHY config packet on the bus through the specified host. * This function sends a PHY config packet on the bus through the specified
* host.
* *
* Return value: 0 for success or error number otherwise. * Return value: 0 for success or negative error number otherwise.
*/ */
int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt) int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt)
{ {
...@@ -567,12 +604,16 @@ int hpsb_send_packet(struct hpsb_packet *packet) ...@@ -567,12 +604,16 @@ int hpsb_send_packet(struct hpsb_packet *packet)
WARN_ON(packet->no_waiter && packet->expect_response); WARN_ON(packet->no_waiter && packet->expect_response);
if (!packet->no_waiter || packet->expect_response) { if (!packet->no_waiter || packet->expect_response) {
unsigned long flags;
atomic_inc(&packet->refcnt); atomic_inc(&packet->refcnt);
/* Set the initial "sendtime" to 10 seconds from now, to /* Set the initial "sendtime" to 10 seconds from now, to
prevent premature expiry. If a packet takes more than prevent premature expiry. If a packet takes more than
10 seconds to hit the wire, we have bigger problems :) */ 10 seconds to hit the wire, we have bigger problems :) */
packet->sendtime = jiffies + 10 * HZ; packet->sendtime = jiffies + 10 * HZ;
skb_queue_tail(&host->pending_packet_queue, packet->skb); spin_lock_irqsave(&pending_packets_lock, flags);
list_add_tail(&packet->queue, &host->pending_packets);
spin_unlock_irqrestore(&pending_packets_lock, flags);
} }
if (packet->node_id == host->node_id) { if (packet->node_id == host->node_id) {
...@@ -621,6 +662,12 @@ static void complete_packet(void *data) ...@@ -621,6 +662,12 @@ static void complete_packet(void *data)
complete((struct completion *) data); complete((struct completion *) data);
} }
/**
* hpsb_send_packet_and_wait - enqueue packet, block until transaction completes
* @packet: packet to send
*
* Return value: 0 on success, negative errno on failure.
*/
int hpsb_send_packet_and_wait(struct hpsb_packet *packet) int hpsb_send_packet_and_wait(struct hpsb_packet *packet)
{ {
struct completion done; struct completion done;
...@@ -642,86 +689,97 @@ static void send_packet_nocare(struct hpsb_packet *packet) ...@@ -642,86 +689,97 @@ static void send_packet_nocare(struct hpsb_packet *packet)
} }
} }
static size_t packet_size_to_data_size(size_t packet_size, size_t header_size,
size_t buffer_size, int tcode)
{
size_t ret = packet_size <= header_size ? 0 : packet_size - header_size;
if (unlikely(ret > buffer_size))
ret = buffer_size;
if (unlikely(ret + header_size != packet_size))
HPSB_ERR("unexpected packet size %zd (tcode %d), bug?",
packet_size, tcode);
return ret;
}
static void handle_packet_response(struct hpsb_host *host, int tcode, static void handle_packet_response(struct hpsb_host *host, int tcode,
quadlet_t *data, size_t size) quadlet_t *data, size_t size)
{ {
struct hpsb_packet *packet = NULL; struct hpsb_packet *packet;
struct sk_buff *skb; int tlabel = (data[0] >> 10) & 0x3f;
int tcode_match = 0; size_t header_size;
int tlabel;
unsigned long flags; unsigned long flags;
tlabel = (data[0] >> 10) & 0x3f; spin_lock_irqsave(&pending_packets_lock, flags);
spin_lock_irqsave(&host->pending_packet_queue.lock, flags);
skb_queue_walk(&host->pending_packet_queue, skb) { list_for_each_entry(packet, &host->pending_packets, queue)
packet = (struct hpsb_packet *)skb->data; if (packet->tlabel == tlabel &&
if ((packet->tlabel == tlabel) packet->node_id == (data[1] >> 16))
&& (packet->node_id == (data[1] >> 16))){ goto found;
break;
}
packet = NULL;
}
if (packet == NULL) { spin_unlock_irqrestore(&pending_packets_lock, flags);
HPSB_DEBUG("unsolicited response packet received - no tlabel match"); HPSB_DEBUG("unsolicited response packet received - %s",
dump_packet("contents", data, 16, -1); "no tlabel match");
spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags); dump_packet("contents", data, 16, -1);
return; return;
}
found:
switch (packet->tcode) { switch (packet->tcode) {
case TCODE_WRITEQ: case TCODE_WRITEQ:
case TCODE_WRITEB: case TCODE_WRITEB:
if (tcode != TCODE_WRITE_RESPONSE) if (unlikely(tcode != TCODE_WRITE_RESPONSE))
break; break;
tcode_match = 1; header_size = 12;
memcpy(packet->header, data, 12); size = 0;
break; goto dequeue;
case TCODE_READQ: case TCODE_READQ:
if (tcode != TCODE_READQ_RESPONSE) if (unlikely(tcode != TCODE_READQ_RESPONSE))
break; break;
tcode_match = 1; header_size = 16;
memcpy(packet->header, data, 16); size = 0;
break; goto dequeue;
case TCODE_READB: case TCODE_READB:
if (tcode != TCODE_READB_RESPONSE) if (unlikely(tcode != TCODE_READB_RESPONSE))
break; break;
tcode_match = 1; header_size = 16;
BUG_ON(packet->skb->len - sizeof(*packet) < size - 16); size = packet_size_to_data_size(size, header_size,
memcpy(packet->header, data, 16); packet->allocated_data_size,
memcpy(packet->data, data + 4, size - 16); tcode);
break; goto dequeue;
case TCODE_LOCK_REQUEST: case TCODE_LOCK_REQUEST:
if (tcode != TCODE_LOCK_RESPONSE) if (unlikely(tcode != TCODE_LOCK_RESPONSE))
break; break;
tcode_match = 1; header_size = 16;
size = min((size - 16), (size_t)8); size = packet_size_to_data_size(min(size, (size_t)(16 + 8)),
BUG_ON(packet->skb->len - sizeof(*packet) < size); header_size,
memcpy(packet->header, data, 16); packet->allocated_data_size,
memcpy(packet->data, data + 4, size); tcode);
break; goto dequeue;
} }
if (!tcode_match) { spin_unlock_irqrestore(&pending_packets_lock, flags);
spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags); HPSB_DEBUG("unsolicited response packet received - %s",
HPSB_INFO("unsolicited response packet received - tcode mismatch"); "tcode mismatch");
dump_packet("contents", data, 16, -1); dump_packet("contents", data, 16, -1);
return; return;
}
__skb_unlink(skb, &host->pending_packet_queue); dequeue:
list_del_init(&packet->queue);
spin_unlock_irqrestore(&pending_packets_lock, flags);
if (packet->state == hpsb_queued) { if (packet->state == hpsb_queued) {
packet->sendtime = jiffies; packet->sendtime = jiffies;
packet->ack_code = ACK_PENDING; packet->ack_code = ACK_PENDING;
} }
packet->state = hpsb_complete; packet->state = hpsb_complete;
spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
memcpy(packet->header, data, header_size);
if (size)
memcpy(packet->data, data + 4, size);
queue_packet_complete(packet); queue_packet_complete(packet);
} }
...@@ -735,6 +793,7 @@ static struct hpsb_packet *create_reply_packet(struct hpsb_host *host, ...@@ -735,6 +793,7 @@ static struct hpsb_packet *create_reply_packet(struct hpsb_host *host,
p = hpsb_alloc_packet(dsize); p = hpsb_alloc_packet(dsize);
if (unlikely(p == NULL)) { if (unlikely(p == NULL)) {
/* FIXME - send data_error response */ /* FIXME - send data_error response */
HPSB_ERR("out of memory, cannot send response packet");
return NULL; return NULL;
} }
...@@ -784,7 +843,6 @@ static void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode, ...@@ -784,7 +843,6 @@ static void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode,
static void fill_async_write_resp(struct hpsb_packet *packet, int rcode) static void fill_async_write_resp(struct hpsb_packet *packet, int rcode)
{ {
PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE); PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE);
packet->header[2] = 0;
packet->header_size = 12; packet->header_size = 12;
packet->data_size = 0; packet->data_size = 0;
} }
...@@ -801,12 +859,9 @@ static void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extc ...@@ -801,12 +859,9 @@ static void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extc
packet->data_size = length; packet->data_size = length;
} }
#define PREP_REPLY_PACKET(length) \
packet = create_reply_packet(host, data, length); \
if (packet == NULL) break
static void handle_incoming_packet(struct hpsb_host *host, int tcode, static void handle_incoming_packet(struct hpsb_host *host, int tcode,
quadlet_t *data, size_t size, int write_acked) quadlet_t *data, size_t size,
int write_acked)
{ {
struct hpsb_packet *packet; struct hpsb_packet *packet;
int length, rcode, extcode; int length, rcode, extcode;
...@@ -816,74 +871,72 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode, ...@@ -816,74 +871,72 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode,
u16 flags = (u16) data[0]; u16 flags = (u16) data[0];
u64 addr; u64 addr;
/* big FIXME - no error checking is done for an out of bounds length */ /* FIXME?
* Out-of-bounds lengths are left for highlevel_read|write to cap. */
switch (tcode) { switch (tcode) {
case TCODE_WRITEQ: case TCODE_WRITEQ:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
rcode = highlevel_write(host, source, dest, data+3, rcode = highlevel_write(host, source, dest, data + 3,
addr, 4, flags); addr, 4, flags);
goto handle_write_request;
if (!write_acked
&& (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK)
&& (rcode >= 0)) {
/* not a broadcast write, reply */
PREP_REPLY_PACKET(0);
fill_async_write_resp(packet, rcode);
send_packet_nocare(packet);
}
break;
case TCODE_WRITEB: case TCODE_WRITEB:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
rcode = highlevel_write(host, source, dest, data+4, rcode = highlevel_write(host, source, dest, data + 4,
addr, data[3]>>16, flags); addr, data[3] >> 16, flags);
handle_write_request:
if (!write_acked if (rcode < 0 || write_acked ||
&& (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK) NODEID_TO_NODE(data[0] >> 16) == NODE_MASK)
&& (rcode >= 0)) { return;
/* not a broadcast write, reply */ /* not a broadcast write, reply */
PREP_REPLY_PACKET(0); packet = create_reply_packet(host, data, 0);
if (packet) {
fill_async_write_resp(packet, rcode); fill_async_write_resp(packet, rcode);
send_packet_nocare(packet); send_packet_nocare(packet);
} }
break; return;
case TCODE_READQ: case TCODE_READQ:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
rcode = highlevel_read(host, source, &buffer, addr, 4, flags); rcode = highlevel_read(host, source, &buffer, addr, 4, flags);
if (rcode < 0)
return;
if (rcode >= 0) { packet = create_reply_packet(host, data, 0);
PREP_REPLY_PACKET(0); if (packet) {
fill_async_readquad_resp(packet, rcode, buffer); fill_async_readquad_resp(packet, rcode, buffer);
send_packet_nocare(packet); send_packet_nocare(packet);
} }
break; return;
case TCODE_READB: case TCODE_READB:
length = data[3] >> 16; length = data[3] >> 16;
PREP_REPLY_PACKET(length); packet = create_reply_packet(host, data, length);
if (!packet)
return;
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
rcode = highlevel_read(host, source, packet->data, addr, rcode = highlevel_read(host, source, packet->data, addr,
length, flags); length, flags);
if (rcode < 0) {
if (rcode >= 0) {
fill_async_readblock_resp(packet, rcode, length);
send_packet_nocare(packet);
} else {
hpsb_free_packet(packet); hpsb_free_packet(packet);
return;
} }
break; fill_async_readblock_resp(packet, rcode, length);
send_packet_nocare(packet);
return;
case TCODE_LOCK_REQUEST: case TCODE_LOCK_REQUEST:
length = data[3] >> 16; length = data[3] >> 16;
extcode = data[3] & 0xffff; extcode = data[3] & 0xffff;
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
PREP_REPLY_PACKET(8); packet = create_reply_packet(host, data, 8);
if (!packet)
return;
if ((extcode == 0) || (extcode >= 7)) { if (extcode == 0 || extcode >= 7) {
/* let switch default handle error */ /* let switch default handle error */
length = 0; length = 0;
} }
...@@ -891,12 +944,12 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode, ...@@ -891,12 +944,12 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode,
switch (length) { switch (length) {
case 4: case 4:
rcode = highlevel_lock(host, source, packet->data, addr, rcode = highlevel_lock(host, source, packet->data, addr,
data[4], 0, extcode,flags); data[4], 0, extcode, flags);
fill_async_lock_resp(packet, rcode, extcode, 4); fill_async_lock_resp(packet, rcode, extcode, 4);
break; break;
case 8: case 8:
if ((extcode != EXTCODE_FETCH_ADD) if (extcode != EXTCODE_FETCH_ADD &&
&& (extcode != EXTCODE_LITTLE_ADD)) { extcode != EXTCODE_LITTLE_ADD) {
rcode = highlevel_lock(host, source, rcode = highlevel_lock(host, source,
packet->data, addr, packet->data, addr,
data[5], data[4], data[5], data[4],
...@@ -920,29 +973,38 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode, ...@@ -920,29 +973,38 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode,
break; break;
default: default:
rcode = RCODE_TYPE_ERROR; rcode = RCODE_TYPE_ERROR;
fill_async_lock_resp(packet, rcode, fill_async_lock_resp(packet, rcode, extcode, 0);
extcode, 0);
} }
if (rcode >= 0) { if (rcode < 0)
send_packet_nocare(packet);
} else {
hpsb_free_packet(packet); hpsb_free_packet(packet);
} else
break; send_packet_nocare(packet);
return;
} }
} }
#undef PREP_REPLY_PACKET
/**
* hpsb_packet_received - hand over received packet to the core
*
* For host driver module usage.
*
* The contents of data are expected to be the full packet but with the CRCs
* left out (data block follows header immediately), with the header (i.e. the
* first four quadlets) in machine byte order and the data block in big endian.
* *@data can be safely overwritten after this call.
*
* If the packet is a write request, @write_acked is to be set to true if it was
* ack_complete'd already, false otherwise. This argument is ignored for any
* other packet type.
*/
void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size, void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
int write_acked) int write_acked)
{ {
int tcode; int tcode;
if (host->in_bus_reset) { if (unlikely(host->in_bus_reset)) {
HPSB_INFO("received packet during reset; ignoring"); HPSB_DEBUG("received packet during reset; ignoring");
return; return;
} }
...@@ -976,23 +1038,27 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size, ...@@ -976,23 +1038,27 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
break; break;
default: default:
HPSB_NOTICE("received packet with bogus transaction code %d", HPSB_DEBUG("received packet with bogus transaction code %d",
tcode); tcode);
break; break;
} }
} }
static void abort_requests(struct hpsb_host *host) static void abort_requests(struct hpsb_host *host)
{ {
struct hpsb_packet *packet; struct hpsb_packet *packet, *p;
struct sk_buff *skb; struct list_head tmp;
unsigned long flags;
host->driver->devctl(host, CANCEL_REQUESTS, 0); host->driver->devctl(host, CANCEL_REQUESTS, 0);
while ((skb = skb_dequeue(&host->pending_packet_queue)) != NULL) { INIT_LIST_HEAD(&tmp);
packet = (struct hpsb_packet *)skb->data; spin_lock_irqsave(&pending_packets_lock, flags);
list_splice_init(&host->pending_packets, &tmp);
spin_unlock_irqrestore(&pending_packets_lock, flags);
list_for_each_entry_safe(packet, p, &tmp, queue) {
list_del_init(&packet->queue);
packet->state = hpsb_complete; packet->state = hpsb_complete;
packet->ack_code = ACKX_ABORTED; packet->ack_code = ACKX_ABORTED;
queue_packet_complete(packet); queue_packet_complete(packet);
...@@ -1002,87 +1068,90 @@ static void abort_requests(struct hpsb_host *host) ...@@ -1002,87 +1068,90 @@ static void abort_requests(struct hpsb_host *host)
void abort_timedouts(unsigned long __opaque) void abort_timedouts(unsigned long __opaque)
{ {
struct hpsb_host *host = (struct hpsb_host *)__opaque; struct hpsb_host *host = (struct hpsb_host *)__opaque;
unsigned long flags; struct hpsb_packet *packet, *p;
struct hpsb_packet *packet; struct list_head tmp;
struct sk_buff *skb; unsigned long flags, expire, j;
unsigned long expire;
spin_lock_irqsave(&host->csr.lock, flags); spin_lock_irqsave(&host->csr.lock, flags);
expire = host->csr.expire; expire = host->csr.expire;
spin_unlock_irqrestore(&host->csr.lock, flags); spin_unlock_irqrestore(&host->csr.lock, flags);
/* Hold the lock around this, since we aren't dequeuing all j = jiffies;
* packets, just ones we need. */ INIT_LIST_HEAD(&tmp);
spin_lock_irqsave(&host->pending_packet_queue.lock, flags); spin_lock_irqsave(&pending_packets_lock, flags);
while (!skb_queue_empty(&host->pending_packet_queue)) {
skb = skb_peek(&host->pending_packet_queue);
packet = (struct hpsb_packet *)skb->data;
if (time_before(packet->sendtime + expire, jiffies)) { list_for_each_entry_safe(packet, p, &host->pending_packets, queue) {
__skb_unlink(skb, &host->pending_packet_queue); if (time_before(packet->sendtime + expire, j))
packet->state = hpsb_complete; list_move_tail(&packet->queue, &tmp);
packet->ack_code = ACKX_TIMEOUT; else
queue_packet_complete(packet);
} else {
/* Since packets are added to the tail, the oldest /* Since packets are added to the tail, the oldest
* ones are first, always. When we get to one that * ones are first, always. When we get to one that
* isn't timed out, the rest aren't either. */ * isn't timed out, the rest aren't either. */
break; break;
}
} }
if (!list_empty(&host->pending_packets))
mod_timer(&host->timeout, j + host->timeout_interval);
if (!skb_queue_empty(&host->pending_packet_queue)) spin_unlock_irqrestore(&pending_packets_lock, flags);
mod_timer(&host->timeout, jiffies + host->timeout_interval);
spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags); list_for_each_entry_safe(packet, p, &tmp, queue) {
list_del_init(&packet->queue);
packet->state = hpsb_complete;
packet->ack_code = ACKX_TIMEOUT;
queue_packet_complete(packet);
}
} }
/* Kernel thread and vars, which handles packets that are completed. Only
* packets that have a "complete" function are sent here. This way, the
* completion is run out of kernel context, and doesn't block the rest of
* the stack. */
static struct task_struct *khpsbpkt_thread; static struct task_struct *khpsbpkt_thread;
static struct sk_buff_head hpsbpkt_queue; static LIST_HEAD(hpsbpkt_queue);
static void queue_packet_complete(struct hpsb_packet *packet) static void queue_packet_complete(struct hpsb_packet *packet)
{ {
unsigned long flags;
if (packet->no_waiter) { if (packet->no_waiter) {
hpsb_free_packet(packet); hpsb_free_packet(packet);
return; return;
} }
if (packet->complete_routine != NULL) { if (packet->complete_routine != NULL) {
skb_queue_tail(&hpsbpkt_queue, packet->skb); spin_lock_irqsave(&pending_packets_lock, flags);
list_add_tail(&packet->queue, &hpsbpkt_queue);
spin_unlock_irqrestore(&pending_packets_lock, flags);
wake_up_process(khpsbpkt_thread); wake_up_process(khpsbpkt_thread);
} }
return; return;
} }
/*
* Kernel thread which handles packets that are completed. This way the
* packet's "complete" function is asynchronously run in process context.
* Only packets which have a "complete" function may be sent here.
*/
static int hpsbpkt_thread(void *__hi) static int hpsbpkt_thread(void *__hi)
{ {
struct sk_buff *skb; struct hpsb_packet *packet, *p;
struct hpsb_packet *packet; struct list_head tmp;
void (*complete_routine)(void*); int may_schedule;
void *complete_data;
current->flags |= PF_NOFREEZE; current->flags |= PF_NOFREEZE;
while (!kthread_should_stop()) { while (!kthread_should_stop()) {
while ((skb = skb_dequeue(&hpsbpkt_queue)) != NULL) {
packet = (struct hpsb_packet *)skb->data;
complete_routine = packet->complete_routine;
complete_data = packet->complete_data;
packet->complete_routine = packet->complete_data = NULL; INIT_LIST_HEAD(&tmp);
spin_lock_irq(&pending_packets_lock);
list_splice_init(&hpsbpkt_queue, &tmp);
spin_unlock_irq(&pending_packets_lock);
complete_routine(complete_data); list_for_each_entry_safe(packet, p, &tmp, queue) {
list_del_init(&packet->queue);
packet->complete_routine(packet->complete_data);
} }
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (!skb_peek(&hpsbpkt_queue)) spin_lock_irq(&pending_packets_lock);
may_schedule = list_empty(&hpsbpkt_queue);
spin_unlock_irq(&pending_packets_lock);
if (may_schedule)
schedule(); schedule();
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
} }
...@@ -1093,8 +1162,6 @@ static int __init ieee1394_init(void) ...@@ -1093,8 +1162,6 @@ static int __init ieee1394_init(void)
{ {
int i, ret; int i, ret;
skb_queue_head_init(&hpsbpkt_queue);
/* non-fatal error */ /* non-fatal error */
if (hpsb_init_config_roms()) { if (hpsb_init_config_roms()) {
HPSB_ERR("Failed to initialize some config rom entries.\n"); HPSB_ERR("Failed to initialize some config rom entries.\n");
...@@ -1268,7 +1335,6 @@ EXPORT_SYMBOL(hpsb_destroy_hostinfo); ...@@ -1268,7 +1335,6 @@ EXPORT_SYMBOL(hpsb_destroy_hostinfo);
EXPORT_SYMBOL(hpsb_set_hostinfo_key); EXPORT_SYMBOL(hpsb_set_hostinfo_key);
EXPORT_SYMBOL(hpsb_get_hostinfo_bykey); EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
EXPORT_SYMBOL(hpsb_set_hostinfo); EXPORT_SYMBOL(hpsb_set_hostinfo);
EXPORT_SYMBOL(highlevel_host_reset);
/** nodemgr.c **/ /** nodemgr.c **/
EXPORT_SYMBOL(hpsb_node_fill_packet); EXPORT_SYMBOL(hpsb_node_fill_packet);
...@@ -1311,11 +1377,10 @@ EXPORT_SYMBOL(hpsb_iso_wake); ...@@ -1311,11 +1377,10 @@ EXPORT_SYMBOL(hpsb_iso_wake);
EXPORT_SYMBOL(hpsb_iso_recv_flush); EXPORT_SYMBOL(hpsb_iso_recv_flush);
/** csr1212.c **/ /** csr1212.c **/
EXPORT_SYMBOL(csr1212_new_directory);
EXPORT_SYMBOL(csr1212_attach_keyval_to_directory); EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
EXPORT_SYMBOL(csr1212_detach_keyval_from_directory); EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
EXPORT_SYMBOL(csr1212_release_keyval); EXPORT_SYMBOL(csr1212_get_keyval);
EXPORT_SYMBOL(csr1212_read); EXPORT_SYMBOL(csr1212_new_directory);
EXPORT_SYMBOL(csr1212_parse_keyval); EXPORT_SYMBOL(csr1212_parse_keyval);
EXPORT_SYMBOL(_csr1212_read_keyval); EXPORT_SYMBOL(csr1212_read);
EXPORT_SYMBOL(_csr1212_destroy_keyval); EXPORT_SYMBOL(csr1212_release_keyval);
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/skbuff.h>
#include <linux/types.h> #include <linux/types.h>
#include <asm/atomic.h> #include <asm/atomic.h>
...@@ -13,7 +12,7 @@ ...@@ -13,7 +12,7 @@
struct hpsb_packet { struct hpsb_packet {
/* This struct is basically read-only for hosts with the exception of /* This struct is basically read-only for hosts with the exception of
* the data buffer contents and xnext - see below. */ * the data buffer contents and driver_list. */
/* This can be used for host driver internal linking. /* This can be used for host driver internal linking.
* *
...@@ -49,134 +48,65 @@ struct hpsb_packet { ...@@ -49,134 +48,65 @@ struct hpsb_packet {
/* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */ /* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */
unsigned speed_code:2; unsigned speed_code:2;
/*
* *header and *data are guaranteed to be 32-bit DMAable and may be
* overwritten to allow in-place byte swapping. Neither of these is
* CRCed (the sizes also don't include CRC), but contain space for at
* least one additional quadlet to allow in-place CRCing. The memory is
* also guaranteed to be DMA mappable.
*/
quadlet_t *header;
quadlet_t *data;
size_t header_size;
size_t data_size;
struct hpsb_host *host; struct hpsb_host *host;
unsigned int generation; unsigned int generation;
atomic_t refcnt; atomic_t refcnt;
struct list_head queue;
/* Function (and possible data to pass to it) to call when this /* Function (and possible data to pass to it) to call when this
* packet is completed. */ * packet is completed. */
void (*complete_routine)(void *); void (*complete_routine)(void *);
void *complete_data; void *complete_data;
/* XXX This is just a hack at the moment */
struct sk_buff *skb;
/* Store jiffies for implementing bus timeouts. */ /* Store jiffies for implementing bus timeouts. */
unsigned long sendtime; unsigned long sendtime;
quadlet_t embedded_header[5]; /* Sizes are in bytes. *data can be DMA-mapped. */
size_t allocated_data_size; /* as allocated */
size_t data_size; /* as filled in */
size_t header_size; /* as filled in, not counting the CRC */
quadlet_t *data;
quadlet_t header[5];
quadlet_t embedded_data[0]; /* keep as last member */
}; };
/* Set a task for when a packet completes */
void hpsb_set_packet_complete_task(struct hpsb_packet *packet, void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
void (*routine)(void *), void *data); void (*routine)(void *), void *data);
static inline struct hpsb_packet *driver_packet(struct list_head *l) static inline struct hpsb_packet *driver_packet(struct list_head *l)
{ {
return list_entry(l, struct hpsb_packet, driver_list); return list_entry(l, struct hpsb_packet, driver_list);
} }
void abort_timedouts(unsigned long __opaque); void abort_timedouts(unsigned long __opaque);
struct hpsb_packet *hpsb_alloc_packet(size_t data_size); struct hpsb_packet *hpsb_alloc_packet(size_t data_size);
void hpsb_free_packet(struct hpsb_packet *packet); void hpsb_free_packet(struct hpsb_packet *packet);
/* /**
* Generation counter for the complete 1394 subsystem. Generation gets * get_hpsb_generation - generation counter for the complete 1394 subsystem
* incremented on every change in the subsystem (e.g. bus reset).
* *
* Use the functions, not the variable. * Generation gets incremented on every change in the subsystem (notably on bus
* resets). Use the functions, not the variable.
*/ */
static inline unsigned int get_hpsb_generation(struct hpsb_host *host) static inline unsigned int get_hpsb_generation(struct hpsb_host *host)
{ {
return atomic_read(&host->generation); return atomic_read(&host->generation);
} }
/*
* Send a PHY configuration packet, return 0 on success, negative
* errno on failure.
*/
int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt); int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt);
/*
* Queue packet for transmitting, return 0 on success, negative errno
* on failure.
*/
int hpsb_send_packet(struct hpsb_packet *packet); int hpsb_send_packet(struct hpsb_packet *packet);
/*
* Queue packet for transmitting, and block until the transaction
* completes. Return 0 on success, negative errno on failure.
*/
int hpsb_send_packet_and_wait(struct hpsb_packet *packet); int hpsb_send_packet_and_wait(struct hpsb_packet *packet);
/* Initiate bus reset on the given host. Returns 1 if bus reset already in
* progress, 0 otherwise. */
int hpsb_reset_bus(struct hpsb_host *host, int type); int hpsb_reset_bus(struct hpsb_host *host, int type);
int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer, int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
u64 *local_time); u64 *local_time);
/*
* The following functions are exported for host driver module usage. All of
* them are safe to use in interrupt contexts, although some are quite
* complicated so you may want to run them in bottom halves instead of calling
* them directly.
*/
/* Notify a bus reset to the core. Returns 1 if bus reset already in progress,
* 0 otherwise. */
int hpsb_bus_reset(struct hpsb_host *host); int hpsb_bus_reset(struct hpsb_host *host);
/*
* Hand over received selfid packet to the core. Complement check (second
* quadlet is complement of first) is expected to be done and successful.
*/
void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid); void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid);
/*
* Notify completion of SelfID stage to the core and report new physical ID
* and whether host is root now.
*/
void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot); void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot);
/*
* Notify core of sending a packet. Ackcode is the ack code returned for async
* transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE
* for other cases (internal errors that don't justify a panic). Safe to call
* from within a transmit packet routine.
*/
void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
int ackcode); int ackcode);
/*
* Hand over received packet to the core. The contents of data are expected to
* be the full packet but with the CRCs left out (data block follows header
* immediately), with the header (i.e. the first four quadlets) in machine byte
* order and the data block in big endian. *data can be safely overwritten
* after this call.
*
* If the packet is a write request, write_acked is to be set to true if it was
* ack_complete'd already, false otherwise. This arg is ignored for any other
* packet type.
*/
void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size, void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
int write_acked); int write_acked);
/* /*
* CHARACTER DEVICE DISPATCHING * CHARACTER DEVICE DISPATCHING
* *
...@@ -217,7 +147,9 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size, ...@@ -217,7 +147,9 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
#define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, \ #define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, \
IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16) IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
/* return the index (within a minor number block) of a file */ /**
* ieee1394_file_to_instance - get the index within a minor number block
*/
static inline unsigned char ieee1394_file_to_instance(struct file *file) static inline unsigned char ieee1394_file_to_instance(struct file *file)
{ {
return file->f_path.dentry->d_inode->i_cindex; return file->f_path.dentry->d_inode->i_cindex;
......
...@@ -10,11 +10,16 @@ ...@@ -10,11 +10,16 @@
*/ */
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/compiler.h>
#include <linux/hardirq.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/sched.h> /* because linux/wait.h is broken if CONFIG_SMP=n */
#include <linux/wait.h> #include <linux/wait.h>
#include <asm/bug.h> #include <asm/bug.h>
#include <asm/errno.h> #include <asm/errno.h>
#include <asm/system.h>
#include "ieee1394.h" #include "ieee1394.h"
#include "ieee1394_types.h" #include "ieee1394_types.h"
...@@ -32,7 +37,7 @@ ...@@ -32,7 +37,7 @@
#ifndef HPSB_DEBUG_TLABELS #ifndef HPSB_DEBUG_TLABELS
static static
#endif #endif
spinlock_t hpsb_tlabel_lock = SPIN_LOCK_UNLOCKED; DEFINE_SPINLOCK(hpsb_tlabel_lock);
static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq); static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
...@@ -212,6 +217,15 @@ void hpsb_free_tlabel(struct hpsb_packet *packet) ...@@ -212,6 +217,15 @@ void hpsb_free_tlabel(struct hpsb_packet *packet)
wake_up_interruptible(&tlabel_wq); wake_up_interruptible(&tlabel_wq);
} }
/**
* hpsb_packet_success - Make sense of the ack and reply codes
*
* Make sense of the ack and reply codes and return more convenient error codes:
* 0 = success. -%EBUSY = node is busy, try again. -%EAGAIN = error which can
* probably resolved by retry. -%EREMOTEIO = node suffers from an internal
* error. -%EACCES = this transaction is not allowed on requested address.
* -%EINVAL = invalid address at node.
*/
int hpsb_packet_success(struct hpsb_packet *packet) int hpsb_packet_success(struct hpsb_packet *packet)
{ {
switch (packet->ack_code) { switch (packet->ack_code) {
...@@ -364,6 +378,13 @@ struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 * buffer, ...@@ -364,6 +378,13 @@ struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 * buffer,
} }
packet->host = host; packet->host = host;
/* Because it is too difficult to determine all PHY speeds and link
* speeds here, we use S100... */
packet->speed_code = IEEE1394_SPEED_100;
/* ...and prevent hpsb_send_packet() from overriding it. */
packet->node_id = LOCAL_BUS | ALL_NODES;
if (hpsb_get_tlabel(packet)) { if (hpsb_get_tlabel(packet)) {
hpsb_free_packet(packet); hpsb_free_packet(packet);
return NULL; return NULL;
...@@ -493,6 +514,16 @@ struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host, ...@@ -493,6 +514,16 @@ struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host,
* avoid in kernel buffers for user space callers * avoid in kernel buffers for user space callers
*/ */
/**
* hpsb_read - generic read function
*
* Recognizes the local node ID and act accordingly. Automatically uses a
* quadlet read request if @length == 4 and and a block read request otherwise.
* It does not yet support lengths that are not a multiple of 4.
*
* You must explicitly specifiy the @generation for which the node ID is valid,
* to avoid sending packets to the wrong nodes when we race with a bus reset.
*/
int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation, int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, quadlet_t * buffer, size_t length) u64 addr, quadlet_t * buffer, size_t length)
{ {
...@@ -532,6 +563,16 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation, ...@@ -532,6 +563,16 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
return retval; return retval;
} }
/**
* hpsb_write - generic write function
*
* Recognizes the local node ID and act accordingly. Automatically uses a
* quadlet write request if @length == 4 and and a block write request
* otherwise. It does not yet support lengths that are not a multiple of 4.
*
* You must explicitly specifiy the @generation for which the node ID is valid,
* to avoid sending packets to the wrong nodes when we race with a bus reset.
*/
int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation, int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, quadlet_t * buffer, size_t length) u64 addr, quadlet_t * buffer, size_t length)
{ {
......
...@@ -27,27 +27,7 @@ struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host, ...@@ -27,27 +27,7 @@ struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host,
struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer, struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer,
int length, int channel, int tag, int length, int channel, int tag,
int sync); int sync);
/*
* hpsb_packet_success - Make sense of the ack and reply codes and
* return more convenient error codes:
* 0 success
* -EBUSY node is busy, try again
* -EAGAIN error which can probably resolved by retry
* -EREMOTEIO node suffers from an internal error
* -EACCES this transaction is not allowed on requested address
* -EINVAL invalid address at node
*/
int hpsb_packet_success(struct hpsb_packet *packet); int hpsb_packet_success(struct hpsb_packet *packet);
/*
* The generic read and write functions. All recognize the local node ID
* and act accordingly. Read and write automatically use quadlet commands if
* length == 4 and and block commands otherwise (however, they do not yet
* support lengths that are not a multiple of 4). You must explicitly specifiy
* the generation for which the node ID is valid, to avoid sending packets to
* the wrong nodes when we race with a bus reset.
*/
int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation, int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, quadlet_t *buffer, size_t length); u64 addr, quadlet_t *buffer, size_t length);
int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation, int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
......
...@@ -10,11 +10,15 @@ ...@@ -10,11 +10,15 @@
*/ */
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "hosts.h" #include "hosts.h"
#include "iso.h" #include "iso.h"
/**
* hpsb_iso_stop - stop DMA
*/
void hpsb_iso_stop(struct hpsb_iso *iso) void hpsb_iso_stop(struct hpsb_iso *iso)
{ {
if (!(iso->flags & HPSB_ISO_DRIVER_STARTED)) if (!(iso->flags & HPSB_ISO_DRIVER_STARTED))
...@@ -25,6 +29,9 @@ void hpsb_iso_stop(struct hpsb_iso *iso) ...@@ -25,6 +29,9 @@ void hpsb_iso_stop(struct hpsb_iso *iso)
iso->flags &= ~HPSB_ISO_DRIVER_STARTED; iso->flags &= ~HPSB_ISO_DRIVER_STARTED;
} }
/**
* hpsb_iso_shutdown - deallocate buffer and DMA context
*/
void hpsb_iso_shutdown(struct hpsb_iso *iso) void hpsb_iso_shutdown(struct hpsb_iso *iso)
{ {
if (iso->flags & HPSB_ISO_DRIVER_INIT) { if (iso->flags & HPSB_ISO_DRIVER_INIT) {
...@@ -130,6 +137,9 @@ static struct hpsb_iso *hpsb_iso_common_init(struct hpsb_host *host, ...@@ -130,6 +137,9 @@ static struct hpsb_iso *hpsb_iso_common_init(struct hpsb_host *host,
return NULL; return NULL;
} }
/**
* hpsb_iso_n_ready - returns number of packets ready to send or receive
*/
int hpsb_iso_n_ready(struct hpsb_iso *iso) int hpsb_iso_n_ready(struct hpsb_iso *iso)
{ {
unsigned long flags; unsigned long flags;
...@@ -142,6 +152,9 @@ int hpsb_iso_n_ready(struct hpsb_iso *iso) ...@@ -142,6 +152,9 @@ int hpsb_iso_n_ready(struct hpsb_iso *iso)
return val; return val;
} }
/**
* hpsb_iso_xmit_init - allocate the buffer and DMA context
*/
struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host, struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
unsigned int data_buf_size, unsigned int data_buf_size,
unsigned int buf_packets, unsigned int buf_packets,
...@@ -172,6 +185,11 @@ struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host, ...@@ -172,6 +185,11 @@ struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
return NULL; return NULL;
} }
/**
* hpsb_iso_recv_init - allocate the buffer and DMA context
*
* Note, if channel = -1, multi-channel receive is enabled.
*/
struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host, struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
unsigned int data_buf_size, unsigned int data_buf_size,
unsigned int buf_packets, unsigned int buf_packets,
...@@ -199,6 +217,11 @@ struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host, ...@@ -199,6 +217,11 @@ struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
return NULL; return NULL;
} }
/**
* hpsb_iso_recv_listen_channel
*
* multi-channel only
*/
int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel) int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
{ {
if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64) if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
...@@ -206,6 +229,11 @@ int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel) ...@@ -206,6 +229,11 @@ int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel); return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel);
} }
/**
* hpsb_iso_recv_unlisten_channel
*
* multi-channel only
*/
int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel) int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
{ {
if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64) if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
...@@ -213,6 +241,11 @@ int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel) ...@@ -213,6 +241,11 @@ int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel); return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel);
} }
/**
* hpsb_iso_recv_set_channel_mask
*
* multi-channel only
*/
int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask) int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
{ {
if (iso->type != HPSB_ISO_RECV || iso->channel != -1) if (iso->type != HPSB_ISO_RECV || iso->channel != -1)
...@@ -221,6 +254,12 @@ int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask) ...@@ -221,6 +254,12 @@ int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
(unsigned long)&mask); (unsigned long)&mask);
} }
/**
* hpsb_iso_recv_flush - check for arrival of new packets
*
* check for arrival of new packets immediately (even if irq_interval
* has not yet been reached)
*/
int hpsb_iso_recv_flush(struct hpsb_iso *iso) int hpsb_iso_recv_flush(struct hpsb_iso *iso)
{ {
if (iso->type != HPSB_ISO_RECV) if (iso->type != HPSB_ISO_RECV)
...@@ -238,6 +277,9 @@ static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle) ...@@ -238,6 +277,9 @@ static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle)
return retval; return retval;
} }
/**
* hpsb_iso_xmit_start - start DMA
*/
int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer) int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
{ {
if (iso->type != HPSB_ISO_XMIT) if (iso->type != HPSB_ISO_XMIT)
...@@ -270,6 +312,9 @@ int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer) ...@@ -270,6 +312,9 @@ int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
return 0; return 0;
} }
/**
* hpsb_iso_recv_start - start DMA
*/
int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync) int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
{ {
int retval = 0; int retval = 0;
...@@ -306,8 +351,7 @@ int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync) ...@@ -306,8 +351,7 @@ int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
} }
/* check to make sure the user has not supplied bogus values of offset/len /* check to make sure the user has not supplied bogus values of offset/len
that would cause the kernel to access memory outside the buffer */ * that would cause the kernel to access memory outside the buffer */
static int hpsb_iso_check_offset_len(struct hpsb_iso *iso, static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
unsigned int offset, unsigned short len, unsigned int offset, unsigned short len,
unsigned int *out_offset, unsigned int *out_offset,
...@@ -331,6 +375,12 @@ static int hpsb_iso_check_offset_len(struct hpsb_iso *iso, ...@@ -331,6 +375,12 @@ static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
return 0; return 0;
} }
/**
* hpsb_iso_xmit_queue_packet - queue a packet for transmission.
*
* @offset is relative to the beginning of the DMA buffer, where the packet's
* data payload should already have been placed.
*/
int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
u8 tag, u8 sy) u8 tag, u8 sy)
{ {
...@@ -380,6 +430,9 @@ int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, ...@@ -380,6 +430,9 @@ int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
return rv; return rv;
} }
/**
* hpsb_iso_xmit_sync - wait until all queued packets have been transmitted
*/
int hpsb_iso_xmit_sync(struct hpsb_iso *iso) int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
{ {
if (iso->type != HPSB_ISO_XMIT) if (iso->type != HPSB_ISO_XMIT)
...@@ -390,6 +443,15 @@ int hpsb_iso_xmit_sync(struct hpsb_iso *iso) ...@@ -390,6 +443,15 @@ int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
iso->buf_packets); iso->buf_packets);
} }
/**
* hpsb_iso_packet_sent
*
* Available to low-level drivers.
*
* Call after a packet has been transmitted to the bus (interrupt context is
* OK). @cycle is the _exact_ cycle the packet was sent on. @error should be
* non-zero if some sort of error occurred when sending the packet.
*/
void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error) void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
{ {
unsigned long flags; unsigned long flags;
...@@ -413,6 +475,13 @@ void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error) ...@@ -413,6 +475,13 @@ void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
spin_unlock_irqrestore(&iso->lock, flags); spin_unlock_irqrestore(&iso->lock, flags);
} }
/**
* hpsb_iso_packet_received
*
* Available to low-level drivers.
*
* Call after a packet has been received (interrupt context is OK).
*/
void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
u16 total_len, u16 cycle, u8 channel, u8 tag, u16 total_len, u16 cycle, u8 channel, u8 tag,
u8 sy) u8 sy)
...@@ -442,6 +511,11 @@ void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, ...@@ -442,6 +511,11 @@ void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
spin_unlock_irqrestore(&iso->lock, flags); spin_unlock_irqrestore(&iso->lock, flags);
} }
/**
* hpsb_iso_recv_release_packets - release packets, reuse buffer
*
* @n_packets have been read out of the buffer, re-use the buffer space
*/
int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets) int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
{ {
unsigned long flags; unsigned long flags;
...@@ -477,6 +551,13 @@ int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets) ...@@ -477,6 +551,13 @@ int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
return rv; return rv;
} }
/**
* hpsb_iso_wake
*
* Available to low-level drivers.
*
* Call to wake waiting processes after buffer space has opened up.
*/
void hpsb_iso_wake(struct hpsb_iso *iso) void hpsb_iso_wake(struct hpsb_iso *iso)
{ {
wake_up_interruptible(&iso->waitq); wake_up_interruptible(&iso->waitq);
......
...@@ -150,8 +150,6 @@ struct hpsb_iso { ...@@ -150,8 +150,6 @@ struct hpsb_iso {
/* functions available to high-level drivers (e.g. raw1394) */ /* functions available to high-level drivers (e.g. raw1394) */
/* allocate the buffer and DMA context */
struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host,
unsigned int data_buf_size, unsigned int data_buf_size,
unsigned int buf_packets, unsigned int buf_packets,
...@@ -159,8 +157,6 @@ struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, ...@@ -159,8 +157,6 @@ struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host,
int speed, int speed,
int irq_interval, int irq_interval,
void (*callback)(struct hpsb_iso*)); void (*callback)(struct hpsb_iso*));
/* note: if channel = -1, multi-channel receive is enabled */
struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host,
unsigned int data_buf_size, unsigned int data_buf_size,
unsigned int buf_packets, unsigned int buf_packets,
...@@ -168,56 +164,29 @@ struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, ...@@ -168,56 +164,29 @@ struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host,
int dma_mode, int dma_mode,
int irq_interval, int irq_interval,
void (*callback)(struct hpsb_iso*)); void (*callback)(struct hpsb_iso*));
/* multi-channel only */
int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel); int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel);
int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel); int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel);
int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask); int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask);
/* start/stop DMA */
int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle, int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle,
int prebuffer); int prebuffer);
int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle, int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle,
int tag_mask, int sync); int tag_mask, int sync);
void hpsb_iso_stop(struct hpsb_iso *iso); void hpsb_iso_stop(struct hpsb_iso *iso);
/* deallocate buffer and DMA context */
void hpsb_iso_shutdown(struct hpsb_iso *iso); void hpsb_iso_shutdown(struct hpsb_iso *iso);
/* queue a packet for transmission.
* 'offset' is relative to the beginning of the DMA buffer, where the packet's
* data payload should already have been placed. */
int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
u8 tag, u8 sy); u8 tag, u8 sy);
/* wait until all queued packets have been transmitted to the bus */
int hpsb_iso_xmit_sync(struct hpsb_iso *iso); int hpsb_iso_xmit_sync(struct hpsb_iso *iso);
int hpsb_iso_recv_release_packets(struct hpsb_iso *recv,
/* N packets have been read out of the buffer, re-use the buffer space */ unsigned int n_packets);
int hpsb_iso_recv_release_packets(struct hpsb_iso *recv,
unsigned int n_packets);
/* check for arrival of new packets immediately (even if irq_interval
* has not yet been reached) */
int hpsb_iso_recv_flush(struct hpsb_iso *iso); int hpsb_iso_recv_flush(struct hpsb_iso *iso);
/* returns # of packets ready to send or receive */
int hpsb_iso_n_ready(struct hpsb_iso *iso); int hpsb_iso_n_ready(struct hpsb_iso *iso);
/* the following are callbacks available to low-level drivers */ /* the following are callbacks available to low-level drivers */
/* call after a packet has been transmitted to the bus (interrupt context is OK)
* 'cycle' is the _exact_ cycle the packet was sent on
* 'error' should be non-zero if some sort of error occurred when sending the
* packet */
void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error); void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error);
/* call after a packet has been received (interrupt context OK) */
void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
u16 total_len, u16 cycle, u8 channel, u8 tag, u16 total_len, u16 cycle, u8 channel, u8 tag,
u8 sy); u8 sy);
/* call to wake waiting processes after buffer space has opened up. */
void hpsb_iso_wake(struct hpsb_iso *iso); void hpsb_iso_wake(struct hpsb_iso *iso);
#endif /* IEEE1394_ISO_H */ #endif /* IEEE1394_ISO_H */
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <asm/atomic.h> #include <asm/atomic.h>
...@@ -115,7 +116,7 @@ static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length, ...@@ -115,7 +116,7 @@ static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,
static int nodemgr_get_max_rom(quadlet_t *bus_info_data, void *__ci) static int nodemgr_get_max_rom(quadlet_t *bus_info_data, void *__ci)
{ {
return (CSR1212_BE32_TO_CPU(bus_info_data[2]) >> 8) & 0x3; return (be32_to_cpu(bus_info_data[2]) >> 8) & 0x3;
} }
static struct csr1212_bus_ops nodemgr_csr_ops = { static struct csr1212_bus_ops nodemgr_csr_ops = {
...@@ -580,7 +581,7 @@ static void nodemgr_create_drv_files(struct hpsb_protocol_driver *driver) ...@@ -580,7 +581,7 @@ static void nodemgr_create_drv_files(struct hpsb_protocol_driver *driver)
goto fail; goto fail;
return; return;
fail: fail:
HPSB_ERR("Failed to add sysfs attribute for driver %s", driver->name); HPSB_ERR("Failed to add sysfs attribute");
} }
...@@ -604,8 +605,7 @@ static void nodemgr_create_ne_dev_files(struct node_entry *ne) ...@@ -604,8 +605,7 @@ static void nodemgr_create_ne_dev_files(struct node_entry *ne)
goto fail; goto fail;
return; return;
fail: fail:
HPSB_ERR("Failed to add sysfs attribute for node %016Lx", HPSB_ERR("Failed to add sysfs attribute");
(unsigned long long)ne->guid);
} }
...@@ -619,7 +619,7 @@ static void nodemgr_create_host_dev_files(struct hpsb_host *host) ...@@ -619,7 +619,7 @@ static void nodemgr_create_host_dev_files(struct hpsb_host *host)
goto fail; goto fail;
return; return;
fail: fail:
HPSB_ERR("Failed to add sysfs attribute for host %d", host->id); HPSB_ERR("Failed to add sysfs attribute");
} }
...@@ -679,8 +679,7 @@ static void nodemgr_create_ud_dev_files(struct unit_directory *ud) ...@@ -679,8 +679,7 @@ static void nodemgr_create_ud_dev_files(struct unit_directory *ud)
} }
return; return;
fail: fail:
HPSB_ERR("Failed to add sysfs attributes for unit %s", HPSB_ERR("Failed to add sysfs attribute");
ud->device.bus_id);
} }
...@@ -1144,13 +1143,13 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent ...@@ -1144,13 +1143,13 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
last_key_id = kv->key.id; last_key_id = kv->key.id;
} }
if (ne->vendor_name_kv && if (ne->vendor_name_kv) {
device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv)) int error = device_create_file(&ne->device,
goto fail; &dev_attr_ne_vendor_name_kv);
return;
fail: if (error && error != -EEXIST)
HPSB_ERR("Failed to add sysfs attribute for node %016Lx", HPSB_ERR("Failed to add sysfs attribute");
(unsigned long long)ne->guid); }
} }
#ifdef CONFIG_HOTPLUG #ifdef CONFIG_HOTPLUG
...@@ -1738,7 +1737,19 @@ static int nodemgr_host_thread(void *__hi) ...@@ -1738,7 +1737,19 @@ static int nodemgr_host_thread(void *__hi)
return 0; return 0;
} }
int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)) /**
* nodemgr_for_each_host - call a function for each IEEE 1394 host
* @data: an address to supply to the callback
* @cb: function to call for each host
*
* Iterate the hosts, calling a given function with supplied data for each host.
* If the callback fails on a host, i.e. if it returns a non-zero value, the
* iteration is stopped.
*
* Return value: 0 on success, non-zero on failure (same as returned by last run
* of the callback).
*/
int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *))
{ {
struct class_device *cdev; struct class_device *cdev;
struct hpsb_host *host; struct hpsb_host *host;
...@@ -1748,7 +1759,7 @@ int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)) ...@@ -1748,7 +1759,7 @@ int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
list_for_each_entry(cdev, &hpsb_host_class.children, node) { list_for_each_entry(cdev, &hpsb_host_class.children, node) {
host = container_of(cdev, struct hpsb_host, class_dev); host = container_of(cdev, struct hpsb_host, class_dev);
if ((error = cb(host, __data))) if ((error = cb(host, data)))
break; break;
} }
up(&hpsb_host_class.sem); up(&hpsb_host_class.sem);
...@@ -1756,7 +1767,7 @@ int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)) ...@@ -1756,7 +1767,7 @@ int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
return error; return error;
} }
/* The following four convenience functions use a struct node_entry /* The following two convenience functions use a struct node_entry
* for addressing a node on the bus. They are intended for use by any * for addressing a node on the bus. They are intended for use by any
* process context, not just the nodemgr thread, so we need to be a * process context, not just the nodemgr thread, so we need to be a
* little careful when reading out the node ID and generation. The * little careful when reading out the node ID and generation. The
...@@ -1771,12 +1782,20 @@ int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)) ...@@ -1771,12 +1782,20 @@ int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
* ID's. * ID's.
*/ */
void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt) /**
* hpsb_node_fill_packet - fill some destination information into a packet
* @ne: destination node
* @packet: packet to fill in
*
* This will fill in the given, pre-initialised hpsb_packet with the current
* information from the node entry (host, node ID, bus generation number).
*/
void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet)
{ {
pkt->host = ne->host; packet->host = ne->host;
pkt->generation = ne->generation; packet->generation = ne->generation;
barrier(); barrier();
pkt->node_id = ne->nodeid; packet->node_id = ne->nodeid;
} }
int hpsb_node_write(struct node_entry *ne, u64 addr, int hpsb_node_write(struct node_entry *ne, u64 addr,
......
...@@ -153,30 +153,10 @@ static inline int hpsb_node_entry_valid(struct node_entry *ne) ...@@ -153,30 +153,10 @@ static inline int hpsb_node_entry_valid(struct node_entry *ne)
{ {
return ne->generation == get_hpsb_generation(ne->host); return ne->generation == get_hpsb_generation(ne->host);
} }
void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet);
/*
* This will fill in the given, pre-initialised hpsb_packet with the current
* information from the node entry (host, node ID, generation number). It will
* return false if the node owning the GUID is not accessible (and not modify
* the hpsb_packet) and return true otherwise.
*
* Note that packet sending may still fail in hpsb_send_packet if a bus reset
* happens while you are trying to set up the packet (due to obsolete generation
* number). It will at least reliably fail so that you don't accidentally and
* unknowingly send your packet to the wrong node.
*/
void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt);
int hpsb_node_read(struct node_entry *ne, u64 addr,
quadlet_t *buffer, size_t length);
int hpsb_node_write(struct node_entry *ne, u64 addr, int hpsb_node_write(struct node_entry *ne, u64 addr,
quadlet_t *buffer, size_t length); quadlet_t *buffer, size_t length);
int hpsb_node_lock(struct node_entry *ne, u64 addr, int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *));
int extcode, quadlet_t *data, quadlet_t arg);
/* Iterate the hosts, calling a given function with supplied data for each
* host. */
int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *));
int init_ieee1394_nodemgr(void); int init_ieee1394_nodemgr(void);
void cleanup_ieee1394_nodemgr(void); void cleanup_ieee1394_nodemgr(void);
......
...@@ -507,9 +507,8 @@ static void ohci_initialize(struct ti_ohci *ohci) ...@@ -507,9 +507,8 @@ static void ohci_initialize(struct ti_ohci *ohci)
/* Set up self-id dma buffer */ /* Set up self-id dma buffer */
reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus); reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);
/* enable self-id and phys */ /* enable self-id */
reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID | reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID);
OHCI1394_LinkControl_RcvPhyPkt);
/* Set the Config ROM mapping register */ /* Set the Config ROM mapping register */
reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus); reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);
...@@ -518,9 +517,6 @@ static void ohci_initialize(struct ti_ohci *ohci) ...@@ -518,9 +517,6 @@ static void ohci_initialize(struct ti_ohci *ohci)
ohci->max_packet_size = ohci->max_packet_size =
1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1); 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
/* Don't accept phy packets into AR request context */
reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
/* Clear the interrupt mask */ /* Clear the interrupt mask */
reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
...@@ -617,7 +613,7 @@ static void ohci_initialize(struct ti_ohci *ohci) ...@@ -617,7 +613,7 @@ static void ohci_initialize(struct ti_ohci *ohci)
#endif #endif
PRINT(KERN_DEBUG, "Serial EEPROM has suspicious values, " PRINT(KERN_DEBUG, "Serial EEPROM has suspicious values, "
"attempting to setting max_packet_size to 512 bytes"); "attempting to set max_packet_size to 512 bytes");
reg_write(ohci, OHCI1394_BusOptions, reg_write(ohci, OHCI1394_BusOptions,
(reg_read(ohci, OHCI1394_BusOptions) & 0xf007) | 0x8002); (reg_read(ohci, OHCI1394_BusOptions) & 0xf007) | 0x8002);
ohci->max_packet_size = 512; ohci->max_packet_size = 512;
...@@ -2377,6 +2373,7 @@ static irqreturn_t ohci_irq_handler(int irq, void *dev_id) ...@@ -2377,6 +2373,7 @@ static irqreturn_t ohci_irq_handler(int irq, void *dev_id)
if (event & OHCI1394_postedWriteErr) { if (event & OHCI1394_postedWriteErr) {
PRINT(KERN_ERR, "physical posted write error"); PRINT(KERN_ERR, "physical posted write error");
/* no recovery strategy yet, had to involve protocol drivers */ /* no recovery strategy yet, had to involve protocol drivers */
event &= ~OHCI1394_postedWriteErr;
} }
if (event & OHCI1394_cycleTooLong) { if (event & OHCI1394_cycleTooLong) {
if(printk_ratelimit()) if(printk_ratelimit())
...@@ -3658,6 +3655,7 @@ static struct pci_driver ohci1394_pci_driver = { ...@@ -3658,6 +3655,7 @@ static struct pci_driver ohci1394_pci_driver = {
/* essentially the only purpose of this code is to allow another /* essentially the only purpose of this code is to allow another
module to hook into ohci's interrupt handler */ module to hook into ohci's interrupt handler */
/* returns zero if successful, one if DMA context is locked up */
int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg) int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
{ {
int i=0; int i=0;
......
...@@ -461,9 +461,7 @@ int ohci1394_register_iso_tasklet(struct ti_ohci *ohci, ...@@ -461,9 +461,7 @@ int ohci1394_register_iso_tasklet(struct ti_ohci *ohci,
struct ohci1394_iso_tasklet *tasklet); struct ohci1394_iso_tasklet *tasklet);
void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci, void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
struct ohci1394_iso_tasklet *tasklet); struct ohci1394_iso_tasklet *tasklet);
int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
/* returns zero if successful, one if DMA context is locked up */
int ohci1394_stop_context (struct ti_ohci *ohci, int reg, char *msg);
struct ti_ohci *ohci1394_get_struct(int card_num); struct ti_ohci *ohci1394_get_struct(int card_num);
#endif #endif
...@@ -938,7 +938,8 @@ static int handle_async_send(struct file_info *fi, struct pending_request *req) ...@@ -938,7 +938,8 @@ static int handle_async_send(struct file_info *fi, struct pending_request *req)
int header_length = req->req.misc & 0xffff; int header_length = req->req.misc & 0xffff;
int expect_response = req->req.misc >> 16; int expect_response = req->req.misc >> 16;
if ((header_length > req->req.length) || (header_length < 12)) { if (header_length > req->req.length || header_length < 12 ||
header_length > FIELD_SIZEOF(struct hpsb_packet, header)) {
req->req.error = RAW1394_ERROR_INVALID_ARG; req->req.error = RAW1394_ERROR_INVALID_ARG;
req->req.length = 0; req->req.length = 0;
queue_complete_req(req); queue_complete_req(req);
......
...@@ -59,8 +59,10 @@ ...@@ -59,8 +59,10 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/mm.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/stat.h> #include <linux/stat.h>
...@@ -469,19 +471,13 @@ static void sbp2util_write_doorbell(struct work_struct *work) ...@@ -469,19 +471,13 @@ static void sbp2util_write_doorbell(struct work_struct *work)
static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu) static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu)
{ {
struct sbp2_fwhost_info *hi = lu->hi; struct sbp2_fwhost_info *hi = lu->hi;
int i;
unsigned long flags, orbs;
struct sbp2_command_info *cmd; struct sbp2_command_info *cmd;
int i, orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS;
orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS;
spin_lock_irqsave(&lu->cmd_orb_lock, flags);
for (i = 0; i < orbs; i++) { for (i = 0; i < orbs; i++) {
cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) { if (!cmd)
spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
return -ENOMEM; return -ENOMEM;
}
cmd->command_orb_dma = dma_map_single(hi->host->device.parent, cmd->command_orb_dma = dma_map_single(hi->host->device.parent,
&cmd->command_orb, &cmd->command_orb,
sizeof(struct sbp2_command_orb), sizeof(struct sbp2_command_orb),
...@@ -489,11 +485,10 @@ static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu) ...@@ -489,11 +485,10 @@ static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu)
cmd->sge_dma = dma_map_single(hi->host->device.parent, cmd->sge_dma = dma_map_single(hi->host->device.parent,
&cmd->scatter_gather_element, &cmd->scatter_gather_element,
sizeof(cmd->scatter_gather_element), sizeof(cmd->scatter_gather_element),
DMA_BIDIRECTIONAL); DMA_TO_DEVICE);
INIT_LIST_HEAD(&cmd->list); INIT_LIST_HEAD(&cmd->list);
list_add_tail(&cmd->list, &lu->cmd_orb_completed); list_add_tail(&cmd->list, &lu->cmd_orb_completed);
} }
spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
return 0; return 0;
} }
...@@ -514,7 +509,7 @@ static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu) ...@@ -514,7 +509,7 @@ static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu)
DMA_TO_DEVICE); DMA_TO_DEVICE);
dma_unmap_single(host->device.parent, cmd->sge_dma, dma_unmap_single(host->device.parent, cmd->sge_dma,
sizeof(cmd->scatter_gather_element), sizeof(cmd->scatter_gather_element),
DMA_BIDIRECTIONAL); DMA_TO_DEVICE);
kfree(cmd); kfree(cmd);
} }
spin_unlock_irqrestore(&lu->cmd_orb_lock, flags); spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
...@@ -757,6 +752,11 @@ static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud) ...@@ -757,6 +752,11 @@ static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud)
SBP2_ERR("failed to register lower 4GB address range"); SBP2_ERR("failed to register lower 4GB address range");
goto failed_alloc; goto failed_alloc;
} }
#else
if (dma_set_mask(hi->host->device.parent, DMA_32BIT_MASK)) {
SBP2_ERR("failed to set 4GB DMA mask");
goto failed_alloc;
}
#endif #endif
} }
...@@ -865,11 +865,8 @@ static int sbp2_start_device(struct sbp2_lu *lu) ...@@ -865,11 +865,8 @@ static int sbp2_start_device(struct sbp2_lu *lu)
if (!lu->login_orb) if (!lu->login_orb)
goto alloc_fail; goto alloc_fail;
if (sbp2util_create_command_orb_pool(lu)) { if (sbp2util_create_command_orb_pool(lu))
SBP2_ERR("sbp2util_create_command_orb_pool failed!"); goto alloc_fail;
sbp2_remove_device(lu);
return -ENOMEM;
}
/* Wait a second before trying to log in. Previously logged in /* Wait a second before trying to log in. Previously logged in
* initiators need a chance to reconnect. */ * initiators need a chance to reconnect. */
...@@ -1628,7 +1625,7 @@ static void sbp2_link_orb_command(struct sbp2_lu *lu, ...@@ -1628,7 +1625,7 @@ static void sbp2_link_orb_command(struct sbp2_lu *lu,
DMA_TO_DEVICE); DMA_TO_DEVICE);
dma_sync_single_for_device(hi->host->device.parent, cmd->sge_dma, dma_sync_single_for_device(hi->host->device.parent, cmd->sge_dma,
sizeof(cmd->scatter_gather_element), sizeof(cmd->scatter_gather_element),
DMA_BIDIRECTIONAL); DMA_TO_DEVICE);
/* check to see if there are any previous orbs to use */ /* check to see if there are any previous orbs to use */
spin_lock_irqsave(&lu->cmd_orb_lock, flags); spin_lock_irqsave(&lu->cmd_orb_lock, flags);
...@@ -1794,7 +1791,7 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, ...@@ -1794,7 +1791,7 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
DMA_TO_DEVICE); DMA_TO_DEVICE);
dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma, dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma,
sizeof(cmd->scatter_gather_element), sizeof(cmd->scatter_gather_element),
DMA_BIDIRECTIONAL); DMA_TO_DEVICE);
/* Grab SCSI command pointers and check status. */ /* Grab SCSI command pointers and check status. */
/* /*
* FIXME: If the src field in the status is 1, the ORB DMA must * FIXME: If the src field in the status is 1, the ORB DMA must
...@@ -1926,7 +1923,7 @@ static void sbp2scsi_complete_all_commands(struct sbp2_lu *lu, u32 status) ...@@ -1926,7 +1923,7 @@ static void sbp2scsi_complete_all_commands(struct sbp2_lu *lu, u32 status)
DMA_TO_DEVICE); DMA_TO_DEVICE);
dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma, dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma,
sizeof(cmd->scatter_gather_element), sizeof(cmd->scatter_gather_element),
DMA_BIDIRECTIONAL); DMA_TO_DEVICE);
sbp2util_mark_command_completed(lu, cmd); sbp2util_mark_command_completed(lu, cmd);
if (cmd->Current_SCpnt) { if (cmd->Current_SCpnt) {
cmd->Current_SCpnt->result = status << 16; cmd->Current_SCpnt->result = status << 16;
...@@ -2057,7 +2054,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt) ...@@ -2057,7 +2054,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
dma_sync_single_for_cpu(hi->host->device.parent, dma_sync_single_for_cpu(hi->host->device.parent,
cmd->sge_dma, cmd->sge_dma,
sizeof(cmd->scatter_gather_element), sizeof(cmd->scatter_gather_element),
DMA_BIDIRECTIONAL); DMA_TO_DEVICE);
sbp2util_mark_command_completed(lu, cmd); sbp2util_mark_command_completed(lu, cmd);
if (cmd->Current_SCpnt) { if (cmd->Current_SCpnt) {
cmd->Current_SCpnt->result = DID_ABORT << 16; cmd->Current_SCpnt->result = DID_ABORT << 16;
......
...@@ -250,15 +250,15 @@ enum sbp2_dma_types { ...@@ -250,15 +250,15 @@ enum sbp2_dma_types {
/* Per SCSI command */ /* Per SCSI command */
struct sbp2_command_info { struct sbp2_command_info {
struct list_head list; struct list_head list;
struct sbp2_command_orb command_orb ____cacheline_aligned; struct sbp2_command_orb command_orb;
dma_addr_t command_orb_dma ____cacheline_aligned; dma_addr_t command_orb_dma;
struct scsi_cmnd *Current_SCpnt; struct scsi_cmnd *Current_SCpnt;
void (*Current_done)(struct scsi_cmnd *); void (*Current_done)(struct scsi_cmnd *);
/* Also need s/g structure for each sbp2 command */ /* Also need s/g structure for each sbp2 command */
struct sbp2_unrestricted_page_table struct sbp2_unrestricted_page_table
scatter_gather_element[SG_ALL] ____cacheline_aligned; scatter_gather_element[SG_ALL] __attribute__((aligned(8)));
dma_addr_t sge_dma ____cacheline_aligned; dma_addr_t sge_dma;
void *sge_buffer; void *sge_buffer;
dma_addr_t cmd_dma; dma_addr_t cmd_dma;
enum sbp2_dma_types dma_type; enum sbp2_dma_types dma_type;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment