Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dbd7a788 authored by Rajesh Shah's avatar Rajesh Shah Committed by Greg Kroah-Hartman
Browse files

[PATCH] shpchp: use the PCI core for hotplug resource management



This patch converts the standard hotplug controller driver to use
the PCI core for resource management. This eliminates a whole lot
of duplicated code, and integrates shpchp in the system's normal
PCI handling code.

Signed-off-by: default avatarRajesh Shah <rajesh.shah@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent e3b1bd57
Loading
Loading
Loading
Loading
+1 −56
Original line number Diff line number Diff line
@@ -63,14 +63,7 @@ struct pci_func {
	u8 switch_save;
	u8 presence_save;
	u8 pwr_save;
	u32 base_length[0x06];
	u8 base_type[0x06];
	u16 reserved2;
	u32 config_space[0x20];
	struct pci_resource *mem_head;
	struct pci_resource *p_mem_head;
	struct pci_resource *io_head;
	struct pci_resource *bus_head;
	struct pci_dev* pci_dev;
};

@@ -96,12 +89,6 @@ struct slot {
	struct list_head	slot_list;
};

struct pci_resource {
	struct pci_resource * next;
	u32 base;
	u32 length;
};

struct event_info {
	u32 event_type;
	u8 hp_slot;
@@ -113,10 +100,6 @@ struct controller {
	void * hpc_ctlr_handle;		/* HPC controller handle */
	int num_slots;			/* Number of slots on ctlr */
	int slot_num_inc;		/* 1 or -1 */
	struct pci_resource *mem_head;
	struct pci_resource *p_mem_head;
	struct pci_resource *io_head;
	struct pci_resource *bus_head;
	struct pci_dev *pci_dev;
	struct pci_bus *pci_bus;
	struct event_info event_queue[10];
@@ -139,20 +122,6 @@ struct controller {
	u16 vendor_id;
};

struct irq_mapping {
	u8 barber_pole;
	u8 valid_INT;
	u8 interrupt[4];
};

struct resource_lists {
	struct pci_resource *mem_head;
	struct pci_resource *p_mem_head;
	struct pci_resource *io_head;
	struct pci_resource *bus_head;
	struct irq_mapping *irqs;
};

/* Define AMD SHPC ID  */
#define PCI_DEVICE_ID_AMD_GOLAM_7450	0x7450 

@@ -197,7 +166,6 @@ struct resource_lists {
#define msg_HPC_rev_error	"Unsupported revision of the PCI hot plug controller found.\n"
#define msg_HPC_non_shpc	"The PCI hot plug controller is not supported by this driver.\n"
#define msg_HPC_not_supported	"This system is not supported by this version of shpcphd mdoule. Upgrade to a newer version of shpchpd\n"
#define msg_unable_to_save	"Unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n"
#define msg_button_on		"PCI slot #%d - powering on due to button press.\n"
#define msg_button_off		"PCI slot #%d - powering off due to button press.\n"
#define msg_button_cancel	"PCI slot #%d - action canceled due to button press.\n"
@@ -207,7 +175,6 @@ struct resource_lists {
extern void shpchp_create_ctrl_files	(struct controller *ctrl);

/* controller functions */
extern int	shpchprm_find_available_resources(struct controller *ctrl);
extern int	shpchp_event_start_thread(void);
extern void	shpchp_event_stop_thread(void);
extern struct 	pci_func *shpchp_slot_create(unsigned char busnumber);
@@ -220,19 +187,10 @@ extern u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id);
extern u8	shpchp_handle_presence_change(u8 hp_slot, void *inst_id);
extern u8	shpchp_handle_power_fault(u8 hp_slot, void *inst_id);

/* resource functions */
extern int	shpchp_resource_sort_and_combine(struct pci_resource **head);

/* pci functions */
extern int	shpchp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
/*extern int	shpchp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num, struct slot *slot);*/
extern int	shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num);
extern int	shpchp_save_used_resources(struct controller *ctrl, struct pci_func * func, int flag);
extern int	shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot);
extern void	shpchp_destroy_board_resources(struct pci_func * func);
extern int	shpchp_return_board_resources(struct pci_func * func, struct resource_lists * resources);
extern void	shpchp_destroy_resource_list(struct resource_lists * resources);
extern int	shpchp_configure_device(struct controller* ctrl, struct pci_func* func);
extern int	shpchp_configure_device(struct slot *p_slot);
extern int	shpchp_unconfigure_device(struct pci_func* func);


@@ -240,10 +198,6 @@ extern int shpchp_unconfigure_device(struct pci_func* func);
extern struct controller *shpchp_ctrl_list;
extern struct pci_func *shpchp_slot_list[256];

/* These are added to support AMD shpc */
extern u8 shpchp_nic_irq;
extern u8 shpchp_disk_irq;

struct ctrl_reg {
	volatile u32 base_offset;
	volatile u32 slot_avail1;
@@ -398,15 +352,6 @@ static inline int wait_for_ctrl_irq (struct controller *ctrl)
	return retval;
}

/* Puts node back in the resource list pointed to by head */
static inline void return_resource(struct pci_resource **head, struct pci_resource *node)
{
	if (!node || !head)
		return;
	node->next = *head;
	*head = node;
}

#define SLOT_NAME_SIZE 10

static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
+2 −34
Original line number Diff line number Diff line
@@ -418,15 +418,7 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
		goto err_out_free_ctrl_bus;
	}

	/* Get IO, memory, and IRQ resources for new devices */
	rc = shpchprm_find_available_resources(ctrl);
	ctrl->add_support = !rc;
	
	if (rc) {
		dbg("shpchprm_find_available_resources = %#x\n", rc);
		err("unable to locate PCI configuration resources for hot plug add.\n");
		goto err_out_free_ctrl_bus;
	}
	ctrl->add_support = 1;
	
	/* Setup the slot information structures */
	rc = init_slots(ctrl);
