Commit 10534140 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:
  firewire: new stack is no longer experimental
  firewire: net: better FIFO address range check and rcodes
  firewire: net: fix card driver reloading
  firewire: core: fix iso context shutdown on card removal
  firewire: core: fix DMA unmapping in iso buffer removal
  firewire: net: adjust net_device ops
  firewire: net: remove unused code
  firewire: net: allow for unordered unit discovery
  firewire: net: style changes
  firewire: net: add Kconfig item, rename driver
  firewire: add IPv4 support
parents b88f8a54 0c53decd
comment "A new alternative FireWire stack is available with EXPERIMENTAL=y" comment "You can enable one or both FireWire driver stacks."
depends on EXPERIMENTAL=n comment "See the help texts for more information."
comment "Enable only one of the two stacks, unless you know what you are doing"
depends on EXPERIMENTAL
config FIREWIRE config FIREWIRE
tristate "New FireWire stack, EXPERIMENTAL" tristate "FireWire driver stack"
depends on EXPERIMENTAL
select CRC_ITU_T select CRC_ITU_T
help help
This is the "Juju" FireWire stack, a new alternative implementation This is the new-generation IEEE 1394 (FireWire) driver stack
designed for robustness and simplicity. You can build either this a.k.a. Juju, a new implementation designed for robustness and
stack, or the old stack (the ieee1394 driver, ohci1394 etc.) or both. simplicity.
Please read http://ieee1394.wiki.kernel.org/index.php/Juju_Migration See http://ieee1394.wiki.kernel.org/index.php/Juju_Migration
before you enable the new stack. for information about migration from the older Linux 1394 stack
to the new driver stack.
To compile this driver as a module, say M here: the module will be To compile this driver as a module, say M here: the module will be
called firewire-core. called firewire-core.
This module functionally replaces ieee1394, raw1394, and video1394. This module functionally replaces ieee1394, raw1394, and video1394.
To access it from application programs, you generally need at least To access it from application programs, you generally need at least
libraw1394 version 2. IIDC/DCAM applications also need libdc1394 libraw1394 v2. IIDC/DCAM applications need libdc1394 v2.
version 2. No libraries are required to access storage devices No libraries are required to access storage devices through the
through the firewire-sbp2 driver. firewire-sbp2 driver.
NOTE:
FireWire audio devices currently require the old drivers (ieee1394,
ohci1394, raw1394).
config FIREWIRE_OHCI config FIREWIRE_OHCI
tristate "OHCI-1394 controllers" tristate "OHCI-1394 controllers"
...@@ -37,11 +38,9 @@ config FIREWIRE_OHCI ...@@ -37,11 +38,9 @@ config FIREWIRE_OHCI
stack. stack.
NOTE: NOTE:
If you want to install firewire-ohci and ohci1394 together, you
You should only build either firewire-ohci or the old ohci1394 driver, should configure them only as modules and blacklist the driver(s)
but not both. If you nevertheless want to install both, you should which you don't want to have auto-loaded. Add either
configure them only as modules and blacklist the driver(s) which you
don't want to have auto-loaded. Add either
blacklist firewire-ohci blacklist firewire-ohci
or or
...@@ -50,12 +49,7 @@ config FIREWIRE_OHCI ...@@ -50,12 +49,7 @@ config FIREWIRE_OHCI
blacklist dv1394 blacklist dv1394
to /etc/modprobe.conf or /etc/modprobe.d/* and update modprobe.conf to /etc/modprobe.conf or /etc/modprobe.d/* and update modprobe.conf
depending on your distribution. The latter two modules should be depending on your distribution.
blacklisted together with ohci1394 because they depend on ohci1394.
If you have an old modprobe which doesn't implement the blacklist
directive, use "install modulename /bin/true" for the modules to be
blacklisted.
config FIREWIRE_OHCI_DEBUG config FIREWIRE_OHCI_DEBUG
bool bool
...@@ -77,3 +71,17 @@ config FIREWIRE_SBP2 ...@@ -77,3 +71,17 @@ config FIREWIRE_SBP2
You should also enable support for disks, CD-ROMs, etc. in the SCSI You should also enable support for disks, CD-ROMs, etc. in the SCSI
configuration section. configuration section.
config FIREWIRE_NET
tristate "IP networking over 1394 (EXPERIMENTAL)"
depends on FIREWIRE && INET && EXPERIMENTAL
help
This enables IPv4 over IEEE 1394, providing IP connectivity with
other implementations of RFC 2734 as found on several operating
systems. Multicast support is currently limited.
NOTE, this driver is not stable yet!
To compile this driver as a module, say M here: The module will be
called firewire-net. It replaces eth1394 of the classic IEEE 1394
stack.
...@@ -6,7 +6,9 @@ firewire-core-y += core-card.o core-cdev.o core-device.o \ ...@@ -6,7 +6,9 @@ firewire-core-y += core-card.o core-cdev.o core-device.o \
core-iso.o core-topology.o core-transaction.o core-iso.o core-topology.o core-transaction.o
firewire-ohci-y += ohci.o firewire-ohci-y += ohci.o
firewire-sbp2-y += sbp2.o firewire-sbp2-y += sbp2.o
firewire-net-y += net.o
obj-$(CONFIG_FIREWIRE) += firewire-core.o obj-$(CONFIG_FIREWIRE) += firewire-core.o
obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o
obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o
obj-$(CONFIG_FIREWIRE_NET) += firewire-net.o
...@@ -176,6 +176,7 @@ int fw_core_add_descriptor(struct fw_descriptor *desc) ...@@ -176,6 +176,7 @@ int fw_core_add_descriptor(struct fw_descriptor *desc)
return 0; return 0;
} }
EXPORT_SYMBOL(fw_core_add_descriptor);
void fw_core_remove_descriptor(struct fw_descriptor *desc) void fw_core_remove_descriptor(struct fw_descriptor *desc)
{ {
...@@ -189,6 +190,7 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc) ...@@ -189,6 +190,7 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc)
mutex_unlock(&card_mutex); mutex_unlock(&card_mutex);
} }
EXPORT_SYMBOL(fw_core_remove_descriptor);
static void allocate_broadcast_channel(struct fw_card *card, int generation) static void allocate_broadcast_channel(struct fw_card *card, int generation)
{ {
...@@ -459,11 +461,11 @@ EXPORT_SYMBOL(fw_card_add); ...@@ -459,11 +461,11 @@ EXPORT_SYMBOL(fw_card_add);
/* /*
* The next few functions implements a dummy driver that use once a * The next few functions implement a dummy driver that is used once a card
* card driver shuts down an fw_card. This allows the driver to * driver shuts down an fw_card. This allows the driver to cleanly unload,
* cleanly unload, as all IO to the card will be handled by the dummy * as all IO to the card will be handled (and failed) by the dummy driver
* driver instead of calling into the (possibly) unloaded module. The * instead of calling into the module. Only functions for iso context
* dummy driver just fails all IO. * shutdown still need to be provided by the card driver.
*/ */
static int dummy_enable(struct fw_card *card, u32 *config_rom, size_t length) static int dummy_enable(struct fw_card *card, u32 *config_rom, size_t length)
...@@ -510,7 +512,7 @@ static int dummy_enable_phys_dma(struct fw_card *card, ...@@ -510,7 +512,7 @@ static int dummy_enable_phys_dma(struct fw_card *card,
return -ENODEV; return -ENODEV;
} }
static struct fw_card_driver dummy_driver = { static const struct fw_card_driver dummy_driver_template = {
.enable = dummy_enable, .enable = dummy_enable,
.update_phy_reg = dummy_update_phy_reg, .update_phy_reg = dummy_update_phy_reg,
.set_config_rom = dummy_set_config_rom, .set_config_rom = dummy_set_config_rom,
...@@ -529,6 +531,8 @@ void fw_card_release(struct kref *kref) ...@@ -529,6 +531,8 @@ void fw_card_release(struct kref *kref)
void fw_core_remove_card(struct fw_card *card) void fw_core_remove_card(struct fw_card *card)
{ {
struct fw_card_driver dummy_driver = dummy_driver_template;
card->driver->update_phy_reg(card, 4, card->driver->update_phy_reg(card, 4,
PHY_LINK_ACTIVE | PHY_CONTENDER, 0); PHY_LINK_ACTIVE | PHY_CONTENDER, 0);
fw_core_initiate_bus_reset(card, 1); fw_core_initiate_bus_reset(card, 1);
...@@ -537,7 +541,9 @@ void fw_core_remove_card(struct fw_card *card) ...@@ -537,7 +541,9 @@ void fw_core_remove_card(struct fw_card *card)
list_del_init(&card->link); list_del_init(&card->link);
mutex_unlock(&card_mutex); mutex_unlock(&card_mutex);
/* Set up the dummy driver. */ /* Switch off most of the card driver interface. */
dummy_driver.free_iso_context = card->driver->free_iso_context;
dummy_driver.stop_iso = card->driver->stop_iso;
card->driver = &dummy_driver; card->driver = &dummy_driver;
fw_destroy_nodes(card); fw_destroy_nodes(card);
......
...@@ -71,7 +71,7 @@ int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card, ...@@ -71,7 +71,7 @@ int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
for (j = 0; j < i; j++) { for (j = 0; j < i; j++) {
address = page_private(buffer->pages[j]); address = page_private(buffer->pages[j]);
dma_unmap_page(card->device, address, dma_unmap_page(card->device, address,
PAGE_SIZE, DMA_TO_DEVICE); PAGE_SIZE, direction);
__free_page(buffer->pages[j]); __free_page(buffer->pages[j]);
} }
kfree(buffer->pages); kfree(buffer->pages);
...@@ -80,6 +80,7 @@ int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card, ...@@ -80,6 +80,7 @@ int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
return -ENOMEM; return -ENOMEM;
} }
EXPORT_SYMBOL(fw_iso_buffer_init);
int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma) int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma)
{ {
...@@ -107,13 +108,14 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, ...@@ -107,13 +108,14 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
for (i = 0; i < buffer->page_count; i++) { for (i = 0; i < buffer->page_count; i++) {
address = page_private(buffer->pages[i]); address = page_private(buffer->pages[i]);
dma_unmap_page(card->device, address, dma_unmap_page(card->device, address,
PAGE_SIZE, DMA_TO_DEVICE); PAGE_SIZE, buffer->direction);
__free_page(buffer->pages[i]); __free_page(buffer->pages[i]);
} }
kfree(buffer->pages); kfree(buffer->pages);
buffer->pages = NULL; buffer->pages = NULL;
} }
EXPORT_SYMBOL(fw_iso_buffer_destroy);
struct fw_iso_context *fw_iso_context_create(struct fw_card *card, struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
int type, int channel, int speed, size_t header_size, int type, int channel, int speed, size_t header_size,
...@@ -136,6 +138,7 @@ struct fw_iso_context *fw_iso_context_create(struct fw_card *card, ...@@ -136,6 +138,7 @@ struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
return ctx; return ctx;
} }
EXPORT_SYMBOL(fw_iso_context_create);
void fw_iso_context_destroy(struct fw_iso_context *ctx) void fw_iso_context_destroy(struct fw_iso_context *ctx)
{ {
...@@ -143,12 +146,14 @@ void fw_iso_context_destroy(struct fw_iso_context *ctx) ...@@ -143,12 +146,14 @@ void fw_iso_context_destroy(struct fw_iso_context *ctx)
card->driver->free_iso_context(ctx); card->driver->free_iso_context(ctx);
} }
EXPORT_SYMBOL(fw_iso_context_destroy);
int fw_iso_context_start(struct fw_iso_context *ctx, int fw_iso_context_start(struct fw_iso_context *ctx,
int cycle, int sync, int tags) int cycle, int sync, int tags)
{ {
return ctx->card->driver->start_iso(ctx, cycle, sync, tags); return ctx->card->driver->start_iso(ctx, cycle, sync, tags);
} }
EXPORT_SYMBOL(fw_iso_context_start);
int fw_iso_context_queue(struct fw_iso_context *ctx, int fw_iso_context_queue(struct fw_iso_context *ctx,
struct fw_iso_packet *packet, struct fw_iso_packet *packet,
...@@ -159,11 +164,13 @@ int fw_iso_context_queue(struct fw_iso_context *ctx, ...@@ -159,11 +164,13 @@ int fw_iso_context_queue(struct fw_iso_context *ctx,
return card->driver->queue_iso(ctx, packet, buffer, payload); return card->driver->queue_iso(ctx, packet, buffer, payload);
} }
EXPORT_SYMBOL(fw_iso_context_queue);
int fw_iso_context_stop(struct fw_iso_context *ctx) int fw_iso_context_stop(struct fw_iso_context *ctx)
{ {
return ctx->card->driver->stop_iso(ctx); return ctx->card->driver->stop_iso(ctx);
} }
EXPORT_SYMBOL(fw_iso_context_stop);
/* /*
* Isochronous bus resource management (channels, bandwidth), client side * Isochronous bus resource management (channels, bandwidth), client side
......
#ifndef _FIREWIRE_CORE_H #ifndef _FIREWIRE_CORE_H
#define _FIREWIRE_CORE_H #define _FIREWIRE_CORE_H
#include <linux/dma-mapping.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/idr.h> #include <linux/idr.h>
...@@ -97,17 +96,6 @@ int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset); ...@@ -97,17 +96,6 @@ int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset);
int fw_compute_block_crc(u32 *block); int fw_compute_block_crc(u32 *block);
void fw_schedule_bm_work(struct fw_card *card, unsigned long delay); void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);
struct fw_descriptor {
struct list_head link;
size_t length;
u32 immediate;
u32 key;
const u32 *data;
};
int fw_core_add_descriptor(struct fw_descriptor *desc);
void fw_core_remove_descriptor(struct fw_descriptor *desc);
/* -cdev */ /* -cdev */
...@@ -130,77 +118,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event); ...@@ -130,77 +118,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event);
/* -iso */ /* -iso */
/*
* The iso packet format allows for an immediate header/payload part
* stored in 'header' immediately after the packet info plus an
* indirect payload part that is pointer to by the 'payload' field.
* Applications can use one or the other or both to implement simple
* low-bandwidth streaming (e.g. audio) or more advanced
* scatter-gather streaming (e.g. assembling video frame automatically).
*/
struct fw_iso_packet {
u16 payload_length; /* Length of indirect payload. */
u32 interrupt:1; /* Generate interrupt on this packet */
u32 skip:1; /* Set to not send packet at all. */
u32 tag:2;
u32 sy:4;
u32 header_length:8; /* Length of immediate header. */
u32 header[0];
};
#define FW_ISO_CONTEXT_TRANSMIT 0
#define FW_ISO_CONTEXT_RECEIVE 1
#define FW_ISO_CONTEXT_MATCH_TAG0 1
#define FW_ISO_CONTEXT_MATCH_TAG1 2
#define FW_ISO_CONTEXT_MATCH_TAG2 4
#define FW_ISO_CONTEXT_MATCH_TAG3 8
#define FW_ISO_CONTEXT_MATCH_ALL_TAGS 15
/*
* An iso buffer is just a set of pages mapped for DMA in the
* specified direction. Since the pages are to be used for DMA, they
* are not mapped into the kernel virtual address space. We store the
* DMA address in the page private. The helper function
* fw_iso_buffer_map() will map the pages into a given vma.
*/
struct fw_iso_buffer {
enum dma_data_direction direction;
struct page **pages;
int page_count;
};
typedef void (*fw_iso_callback_t)(struct fw_iso_context *context,
u32 cycle, size_t header_length,
void *header, void *data);
struct fw_iso_context {
struct fw_card *card;
int type;
int channel;
int speed;
size_t header_size;
fw_iso_callback_t callback;
void *callback_data;
};
int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
int page_count, enum dma_data_direction direction);
int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma); int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma);
void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card);
struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
int type, int channel, int speed, size_t header_size,
fw_iso_callback_t callback, void *callback_data);
int fw_iso_context_queue(struct fw_iso_context *ctx,
struct fw_iso_packet *packet,
struct fw_iso_buffer *buffer,
unsigned long payload);
int fw_iso_context_start(struct fw_iso_context *ctx,
int cycle, int sync, int tags);
int fw_iso_context_stop(struct fw_iso_context *ctx);
void fw_iso_context_destroy(struct fw_iso_context *ctx);
void fw_iso_resource_manage(struct fw_card *card, int generation, void fw_iso_resource_manage(struct fw_card *card, int generation,
u64 channels_mask, int *channel, int *bandwidth, bool allocate); u64 channels_mask, int *channel, int *bandwidth, bool allocate);
...@@ -285,9 +203,4 @@ void fw_flush_transactions(struct fw_card *card); ...@@ -285,9 +203,4 @@ void fw_flush_transactions(struct fw_card *card);
void fw_send_phy_config(struct fw_card *card, void fw_send_phy_config(struct fw_card *card,
int node_id, int generation, int gap_count); int node_id, int generation, int gap_count);
static inline int fw_stream_packet_destination_id(int tag, int channel, int sy)
{
return tag << 14 | channel << 8 | sy;
}
#endif /* _FIREWIRE_CORE_H */ #endif /* _FIREWIRE_CORE_H */
/*
* IPv4 over IEEE 1394, per RFC 2734
*
* Copyright (C) 2009 Jay Fenlason <fenlason@redhat.com>
*
* based on eth1394 by Ben Collins et al
*/
#include <linux/bug.h>
#include <linux/device.h>
#include <linux/ethtool.h>
#include <linux/firewire.h>
#include <linux/firewire-constants.h>
#include <linux/highmem.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/jiffies.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <asm/unaligned.h>
#include <net/arp.h>
#define FWNET_MAX_FRAGMENTS 25 /* arbitrary limit */
#define FWNET_ISO_PAGE_COUNT (PAGE_SIZE < 16 * 1024 ? 4 : 2)
#define IEEE1394_BROADCAST_CHANNEL 31
#define IEEE1394_ALL_NODES (0xffc0 | 0x003f)
#define IEEE1394_MAX_PAYLOAD_S100 512
#define FWNET_NO_FIFO_ADDR (~0ULL)
#define IANA_SPECIFIER_ID 0x00005eU
#define RFC2734_SW_VERSION 0x000001U
#define IEEE1394_GASP_HDR_SIZE 8
#define RFC2374_UNFRAG_HDR_SIZE 4
#define RFC2374_FRAG_HDR_SIZE 8
#define RFC2374_FRAG_OVERHEAD 4
#define RFC2374_HDR_UNFRAG 0 /* unfragmented */
#define RFC2374_HDR_FIRSTFRAG 1 /* first fragment */
#define RFC2374_HDR_LASTFRAG 2 /* last fragment */
#define RFC2374_HDR_INTFRAG 3 /* interior fragment */
#define RFC2734_HW_ADDR_LEN 16
struct rfc2734_arp {
__be16 hw_type; /* 0x0018 */
__be16 proto_type; /* 0x0806 */
u8 hw_addr_len; /* 16 */
u8 ip_addr_len; /* 4 */
__be16 opcode; /* ARP Opcode */
/* Above is exactly the same format as struct arphdr */
__be64 s_uniq_id; /* Sender's 64bit EUI */
u8 max_rec; /* Sender's max packet size */
u8 sspd; /* Sender's max speed */
__be16 fifo_hi; /* hi 16bits of sender's FIFO addr */
__be32 fifo_lo; /* lo 32bits of sender's FIFO addr */
__be32 sip; /* Sender's IP Address */
__be32 tip; /* IP Address of requested hw addr */
} __attribute__((packed));
/* This header format is specific to this driver implementation. */
#define FWNET_ALEN 8
#define FWNET_HLEN 10
struct fwnet_header {
u8 h_dest[FWNET_ALEN]; /* destination address */
__be16 h_proto; /* packet type ID field */
} __attribute__((packed));
/* IPv4 and IPv6 encapsulation header */
struct rfc2734_header {
u32 w0;
u32 w1;
};
#define fwnet_get_hdr_lf(h) (((h)->w0 & 0xc0000000) >> 30)
#define fwnet_get_hdr_ether_type(h) (((h)->w0 & 0x0000ffff))
#define fwnet_get_hdr_dg_size(h) (((h)->w0 & 0x0fff0000) >> 16)
#define fwnet_get_hdr_fg_off(h) (((h)->w0 & 0x00000fff))
#define fwnet_get_hdr_dgl(h) (((h)->w1 & 0xffff0000) >> 16)
#define fwnet_set_hdr_lf(lf) ((lf) << 30)
#define fwnet_set_hdr_ether_type(et) (et)
#define fwnet_set_hdr_dg_size(dgs) ((dgs) << 16)
#define fwnet_set_hdr_fg_off(fgo) (fgo)
#define fwnet_set_hdr_dgl(dgl) ((dgl) << 16)
static inline void fwnet_make_uf_hdr(struct rfc2734_header *hdr,
unsigned ether_type)
{
hdr->w0 = fwnet_set_hdr_lf(RFC2374_HDR_UNFRAG)
| fwnet_set_hdr_ether_type(ether_type);
}
static inline void fwnet_make_ff_hdr(struct rfc2734_header *hdr,
unsigned ether_type, unsigned dg_size, unsigned dgl)
{
hdr->w0 = fwnet_set_hdr_lf(RFC2374_HDR_FIRSTFRAG)
| fwnet_set_hdr_dg_size(dg_size)
| fwnet_set_hdr_ether_type(ether_type);
hdr->w1 = fwnet_set_hdr_dgl(dgl);
}
static inline void fwnet_make_sf_hdr(struct rfc2734_header *hdr,
unsigned lf, unsigned dg_size, unsigned fg_off, unsigned dgl)
{
hdr->w0 = fwnet_set_hdr_lf(lf)
| fwnet_set_hdr_dg_size(dg_size)
| fwnet_set_hdr_fg_off(fg_off);
hdr->w1 = fwnet_set_hdr_dgl(dgl);
}
/* This list keeps track of what parts of the datagram have been filled in */
struct fwnet_fragment_info {
struct list_head fi_link;
u16 offset;
u16 len;
};
struct fwnet_partial_datagram {
struct list_head pd_link;
struct list_head fi_list;
struct sk_buff *skb;
/* FIXME Why not use skb->data? */
char *pbuf;
u16 datagram_label;
u16 ether_type;
u16 datagram_size;
};
static DEFINE_MUTEX(fwnet_device_mutex);
static LIST_HEAD(fwnet_device_list);
struct fwnet_device {
struct list_head dev_link;
spinlock_t lock;
enum {
FWNET_BROADCAST_ERROR,
FWNET_BROADCAST_RUNNING,
FWNET_BROADCAST_STOPPED,
} broadcast_state;
struct fw_iso_context *broadcast_rcv_context;
struct fw_iso_buffer broadcast_rcv_buffer;
void **broadcast_rcv_buffer_ptrs;
unsigned broadcast_rcv_next_ptr;
unsigned num_broadcast_rcv_ptrs;
unsigned rcv_buffer_size;
/*
* This value is the maximum unfragmented datagram size that can be
* sent by the hardware. It already has the GASP overhead and the
* unfragmented datagram header overhead calculated into it.
*/
unsigned broadcast_xmt_max_payload;
u16 broadcast_xmt_datagramlabel;
/*
* The CSR address that remote nodes must send datagrams to for us to
* receive them.
*/
struct fw_address_handler handler;
u64 local_fifo;
/* List of packets to be sent */
struct list_head packet_list;
/*
* List of packets that were broadcasted. When we get an ISO interrupt
* one of them has been sent
*/
struct list_head broadcasted_list;
/* List of packets that have been sent but not yet acked */
struct list_head sent_list;
struct list_head peer_list;
struct fw_card *card;
struct net_device *netdev;
};
struct fwnet_peer {
struct list_head peer_link;
struct fwnet_device *dev;
u64 guid;
u64 fifo;
/* guarded by dev->lock */
struct list_head pd_list; /* received partial datagrams */
unsigned pdg_size; /* pd_list size */
u16 datagram_label; /* outgoing datagram label */
unsigned max_payload; /* includes RFC2374_FRAG_HDR_SIZE overhead */
int node_id;
int generation;
unsigned speed;
};
/* This is our task struct. It's used for the packet complete callback. */
struct fwnet_packet_task {
/*
* ptask can actually be on dev->packet_list, dev->broadcasted_list,
* or dev->sent_list depending on its current state.
*/
struct list_head pt_link;
struct fw_transaction transaction;
struct rfc2734_header hdr;
struct sk_buff *skb;
struct fwnet_device *dev;
int outstanding_pkts;
unsigned max_payload;
u64 fifo_addr;
u16 dest_node;
u8 generation;
u8 speed;
};
/*
* saddr == NULL means use device source address.
* daddr == NULL means leave destination address (eg unresolved arp).
*/
static int fwnet_header_create(struct sk_buff *skb, struct net_device *net,
unsigned short type, const void *daddr,
const void *saddr, unsigned len)
{
struct fwnet_header *h;
h = (struct fwnet_header *)skb_push(skb, sizeof(*h));
put_unaligned_be16(type, &h->h_proto);
if (net->flags & (IFF_LOOPBACK | IFF_NOARP)) {
memset(h->h_dest, 0, net->addr_len);
return net->hard_header_len;
}
if (daddr) {
memcpy(h->h_dest, daddr, net->addr_len);
return net->hard_header_len;
}
return -net->hard_header_len;
}
static int fwnet_header_rebuild(struct sk_buff *skb)
{
struct fwnet_header *h = (struct fwnet_header *)skb->data;
if (get_unaligned_be16(&h->h_proto) == ETH_P_IP)
return arp_find((unsigned char *)&h->h_dest, skb);
fw_notify("%s: unable to resolve type %04x addresses\n",
skb->dev->name, be16_to_cpu(h->h_proto));
return 0;
}
static int fwnet_header_cache(const struct neighbour *neigh,
struct hh_cache *hh)
{
struct net_device *net;
struct fwnet_header *h;
if (hh->hh_type == cpu_to_be16(ETH_P_802_3))
return -1;
net = neigh->dev;
h = (struct fwnet_header *)((u8 *)hh->hh_data + 16 - sizeof(*h));
h->h_proto = hh->hh_type;
memcpy(h->h_dest, neigh->ha, net->addr_len);
hh->hh_len = FWNET_HLEN;
return 0;
}
/* Called by Address Resolution module to notify changes in address. */
static void fwnet_header_cache_update(struct hh_cache *hh,
const struct net_device *net, const unsigned char *haddr)
{
memcpy((u8 *)hh->hh_data + 16 - FWNET_HLEN, haddr, net->addr_len);
}
static int fwnet_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{
memcpy(haddr, skb->dev->dev_addr, FWNET_ALEN);
return FWNET_ALEN;
}
static const struct header_ops fwnet_header_ops = {
.create = fwnet_header_create,
.rebuild = fwnet_header_rebuild,
.cache = fwnet_header_cache,
.cache_update = fwnet_header_cache_update,
.parse = fwnet_header_parse,
};
/* FIXME: is this correct for all cases? */
static bool fwnet_frag_overlap(struct fwnet_partial_datagram *pd,
unsigned offset, unsigned len)
{
struct fwnet_fragment_info *fi;
unsigned end = offset + len;
list_for_each_entry(fi, &pd->fi_list, fi_link)
if (offset < fi->offset + fi->len && end > fi->offset)
return true;
return false;
}
/* Assumes that new fragment does not overlap any existing fragments */
static struct fwnet_fragment_info *fwnet_frag_new(
struct fwnet_partial_datagram *pd, unsigned offset, unsigned len)
{
struct fwnet_fragment_info *fi, *fi2, *new;
struct list_head *list;
list = &pd->fi_list;
list_for_each_entry(fi, &pd->fi_list, fi_link) {
if (fi->offset + fi->len == offset) {
/* The new fragment can be tacked on to the end */
/* Did the new fragment plug a hole? */
fi2 = list_entry(fi->fi_link.next,
struct fwnet_fragment_info, fi_link);
if (fi->offset + fi->len == fi2->offset) {
/* glue fragments together */
fi->len += len + fi2->len;
list_del(&fi2->fi_link);
kfree(fi2);
} else {
fi->len += len;
}
return fi;
}
if (offset + len == fi->offset) {
/* The new fragment can be tacked on to the beginning */
/* Did the new fragment plug a hole? */
fi2 = list_entry(fi->fi_link.prev,
struct fwnet_fragment_info, fi_link);
if (fi2->offset + fi2->len == fi->offset) {
/* glue fragments together */
fi2->len += fi->len + len;
list_del(&fi->fi_link);
kfree(fi);
return fi2;
}
fi->offset = offset;
fi->len += len;
return fi;
}
if (offset > fi->offset + fi->len) {
list = &fi->fi_link;
break;
}
if (offset + len < fi->offset) {
list = fi->fi_link.prev;
break;
}
}
new = kmalloc(sizeof(*new), GFP_ATOMIC);
if (!new) {
fw_error("out of memory\n");
return NULL;
}
new->offset = offset;
new->len = len;
list_add(&new->fi_link, list);
return new;
}
static struct fwnet_partial_datagram *fwnet_pd_new(struct net_device *net,
struct fwnet_peer *peer, u16 datagram_label, unsigned dg_size,
void *frag_buf, unsigned frag_off, unsigned frag_len)
{
struct fwnet_partial_datagram *new;
struct fwnet_fragment_info *fi;
new = kmalloc(sizeof(*new), GFP_ATOMIC);
if (!new)
goto fail;
INIT_LIST_HEAD(&new->fi_list);
fi = fwnet_frag_new(new, frag_off, frag_len);
if (fi == NULL)
goto fail_w_new;
new->datagram_label = datagram_label;
new->datagram_size = dg_size;
new->skb = dev_alloc_skb(dg_size + net->hard_header_len + 15);
if (new->skb == NULL)
goto fail_w_fi;
skb_reserve(new->skb, (net->hard_header_len + 15) & ~15);
new->pbuf = skb_put(new->skb, dg_size);
memcpy(new->pbuf + frag_off, frag_buf, frag_len);
list_add_tail(&new->pd_link, &peer->pd_list);
return new;
fail_w_fi:
kfree(fi);
fail_w_new:
kfree(new);
fail:
fw_error("out of memory\n");
return NULL;
}
static struct fwnet_partial_datagram *fwnet_pd_find(struct fwnet_peer *peer,
u16 datagram_label)
{
struct fwnet_partial_datagram *pd;
list_for_each_entry(pd, &peer->pd_list, pd_link)
if (pd->datagram_label == datagram_label)
return pd;
return NULL;
}
static void fwnet_pd_delete(struct fwnet_partial_datagram *old)
{
struct fwnet_fragment_info *fi, *n;
list_for_each_entry_safe(fi, n, &old->fi_list, fi_link)
kfree(fi);
list_del(&old->pd_link);
dev_kfree_skb_any(old->skb);
kfree(old);
}
static bool fwnet_pd_update(struct fwnet_peer *peer,
struct fwnet_partial_datagram *pd, void *frag_buf,
unsigned frag_off, unsigned frag_len)
{
if (fwnet_frag_new(pd, frag_off, frag_len) == NULL)
return false;
memcpy(pd->pbuf + frag_off, frag_buf, frag_len);
/*
* Move list entry to beginnig of list so that oldest partial
* datagrams percolate to the end of the list
*/
list_move_tail(&pd->pd_link, &peer->pd_list);
return true;
}
static bool fwnet_pd_is_complete(struct fwnet_partial_datagram *pd)
{
struct fwnet_fragment_info *fi;
fi = list_entry(pd->fi_list.next, struct fwnet_fragment_info, fi_link);
return fi->len == pd->datagram_size;
}
/* caller must hold dev->lock */
static struct fwnet_peer *fwnet_peer_find_by_guid(struct fwnet_device *dev,
u64 guid)
{
struct fwnet_peer *peer;
list_for_each_entry(peer, &dev->peer_list, peer_link)
if (peer->guid == guid)
return peer;
return NULL;
}
/* caller must hold dev->lock */
static struct fwnet_peer *fwnet_peer_find_by_node_id(struct fwnet_device *dev,
int node_id, int generation)
{
struct fwnet_peer *peer;
list_for_each_entry(peer, &dev->peer_list, peer_link)
if (peer->node_id == node_id &&
peer->generation == generation)
return peer;
return NULL;
}
/* See IEEE 1394-2008 table 6-4, table 8-8, table 16-18. */
static unsigned fwnet_max_payload(unsigned max_rec, unsigned speed)
{
max_rec = min(max_rec, speed + 8);
max_rec = min(max_rec, 0xbU); /* <= 4096 */
if (max_rec < 8) {
fw_notify("max_rec %x out of range\n", max_rec);
max_rec = 8;
}
return (1 << (max_rec + 1)) - RFC2374_FRAG_HDR_SIZE;
}
static int fwnet_finish_incoming_packet(struct net_device *net,
struct sk_buff *skb, u16 source_node_id,
bool is_broadcast, u16 ether_type)
{
struct fwnet_device *dev;
static const __be64 broadcast_hw = cpu_to_be64(~0ULL);
int status;
__be64 guid;
dev = netdev_priv(net);
/* Write metadata, and then pass to the receive level */
skb->dev = net;
skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
/*
* Parse the encapsulation header. This actually does the job of
* converting to an ethernet frame header, as well as arp
* conversion if needed. ARP conversion is easier in this
* direction, since we are using ethernet as our backend.
*/
/*
* If this is an ARP packet, convert it. First, we want to make
* use of some of the fields, since they tell us a little bit
* about the sending machine.
*/
if (ether_type == ETH_P_ARP) {
struct rfc2734_arp *arp1394;
struct arphdr *arp;
unsigned char *arp_ptr;
u64 fifo_addr;
u64 peer_guid;
unsigned sspd;
u16 max_payload;
struct fwnet_peer *peer;
unsigned long flags;
arp1394 = (struct rfc2734_arp *)skb->data;
arp = (struct arphdr *)skb->data;
arp_ptr = (unsigned char *)(arp + 1);
peer_guid = get_unaligned_be64(&arp1394->s_uniq_id);
fifo_addr = (u64)get_unaligned_be16(&arp1394->fifo_hi) << 32
| get_unaligned_be32(&arp1394->fifo_lo);
sspd = arp1394->sspd;
/* Sanity check. OS X 10.3 PPC reportedly sends 131. */
if (sspd > SCODE_3200) {
fw_notify("sspd %x out of range\n", sspd);
sspd = SCODE_3200;
}
max_payload = fwnet_max_payload(arp1394->max_rec, sspd);
spin_lock_irqsave(&dev->lock, flags);
peer = fwnet_peer_find_by_guid(dev, peer_guid);
if (peer) {
peer->fifo = fifo_addr;
if (peer->speed > sspd)
peer->speed = sspd;
if (peer->max_payload > max_payload)
peer->max_payload = max_payload;
}
spin_unlock_irqrestore(&dev->lock, flags);
if (!peer) {
fw_notify("No peer for ARP packet from %016llx\n",
(unsigned long long)peer_guid);
goto failed_proto;
}
/*
* Now that we're done with the 1394 specific stuff, we'll
* need to alter some of the data. Believe it or not, all
* that needs to be done is sender_IP_address needs to be
* moved, the destination hardware address get stuffed
* in and the hardware address length set to 8.
*
* IMPORTANT: The code below overwrites 1394 specific data
* needed above so keep the munging of the data for the
* higher level IP stack last.
*/
arp->ar_hln = 8;
/* skip over sender unique id */
arp_ptr += arp->ar_hln;
/* move sender IP addr */
put_unaligned(arp1394->sip, (u32 *)arp_ptr);
/* skip over sender IP addr */
arp_ptr += arp->ar_pln;
if (arp->ar_op == htons(ARPOP_REQUEST))
memset(arp_ptr, 0, sizeof(u64));
else
memcpy(arp_ptr, net->dev_addr, sizeof(u64));
}
/* Now add the ethernet header. */
guid = cpu_to_be64(dev->card->guid);
if (dev_hard_header(skb, net, ether_type,
is_broadcast ? &broadcast_hw : &guid,
NULL, skb->len) >= 0) {
struct fwnet_header *eth;
u16 *rawp;
__be16 protocol;
skb_reset_mac_header(skb);
skb_pull(skb, sizeof(*eth));
eth = (struct fwnet_header *)skb_mac_header(skb);
if (*eth->h_dest & 1) {
if (memcmp(eth->h_dest, net->broadcast,
net->addr_len) == 0)
skb->pkt_type = PACKET_BROADCAST;
#if 0
else
skb->pkt_type = PACKET_MULTICAST;
#endif
} else {
if (memcmp(eth->h_dest, net->dev_addr, net->addr_len))
skb->pkt_type = PACKET_OTHERHOST;
}
if (ntohs(eth->h_proto) >= 1536) {
protocol = eth->h_proto;
} else {
rawp = (u16 *)skb->data;
if (*rawp == 0xffff)
protocol = htons(ETH_P_802_3);
else
protocol = htons(ETH_P_802_2);
}
skb->protocol = protocol;
}
status = netif_rx(skb);
if (status == NET_RX_DROP) {
net->stats.rx_errors++;
net->stats.rx_dropped++;
} else {
net->stats.rx_packets++;
net->stats.rx_bytes += skb->len;
}
if (netif_queue_stopped(net))
netif_wake_queue(net);
return 0;
failed_proto:
net->stats.rx_errors++;
net->stats.rx_dropped++;
dev_kfree_skb_any(skb);
if (netif_queue_stopped(net))
netif_wake_queue(net);
net->last_rx = jiffies;
return 0;
}
static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
int source_node_id, int generation,
bool is_broadcast)
{
struct sk_buff *skb;
struct net_device *net = dev->netdev;
struct rfc2734_header hdr;
unsigned lf;
unsigned long flags;
struct fwnet_peer *peer;
struct fwnet_partial_datagram *pd;
int fg_off;
int dg_size;
u16 datagram_label;
int retval;
u16 ether_type;
hdr.w0 = be32_to_cpu(buf[0]);
lf = fwnet_get_hdr_lf(&hdr);
if (lf == RFC2374_HDR_UNFRAG) {
/*
* An unfragmented datagram has been received by the ieee1394
* bus. Build an skbuff around it so we can pass it to the
* high level network layer.
*/
ether_type = fwnet_get_hdr_ether_type(&hdr);
buf++;
len -= RFC2374_UNFRAG_HDR_SIZE;
skb = dev_alloc_skb(len + net->hard_header_len + 15);
if (unlikely(!skb)) {
fw_error("out of memory\n");
net->stats.rx_dropped++;
return -1;
}
skb_reserve(skb, (net->hard_header_len + 15) & ~15);
memcpy(skb_put(skb, len), buf, len);
return fwnet_finish_incoming_packet(net, skb, source_node_id,
is_broadcast, ether_type);
}
/* A datagram fragment has been received, now the fun begins. */
hdr.w1 = ntohl(buf[1]);
buf += 2;
len -= RFC2374_FRAG_HDR_SIZE;
if (lf == RFC2374_HDR_FIRSTFRAG) {
ether_type = fwnet_get_hdr_ether_type(&hdr);
fg_off = 0;
} else {
ether_type = 0;
fg_off = fwnet_get_hdr_fg_off(&hdr);
}
datagram_label = fwnet_get_hdr_dgl(&hdr);
dg_size = fwnet_get_hdr_dg_size(&hdr); /* ??? + 1 */
spin_lock_irqsave(&dev->lock, flags);
peer = fwnet_peer_find_by_node_id(dev, source_node_id, generation);
if (!peer)
goto bad_proto;
pd = fwnet_pd_find(peer, datagram_label);
if (pd == NULL) {
while (peer->pdg_size >= FWNET_MAX_FRAGMENTS) {
/* remove the oldest */
fwnet_pd_delete(list_first_entry(&peer->pd_list,
struct fwnet_partial_datagram, pd_link));
peer->pdg_size--;
}
pd = fwnet_pd_new(net, peer, datagram_label,
dg_size, buf, fg_off, len);
if (pd == NULL) {
retval = -ENOMEM;
goto bad_proto;
}
peer->pdg_size++;
} else {
if (fwnet_frag_overlap(pd, fg_off, len) ||
pd->datagram_size != dg_size) {
/*
* Differing datagram sizes or overlapping fragments,
* discard old datagram and start a new one.
*/
fwnet_pd_delete(pd);
pd = fwnet_pd_new(net, peer, datagram_label,
dg_size, buf, fg_off, len);
if (pd == NULL) {
retval = -ENOMEM;
peer->pdg_size--;
goto bad_proto;
}
} else {
if (!fwnet_pd_update(peer, pd, buf, fg_off, len)) {
/*
* Couldn't save off fragment anyway
* so might as well obliterate the
* datagram now.
*/
fwnet_pd_delete(pd);
peer->pdg_size--;
goto bad_proto;
}
}
} /* new datagram or add to existing one */
if (lf == RFC2374_HDR_FIRSTFRAG)
pd->ether_type = ether_type;
if (fwnet_pd_is_complete(pd)) {
ether_type = pd->ether_type;
peer->pdg_size--;
skb = skb_get(pd->skb);
fwnet_pd_delete(pd);
spin_unlock_irqrestore(&dev->lock, flags);
return fwnet_finish_incoming_packet(net, skb, source_node_id,
false, ether_type);
}
/*
* Datagram is not complete, we're done for the
* moment.
*/
spin_unlock_irqrestore(&dev->lock, flags);
return 0;
bad_proto:
spin_unlock_irqrestore(&dev->lock, flags);
if (netif_queue_stopped(net))
netif_wake_queue(net);
return 0;
}
static void fwnet_receive_packet(struct fw_card *card, struct fw_request *r,
int tcode, int destination, int source, int generation,
int speed, unsigned long long offset, void *payload,
size_t length, void *callback_data)
{
struct fwnet_device *dev = callback_data;
int rcode;
if (destination == IEEE1394_ALL_NODES) {
kfree(r);
return;
}
if (offset != dev->handler.offset)
rcode = RCODE_ADDRESS_ERROR;
else if (tcode != TCODE_WRITE_BLOCK_REQUEST)
rcode = RCODE_TYPE_ERROR;
else if (fwnet_incoming_packet(dev, payload, length,
source, generation, false) != 0) {
fw_error("Incoming packet failure\n");
rcode = RCODE_CONFLICT_ERROR;
} else
rcode = RCODE_COMPLETE;
fw_send_response(card, r, rcode);
}
static void fwnet_receive_broadcast(struct fw_iso_context *context,
u32 cycle, size_t header_length, void *header, void *data)
{
struct fwnet_device *dev;
struct fw_iso_packet packet;
struct fw_card *card;
__be16 *hdr_ptr;
__be32 *buf_ptr;
int retval;
u32 length;
u16 source_node_id;
u32 specifier_id;
u32 ver;
unsigned long offset;
unsigned long flags;
dev = data;
card = dev->card;
hdr_ptr = header;
length = be16_to_cpup(hdr_ptr);
spin_lock_irqsave(&dev->lock, flags);
offset = dev->rcv_buffer_size * dev->broadcast_rcv_next_ptr;
buf_ptr = dev->broadcast_rcv_buffer_ptrs[dev->broadcast_rcv_next_ptr++];
if (dev->broadcast_rcv_next_ptr == dev->num_broadcast_rcv_ptrs)
dev->broadcast_rcv_next_ptr = 0;
spin_unlock_irqrestore(&dev->lock, flags);
specifier_id = (be32_to_cpu(buf_ptr[0]) & 0xffff) << 8
| (be32_to_cpu(buf_ptr[1]) & 0xff000000) >> 24;
ver = be32_to_cpu(buf_ptr[1]) & 0xffffff;
source_node_id = be32_to_cpu(buf_ptr[0]) >> 16;
if (specifier_id == IANA_SPECIFIER_ID && ver == RFC2734_SW_VERSION) {
buf_ptr += 2;
length -= IEEE1394_GASP_HDR_SIZE;
fwnet_incoming_packet(dev, buf_ptr, length,
source_node_id, -1, true);
}
packet.payload_length = dev->rcv_buffer_size;
packet.interrupt = 1;
packet.skip = 0;
packet.tag = 3;
packet.sy = 0;
packet.header_length = IEEE1394_GASP_HDR_SIZE;
spin_lock_irqsave(&dev->lock, flags);
retval = fw_iso_context_queue(dev->broadcast_rcv_context, &packet,
&dev->broadcast_rcv_buffer, offset);
spin_unlock_irqrestore(&dev->lock, flags);
if (retval < 0)
fw_error("requeue failed\n");
}
static struct kmem_cache *fwnet_packet_task_cache;
static int fwnet_send_packet(struct fwnet_packet_task *ptask);
static void fwnet_transmit_packet_done(struct fwnet_packet_task *ptask)
{
struct fwnet_device *dev;
unsigned long flags;
dev = ptask->dev;
spin_lock_irqsave(&dev->lock, flags);
list_del(&ptask->pt_link);
spin_unlock_irqrestore(&dev->lock, flags);
ptask->outstanding_pkts--; /* FIXME access inside lock */
if (ptask->outstanding_pkts > 0) {
u16 dg_size;
u16 fg_off;
u16 datagram_label;
u16 lf;
struct sk_buff *skb;
/* Update the ptask to point to the next fragment and send it */
lf = fwnet_get_hdr_lf(&ptask->hdr);
switch (lf) {
case RFC2374_HDR_LASTFRAG:
case RFC2374_HDR_UNFRAG:
default:
fw_error("Outstanding packet %x lf %x, header %x,%x\n",
ptask->outstanding_pkts, lf, ptask->hdr.w0,
ptask->hdr.w1);
BUG();
case RFC2374_HDR_FIRSTFRAG:
/* Set frag type here for future interior fragments */
dg_size = fwnet_get_hdr_dg_size(&ptask->hdr);
fg_off = ptask->max_payload - RFC2374_FRAG_HDR_SIZE;
datagram_label = fwnet_get_hdr_dgl(&ptask->hdr);
break;
case RFC2374_HDR_INTFRAG:
dg_size = fwnet_get_hdr_dg_size(&ptask->hdr);
fg_off = fwnet_get_hdr_fg_off(&ptask->hdr)
+ ptask->max_payload - RFC2374_FRAG_HDR_SIZE;
datagram_label = fwnet_get_hdr_dgl(&ptask->hdr);
break;
}
skb = ptask->skb;
skb_pull(skb, ptask->max_payload);
if (ptask->outstanding_pkts > 1) {
fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_INTFRAG,
dg_size, fg_off, datagram_label);
} else {
fwnet_make_sf_hdr(&ptask->hdr, RFC2374_HDR_LASTFRAG,
dg_size, fg_off, datagram_label);
ptask->max_payload = skb->len + RFC2374_FRAG_HDR_SIZE;
}
fwnet_send_packet(ptask);
} else {
dev_kfree_skb_any(ptask->skb);
kmem_cache_free(fwnet_packet_task_cache, ptask);
}
}
static void fwnet_write_complete(struct fw_card *card, int rcode,
void *payload, size_t length, void *data)
{
struct fwnet_packet_task *ptask;
ptask = data;
if (rcode == RCODE_COMPLETE)
fwnet_transmit_packet_done(ptask);
else
fw_error("fwnet_write_complete: failed: %x\n", rcode);
/* ??? error recovery */
}
static int fwnet_send_packet(struct fwnet_packet_task *ptask)
{
struct fwnet_device *dev;
unsigned tx_len;
struct rfc2734_header *bufhdr;
unsigned long flags;
dev = ptask->dev;
tx_len = ptask->max_payload;
switch (fwnet_get_hdr_lf(&ptask->hdr)) {
case RFC2374_HDR_UNFRAG:
bufhdr = (struct rfc2734_header *)
skb_push(ptask->skb, RFC2374_UNFRAG_HDR_SIZE);
put_unaligned_be32(ptask->hdr.w0, &bufhdr->w0);
break;
case RFC2374_HDR_FIRSTFRAG:
case RFC2374_HDR_INTFRAG:
case RFC2374_HDR_LASTFRAG:
bufhdr = (struct rfc2734_header *)
skb_push(ptask->skb, RFC2374_FRAG_HDR_SIZE);
put_unaligned_be32(ptask->hdr.w0, &bufhdr->w0);
put_unaligned_be32(ptask->hdr.w1, &bufhdr->w1);
break;
default:
BUG();
}
if (ptask->dest_node == IEEE1394_ALL_NODES) {
u8 *p;
int generation;
int node_id;
/* ptask->generation may not have been set yet */
generation = dev->card->generation;
smp_rmb();
node_id = dev->card->node_id;
p = skb_push(ptask->skb, 8);
put_unaligned_be32(node_id << 16 | IANA_SPECIFIER_ID >> 8, p);
put_unaligned_be32((IANA_SPECIFIER_ID & 0xff) << 24
| RFC2734_SW_VERSION, &p[4]);
/* We should not transmit if broadcast_channel.valid == 0. */
fw_send_request(dev->card, &ptask->transaction,
TCODE_STREAM_DATA,
fw_stream_packet_destination_id(3,
IEEE1394_BROADCAST_CHANNEL, 0),
generation, SCODE_100, 0ULL, ptask->skb->data,
tx_len + 8, fwnet_write_complete, ptask);
/* FIXME race? */
spin_lock_irqsave(&dev->lock, flags);
list_add_tail(&ptask->pt_link, &dev->broadcasted_list);
spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
fw_send_request(dev->card, &ptask->transaction,
TCODE_WRITE_BLOCK_REQUEST, ptask->dest_node,
ptask->generation, ptask->speed, ptask->fifo_addr,
ptask->skb->data, tx_len, fwnet_write_complete, ptask);
/* FIXME race? */
spin_lock_irqsave(&dev->lock, flags);
list_add_tail(&ptask->pt_link, &dev->sent_list);
spin_unlock_irqrestore(&dev->lock, flags);
dev->netdev->trans_start = jiffies;
return 0;
}
static int fwnet_broadcast_start(struct fwnet_device *dev)
{
struct fw_iso_context *context;
int retval;
unsigned num_packets;
unsigned max_receive;
struct fw_iso_packet packet;
unsigned long offset;
unsigned u;
if (dev->local_fifo == FWNET_NO_FIFO_ADDR) {
/* outside OHCI posted write area? */
static const struct fw_address_region region = {
.start = 0xffff00000000ULL,
.end = CSR_REGISTER_BASE,
};
dev->handler.length = 4096;
dev->handler.address_callback = fwnet_receive_packet;
dev->handler.callback_data = dev;
retval = fw_core_add_address_handler(&dev->handler, &region);
if (retval < 0)
goto failed_initial;
dev->local_fifo = dev->handler.offset;
}
max_receive = 1U << (dev->card->max_receive + 1);
num_packets = (FWNET_ISO_PAGE_COUNT * PAGE_SIZE) / max_receive;
if (!dev->broadcast_rcv_context) {
void **ptrptr;
context = fw_iso_context_create(dev->card,
FW_ISO_CONTEXT_RECEIVE, IEEE1394_BROADCAST_CHANNEL,
dev->card->link_speed, 8, fwnet_receive_broadcast, dev);
if (IS_ERR(context)) {
retval = PTR_ERR(context);
goto failed_context_create;
}
retval = fw_iso_buffer_init(&dev->broadcast_rcv_buffer,
dev->card, FWNET_ISO_PAGE_COUNT, DMA_FROM_DEVICE);
if (retval < 0)
goto failed_buffer_init;
ptrptr = kmalloc(sizeof(void *) * num_packets, GFP_KERNEL);
if (!ptrptr) {
retval = -ENOMEM;
goto failed_ptrs_alloc;
}
dev->broadcast_rcv_buffer_ptrs = ptrptr;
for (u = 0; u < FWNET_ISO_PAGE_COUNT; u++) {
void *ptr;
unsigned v;
ptr = kmap(dev->broadcast_rcv_buffer.pages[u]);
for (v = 0; v < num_packets / FWNET_ISO_PAGE_COUNT; v++)
*ptrptr++ = (void *)
((char *)ptr + v * max_receive);
}
dev->broadcast_rcv_context = context;
} else {
context = dev->broadcast_rcv_context;
}
packet.payload_length = max_receive;
packet.interrupt = 1;
packet.skip = 0;
packet.tag = 3;
packet.sy = 0;
packet.header_length = IEEE1394_GASP_HDR_SIZE;
offset = 0;
for (u = 0; u < num_packets; u++) {
retval = fw_iso_context_queue(context, &packet,
&dev->broadcast_rcv_buffer, offset);
if (retval < 0)
goto failed_rcv_queue;
offset += max_receive;
}
dev->num_broadcast_rcv_ptrs = num_packets;
dev->rcv_buffer_size = max_receive;
dev->broadcast_rcv_next_ptr = 0U;
retval = fw_iso_context_start(context, -1, 0,
FW_ISO_CONTEXT_MATCH_ALL_TAGS); /* ??? sync */
if (retval < 0)
goto failed_rcv_queue;
/* FIXME: adjust it according to the min. speed of all known peers? */
dev->broadcast_xmt_max_payload = IEEE1394_MAX_PAYLOAD_S100
- IEEE1394_GASP_HDR_SIZE - RFC2374_UNFRAG_HDR_SIZE;
dev->broadcast_state = FWNET_BROADCAST_RUNNING;
return 0;
failed_rcv_queue:
kfree(dev->broadcast_rcv_buffer_ptrs);
dev->broadcast_rcv_buffer_ptrs = NULL;
failed_ptrs_alloc:
fw_iso_buffer_destroy(&dev->broadcast_rcv_buffer, dev->card);
failed_buffer_init:
fw_iso_context_destroy(context);
dev->broadcast_rcv_context = NULL;
failed_context_create:
fw_core_remove_address_handler(&dev->handler);
failed_initial:
dev->local_fifo = FWNET_NO_FIFO_ADDR;
return retval;
}
/* ifup */
static int fwnet_open(struct net_device *net)
{
struct fwnet_device *dev = netdev_priv(net);
int ret;
if (dev->broadcast_state == FWNET_BROADCAST_ERROR) {
ret = fwnet_broadcast_start(dev);
if (ret)
return ret;
}
netif_start_queue(net);
return 0;
}
/* ifdown */
static int fwnet_stop(struct net_device *net)
{
netif_stop_queue(net);
/* Deallocate iso context for use by other applications? */
return 0;
}
static int fwnet_tx(struct sk_buff *skb, struct net_device *net)
{
struct fwnet_header hdr_buf;
struct fwnet_device *dev = netdev_priv(net);
__be16 proto;
u16 dest_node;
unsigned max_payload;
u16 dg_size;
u16 *datagram_label_ptr;
struct fwnet_packet_task *ptask;
struct fwnet_peer *peer;
unsigned long flags;
ptask = kmem_cache_alloc(fwnet_packet_task_cache, GFP_ATOMIC);
if (ptask == NULL)
goto fail;
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
goto fail;
/*
* Make a copy of the driver-specific header.
* We might need to rebuild the header on tx failure.
*/
memcpy(&hdr_buf, skb->data, sizeof(hdr_buf));
skb_pull(skb, sizeof(hdr_buf));
proto = hdr_buf.h_proto;
dg_size = skb->len;
/* serialize access to peer, including peer->datagram_label */
spin_lock_irqsave(&dev->lock, flags);
/*
* Set the transmission type for the packet. ARP packets and IP
* broadcast packets are sent via GASP.
*/
if (memcmp(hdr_buf.h_dest, net->broadcast, FWNET_ALEN) == 0
|| proto == htons(ETH_P_ARP)
|| (proto == htons(ETH_P_IP)
&& IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) {
max_payload = dev->broadcast_xmt_max_payload;
datagram_label_ptr = &dev->broadcast_xmt_datagramlabel;
ptask->fifo_addr = FWNET_NO_FIFO_ADDR;
ptask->generation = 0;
ptask->dest_node = IEEE1394_ALL_NODES;
ptask->speed = SCODE_100;
} else {
__be64 guid = get_unaligned((__be64 *)hdr_buf.h_dest);
u8 generation;
peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid));
if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR)
goto fail_unlock;
generation = peer->generation;
dest_node = peer->node_id;
max_payload = peer->max_payload;
datagram_label_ptr = &peer->datagram_label;
ptask->fifo_addr = peer->fifo;
ptask->generation = generation;
ptask->dest_node = dest_node;
ptask->speed = peer->speed;
}
/* If this is an ARP packet, convert it */
if (proto == htons(ETH_P_ARP)) {
struct arphdr *arp = (struct arphdr *)skb->data;
unsigned char *arp_ptr = (unsigned char *)(arp + 1);
struct rfc2734_arp *arp1394 = (struct rfc2734_arp *)skb->data;
__be32 ipaddr;
ipaddr = get_unaligned((__be32 *)(arp_ptr + FWNET_ALEN));
arp1394->hw_addr_len = RFC2734_HW_ADDR_LEN;
arp1394->max_rec = dev->card->max_receive;
arp1394->sspd = dev->card->link_speed;
put_unaligned_be16(dev->local_fifo >> 32,
&arp1394->fifo_hi);
put_unaligned_be32(dev->local_fifo & 0xffffffff,
&arp1394->fifo_lo);
put_unaligned(ipaddr, &arp1394->sip);
}
ptask->hdr.w0 = 0;
ptask->hdr.w1 = 0;
ptask->skb = skb;
ptask->dev = dev;
/* Does it all fit in one packet? */
if (dg_size <= max_payload) {
fwnet_make_uf_hdr(&ptask->hdr, ntohs(proto));
ptask->outstanding_pkts = 1;
max_payload = dg_size + RFC2374_UNFRAG_HDR_SIZE;
} else {
u16 datagram_label;
max_payload -= RFC2374_FRAG_OVERHEAD;
datagram_label = (*datagram_label_ptr)++;
fwnet_make_ff_hdr(&ptask->hdr, ntohs(proto), dg_size,
datagram_label);
ptask->outstanding_pkts = DIV_ROUND_UP(dg_size, max_payload);
max_payload += RFC2374_FRAG_HDR_SIZE;
}
spin_unlock_irqrestore(&dev->lock, flags);
ptask->max_payload = max_payload;
fwnet_send_packet(ptask);
return NETDEV_TX_OK;
fail_unlock:
spin_unlock_irqrestore(&dev->lock, flags);
fail:
if (ptask)
kmem_cache_free(fwnet_packet_task_cache, ptask);
if (skb != NULL)
dev_kfree_skb(skb);
net->stats.tx_dropped++;
net->stats.tx_errors++;
/*
* 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_OK;
}
static int fwnet_change_mtu(struct net_device *net, int new_mtu)
{
if (new_mtu < 68)
return -EINVAL;
net->mtu = new_mtu;
return 0;
}
static void fwnet_get_drvinfo(struct net_device *net,
struct ethtool_drvinfo *info)
{
strcpy(info->driver, KBUILD_MODNAME);
strcpy(info->bus_info, "ieee1394");
}
static struct ethtool_ops fwnet_ethtool_ops = {
.get_drvinfo = fwnet_get_drvinfo,
};
static const struct net_device_ops fwnet_netdev_ops = {
.ndo_open = fwnet_open,
.ndo_stop = fwnet_stop,
.ndo_start_xmit = fwnet_tx,
.ndo_change_mtu = fwnet_change_mtu,
};
static void fwnet_init_dev(struct net_device *net)
{
net->header_ops = &fwnet_header_ops;
net->netdev_ops = &fwnet_netdev_ops;
net->watchdog_timeo = 2 * HZ;
net->flags = IFF_BROADCAST | IFF_MULTICAST;
net->features = NETIF_F_HIGHDMA;
net->addr_len = FWNET_ALEN;
net->hard_header_len = FWNET_HLEN;
net->type = ARPHRD_IEEE1394;
net->tx_queue_len = 10;
SET_ETHTOOL_OPS(net, &fwnet_ethtool_ops);
}
/* caller must hold fwnet_device_mutex */
static struct fwnet_device *fwnet_dev_find(struct fw_card *card)
{
struct fwnet_device *dev;
list_for_each_entry(dev, &fwnet_device_list, dev_link)
if (dev->card == card)
return dev;
return NULL;
}
static int fwnet_add_peer(struct fwnet_device *dev,
struct fw_unit *unit, struct fw_device *device)
{
struct fwnet_peer *peer;
peer = kmalloc(sizeof(*peer), GFP_KERNEL);
if (!peer)
return -ENOMEM;
dev_set_drvdata(&unit->device, peer);
peer->dev = dev;
peer->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4];
peer->fifo = FWNET_NO_FIFO_ADDR;
INIT_LIST_HEAD(&peer->pd_list);
peer->pdg_size = 0;
peer->datagram_label = 0;
peer->speed = device->max_speed;
peer->max_payload = fwnet_max_payload(device->max_rec, peer->speed);
peer->generation = device->generation;
smp_rmb();
peer->node_id = device->node_id;
spin_lock_irq(&dev->lock);
list_add_tail(&peer->peer_link, &dev->peer_list);
spin_unlock_irq(&dev->lock);
return 0;
}
static int fwnet_probe(struct device *_dev)
{
struct fw_unit *unit = fw_unit(_dev);
struct fw_device *device = fw_parent_device(unit);
struct fw_card *card = device->card;
struct net_device *net;
bool allocated_netdev = false;
struct fwnet_device *dev;
unsigned max_mtu;
int ret;
mutex_lock(&fwnet_device_mutex);
dev = fwnet_dev_find(card);
if (dev) {
net = dev->netdev;
goto have_dev;
}
net = alloc_netdev(sizeof(*dev), "firewire%d", fwnet_init_dev);
if (net == NULL) {
ret = -ENOMEM;
goto out;
}
allocated_netdev = true;
SET_NETDEV_DEV(net, card->device);
dev = netdev_priv(net);
spin_lock_init(&dev->lock);
dev->broadcast_state = FWNET_BROADCAST_ERROR;
dev->broadcast_rcv_context = NULL;
dev->broadcast_xmt_max_payload = 0;
dev->broadcast_xmt_datagramlabel = 0;
dev->local_fifo = FWNET_NO_FIFO_ADDR;
INIT_LIST_HEAD(&dev->packet_list);
INIT_LIST_HEAD(&dev->broadcasted_list);
INIT_LIST_HEAD(&dev->sent_list);
INIT_LIST_HEAD(&dev->peer_list);
dev->card = card;
dev->netdev = net;
/*
* Use the RFC 2734 default 1500 octets or the maximum payload
* as initial MTU
*/
max_mtu = (1 << (card->max_receive + 1))
- sizeof(struct rfc2734_header) - IEEE1394_GASP_HDR_SIZE;
net->mtu = min(1500U, max_mtu);
/* Set our hardware address while we're at it */
put_unaligned_be64(card->guid, net->dev_addr);
put_unaligned_be64(~0ULL, net->broadcast);
ret = register_netdev(net);
if (ret) {
fw_error("Cannot register the driver\n");
goto out;
}
list_add_tail(&dev->dev_link, &fwnet_device_list);
fw_notify("%s: IPv4 over FireWire on device %016llx\n",
net->name, (unsigned long long)card->guid);
have_dev:
ret = fwnet_add_peer(dev, unit, device);
if (ret && allocated_netdev) {
unregister_netdev(net);
list_del(&dev->dev_link);
}
out:
if (ret && allocated_netdev)
free_netdev(net);
mutex_unlock(&fwnet_device_mutex);
return ret;
}
static void fwnet_remove_peer(struct fwnet_peer *peer)
{
struct fwnet_partial_datagram *pd, *pd_next;
spin_lock_irq(&peer->dev->lock);
list_del(&peer->peer_link);
spin_unlock_irq(&peer->dev->lock);
list_for_each_entry_safe(pd, pd_next, &peer->pd_list, pd_link)
fwnet_pd_delete(pd);
kfree(peer);
}
static int fwnet_remove(struct device *_dev)
{
struct fwnet_peer *peer = dev_get_drvdata(_dev);
struct fwnet_device *dev = peer->dev;
struct net_device *net;
struct fwnet_packet_task *ptask, *pt_next;
mutex_lock(&fwnet_device_mutex);
fwnet_remove_peer(peer);
if (list_empty(&dev->peer_list)) {
net = dev->netdev;
unregister_netdev(net);
if (dev->local_fifo != FWNET_NO_FIFO_ADDR)
fw_core_remove_address_handler(&dev->handler);
if (dev->broadcast_rcv_context) {
fw_iso_context_stop(dev->broadcast_rcv_context);
fw_iso_buffer_destroy(&dev->broadcast_rcv_buffer,
dev->card);
fw_iso_context_destroy(dev->broadcast_rcv_context);
}
list_for_each_entry_safe(ptask, pt_next,
&dev->packet_list, pt_link) {
dev_kfree_skb_any(ptask->skb);
kmem_cache_free(fwnet_packet_task_cache, ptask);
}
list_for_each_entry_safe(ptask, pt_next,
&dev->broadcasted_list, pt_link) {
dev_kfree_skb_any(ptask->skb);
kmem_cache_free(fwnet_packet_task_cache, ptask);
}
list_for_each_entry_safe(ptask, pt_next,
&dev->sent_list, pt_link) {
dev_kfree_skb_any(ptask->skb);
kmem_cache_free(fwnet_packet_task_cache, ptask);
}
list_del(&dev->dev_link);
free_netdev(net);
}
mutex_unlock(&fwnet_device_mutex);
return 0;
}
/*
* FIXME abort partially sent fragmented datagrams,
* discard partially received fragmented datagrams
*/
static void fwnet_update(struct fw_unit *unit)
{
struct fw_device *device = fw_parent_device(unit);
struct fwnet_peer *peer = dev_get_drvdata(&unit->device);
int generation;
generation = device->generation;
spin_lock_irq(&peer->dev->lock);
peer->node_id = device->node_id;
peer->generation = generation;
spin_unlock_irq(&peer->dev->lock);
}
static const struct ieee1394_device_id fwnet_id_table[] = {
{
.match_flags = IEEE1394_MATCH_SPECIFIER_ID |
IEEE1394_MATCH_VERSION,
.specifier_id = IANA_SPECIFIER_ID,
.version = RFC2734_SW_VERSION,
},
{ }
};
static struct fw_driver fwnet_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "net",
.bus = &fw_bus_type,
.probe = fwnet_probe,
.remove = fwnet_remove,
},
.update = fwnet_update,
.id_table = fwnet_id_table,
};
static const u32 rfc2374_unit_directory_data[] = {
0x00040000, /* directory_length */
0x1200005e, /* unit_specifier_id: IANA */
0x81000003, /* textual descriptor offset */
0x13000001, /* unit_sw_version: RFC 2734 */
0x81000005, /* textual descriptor offset */
0x00030000, /* descriptor_length */
0x00000000, /* text */
0x00000000, /* minimal ASCII, en */
0x49414e41, /* I A N A */
0x00030000, /* descriptor_length */
0x00000000, /* text */
0x00000000, /* minimal ASCII, en */
0x49507634, /* I P v 4 */
};
static struct fw_descriptor rfc2374_unit_directory = {
.length = ARRAY_SIZE(rfc2374_unit_directory_data),
.key = (CSR_DIRECTORY | CSR_UNIT) << 24,
.data = rfc2374_unit_directory_data
};
static int __init fwnet_init(void)
{
int err;
err = fw_core_add_descriptor(&rfc2374_unit_directory);
if (err)
return err;
fwnet_packet_task_cache = kmem_cache_create("packet_task",
sizeof(struct fwnet_packet_task), 0, 0, NULL);
if (!fwnet_packet_task_cache) {
err = -ENOMEM;
goto out;
}
err = driver_register(&fwnet_driver.driver);
if (!err)
return 0;
kmem_cache_destroy(fwnet_packet_task_cache);
out:
fw_core_remove_descriptor(&rfc2374_unit_directory);
return err;
}
module_init(fwnet_init);
static void __exit fwnet_cleanup(void)
{
driver_unregister(&fwnet_driver.driver);
kmem_cache_destroy(fwnet_packet_task_cache);
fw_core_remove_descriptor(&rfc2374_unit_directory);
}
module_exit(fwnet_cleanup);
MODULE_AUTHOR("Jay Fenlason <fenlason@redhat.com>");
MODULE_DESCRIPTION("IPv4 over IEEE1394 as per RFC 2734");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(ieee1394, fwnet_id_table);
...@@ -4,7 +4,7 @@ menu "IEEE 1394 (FireWire) support" ...@@ -4,7 +4,7 @@ menu "IEEE 1394 (FireWire) support"
source "drivers/firewire/Kconfig" source "drivers/firewire/Kconfig"
config IEEE1394 config IEEE1394
tristate "Stable FireWire stack" tristate "Legacy alternative FireWire driver stack"
depends on PCI || BROKEN depends on PCI || BROKEN
help help
IEEE 1394 describes a high performance serial bus, which is also IEEE 1394 describes a high performance serial bus, which is also
...@@ -33,11 +33,9 @@ config IEEE1394_OHCI1394 ...@@ -33,11 +33,9 @@ config IEEE1394_OHCI1394
module will be called ohci1394. module will be called ohci1394.
NOTE: NOTE:
If you want to install firewire-ohci and ohci1394 together, you
You should only build either ohci1394 or the new firewire-ohci driver, should configure them only as modules and blacklist the driver(s)
but not both. If you nevertheless want to install both, you should which you don't want to have auto-loaded. Add either
configure them only as modules and blacklist the driver(s) which you
don't want to have auto-loaded. Add either
blacklist firewire-ohci blacklist firewire-ohci
or or
...@@ -46,12 +44,7 @@ config IEEE1394_OHCI1394 ...@@ -46,12 +44,7 @@ config IEEE1394_OHCI1394
blacklist dv1394 blacklist dv1394
to /etc/modprobe.conf or /etc/modprobe.d/* and update modprobe.conf to /etc/modprobe.conf or /etc/modprobe.d/* and update modprobe.conf
depending on your distribution. The latter two modules should be depending on your distribution.
blacklisted together with ohci1394 because they depend on ohci1394.
If you have an old modprobe which doesn't implement the blacklist
directive, use "install modulename /bin/true" for the modules to be
blacklisted.
comment "PCILynx controller requires I2C" comment "PCILynx controller requires I2C"
depends on IEEE1394 && I2C=n depends on IEEE1394 && I2C=n
...@@ -105,7 +98,7 @@ config IEEE1394_ETH1394_ROM_ENTRY ...@@ -105,7 +98,7 @@ config IEEE1394_ETH1394_ROM_ENTRY
default n default n
config IEEE1394_ETH1394 config IEEE1394_ETH1394
tristate "IP over 1394" tristate "IP networking over 1394 (experimental)"
depends on IEEE1394 && EXPERIMENTAL && INET depends on IEEE1394 && EXPERIMENTAL && INET
select IEEE1394_ETH1394_ROM_ENTRY select IEEE1394_ETH1394_ROM_ENTRY
help help
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/list.h> #include <linux/list.h>
...@@ -355,4 +356,90 @@ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, ...@@ -355,4 +356,90 @@ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
int generation, int speed, unsigned long long offset, int generation, int speed, unsigned long long offset,
void *payload, size_t length); void *payload, size_t length);
static inline int fw_stream_packet_destination_id(int tag, int channel, int sy)
{
return tag << 14 | channel << 8 | sy;
}
struct fw_descriptor {
struct list_head link;
size_t length;
u32 immediate;
u32 key;
const u32 *data;
};
int fw_core_add_descriptor(struct fw_descriptor *desc);
void fw_core_remove_descriptor(struct fw_descriptor *desc);
/*
* The iso packet format allows for an immediate header/payload part
* stored in 'header' immediately after the packet info plus an
* indirect payload part that is pointer to by the 'payload' field.
* Applications can use one or the other or both to implement simple
* low-bandwidth streaming (e.g. audio) or more advanced
* scatter-gather streaming (e.g. assembling video frame automatically).
*/
struct fw_iso_packet {
u16 payload_length; /* Length of indirect payload. */
u32 interrupt:1; /* Generate interrupt on this packet */
u32 skip:1; /* Set to not send packet at all. */
u32 tag:2;
u32 sy:4;
u32 header_length:8; /* Length of immediate header. */
u32 header[0];
};
#define FW_ISO_CONTEXT_TRANSMIT 0
#define FW_ISO_CONTEXT_RECEIVE 1
#define FW_ISO_CONTEXT_MATCH_TAG0 1
#define FW_ISO_CONTEXT_MATCH_TAG1 2
#define FW_ISO_CONTEXT_MATCH_TAG2 4
#define FW_ISO_CONTEXT_MATCH_TAG3 8
#define FW_ISO_CONTEXT_MATCH_ALL_TAGS 15
/*
* An iso buffer is just a set of pages mapped for DMA in the
* specified direction. Since the pages are to be used for DMA, they
* are not mapped into the kernel virtual address space. We store the
* DMA address in the page private. The helper function
* fw_iso_buffer_map() will map the pages into a given vma.
*/
struct fw_iso_buffer {
enum dma_data_direction direction;
struct page **pages;
int page_count;
};
int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
int page_count, enum dma_data_direction direction);
void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card);
struct fw_iso_context;
typedef void (*fw_iso_callback_t)(struct fw_iso_context *context,
u32 cycle, size_t header_length,
void *header, void *data);
struct fw_iso_context {
struct fw_card *card;
int type;
int channel;
int speed;
size_t header_size;
fw_iso_callback_t callback;
void *callback_data;
};
struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
int type, int channel, int speed, size_t header_size,
fw_iso_callback_t callback, void *callback_data);
int fw_iso_context_queue(struct fw_iso_context *ctx,
struct fw_iso_packet *packet,
struct fw_iso_buffer *buffer,
unsigned long payload);
int fw_iso_context_start(struct fw_iso_context *ctx,
int cycle, int sync, int tags);
int fw_iso_context_stop(struct fw_iso_context *ctx);
void fw_iso_context_destroy(struct fw_iso_context *ctx);
#endif /* _LINUX_FIREWIRE_H */ #endif /* _LINUX_FIREWIRE_H */
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