#include "nodemgr.h"
#include "dma.h"
#include "iso.h"
+#include "config_roms.h"
/*
* Disable the nodemgr detection and config rom reading functionality.
void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
void (*routine)(void *), void *data)
{
- BUG_ON(packet->complete_routine != NULL);
+ WARN_ON(packet->complete_routine != NULL);
packet->complete_routine = routine;
packet->complete_data = data;
return;
*/
struct hpsb_packet *hpsb_alloc_packet(size_t data_size)
{
- struct hpsb_packet *packet = NULL;
- void *data = NULL;
-
- packet = kmem_cache_alloc(hpsb_packet_cache, GFP_ATOMIC);
- if (packet == NULL)
- return NULL;
-
- memset(packet, 0, sizeof(struct hpsb_packet));
- packet->header = packet->embedded_header;
-
- if (data_size) {
- data = kmalloc(data_size + 8, GFP_ATOMIC);
- if (data == NULL) {
+ struct hpsb_packet *packet = NULL;
+ void *data = NULL;
+ int gfp_flags = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
+
+ packet = kmem_cache_alloc(hpsb_packet_cache, gfp_flags);
+ if (packet == NULL)
+ return NULL;
+
+ memset(packet, 0, sizeof(*packet));
+
+ packet->header = packet->embedded_header;
+ INIT_LIST_HEAD(&packet->list);
+ packet->state = hpsb_unused;
+ packet->generation = -1;
+ atomic_set(&packet->refcnt, 1);
+
+ if (data_size) {
+ data_size = (data_size + 3) & ~3;
+ data = kmalloc(data_size + 8, gfp_flags);
+ if (data == NULL) {
kmem_cache_free(hpsb_packet_cache, packet);
- return NULL;
- }
-
- packet->data = data;
- packet->data_size = data_size;
- }
+ return NULL;
+ }
- INIT_LIST_HEAD(&packet->list);
- packet->complete_routine = NULL;
- packet->complete_data = NULL;
- packet->state = hpsb_unused;
- packet->generation = -1;
+ packet->data = data;
+ packet->data_size = data_size;
+ }
- return packet;
+ return packet;
}
* hpsb_free_packet - free packet and data associated with it
* @packet: packet to free (is NULL safe)
*
- * This function will free packet->data, packet->header and finally the packet
- * itself.
+ * This function will free packet->data and finally the packet itself.
*/
void hpsb_free_packet(struct hpsb_packet *packet)
{
- if (!packet) return;
-
- kfree(packet->data);
- kmem_cache_free(hpsb_packet_cache, packet);
+ if (packet && atomic_dec_and_test(&packet->refcnt)) {
+ kfree(packet->data);
+ kmem_cache_free(hpsb_packet_cache, packet);
+ }
}
void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
int ackcode)
{
- unsigned long flags;
-
- packet->ack_code = ackcode;
+ packet->ack_code = ackcode;
- if (packet->no_waiter) {
- /* must not have a tlabel allocated */
- hpsb_free_packet(packet);
- return;
- }
+ if (packet->no_waiter) {
+ /* must not have a tlabel allocated */
+ hpsb_free_packet(packet);
+ return;
+ }
- if (ackcode != ACK_PENDING || !packet->expect_response) {
- packet->state = hpsb_complete;
- queue_packet_complete(packet);
- return;
- }
+ if (ackcode != ACK_PENDING || !packet->expect_response) {
+ atomic_dec(&packet->refcnt);
+ list_del(&packet->list);
+ packet->state = hpsb_complete;
+ queue_packet_complete(packet);
+ return;
+ }
- packet->state = hpsb_pending;
- packet->sendtime = jiffies;
+ if (packet->state == hpsb_complete) {
+ hpsb_free_packet(packet);
+ return;
+ }
- spin_lock_irqsave(&host->pending_pkt_lock, flags);
- list_add_tail(&packet->list, &host->pending_packets);
- spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
+ atomic_dec(&packet->refcnt);
+ packet->state = hpsb_pending;
+ packet->sendtime = jiffies;
mod_timer(&host->timeout, jiffies + host->timeout_interval);
}
*/
int hpsb_send_packet(struct hpsb_packet *packet)
{
- struct hpsb_host *host = packet->host;
+ struct hpsb_host *host = packet->host;
if (host->is_shutdown)
return -EINVAL;
packet->state = hpsb_queued;
+ if (!packet->no_waiter || packet->expect_response) {
+ unsigned long flags;
+
+ atomic_inc(&packet->refcnt);
+ spin_lock_irqsave(&host->pending_pkt_lock, flags);
+ list_add_tail(&packet->list, &host->pending_packets);
+ spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
+ }
+
if (packet->node_id == host->node_id)
{ /* it is a local request, so handle it locally */
quadlet_t *data;
break;
}
- packet->state = hpsb_complete;
+ if (packet->state == hpsb_queued) {
+ packet->sendtime = jiffies;
+ packet->ack_code = ACK_PENDING;
+ }
+
+ packet->state = hpsb_complete;
queue_packet_complete(packet);
}
complete_and_exit(&khpsbpkt_complete, 0);
}
+
static int __init ieee1394_init(void)
{
int i;
+ if (hpsb_init_config_roms()) {
+ HPSB_ERR("Failed to initialize some config rom entries.\n");
+ HPSB_ERR("Some features may not be available\n");
+ }
+
khpsbpkt_pid = kernel_thread(hpsbpkt_thread, NULL, CLONE_KERNEL);
if (khpsbpkt_pid < 0) {
HPSB_ERR("Failed to start hpsbpkt thread!\n");
devfs_mk_dir("ieee1394");
hpsb_packet_cache = kmem_cache_create("hpsb_packet", sizeof(struct hpsb_packet),
- 0, 0, NULL, NULL);
+ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
bus_register(&ieee1394_bus_type);
for (i = 0; fw_bus_attrs[i]; i++)
kmem_cache_destroy(hpsb_packet_cache);
+ hpsb_cleanup_config_roms();
+
unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
devfs_remove("ieee1394");
}