@@ -497,18 +489,6 @@ static int shpc_start_thread(void)
	return retval;
}

static inline void __exit
free_shpchp_res(struct pci_resource *res)
{
	struct pci_resource *tres;

	while (res) {
		tres = res;
		res = res->next;
		kfree(tres);
	}
}

static void __exit unload_shpchpd(void)
{
	struct pci_func *next;
@@ -522,11 +502,6 @@ static void __exit unload_shpchpd(void)
	while (ctrl) {
		cleanup_slots(ctrl);

		free_shpchp_res(ctrl->io_head);
		free_shpchp_res(ctrl->mem_head);
		free_shpchp_res(ctrl->p_mem_head);
		free_shpchp_res(ctrl->bus_head);

		kfree (ctrl->pci_bus);

		dbg("%s: calling release_ctlr\n", __FUNCTION__);
@@ -541,11 +516,6 @@ static void __exit unload_shpchpd(void)
	for (loop = 0; loop < 256; loop++) {
		next = shpchp_slot_list[loop];
		while (next != NULL) {
			free_shpchp_res(next->io_head);
			free_shpchp_res(next->mem_head);
			free_shpchp_res(next->p_mem_head);
			free_shpchp_res(next->bus_head);

			TempSlot = next;
			next = next->next;
			kfree(TempSlot);
@@ -607,9 +577,7 @@ static int __init shpcd_init(void)
	if (retval) {
		shpchprm_cleanup();
		shpchp_event_stop_thread();
	} else
		shpchprm_print_pirt();

	}
	return retval;
}

+42 −1582

File changed.

Preview size limit exceeded, changes collapsed.

+53 −429
Original line number Diff line number Diff line
@@ -37,46 +37,69 @@
#include <linux/pci.h>
#include "../pci.h"
#include "shpchp.h"
#ifndef CONFIG_IA64
#include "../../../arch/i386/pci/pci.h"    /* horrible hack showing how processor dependant we are... */
#endif

int shpchp_configure_device (struct controller* ctrl, struct pci_func* func)  
int shpchp_configure_device(struct slot *p_slot)
{
	unsigned char bus;
	struct pci_bus *child;
	int num;

	if (func->pci_dev == NULL)
		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));

	/* Still NULL ? Well then scan for it ! */
	if (func->pci_dev == NULL) {
		num = pci_scan_slot(ctrl->pci_dev->subordinate, PCI_DEVFN(func->device, func->function));
		if (num) {
			dbg("%s: subordiante %p number %x\n", __FUNCTION__, ctrl->pci_dev->subordinate,
				ctrl->pci_dev->subordinate->number);
			pci_bus_add_devices(ctrl->pci_dev->subordinate);
		}
	struct pci_dev *dev;
	struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
	int num, fn;

		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));
		if (func->pci_dev == NULL) {
			dbg("ERROR: pci_dev still null\n");
			return 0;
		}
	dev = pci_find_slot(p_slot->bus, PCI_DEVFN(p_slot->device, 0));
	if (dev) {
		err("Device %s already exists at %x:%x, cannot hot-add\n",
				pci_name(dev), p_slot->bus, p_slot->device);
		return -EINVAL;
	}

	if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
		pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus);
		child = pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus);
		pci_do_scan_bus(child);
	num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0));
	if (num == 0) {
		err("No new device found\n");
		return -ENODEV;
	}

	for (fn = 0; fn < 8; fn++) {
		if (!(dev = pci_find_slot(p_slot->bus,
					PCI_DEVFN(p_slot->device, fn))))
			continue;
		if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
			err("Cannot hot-add display device %s\n",
					pci_name(dev));
			continue;
		}
		if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
				(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
			/* Find an unused bus number for the new bridge */
			struct pci_bus *child;
			unsigned char busnr, start = parent->secondary;
			unsigned char end = parent->subordinate;
			for (busnr = start; busnr <= end; busnr++) {
				if (!pci_find_bus(pci_domain_nr(parent),
							busnr))
					break;
			}
			if (busnr >= end) {
				err("No free bus for hot-added bridge\n");
				continue;
			}
			child = pci_add_new_bus(parent, dev, busnr);
			if (!child) {
				err("Cannot add new bus for %s\n",
						pci_name(dev));
				continue;
			}
			child->subordinate = pci_do_scan_bus(child);
			pci_bus_size_bridges(child);
		}
		/* TBD: program firmware provided _HPP values */
		/* program_fw_provided_values(dev); */
	}

	pci_bus_assign_resources(parent);
	pci_bus_add_devices(parent);
	pci_enable_bridges(parent);
	return 0;
}


