#include <linux/smp_lock.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
+#include <linux/kthread.h>
#include "cpqphp.h"
static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,
u8 behind_bridge, struct resource_lists *resources);
static void interrupt_event_handler(struct controller *ctrl);
-static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */
-static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */
-static int event_finished;
-static unsigned long pushbutton_pending; /* = 0 */
-/* things needed for the long_delay function */
-static struct semaphore delay_sem;
-static wait_queue_head_t delay_wait;
+static struct task_struct *cpqhp_event_thread;
+static unsigned long pushbutton_pending; /* = 0 */
/* delay is in jiffies to wait for */
static void long_delay(int delay)
{
- DECLARE_WAITQUEUE(wait, current);
-
- /* only allow 1 customer into the delay queue at once
- * yes this makes some people wait even longer, but who really cares?
- * this is for _huge_ delays to make the hardware happy as the
- * signals bounce around
+ /*
+ * XXX(hch): if someone is bored please convert all callers
+ * to call msleep_interruptible directly. They really want
+ * to specify timeouts in natural units and spend a lot of
+ * effort converting them to jiffies..
*/
- down (&delay_sem);
-
- init_waitqueue_head(&delay_wait);
-
- add_wait_queue(&delay_wait, &wait);
msleep_interruptible(jiffies_to_msecs(delay));
- remove_wait_queue(&delay_wait, &wait);
-
- up(&delay_sem);
}
}
/**
- * cpqhp_find_slot: find the struct slot of given device
+ * cpqhp_find_slot - find the struct slot of given device
* @ctrl: scan lots of this controller
* @device: the device id to find
*/
/**
- * sort_by_size: sort nodes on the list by their length, smallest first.
+ * sort_by_size - sort nodes on the list by their length, smallest first.
* @head: list to sort
- *
*/
static int sort_by_size(struct pci_resource **head)
{
/**
- * sort_by_max_size: sort nodes on the list by their length, largest first.
+ * sort_by_max_size - sort nodes on the list by their length, largest first.
* @head: list to sort
- *
*/
static int sort_by_max_size(struct pci_resource **head)
{
/**
- * do_pre_bridge_resource_split: find node of resources that are unused
- *
+ * do_pre_bridge_resource_split - find node of resources that are unused
+ * @head: new list head
+ * @orig_head: original list head
+ * @alignment: max node size (?)
*/
static struct pci_resource *do_pre_bridge_resource_split(struct pci_resource **head,
struct pci_resource **orig_head, u32 alignment)
/**
- * do_bridge_resource_split: find one node of resources that aren't in use
- *
+ * do_bridge_resource_split - find one node of resources that aren't in use
+ * @head: list head
+ * @alignment: max node size (?)
*/
static struct pci_resource *do_bridge_resource_split(struct pci_resource **head, u32 alignment)
{
/**
- * get_io_resource: find first node of given size not in ISA aliasing window.
+ * get_io_resource - find first node of given size not in ISA aliasing window.
* @head: list to search
* @size: size of node to find, must be a power of two.
*
- * Description: this function sorts the resource list by size and then returns
+ * Description: This function sorts the resource list by size and then returns
* returns the first node of "size" length that is not in the ISA aliasing
* window. If it finds a node larger than "size" it will split it up.
- *
*/
static struct pci_resource *get_io_resource(struct pci_resource **head, u32 size)
{
/**
- * get_max_resource: get largest node which has at least the given size.
+ * get_max_resource - get largest node which has at least the given size.
* @head: the list to search the node in
* @size: the minimum size of the node to find
*
/**
- * get_resource: find resource of given size and split up larger ones.
+ * get_resource - find resource of given size and split up larger ones.
* @head: the list to search for resources
* @size: the size limit to use
*
/**
- * cpqhp_resource_sort_and_combine: sort nodes by base addresses and clean up.
+ * cpqhp_resource_sort_and_combine - sort nodes by base addresses and clean up
* @head: the list to sort and clean up
*
* Description: Sorts all of the nodes in the list in ascending order by
* their base addresses. Also does garbage collection by
* combining adjacent nodes.
*
- * returns 0 if success
+ * Returns %0 if success.
*/
int cpqhp_resource_sort_and_combine(struct pci_resource **head)
{
}
if (schedule_flag) {
- up(&event_semaphore);
- dbg("Signal event_semaphore\n");
+ wake_up_process(cpqhp_event_thread);
+ dbg("Waking even thread");
}
return IRQ_HANDLED;
}
/**
* cpqhp_slot_create - Creates a node and adds it to the proper bus.
- * @busnumber - bus where new node is to be located
+ * @busnumber: bus where new node is to be located
*
- * Returns pointer to the new node or NULL if unsuccessful
+ * Returns pointer to the new node or %NULL if unsuccessful.
*/
struct pci_func *cpqhp_slot_create(u8 busnumber)
{
struct pci_func *new_slot;
struct pci_func *next;
- new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL);
-
+ new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL);
if (new_slot == NULL) {
/* I'm not dead yet!
* You will be. */
return new_slot;
}
- memset(new_slot, 0, sizeof(struct pci_func));
-
new_slot->next = NULL;
new_slot->configured = 1;
* slot_remove - Removes a node from the linked list of slots.
* @old_slot: slot to remove
*
- * Returns 0 if successful, !0 otherwise.
+ * Returns %0 if successful, !0 otherwise.
*/
static int slot_remove(struct pci_func * old_slot)
{
* bridge_slot_remove - Removes a node from the linked list of slots.
* @bridge: bridge to remove
*
- * Returns 0 if successful, !0 otherwise.
+ * Returns %0 if successful, !0 otherwise.
*/
static int bridge_slot_remove(struct pci_func *bridge)
{
* cpqhp_slot_find - Looks for a node by bus, and device, multiple functions accessed
* @bus: bus to find
* @device: device to find
- * @index: is 0 for first function found, 1 for the second...
+ * @index: is %0 for first function found, %1 for the second...
*
* Returns pointer to the node if successful, %NULL otherwise.
*/
/**
- * set_controller_speed - set the frequency and/or mode of a specific
- * controller segment.
- *
+ * set_controller_speed - set the frequency and/or mode of a specific controller segment.
* @ctrl: controller to change frequency/mode for.
* @adapter_speed: the speed of the adapter we want to match.
* @hp_slot: the slot number where the adapter is installed.
*
- * Returns 0 if we successfully change frequency and/or mode to match the
+ * Returns %0 if we successfully change frequency and/or mode to match the
* adapter speed.
- *
*/
static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_slot)
{
/**
* board_replaced - Called after a board has been replaced in the system.
+ * @func: PCI device/function information
+ * @ctrl: hotplug controller
*
- * This is only used if we don't have resources for hot add
- * Turns power on for the board
- * Checks to see if board is the same
- * If board is same, reconfigures it
+ * This is only used if we don't have resources for hot add.
+ * Turns power on for the board.
+ * Checks to see if board is the same.
+ * If board is same, reconfigures it.
* If board isn't same, turns it back off.
- *
*/
static u32 board_replaced(struct pci_func *func, struct controller *ctrl)
{
/**
* board_added - Called after a board has been added to the system.
+ * @func: PCI device/function info
+ * @ctrl: hotplug controller
*
- * Turns power on for the board
- * Configures board
- *
+ * Turns power on for the board.
+ * Configures board.
*/
static u32 board_added(struct pci_func *func, struct controller *ctrl)
{
/**
- * remove_board - Turns off slot and LED's
- *
+ * remove_board - Turns off slot and LEDs
+ * @func: PCI device/function info
+ * @replace_flag: whether replacing or adding a new device
+ * @ctrl: target controller
*/
static u32 remove_board(struct pci_func * func, u32 replace_flag, struct controller * ctrl)
{
static void pushbutton_helper_thread(unsigned long data)
{
pushbutton_pending = data;
- up(&event_semaphore);
+ wake_up_process(cpqhp_event_thread);
}
{
struct controller *ctrl;
- daemonize("phpd_event");
-
while (1) {
dbg("!!!!event_thread sleeping\n");
- down_interruptible (&event_semaphore);
- dbg("event_thread woken finished = %d\n", event_finished);
- if (event_finished) break;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+
+ if (kthread_should_stop())
+ break;
/* Do stuff here */
if (pushbutton_pending)
cpqhp_pushbutton_thread(pushbutton_pending);
interrupt_event_handler(ctrl);
}
dbg("event_thread signals exit\n");
- up(&event_exit);
return 0;
}
-
int cpqhp_event_start_thread(void)
{
- int pid;
-
- /* initialize our semaphores */
- init_MUTEX(&delay_sem);
- init_MUTEX_LOCKED(&event_semaphore);
- init_MUTEX_LOCKED(&event_exit);
- event_finished=0;
-
- pid = kernel_thread(event_thread, NULL, 0);
- if (pid < 0) {
+ cpqhp_event_thread = kthread_run(event_thread, NULL, "phpd_event");
+ if (IS_ERR(cpqhp_event_thread)) {
err ("Can't start up our event thread\n");
- return -1;
+ return PTR_ERR(cpqhp_event_thread);
}
- dbg("Our event thread pid = %d\n", pid);
+
return 0;
}
void cpqhp_event_stop_thread(void)
{
- event_finished = 1;
- dbg("event_thread finish command given\n");
- up(&event_semaphore);
- dbg("wait for event_thread to exit\n");
- down(&event_exit);
+ kthread_stop(cpqhp_event_thread);
}
/**
- * cpqhp_pushbutton_thread
+ * cpqhp_pushbutton_thread - handle pushbutton events
+ * @slot: target slot (struct)
*
- * Scheduled procedure to handle blocking stuff for the pushbuttons
+ * Scheduled procedure to handle blocking stuff for the pushbuttons.
* Handles all pending events and exits.
- *
*/
void cpqhp_pushbutton_thread(unsigned long slot)
{
return ;
}
- if (func != NULL && ctrl != NULL) {
- if (cpqhp_process_SS(ctrl, func) != 0) {
- amber_LED_on (ctrl, hp_slot);
- green_LED_on (ctrl, hp_slot);
-
- set_SOGO(ctrl);
+ if (cpqhp_process_SS(ctrl, func) != 0) {
+ amber_LED_on(ctrl, hp_slot);
+ green_LED_on(ctrl, hp_slot);
- /* Wait for SOBS to be unset */
- wait_for_ctrl_irq (ctrl);
- }
+ set_SOGO(ctrl);
+
+ /* Wait for SOBS to be unset */
+ wait_for_ctrl_irq(ctrl);
}
p_slot->state = STATIC_STATE;
}
/**
- * switch_leds: switch the leds, go from one site to the other.
+ * switch_leds - switch the leds, go from one site to the other.
* @ctrl: controller to use
* @num_of_slots: number of slots to use
+ * @work_LED: LED control value
* @direction: 1 to start from the left side, 0 to start right.
*/
static void switch_leds(struct controller *ctrl, const int num_of_slots,
}
/**
- * hardware_test - runs hardware tests
+ * cpqhp_hardware_test - runs hardware tests
+ * @ctrl: target controller
+ * @test_num: the number written to the "test" file in sysfs.
*
* For hot plug ctrl folks to play with.
- * test_num is the number written to the "test" file in sysfs
- *
*/
int cpqhp_hardware_test(struct controller *ctrl, int test_num)
{
/**
* configure_new_device - Configures the PCI header information of one board.
- *
* @ctrl: pointer to controller structure
* @func: pointer to function structure
* @behind_bridge: 1 if this is a recursive call, 0 if not
* @resources: pointer to set of resource lists
*
- * Returns 0 if success
- *
+ * Returns 0 if success.
*/
static u32 configure_new_device(struct controller * ctrl, struct pci_func * func,
u8 behind_bridge, struct resource_lists * resources)
/**
* configure_new_function - Configures the PCI header information of one device
- *
* @ctrl: pointer to controller structure
* @func: pointer to function structure
* @behind_bridge: 1 if this is a recursive call, 0 if not
* @resources: pointer to set of resource lists
*
* Calls itself recursively for bridged devices.
- * Returns 0 if success
- *
+ * Returns 0 if success.
*/
static int configure_new_function(struct controller *ctrl, struct pci_func *func,
u8 behind_bridge,