i2o_core.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,683 行 · 第 1/5 页
C
2,683 行
/* * Core I2O structure management * * (C) Copyright 1999-2002 Red Hat Software * * Written by Alan Cox, Building Number Three Ltd * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * A lot of the I2O message side code from this is taken from the * Red Creek RCPCI45 adapter driver by Red Creek Communications * * Fixes/additions: * Philipp Rumpf * Juha Siev鋘en <Juha.Sievanen@cs.Helsinki.FI> * Auvo H鋕kinen <Auvo.Hakkinen@cs.Helsinki.FI> * Deepak Saxena <deepak@plexity.net> * Boji T Kannanthanam <boji.t.kannanthanam@intel.com> * Alan Cox <alan@redhat.com>: * Ported to Linux 2.5. * Markus Lidel <Markus.Lidel@shadowconnect.com>: * Minor fixes for 2.6. * */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/pci.h>#include <linux/i2o.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/spinlock.h>#include <linux/smp_lock.h>#include <linux/bitops.h>#include <linux/wait.h>#include <linux/delay.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/sched.h>#include <asm/semaphore.h>#include <linux/completion.h>#include <linux/workqueue.h>#include <asm/io.h>#include <linux/reboot.h>#ifdef CONFIG_MTRR#include <asm/mtrr.h>#endif // CONFIG_MTRR#include "i2o_lan.h"//#define DRIVERDEBUG#ifdef DRIVERDEBUG#define dprintk(s, args...) printk(s, ## args)#else#define dprintk(s, args...)#endif/* OSM table */static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES];/* Controller list */static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS];struct i2o_controller *i2o_controller_chain;int i2o_num_controllers;/* Initiator Context for Core message */static int core_context;/* Initialization && shutdown functions */void i2o_sys_init(void);static void i2o_sys_shutdown(void);static int i2o_reset_controller(struct i2o_controller *);static int i2o_reboot_event(struct notifier_block *, unsigned long , void *);static int i2o_online_controller(struct i2o_controller *);static int i2o_init_outbound_q(struct i2o_controller *);static int i2o_post_outbound_messages(struct i2o_controller *);/* Reply handler */static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *, struct i2o_message *);/* Various helper functions */static int i2o_lct_get(struct i2o_controller *);static int i2o_lct_notify(struct i2o_controller *);static int i2o_hrt_get(struct i2o_controller *);static int i2o_build_sys_table(void);static int i2o_systab_send(struct i2o_controller *c);/* I2O core event handler */static int i2o_core_evt(void *);static int evt_pid;static int evt_running;/* Dynamic LCT update handler */static int i2o_dyn_lct(void *);void i2o_report_controller_unit(struct i2o_controller *, struct i2o_device *);static void i2o_pci_dispose(struct i2o_controller *c);/* * I2O System Table. Contains information about * all the IOPs in the system. Used to inform IOPs * about each other's existence. * * sys_tbl_ver is the CurrentChangeIndicator that is * used by IOPs to track changes. */static struct i2o_sys_tbl *sys_tbl;static int sys_tbl_ind;static int sys_tbl_len;/* * This spin lock is used to keep a device from being * added and deleted concurrently across CPUs or interrupts. * This can occur when a user creates a device and immediatelly * deletes it before the new_dev_notify() handler is called. */static spinlock_t i2o_dev_lock = SPIN_LOCK_UNLOCKED;/* * Structures and definitions for synchronous message posting. * See i2o_post_wait() for description. */ struct i2o_post_wait_data{ int *status; /* Pointer to status block on caller stack */ int *complete; /* Pointer to completion flag on caller stack */ u32 id; /* Unique identifier */ wait_queue_head_t *wq; /* Wake up for caller (NULL for dead) */ struct i2o_post_wait_data *next; /* Chain */ void *mem[2]; /* Memory blocks to recover on failure path */ dma_addr_t phys[2]; /* Physical address of blocks to recover */ u32 size[2]; /* Size of blocks to recover */};static struct i2o_post_wait_data *post_wait_queue;static u32 post_wait_id; // Unique ID for each post_waitstatic spinlock_t post_wait_lock = SPIN_LOCK_UNLOCKED;static void i2o_post_wait_complete(struct i2o_controller *, u32, int);/* OSM descriptor handler */ static struct i2o_handler i2o_core_handler ={ (void *)i2o_core_reply, NULL, NULL, NULL, "I2O core layer", 0, I2O_CLASS_EXECUTIVE};/* * Used when queueing a reply to be handled later */ struct reply_info{ struct i2o_controller *iop; u32 msg[MSG_FRAME_SIZE];};static struct reply_info evt_reply;static struct reply_info events[I2O_EVT_Q_LEN];static int evt_in;static int evt_out;static int evt_q_len;#define MODINC(x,y) ((x) = ((x) + 1) % (y))/* * I2O configuration spinlock. This isnt a big deal for contention * so we have one only */static DECLARE_MUTEX(i2o_configuration_lock);/* * Event spinlock. Used to keep event queue sane and from * handling multiple events simultaneously. */static spinlock_t i2o_evt_lock = SPIN_LOCK_UNLOCKED;/* * Semaphore used to synchronize event handling thread with * interrupt handler. */ static DECLARE_MUTEX(evt_sem);static DECLARE_COMPLETION(evt_dead);static DECLARE_WAIT_QUEUE_HEAD(evt_wait);static struct notifier_block i2o_reboot_notifier ={ i2o_reboot_event, NULL, 0};/* * Config options */static int verbose;#if BITS_PER_LONG == 64/** * i2o_context_list_add - append an ptr to the context list and return a * matching context id. * @ptr: pointer to add to the context list * @c: controller to which the context list belong * returns context id, which could be used in the transaction context * field. * * Because the context field in I2O is only 32-bit large, on 64-bit the * pointer is to large to fit in the context field. The i2o_context_list * functiones map pointers to context fields. */u32 i2o_context_list_add(void *ptr, struct i2o_controller *c) { u32 context = 1; struct i2o_context_list_element **entry = &c->context_list; struct i2o_context_list_element *element; unsigned long flags; spin_lock_irqsave(&c->context_list_lock, flags); while(*entry && ((*entry)->flags & I2O_CONTEXT_LIST_USED)) { if((*entry)->context >= context) context = (*entry)->context + 1; entry = &((*entry)->next); } if(!*entry) { if(unlikely(!context)) { spin_unlock_irqrestore(&c->context_list_lock, flags); printk(KERN_EMERG "i2o_core: context list overflow\n"); return 0; } element = kmalloc(sizeof(struct i2o_context_list_element), GFP_KERNEL); if(!element) { printk(KERN_EMERG "i2o_core: could not allocate memory for context list element\n"); return 0; } element->context = context; element->next = NULL; *entry = element; } else element = *entry; element->ptr = ptr; element->flags = I2O_CONTEXT_LIST_USED; spin_unlock_irqrestore(&c->context_list_lock, flags); dprintk(KERN_DEBUG "i2o_core: add context to list %p -> %d\n", ptr, context); return context;}/** * i2o_context_list_remove - remove a ptr from the context list and return * the matching context id. * @ptr: pointer to be removed from the context list * @c: controller to which the context list belong * returns context id, which could be used in the transaction context * field. */u32 i2o_context_list_remove(void *ptr, struct i2o_controller *c) { struct i2o_context_list_element **entry = &c->context_list; struct i2o_context_list_element *element; u32 context; unsigned long flags; spin_lock_irqsave(&c->context_list_lock, flags); while(*entry && ((*entry)->ptr != ptr)) entry = &((*entry)->next); if(unlikely(!*entry)) { spin_unlock_irqrestore(&c->context_list_lock, flags); printk(KERN_WARNING "i2o_core: could not remove nonexistent ptr %p\n", ptr); return 0; } element = *entry; context = element->context; element->ptr = NULL; element->flags |= I2O_CONTEXT_LIST_DELETED; spin_unlock_irqrestore(&c->context_list_lock, flags); dprintk(KERN_DEBUG "i2o_core: markt as deleted in context list %p -> %d\n", ptr, context); return context;}/** * i2o_context_list_get - get a ptr from the context list and remove it * from the list. * @context: context id to which the pointer belong * @c: controller to which the context list belong * returns pointer to the matching context id */void *i2o_context_list_get(u32 context, struct i2o_controller *c) { struct i2o_context_list_element **entry = &c->context_list; struct i2o_context_list_element *element; void *ptr; int count = 0; unsigned long flags; spin_lock_irqsave(&c->context_list_lock, flags); while(*entry && ((*entry)->context != context)) { entry = &((*entry)->next); count ++; } if(unlikely(!*entry)) { spin_unlock_irqrestore(&c->context_list_lock, flags); printk(KERN_WARNING "i2o_core: context id %d not found\n", context); return NULL; } element = *entry; ptr = element->ptr; if(count >= I2O_CONTEXT_LIST_MIN_LENGTH) { *entry = (*entry)->next; kfree(element); } else { element->ptr = NULL; element->flags &= !I2O_CONTEXT_LIST_USED; } spin_unlock_irqrestore(&c->context_list_lock, flags); dprintk(KERN_DEBUG "i2o_core: get ptr from context list %d -> %p\n", context, ptr); return ptr;}#endif/* * I2O Core reply handler */static void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m){ u32 *msg=(u32 *)m; u32 status; u32 context = msg[2]; if (msg[0] & MSG_FAIL) // Fail bit is set { u32 *preserved_msg = (u32*)(c->msg_virt + msg[7]); i2o_report_status(KERN_INFO, "i2o_core", msg); i2o_dump_message(preserved_msg); /* If the failed request needs special treatment, * it should be done here. */ /* Release the preserved msg by resubmitting it as a NOP */ preserved_msg[0] = cpu_to_le32(THREE_WORD_MSG_SIZE | SGL_OFFSET_0); preserved_msg[1] = cpu_to_le32(I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0); preserved_msg[2] = 0; i2o_post_message(c, msg[7]); /* If reply to i2o_post_wait failed, return causes a timeout */ return; } #ifdef DRIVERDEBUG i2o_report_status(KERN_INFO, "i2o_core", msg);#endif if(msg[2]&0x80000000) // Post wait message { if (msg[4] >> 24) status = (msg[4] & 0xFFFF); else status = I2O_POST_WAIT_OK; i2o_post_wait_complete(c, context, status); return; } if(m->function == I2O_CMD_UTIL_EVT_REGISTER) { memcpy(events[evt_in].msg, msg, (msg[0]>>16)<<2); events[evt_in].iop = c; spin_lock(&i2o_evt_lock); MODINC(evt_in, I2O_EVT_Q_LEN); if(evt_q_len == I2O_EVT_Q_LEN) MODINC(evt_out, I2O_EVT_Q_LEN); else evt_q_len++; spin_unlock(&i2o_evt_lock); up(&evt_sem); wake_up_interruptible(&evt_wait); return; } if(m->function == I2O_CMD_LCT_NOTIFY) { up(&c->lct_sem); return; } /* * If this happens, we want to dump the message to the syslog so * it can be sent back to the card manufacturer by the end user * to aid in debugging. * */ printk(KERN_WARNING "%s: Unsolicited message reply sent to core!" "Message dumped to syslog\n", c->name); i2o_dump_message(msg); return;}/** * i2o_install_handler - install a message handler * @h: Handler structure * * Install an I2O handler - these handle the asynchronous messaging * from the card once it has initialised. If the table of handlers is * full then -ENOSPC is returned. On a success 0 is returned and the * context field is set by the function. The structure is part of the * system from this time onwards. It must not be freed until it has * been uninstalled */ int i2o_install_handler(struct i2o_handler *h){ int i; down(&i2o_configuration_lock); for(i=0;i<MAX_I2O_MODULES;i++) { if(i2o_handlers[i]==NULL) { h->context = i; i2o_handlers[i]=h; up(&i2o_configuration_lock); return 0; } } up(&i2o_configuration_lock); return -ENOSPC;}/** * i2o_remove_handler - remove an i2o message handler * @h: handler * * Remove a message handler previously installed with i2o_install_handler. * After this function returns the handler object can be freed or re-used */ int i2o_remove_handler(struct i2o_handler *h){ i2o_handlers[h->context]=NULL; return 0;} /* * Each I2O controller has a chain of devices on it. * Each device has a pointer to its LCT entry to be used * for fun purposes. *//** * i2o_install_device - attach a device to a controller * @c: controller * @d: device * * Add a new device to an i2o controller. This can be called from * non interrupt contexts only. It adds the device and marks it as * unclaimed. The device memory becomes part of the kernel and must * be uninstalled before being freed or reused. Zero is returned * on success. */ int i2o_install_device(struct i2o_controller *c, struct i2o_device *d){ int i; down(&i2o_configuration_lock); d->controller=c; d->owner=NULL; d->next=c->devices; d->prev=NULL; if (c->devices != NULL) c->devices->prev=d; c->devices=d; *d->dev_name = 0; for(i = 0; i < I2O_MAX_MANAGERS; i++) d->managers[i] = NULL; up(&i2o_configuration_lock); return 0;}/* we need this version to call out of i2o_delete_controller */int __i2o_delete_device(struct i2o_device *d){ struct i2o_device **p; int i; p=&(d->controller->devices); /* * Hey we have a driver! * Check to see if the driver wants us to notify it of * device deletion. If it doesn't we assume that it * is unsafe to delete a device with an owner and * fail. */ if(d->owner) { if(d->owner->dev_del_notify) { dprintk(KERN_INFO "Device has owner, notifying\n"); d->owner->dev_del_notify(d->controller, d); if(d->owner) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?