int shpchp_unconfigure_device(struct pci_func* func) 
{
	int rc = 0;
@@ -95,44 +118,6 @@ int shpchp_unconfigure_device(struct pci_func* func)
	return rc;
}

/*
 * shpchp_set_irq
 *
 * @bus_num: bus number of PCI device
 * @dev_num: device number of PCI device
 * @slot: pointer to u8 where slot number will be returned
 */
int shpchp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
{
#if defined(CONFIG_X86) && !defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_64)
	int rc;
	u16 temp_word;
	struct pci_dev fakedev;
	struct pci_bus fakebus;

	fakedev.devfn = dev_num << 3;
	fakedev.bus = &fakebus;
	fakebus.number = bus_num;
	dbg("%s: dev %d, bus %d, pin %d, num %d\n",
	    __FUNCTION__, dev_num, bus_num, int_pin, irq_num);
	rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num);
	dbg("%s: rc %d\n", __FUNCTION__, rc);
	if (!rc)
		return !rc;

	/* set the Edge Level Control Register (ELCR) */
	temp_word = inb(0x4d0);
	temp_word |= inb(0x4d1) << 8;

	temp_word |= 0x01 << irq_num;

	/* This should only be for x86 as it sets the Edge Level Control Register */
	outb((u8) (temp_word & 0xFF), 0x4d0);
	outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1);
#endif
	return 0;
}

/* More PCI configuration routines; this time centered around hotplug controller */


@@ -447,364 +432,3 @@ int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot)
	return 0;
}

/*
 * shpchp_save_used_resources
 *
 * Stores used resource information for existing boards.  this is
 * for boards that were in the system when this driver was loaded.
 * this function is for hot plug ADD
 *
 * returns 0 if success
 * if disable  == 1(DISABLE_CARD),
 *  it loops for all functions of the slot and disables them.
 * else, it just get resources of the function and return.
 */
int shpchp_save_used_resources(struct controller *ctrl, struct pci_func *func, int disable)
{
	u8 cloop;
	u8 header_type;
	u8 secondary_bus;
	u8 temp_byte;
	u16 command;
	u16 save_command;
	u16 w_base, w_length;
	u32 temp_register;
	u32 save_base;
	u32 base, length;
	u64 base64 = 0;
	int index = 0;
	unsigned int devfn;
	struct pci_resource *mem_node = NULL;
	struct pci_resource *p_mem_node = NULL;
	struct pci_resource *t_mem_node;
	struct pci_resource *io_node;
	struct pci_resource *bus_node;
	struct pci_bus lpci_bus, *pci_bus;
	memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
	pci_bus = &lpci_bus;

	if (disable)
		func = shpchp_slot_find(func->bus, func->device, index++);

	while ((func != NULL) && func->is_a_board) {
		pci_bus->number = func->bus;
		devfn = PCI_DEVFN(func->device, func->function);

		/* Save the command register */
		pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command);

		if (disable) {
			/* disable card */
			command = 0x00;
			pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
		}

		/* Check for Bridge */
		pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);

		if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {     /* PCI-PCI Bridge */
			dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n",
					func->bus, func->device, save_command);
			if (disable) {
				/* Clear Bridge Control Register */
				command = 0x00;
				pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
			}

			pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
			pci_bus_read_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte);

			bus_node = kmalloc(sizeof(struct pci_resource),
						GFP_KERNEL);
			if (!bus_node)
				return -ENOMEM;

			bus_node->base = (ulong)secondary_bus;
			bus_node->length = (ulong)(temp_byte - secondary_bus + 1);

			bus_node->next = func->bus_head;
			func->bus_head = bus_node;

			/* Save IO base and Limit registers */
			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &temp_byte);
			base = temp_byte;
			pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &temp_byte);
			length = temp_byte;

			if ((base <= length) && (!disable || (save_command & PCI_COMMAND_IO))) {
				io_node = kmalloc(sizeof(struct pci_resource),
							GFP_KERNEL);
				if (!io_node)
					return -ENOMEM;

				io_node->base = (ulong)(base & PCI_IO_RANGE_MASK) << 8;
				io_node->length = (ulong)(length - base + 0x10) << 8;

				io_node->next = func->io_head;
				func->io_head = io_node;
			}

			/* Save memory base and Limit registers */
			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base);
			pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length);

			if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
				mem_node = kmalloc(sizeof(struct pci_resource),
						GFP_KERNEL);
				if (!mem_node)
					return -ENOMEM;

				mem_node->base = (ulong)w_base << 16;
				mem_node->length = (ulong)(w_length - w_base + 0x10) << 16;

				mem_node->next = func->mem_head;
				func->mem_head = mem_node;
			}
			/* Save prefetchable memory base and Limit registers */
			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base);
			pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length);

			if ((w_base <= w_length) && (!disable || (save_command & PCI_COMMAND_MEMORY))) {
				p_mem_node = kmalloc(sizeof(struct pci_resource),
						GFP_KERNEL);
				if (!p_mem_node)
					return -ENOMEM;

				p_mem_node->base = (ulong)w_base << 16;
				p_mem_node->length = (ulong)(w_length - w_base + 0x10) << 16;

				p_mem_node->next = func->p_mem_head;
				func->p_mem_head = p_mem_node;
			}
		} else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
			dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n",
					func->bus, func->device, save_command);

			/* Figure out IO and memory base lengths */
			for (cloop = PCI_BASE_ADDRESS_0; cloop <= PCI_BASE_ADDRESS_5; cloop += 4) {
				pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base);

				temp_register = 0xFFFFFFFF;
				pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register);
				pci_bus_read_config_dword(pci_bus, devfn, cloop, &temp_register);

				if (!disable)
					pci_bus_write_config_dword(pci_bus, devfn, cloop, save_base);

				if (!temp_register)
					continue;

				base = temp_register;

				if ((base & PCI_BASE_ADDRESS_SPACE_IO) &&
						(!disable || (save_command & PCI_COMMAND_IO))) {
					/* IO base */
					/* set temp_register = amount of IO space requested */
					base = base & 0xFFFFFFFCL;
					base = (~base) + 1;

					io_node =  kmalloc(sizeof (struct pci_resource),
								GFP_KERNEL);
					if (!io_node)
						return -ENOMEM;

					io_node->base = (ulong)save_base & PCI_BASE_ADDRESS_IO_MASK;
					io_node->length = (ulong)base;
					dbg("sur adapter: IO bar=0x%x(length=0x%x)\n",
						io_node->base, io_node->length);

					io_node->next = func->io_head;
					func->io_head = io_node;
				} else {  /* map Memory */
					int prefetchable = 1;
					/* struct pci_resources **res_node; */
					char *res_type_str = "PMEM";
					u32 temp_register2;

					t_mem_node = kmalloc(sizeof (struct pci_resource),
								GFP_KERNEL);
					if (!t_mem_node)
						return -ENOMEM;

					if (!(base & PCI_BASE_ADDRESS_MEM_PREFETCH) &&
							(!disable || (save_command & PCI_COMMAND_MEMORY))) {
						prefetchable = 0;
						mem_node = t_mem_node;
						res_type_str++;
					} else
						p_mem_node = t_mem_node;

					base = base & 0xFFFFFFF0L;
					base = (~base) + 1;

					switch (temp_register & PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
					case PCI_BASE_ADDRESS_MEM_TYPE_32:
						if (prefetchable) {
							p_mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
							p_mem_node->length = (ulong)base;
							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n",
								res_type_str, 
								p_mem_node->base,
								p_mem_node->length);

							p_mem_node->next = func->p_mem_head;
							func->p_mem_head = p_mem_node;
						} else {
							mem_node->base = (ulong)save_base & PCI_BASE_ADDRESS_MEM_MASK;
							mem_node->length = (ulong)base;
							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n",
								res_type_str, 
								mem_node->base,
								mem_node->length);

							mem_node->next = func->mem_head;
							func->mem_head = mem_node;
						}
						break;
					case PCI_BASE_ADDRESS_MEM_TYPE_64:
						pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &temp_register2);
						base64 = temp_register2;
						base64 = (base64 << 32) | save_base;

						if (temp_register2) {
							dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n", 
								res_type_str, temp_register2, (u32)base64);
							base64 &= 0x00000000FFFFFFFFL;
						}

						if (prefetchable) {
							p_mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
							p_mem_node->length = base;
							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n",
								res_type_str, 
								p_mem_node->base,
								p_mem_node->length);

							p_mem_node->next = func->p_mem_head;
							func->p_mem_head = p_mem_node;
						} else {
							mem_node->base = base64 & PCI_BASE_ADDRESS_MEM_MASK;
							mem_node->length = base;
							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n",
								res_type_str, 
								mem_node->base,
								mem_node->length);

							mem_node->next = func->mem_head;
							func->mem_head = mem_node;
						}
						cloop += 4;
						break;
					default:
						dbg("asur: reserved BAR type=0x%x\n",
							temp_register);
						break;
					}
				} 
			}	/* End of base register loop */
		} else {	/* Some other unknown header type */
			dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n",
					func->bus, func->device);
		}

		/* find the next device in this slot */
		if (!disable)
			break;
		func = shpchp_slot_find(func->bus, func->device, index++);
	}

	return 0;
}

/**
 * kfree_resource_list: release memory of all list members
 * @res: resource list to free
 */
static inline void
return_resource_list(struct pci_resource **func, struct pci_resource **res)
{
	struct pci_resource *node;
	struct pci_resource *t_node;

	node = *func;
	*func = NULL;
	while (node) {
		t_node = node->next;
		return_resource(res, node);
		node = t_node;
	}
}

/*
 * shpchp_return_board_resources
 *
 * this routine returns all resources allocated to a board to
 * the available pool.
 *
 * returns 0 if success
 */
int shpchp_return_board_resources(struct pci_func * func,
					struct resource_lists * resources)
{
	int rc;
	dbg("%s\n", __FUNCTION__);

	if (!func)
		return 1;

	return_resource_list(&(func->io_head),&(resources->io_head));
	return_resource_list(&(func->mem_head),&(resources->mem_head));
	return_resource_list(&(func->p_mem_head),&(resources->p_mem_head));
	return_resource_list(&(func->bus_head),&(resources->bus_head));

	rc = shpchp_resource_sort_and_combine(&(resources->mem_head));
	rc |= shpchp_resource_sort_and_combine(&(resources->p_mem_head));
	rc |= shpchp_resource_sort_and_combine(&(resources->io_head));
	rc |= shpchp_resource_sort_and_combine(&(resources->bus_head));

	return rc;
}

/**
 * kfree_resource_list: release memory of all list members
 * @res: resource list to free
 */
static inline void
kfree_resource_list(struct pci_resource **r)
{
	struct pci_resource *res, *tres;

	res = *r;
	*r = NULL;

	while (res) {
		tres = res;
		res = res->next;
		kfree(tres);
	}
}

/**
 * shpchp_destroy_resource_list: put node back in the resource list
 * @resources: list to put nodes back
 */
void shpchp_destroy_resource_list(struct resource_lists *resources)
{
	kfree_resource_list(&(resources->io_head));
	kfree_resource_list(&(resources->mem_head));
	kfree_resource_list(&(resources->p_mem_head));
	kfree_resource_list(&(resources->bus_head));
}

/**
 * shpchp_destroy_board_resources: put node back in the resource list
 * @resources: list to put nodes back
 */
void shpchp_destroy_board_resources(struct pci_func * func)
{
	kfree_resource_list(&(func->io_head));
	kfree_resource_list(&(func->mem_head));
	kfree_resource_list(&(func->p_mem_head));
	kfree_resource_list(&(func->bus_head));
}
+70 −51
Original line number Diff line number Diff line
@@ -40,43 +40,49 @@

static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, char *buf)
{
	struct pci_dev *pci_dev;
	struct controller *ctrl;
	struct pci_dev *pdev;
	char * out = buf;
	int index;
	struct pci_resource *res;
	int index, busnr;
	struct resource *res;
	struct pci_bus *bus;

	pci_dev = container_of (dev, struct pci_dev, dev);
	ctrl = pci_get_drvdata(pci_dev);
	pdev = container_of (dev, struct pci_dev, dev);
	bus = pdev->subordinate;

	out += sprintf(buf, "Free resources: memory\n");
	index = 11;
	res = ctrl->mem_head;
	while (res && index--) {
		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
		res = res->next;
	for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) {
		res = bus->resource[index];
		if (res && (res->flags & IORESOURCE_MEM) &&
				!(res->flags & IORESOURCE_PREFETCH)) {
			out += sprintf(out, "start = %8.8lx, length = %8.8lx\n",
					res->start, (res->end - res->start));
		}
	}
	out += sprintf(out, "Free resources: prefetchable memory\n");
	index = 11;
	res = ctrl->p_mem_head;
	while (res && index--) {
		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
		res = res->next;
	for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) {
		res = bus->resource[index];
		if (res && (res->flags & IORESOURCE_MEM) &&
			       (res->flags & IORESOURCE_PREFETCH)) {
			out += sprintf(out, "start = %8.8lx, length = %8.8lx\n",
					res->start, (res->end - res->start));
		}
	}
	out += sprintf(out, "Free resources: IO\n");
	index = 11;
	res = ctrl->io_head;
	while (res && index--) {
		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
		res = res->next;
	for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) {
		res = bus->resource[index];
		if (res && (res->flags & IORESOURCE_IO)) {
			out += sprintf(out, "start = %8.8lx, length = %8.8lx\n",
					res->start, (res->end - res->start));
		}
	}
	out += sprintf(out, "Free resources: bus numbers\n");
	index = 11;
	res = ctrl->bus_head;
	while (res && index--) {
		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
		res = res->next;
	for (busnr = bus->secondary; busnr <= bus->subordinate; busnr++) {
		if (!pci_find_bus(pci_domain_nr(bus), busnr))
			break;
	}
	if (busnr < bus->subordinate)
		out += sprintf(out, "start = %8.8x, length = %8.8x\n",
				busnr, (bus->subordinate - busnr));

	return out - buf;
}
@@ -84,16 +90,16 @@ static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL);

static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char *buf)
{
	struct pci_dev *pci_dev;
	struct pci_dev *pdev, *fdev;
	struct controller *ctrl;
	char * out = buf;
	int index;
	struct pci_resource *res;
	struct resource *res;
	struct pci_func *new_slot;
	struct slot *slot;

	pci_dev = container_of (dev, struct pci_dev, dev);
	ctrl = pci_get_drvdata(pci_dev);
	pdev = container_of (dev, struct pci_dev, dev);
	ctrl = pci_get_drvdata(pdev);

	slot=ctrl->slot;

@@ -101,34 +107,47 @@ static ssize_t show_dev (struct device *dev, struct device_attribute *attr, char
		new_slot = shpchp_slot_find(slot->bus, slot->device, 0);
		if (!new_slot)
			break;
		fdev = new_slot->pci_dev;
		if (!fdev)
			break;
		out += sprintf(out, "assigned resources: memory\n");
		index = 11;
		res = new_slot->mem_head;
		while (res && index--) {
			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
			res = res->next;
		for (index=0; index <= PCI_NUM_RESOURCES; index++) {
			res = &(fdev->resource[index]);
			if (res && (res->flags & IORESOURCE_MEM) &&
					!(res->flags & IORESOURCE_PREFETCH)) {
				out += sprintf(out,
					"start = %8.8lx, length = %8.8lx\n",
					res->start, (res->end - res->start));
			}
		}
		out += sprintf(out, "assigned resources: prefetchable memory\n");
		index = 11;
		res = new_slot->p_mem_head;
		while (res && index--) {
			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
			res = res->next;
		for (index=0; index <= PCI_NUM_RESOURCES; index++) {
			res = &(fdev->resource[index]);
			if (res && (res->flags & (IORESOURCE_MEM |
						IORESOURCE_PREFETCH))) {
				out += sprintf(out,
					"start = %8.8lx, length = %8.8lx\n",
					res->start, (res->end - res->start));
			}
		}
		out += sprintf(out, "assigned resources: IO\n");
		index = 11;
		res = new_slot->io_head;
		while (res && index--) {
			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
			res = res->next;
		for (index=0; index <= PCI_NUM_RESOURCES; index++) {
			res = &(fdev->resource[index]);
			if (res && (res->flags & IORESOURCE_IO)) {
				out += sprintf(out,
					"start = %8.8lx, length = %8.8lx\n",
					res->start, (res->end - res->start));
			}
		out += sprintf(out, "assigned resources: bus numbers\n");
		index = 11;
		res = new_slot->bus_head;
		while (res && index--) {
			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length);
			res = res->next;
		}
		out += sprintf(out, "assigned resources: bus numbers\n");
		if (fdev->subordinate)
			out += sprintf(out, "start = %8.8x, length = %8.8x\n",
				fdev->subordinate->secondary,
				(fdev->subordinate->subordinate -
				 fdev->subordinate->secondary));
		else
			out += sprintf(out, "start = %8.8x, length = %8.8x\n",
					fdev->bus->number, 1);
		slot=slot->next;
	}

Loading