Commit 19685246 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge kroah.com:/home/greg/linux/BK/bleed-2.5

into kroah.com:/home/greg/linux/BK/pci-hp-2.5
parents 7d5bea38 b8d261e0
......@@ -9,8 +9,7 @@ obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o
obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550) += cpcihp_zt5550.o
obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC) += cpcihp_generic.o
pci_hotplug-objs := pci_hotplug_core.o \
pci_hotplug_util.o
pci_hotplug-objs := pci_hotplug_core.o
ifdef CONFIG_HOTPLUG_PCI_CPCI
pci_hotplug-objs += cpci_hotplug_core.o \
......
......@@ -578,6 +578,7 @@ static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int
bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
if (!bridge->io_head) {
err("out of memory\n");
kfree(bridge);
return;
}
dbg("16bit I/O range: %04x-%04x\n",
......@@ -592,6 +593,7 @@ static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int
bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
if (!bridge->io_head) {
err("out of memory\n");
kfree(bridge);
return;
}
dbg("32bit I/O range: %08x-%08x\n",
......@@ -613,6 +615,7 @@ static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int
bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
if (!bridge->mem_head) {
err("out of memory\n");
kfree(bridge);
return;
}
dbg("32bit Memory range: %08x-%08x\n",
......@@ -632,6 +635,7 @@ static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int
bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
if (!bridge->p_mem_head) {
err("out of memory\n");
kfree(bridge);
return;
}
dbg("32bit Prefetchable memory range: %08x-%08x\n",
......@@ -647,6 +651,7 @@ static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int
bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1);
if (!bridge->p_mem_head) {
err("out of memory\n");
kfree(bridge);
return;
}
dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n",
......
......@@ -130,7 +130,7 @@ update_latch_status(struct hotplug_slot *hotplug_slot, u8 value)
return -EINVAL;
memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
info.latch_status = value;
return pci_hp_change_slot_info(hotplug_slot->name, &info);
return pci_hp_change_slot_info(hotplug_slot, &info);
}
static int
......@@ -142,7 +142,7 @@ update_adapter_status(struct hotplug_slot *hotplug_slot, u8 value)
return -EINVAL;
memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
info.adapter_status = value;
return pci_hp_change_slot_info(hotplug_slot->name, &info);
return pci_hp_change_slot_info(hotplug_slot, &info);
}
static int
......
......@@ -395,6 +395,8 @@ static int cpci_configure_bridge(struct pci_bus* bus, struct pci_dev* dev)
/* Scan behind bridge */
n = pci_scan_bridge(bus, dev, max, 2);
child = pci_find_bus(max + 1);
if (!child)
return -ENODEV;
#ifdef CONFIG_PROC_FS
pci_proc_attach_bus(child);
#endif
......
......@@ -488,6 +488,8 @@ static int get_slot_mapping (struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *sl
bridgeSlot = 0xFF;
PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table();
if (!PCIIRQRoutingInfoLength)
return -1;
len = (PCIIRQRoutingInfoLength->size -
sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
......
......@@ -188,6 +188,8 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl)
rc++;
p_slot = find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4));
if (!p_slot)
return 0;
// If the switch closed, must be a button
// If not in button mode, nevermind
......@@ -1765,19 +1767,17 @@ void cpqhp_event_stop_thread (void)
static int update_slot_info (struct controller *ctrl, struct slot *slot)
{
struct hotplug_slot_info *info;
char buffer[SLOT_NAME_SIZE];
int result;
info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot);
info->power_status = get_slot_enabled(ctrl, slot);
info->attention_status = cpq_get_attention_status(ctrl, slot);
info->latch_status = cpq_get_latch_status(ctrl, slot);
info->adapter_status = get_presence_status(ctrl, slot);
result = pci_hp_change_slot_info(buffer, info);
result = pci_hp_change_slot_info(slot->hotplug_slot, info);
kfree (info);
return result;
}
......@@ -1799,8 +1799,12 @@ static void interrupt_event_handler(struct controller *ctrl)
hp_slot = ctrl->event_queue[loop].hp_slot;
func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0);
if (!func)
return;
p_slot = find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
if (!p_slot)
return;
dbg("hp_slot %d, func %p, p_slot %p\n",
hp_slot, func, p_slot);
......@@ -2511,8 +2515,14 @@ static int configure_new_function (struct controller * ctrl, struct pci_func * f
// Setup the IO, memory, and prefetchable windows
io_node = get_max_resource(&(resources->io_head), 0x1000);
if (!io_node)
return -ENOMEM;
mem_node = get_max_resource(&(resources->mem_head), 0x100000);
if (!mem_node)
return -ENOMEM;
p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000);
if (!p_mem_node)
return -ENOMEM;
dbg("Setup the IO, memory, and prefetchable windows\n");
dbg("io_node\n");
dbg("(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next);
......
......@@ -473,7 +473,7 @@ int compaq_nvram_load (void *rom_start, struct controller *ctrl)
p_byte += 3;
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
return(2);
return 2;
bus = p_ev_ctrl->bus;
device = p_ev_ctrl->device;
......@@ -490,20 +490,20 @@ int compaq_nvram_load (void *rom_start, struct controller *ctrl)
p_byte += 4;
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
return(2);
return 2;
// Skip forward to the next entry
p_byte += (nummem + numpmem + numio + numbus) * 8;
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
return(2);
return 2;
p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte;
p_byte += 3;
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
return(2);
return 2;
bus = p_ev_ctrl->bus;
device = p_ev_ctrl->device;
......@@ -518,7 +518,7 @@ int compaq_nvram_load (void *rom_start, struct controller *ctrl)
p_byte += 4;
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
return(2);
return 2;
while (nummem--) {
mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
......@@ -530,15 +530,19 @@ int compaq_nvram_load (void *rom_start, struct controller *ctrl)
dbg("mem base = %8.8x\n",mem_node->base);
p_byte += 4;
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
return(2);
if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
kfree(mem_node);
return 2;
}
mem_node->length = *(u32*)p_byte;
dbg("mem length = %8.8x\n",mem_node->length);
p_byte += 4;
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
return(2);
if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
kfree(mem_node);
return 2;
}
mem_node->next = ctrl->mem_head;
ctrl->mem_head = mem_node;
......@@ -554,15 +558,19 @@ int compaq_nvram_load (void *rom_start, struct controller *ctrl)
dbg("pre-mem base = %8.8x\n",p_mem_node->base);
p_byte += 4;
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
return(2);
if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
kfree(p_mem_node);
return 2;
}
p_mem_node->length = *(u32*)p_byte;
dbg("pre-mem length = %8.8x\n",p_mem_node->length);
p_byte += 4;
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
return(2);
if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
kfree(p_mem_node);
return 2;
}
p_mem_node->next = ctrl->p_mem_head;
ctrl->p_mem_head = p_mem_node;
......@@ -578,15 +586,19 @@ int compaq_nvram_load (void *rom_start, struct controller *ctrl)
dbg("io base = %8.8x\n",io_node->base);
p_byte += 4;
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
return(2);
if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
kfree(io_node);
return 2;
}
io_node->length = *(u32*)p_byte;
dbg("io length = %8.8x\n",io_node->length);
p_byte += 4;
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
return(2);
if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
kfree(io_node);
return 2;
}
io_node->next = ctrl->io_head;
ctrl->io_head = io_node;
......@@ -601,15 +613,18 @@ int compaq_nvram_load (void *rom_start, struct controller *ctrl)
bus_node->base = *(u32*)p_byte;
p_byte += 4;
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
return(2);
if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
kfree(bus_node);
return 2;
}
bus_node->length = *(u32*)p_byte;
p_byte += 4;
if (p_byte > ((u8*)p_EV_header + evbuffer_length))
return(2);
if (p_byte > ((u8*)p_EV_header + evbuffer_length)) {
kfree(bus_node);
return 2;
}
bus_node->next = ctrl->bus_head;
ctrl->bus_head = bus_node;
......@@ -623,13 +638,11 @@ int compaq_nvram_load (void *rom_start, struct controller *ctrl)
rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));
if (rc) {
if (rc)
return(rc);
}
} else {
if ((evbuffer[0] != 0) && (!ctrl->push_flag)) {
return(1);
}
if ((evbuffer[0] != 0) && (!ctrl->push_flag))
return 1;
}
return 0;
......
......@@ -435,6 +435,8 @@ static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num
u8 tbus, tdevice, tslot;
PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table();
if (!PCIIRQRoutingInfoLength)
return -1;
len = (PCIIRQRoutingInfoLength->size -
sizeof(struct irq_routing_table)) / sizeof(struct irq_info);
......@@ -1191,7 +1193,7 @@ int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func)
if (temp != func->config_space[cloop >> 2]) {
dbg("Config space compare failure!!! offset = %x\n", cloop);
dbg("bus = %x, device = %x, function = %x\n", func->bus, func->device, func->function);
dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop]);
dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop >> 2]);
return 1;
}
}
......
......@@ -113,6 +113,8 @@ static int read_dev (char *buf, char **start, off_t offset, int len, int *eof, v
while (slot) {
new_slot = cpqhp_slot_find(slot->bus, slot->device, 0);
if (!new_slot)
break;
out += sprintf(out, "assigned resources: memory\n");
index = 11;
res = new_slot->mem_head;
......
......@@ -686,7 +686,6 @@ static int validate (struct slot *slot_cur, int opn)
int ibmphp_update_slot_info (struct slot *slot_cur)
{
struct hotplug_slot_info *info;
char buffer[30];
int rc;
u8 bus_speed;
u8 mode;
......@@ -697,7 +696,6 @@ int ibmphp_update_slot_info (struct slot *slot_cur)
return -ENOMEM;
}
strncpy (buffer, slot_cur->hotplug_slot->name, 30);
info->power_status = SLOT_PWRGD (slot_cur->status);
info->attention_status = SLOT_ATTN (slot_cur->status, slot_cur->ext_status);
info->latch_status = SLOT_LATCH (slot_cur->status);
......@@ -735,7 +733,7 @@ int ibmphp_update_slot_info (struct slot *slot_cur)
info->max_bus_speed = slot_cur->hotplug_slot->info->max_bus_speed;
// To do: bus_names
rc = pci_hp_change_slot_info (buffer, info);
rc = pci_hp_change_slot_info (slot_cur->hotplug_slot, info);
kfree (info);
return rc;
}
......@@ -1057,6 +1055,8 @@ static int ibm_configure_device (struct pci_func *func)
if (func->dev == NULL) {
dev0.bus = ibmphp_find_bus (func->busno);
if (!dev0.bus)
return 0;
dev0.devfn = ((func->device << 3) + (func->function & 0x7));
dev0.sysdata = dev0.bus->sysdata;
......@@ -1097,6 +1097,8 @@ static int is_bus_empty (struct slot * slot_cur)
continue;
}
tmp_slot = ibmphp_get_slot_from_physical_num (i);
if (!tmp_slot)
return 0;
rc = slot_update (&tmp_slot);
if (rc)
return 0;
......@@ -1219,6 +1221,8 @@ static int check_limitations (struct slot *slot_cur)
for (i = slot_cur->bus_on->slot_min; i <= slot_cur->bus_on->slot_max; i++) {
tmp_slot = ibmphp_get_slot_from_physical_num (i);
if (!tmp_slot)
return -ENODEV;
if ((SLOT_PWRGD (tmp_slot->status)) && !(SLOT_CONNECT (tmp_slot->status)))
count++;
}
......
......@@ -65,24 +65,11 @@ static LIST_HEAD (opt_vg_head);
static LIST_HEAD (opt_lo_head);
static void *io_mem;
char *chassis_str, *rxe_str, *str;
/* Local functions */
static int ebda_rsrc_controller (void);
static int ebda_rsrc_rsrc (void);
static int ebda_rio_table (void);
static struct slot *alloc_ibm_slot (void)
{
struct slot *slot;
slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
if (!slot)
return NULL;
memset (slot, 0, sizeof (*slot));
return slot;
}
static struct ebda_hpc_list * __init alloc_ebda_hpc_list (void)
{
struct ebda_hpc_list *list;
......@@ -591,32 +578,6 @@ static int combine_wpg_for_expansion (void)
return 0;
}
static char *convert_2digits_to_char (int var)
{
int bit;
char *str1;
str = (char *) kmalloc (3, GFP_KERNEL);
memset (str, 0, 3);
str1 = (char *) kmalloc (2, GFP_KERNEL);
memset (str, 0, 3);
bit = (int)(var / 10);
switch (bit) {
case 0:
//one digit number
*str = (char)(var + 48);
return str;
default:
//2 digits number
*str1 = (char)(bit + 48);
strncpy (str, str1, 1);
memset (str1, 0, 3);
*str1 = (char)((var % 10) + 48);
strcat (str, str1);
return str;
}
return NULL;
}
/* Since we don't know the max slot number per each chassis, hence go
* through the list of all chassis to find out the range
......@@ -701,7 +662,7 @@ static char *create_file_name (struct slot * slot_cur)
{
struct opt_rio *opt_vg_ptr = NULL;
struct opt_rio_lo *opt_lo_ptr = NULL;
char *ptr_chassis_num, *ptr_rxe_num, *ptr_slot_num;
static char str[30];
int which = 0; /* rxe = 1, chassis = 0 */
u8 number = 1; /* either chassis or rxe # */
u8 first_slot = 1;
......@@ -715,19 +676,7 @@ static char *create_file_name (struct slot * slot_cur)
slot_num = slot_cur->number;
chassis_str = (char *) kmalloc (30, GFP_KERNEL);
memset (chassis_str, 0, 30);
rxe_str = (char *) kmalloc (30, GFP_KERNEL);
memset (rxe_str, 0, 30);
ptr_chassis_num = (char *) kmalloc (3, GFP_KERNEL);
memset (ptr_chassis_num, 0, 3);
ptr_rxe_num = (char *) kmalloc (3, GFP_KERNEL);
memset (ptr_rxe_num, 0, 3);
ptr_slot_num = (char *) kmalloc (3, GFP_KERNEL);
memset (ptr_slot_num, 0, 3);
strcpy (chassis_str, "chassis");
strcpy (rxe_str, "rxe");
memset (str, 0, sizeof(str));
if (rio_table_ptr) {
if (rio_table_ptr->ver_num == 3) {
......@@ -772,31 +721,10 @@ static char *create_file_name (struct slot * slot_cur)
}
}
switch (which) {
case 0:
/* Chassis */
*ptr_chassis_num = (char)(number + 48);
strcat (chassis_str, ptr_chassis_num);
kfree (ptr_chassis_num);
strcat (chassis_str, "slot");
ptr_slot_num = convert_2digits_to_char (slot_num - first_slot + 1);
strcat (chassis_str, ptr_slot_num);
kfree (ptr_slot_num);
return chassis_str;
break;
case 1:
/* RXE */
*ptr_rxe_num = (char)(number + 48);
strcat (rxe_str, ptr_rxe_num);
kfree (ptr_rxe_num);
strcat (rxe_str, "slot");
ptr_slot_num = convert_2digits_to_char (slot_num - first_slot + 1);
strcat (rxe_str, ptr_slot_num);
kfree (ptr_slot_num);
return rxe_str;
break;
}
return NULL;
sprintf(str, "%s%dslot%d",
which == 0 ? "chassis" : "rxe",
number, slot_num - first_slot + 1);
return str;
}
static struct pci_driver ibmphp_driver;
......@@ -818,8 +746,7 @@ static int __init ebda_rsrc_controller (void)
struct ebda_hpc_slot *slot_ptr;
struct bus_info *bus_info_ptr1, *bus_info_ptr2;
int rc;
int retval;
struct slot *slot_cur;
struct slot *tmp_slot;
struct list_head *list;
addr = hpc_list_ptr->phys_addr;
......@@ -844,8 +771,8 @@ static int __init ebda_rsrc_controller (void)
/* init hpc structure */
hpc_ptr = alloc_ebda_hpc (slot_num, bus_num);
if (!hpc_ptr ) {
iounmap (io_mem);
return -ENOMEM;
rc = -ENOMEM;
goto error_no_hpc;
}
hpc_ptr->ctlr_id = ctlr_id;
hpc_ptr->ctlr_relative_id = ctlr;
......@@ -871,8 +798,8 @@ static int __init ebda_rsrc_controller (void)
if (!bus_info_ptr2) {
bus_info_ptr1 = (struct bus_info *) kmalloc (sizeof (struct bus_info), GFP_KERNEL);
if (!bus_info_ptr1) {
iounmap (io_mem);
return -ENOMEM;
rc = -ENOMEM;
goto error_no_hp_slot;
}
memset (bus_info_ptr1, 0, sizeof (struct bus_info));
bus_info_ptr1->slot_min = slot_ptr->slot_num;
......@@ -932,16 +859,20 @@ static int __init ebda_rsrc_controller (void)
hpc_ptr->u.pci_ctlr.dev_fun = readb (io_mem + addr + 1);
hpc_ptr->irq = readb (io_mem + addr + 2);
addr += 3;
debug ("ctrl bus = %x, ctlr devfun = %x, irq = %x\n", hpc_ptr->u.pci_ctlr.bus, hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq);
debug ("ctrl bus = %x, ctlr devfun = %x, irq = %x\n",
hpc_ptr->u.pci_ctlr.bus,
hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq);
break;
case 0:
hpc_ptr->u.isa_ctlr.io_start = readw (io_mem + addr);
hpc_ptr->u.isa_ctlr.io_end = readw (io_mem + addr + 2);
retval = check_region (hpc_ptr->u.isa_ctlr.io_start, (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1));
if (retval)
return -ENODEV;
request_region (hpc_ptr->u.isa_ctlr.io_start, (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1), "ibmphp");
if (!request_region (hpc_ptr->u.isa_ctlr.io_start,
(hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1),
"ibmphp")) {
rc = -ENODEV;
goto error_no_hp_slot;
}
hpc_ptr->irq = readb (io_mem + addr + 4);
addr += 5;
break;
......@@ -954,8 +885,8 @@ static int __init ebda_rsrc_controller (void)
addr += 6;
break;
default:
iounmap (io_mem);
return -ENODEV;
rc = -ENODEV;
goto error_no_hp_slot;
}
//reorganize chassis' linked list
......@@ -971,79 +902,71 @@ static int __init ebda_rsrc_controller (void)
hp_slot_ptr = (struct hotplug_slot *) kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
if (!hp_slot_ptr) {
iounmap (io_mem);
return -ENOMEM;
rc = -ENOMEM;
goto error_no_hp_slot;
}
memset (hp_slot_ptr, 0, sizeof (struct hotplug_slot));
hp_slot_ptr->info = (struct hotplug_slot_info *) kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
if (!hp_slot_ptr->info) {
iounmap (io_mem);
kfree (hp_slot_ptr);
return -ENOMEM;
rc = -ENOMEM;
goto error_no_hp_info;
}
memset (hp_slot_ptr->info, 0, sizeof (struct hotplug_slot_info));
hp_slot_ptr->name = (char *) kmalloc (30, GFP_KERNEL);
if (!hp_slot_ptr->name) {
iounmap (io_mem);
kfree (hp_slot_ptr->info);
kfree (hp_slot_ptr);
return -ENOMEM;
rc = -ENOMEM;
goto error_no_hp_name;
}
hp_slot_ptr->private = alloc_ibm_slot ();
if (!hp_slot_ptr->private) {
iounmap (io_mem);
kfree (hp_slot_ptr->name);
kfree (hp_slot_ptr->info);
kfree (hp_slot_ptr);
return -ENOMEM;
tmp_slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
if (!tmp_slot) {
rc = -ENOMEM;
goto error_no_slot;
}
memset (tmp_slot, 0, sizeof (*tmp_slot));
((struct slot *)hp_slot_ptr->private)->flag = TRUE;
tmp_slot->flag = TRUE;
((struct slot *) hp_slot_ptr->private)->capabilities = hpc_ptr->slots[index].slot_cap;
tmp_slot->capabilities = hpc_ptr->slots[index].slot_cap;
if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX)
((struct slot *) hp_slot_ptr->private)->supported_speed = 3;
tmp_slot->supported_speed = 3;
else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX)
((struct slot *) hp_slot_ptr->private)->supported_speed = 2;
tmp_slot->supported_speed = 2;
else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX)
((struct slot *) hp_slot_ptr->private)->supported_speed = 1;
tmp_slot->supported_speed = 1;
if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP)
((struct slot *) hp_slot_ptr->private)->supported_bus_mode = 1;
tmp_slot->supported_bus_mode = 1;
else
((struct slot *) hp_slot_ptr->private)->supported_bus_mode = 0;
tmp_slot->supported_bus_mode = 0;
((struct slot *) hp_slot_ptr->private)->bus = hpc_ptr->slots[index].slot_bus_num;
tmp_slot->bus = hpc_ptr->slots[index].slot_bus_num;
bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num);
if (!bus_info_ptr1) {
iounmap (io_mem);
return -ENODEV;
rc = -ENODEV;
goto error;
}
((struct slot *) hp_slot_ptr->private)->bus_on = bus_info_ptr1;
tmp_slot->bus_on = bus_info_ptr1;
bus_info_ptr1 = NULL;
((struct slot *) hp_slot_ptr->private)->ctrl = hpc_ptr;
tmp_slot->ctrl = hpc_ptr;
tmp_slot->ctlr_index = hpc_ptr->slots[index].ctl_index;
tmp_slot->number = hpc_ptr->slots[index].slot_num;
tmp_slot->hotplug_slot = hp_slot_ptr;
((struct slot *) hp_slot_ptr->private)->ctlr_index = hpc_ptr->slots[index].ctl_index;
((struct slot *) hp_slot_ptr->private)->number = hpc_ptr->slots[index].slot_num;
hp_slot_ptr->private = tmp_slot;
((struct slot *) hp_slot_ptr->private)->hotplug_slot = hp_slot_ptr;
rc = ibmphp_hpc_fillhpslotinfo (hp_slot_ptr);
if (rc) {
iounmap (io_mem);
return rc;
}
if (rc)
goto error;
rc = ibmphp_init_devno ((struct slot **) &hp_slot_ptr->private);
if (rc) {
iounmap (io_mem);
return rc;
}
if (rc)
goto error;
hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops;
// end of registering ibm slot with hotplug core
......@@ -1057,19 +980,29 @@ static int __init ebda_rsrc_controller (void)
} /* each hpc */
list_for_each (list, &ibmphp_slot_head) {
slot_cur = list_entry (list, struct slot, ibm_slot_list);
tmp_slot = list_entry (list, struct slot, ibm_slot_list);
snprintf (slot_cur->hotplug_slot->name, 30, "%s", create_file_name (slot_cur));
if (chassis_str)
kfree (chassis_str);
if (rxe_str)
kfree (rxe_str);
pci_hp_register (slot_cur->hotplug_slot);
snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot));
pci_hp_register (tmp_slot->hotplug_slot);
}
print_ebda_hpc ();
print_ibm_slot ();
return 0;
error:
kfree (hp_slot_ptr->private);
error_no_slot:
kfree (hp_slot_ptr->name);
error_no_hp_name:
kfree (hp_slot_ptr->info);
error_no_hp_info:
kfree (hp_slot_ptr);
error_no_hp_slot:
free_ebda_hpc (hpc_ptr);
error_no_hpc:
iounmap (io_mem);
return rc;
}
/*
......
......@@ -951,6 +951,7 @@ static int configure_bridge (struct pci_func **func_passed, u8 slotno)
if (rc) {
if (rc == -ENOMEM) {
ibmphp_remove_bus (bus, func->busno);
kfree (amount_needed);
return rc;
}
retval = rc;
......@@ -1621,23 +1622,23 @@ int ibmphp_unconfigure_card (struct slot **slot_cur, int the_end)
}
for (i = 0; i < count; i++) {
if (cur_func->io[count]) {
debug ("io[%d] exists \n", count);
if (cur_func->io[i]) {
debug ("io[%d] exists \n", i);
if (the_end > 0)
ibmphp_remove_resource (cur_func->io[count]);
cur_func->io[count] = NULL;
ibmphp_remove_resource (cur_func->io[i]);
cur_func->io[i] = NULL;
}
if (cur_func->mem[count]) {
debug ("mem[%d] exists \n", count);
if (cur_func->mem[i]) {
debug ("mem[%d] exists \n", i);
if (the_end > 0)
ibmphp_remove_resource (cur_func->mem[count]);
cur_func->mem[count] = NULL;
ibmphp_remove_resource (cur_func->mem[i]);
cur_func->mem[i] = NULL;
}
if (cur_func->pfmem[count]) {
debug ("pfmem[%d] exists \n", count);
if (cur_func->pfmem[i]) {
debug ("pfmem[%d] exists \n", i);
if (the_end > 0)
ibmphp_remove_resource (cur_func->pfmem[count]);
cur_func->pfmem[count] = NULL;
ibmphp_remove_resource (cur_func->pfmem[i]);
cur_func->pfmem[i] = NULL;
}
}
......
......@@ -46,8 +46,11 @@ enum pci_bus_speed {
};
struct hotplug_slot;
struct hotplug_slot_core;
struct hotplug_slot_attribute {
struct attribute attr;
ssize_t (*show)(struct hotplug_slot *, char *);
ssize_t (*store)(struct hotplug_slot *, const char *, size_t);
};
/**
* struct hotplug_slot_ops -the callbacks that the hotplug pci core can use
* @owner: The module owner of this structure
......@@ -131,45 +134,13 @@ struct hotplug_slot {
/* Variables below this are for use only by the hotplug pci core. */
struct list_head slot_list;
struct hotplug_slot_core *core_priv;
struct kobject kobj;
};
extern int pci_hp_register (struct hotplug_slot *slot);
extern int pci_hp_deregister (struct hotplug_slot *slot);
extern int pci_hp_change_slot_info (const char *name,
extern int pci_hp_change_slot_info (struct hotplug_slot *slot,
struct hotplug_slot_info *info);
struct pci_dev_wrapped {
struct pci_dev *dev;
void *data;
};
struct pci_bus_wrapped {
struct pci_bus *bus;
void *data;
};
struct pci_visit {
int (* pre_visit_pci_bus) (struct pci_bus_wrapped *,
struct pci_dev_wrapped *);
int (* post_visit_pci_bus) (struct pci_bus_wrapped *,
struct pci_dev_wrapped *);
int (* pre_visit_pci_dev) (struct pci_dev_wrapped *,
struct pci_bus_wrapped *);
int (* visit_pci_dev) (struct pci_dev_wrapped *,
struct pci_bus_wrapped *);
int (* post_visit_pci_dev) (struct pci_dev_wrapped *,
struct pci_bus_wrapped *);
};
extern int pci_visit_dev (struct pci_visit *fn,
struct pci_dev_wrapped *wrapped_dev,
struct pci_bus_wrapped *wrapped_parent);
int pci_is_dev_in_use(struct pci_dev *dev);
int pci_remove_device_safe(struct pci_dev *dev);
#endif
......@@ -39,9 +39,9 @@
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/pci.h>
#include <linux/dnotify.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include "pci_hotplug.h"
......@@ -67,30 +67,44 @@ static int debug;
//////////////////////////////////////////////////////////////////
/* Random magic number */
#define PCIHPFS_MAGIC 0x52454541
struct hotplug_slot_core {
struct dentry *dir_dentry;
struct dentry *power_dentry;
struct dentry *attention_dentry;
struct dentry *latch_dentry;
struct dentry *adapter_dentry;
struct dentry *test_dentry;
struct dentry *max_bus_speed_dentry;
struct dentry *cur_bus_speed_dentry;
};
static struct super_operations pcihpfs_ops;
static struct file_operations default_file_operations;
static struct inode_operations pcihpfs_dir_inode_operations;
static struct vfsmount *pcihpfs_mount; /* one of the mounts of our fs for reference counting */
static int pcihpfs_mount_count; /* times we have mounted our fs */
static spinlock_t mount_lock; /* protects our mount_count */
static spinlock_t list_lock;
static LIST_HEAD(pci_hotplug_slot_list);
static struct subsystem hotplug_slots_subsys;
static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
struct hotplug_slot *slot=container_of(kobj,
struct hotplug_slot,kobj);
struct hotplug_slot_attribute *attribute =
container_of(attr, struct hotplug_slot_attribute, attr);
return attribute->show ? attribute->show(slot, buf) : 0;
}
static ssize_t hotplug_slot_attr_store(struct kobject *kobj,
struct attribute *attr, const char *buf, size_t len)
{
struct hotplug_slot *slot=container_of(kobj,
struct hotplug_slot,kobj);
struct hotplug_slot_attribute *attribute =
container_of(attr, struct hotplug_slot_attribute, attr);
return attribute->store ? attribute->store(slot, buf, len) : 0;
}
static struct sysfs_ops hotplug_slot_sysfs_ops = {
.show = hotplug_slot_attr_show,
.store = hotplug_slot_attr_store,
};
static struct kobj_type hotplug_slot_ktype = {
.sysfs_ops = &hotplug_slot_sysfs_ops
};
static decl_subsys(hotplug_slots, &hotplug_slot_ktype);
/* these strings match up with the values in pci_bus_speed */
static char *pci_bus_speed_strings[] = {
"33 MHz PCI", /* 0x00 */
......@@ -115,12 +129,6 @@ static char *pci_bus_speed_strings[] = {
"133 MHz PCIX 533", /* 0x13 */
};
#ifdef CONFIG_PROC_FS
extern struct proc_dir_entry *proc_bus_pci_dir;
static struct proc_dir_entry *slotdir = NULL;
static const char *slotdir_name = "slots";
#endif
#ifdef CONFIG_HOTPLUG_PCI_CPCI
extern int cpci_hotplug_init(int debug);
extern void cpci_hotplug_exit(void);
......@@ -129,438 +137,6 @@ static inline int cpci_hotplug_init(int debug) { return 0; }
static inline void cpci_hotplug_exit(void) { }
#endif
static struct inode *pcihpfs_get_inode (struct super_block *sb, int mode, dev_t dev)
{
struct inode *inode = new_inode(sb);
if (inode) {
inode->i_mode = mode;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_rdev = NODEV;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch (mode & S_IFMT) {
default:
init_special_inode(inode, mode, dev);
break;
case S_IFREG:
inode->i_fop = &default_file_operations;
break;
case S_IFDIR:
inode->i_op = &pcihpfs_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
/* directory inodes start off with i_nlink == 2 (for "." entry) */
inode->i_nlink++;
break;
}
}
return inode;
}
/* SMP-safe */
static int pcihpfs_mknod (struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
{
struct inode *inode = pcihpfs_get_inode(dir->i_sb, mode, dev);
int error = -ENOSPC;
if (inode) {
d_instantiate(dentry, inode);
dget(dentry);
error = 0;
}
return error;
}
static int pcihpfs_mkdir (struct inode *dir, struct dentry *dentry, int mode)
{
return pcihpfs_mknod (dir, dentry, mode | S_IFDIR, 0);
}
static int pcihpfs_create (struct inode *dir, struct dentry *dentry, int mode)
{
return pcihpfs_mknod (dir, dentry, mode | S_IFREG, 0);
}
static inline int pcihpfs_positive (struct dentry *dentry)
{
return dentry->d_inode && !d_unhashed(dentry);
}
static int pcihpfs_empty (struct dentry *dentry)
{
struct list_head *list;
spin_lock(&dcache_lock);
list_for_each(list, &dentry->d_subdirs) {
struct dentry *de = list_entry(list, struct dentry, d_child);
if (pcihpfs_positive(de)) {
spin_unlock(&dcache_lock);
return 0;
}
}
spin_unlock(&dcache_lock);
return 1;
}
static int pcihpfs_unlink (struct inode *dir, struct dentry *dentry)
{
int error = -ENOTEMPTY;
if (pcihpfs_empty(dentry)) {
struct inode *inode = dentry->d_inode;
lock_kernel();
inode->i_nlink--;
unlock_kernel();
dput(dentry);
error = 0;
}
return error;
}
#define pcihpfs_rmdir pcihpfs_unlink
/* default file operations */
static ssize_t default_read_file (struct file *file, char *buf, size_t count, loff_t *ppos)
{
dbg ("\n");
return 0;
}
static ssize_t default_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos)
{
dbg ("\n");
return count;
}
static loff_t default_file_lseek (struct file *file, loff_t offset, int orig)
{
loff_t retval = -EINVAL;
lock_kernel();
switch(orig) {
case 0:
if (offset > 0) {
file->f_pos = offset;
retval = file->f_pos;
}
break;
case 1:
if ((offset + file->f_pos) > 0) {
file->f_pos += offset;
retval = file->f_pos;
}
break;
default:
break;
}
unlock_kernel();
return retval;
}
static int default_open (struct inode *inode, struct file *filp)
{
if (inode->u.generic_ip)
filp->private_data = inode->u.generic_ip;
return 0;
}
static struct file_operations default_file_operations = {
.read = default_read_file,
.write = default_write_file,
.open = default_open,
.llseek = default_file_lseek,
};
/* file ops for the "power" files */
static ssize_t power_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
static ssize_t power_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos);
static struct file_operations power_file_operations = {
.read = power_read_file,
.write = power_write_file,
.open = default_open,
.llseek = default_file_lseek,
};
/* file ops for the "attention" files */
static ssize_t attention_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
static ssize_t attention_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos);
static struct file_operations attention_file_operations = {
.read = attention_read_file,
.write = attention_write_file,
.open = default_open,
.llseek = default_file_lseek,
};
/* file ops for the "latch" files */
static ssize_t latch_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
static struct file_operations latch_file_operations = {
.read = latch_read_file,
.write = default_write_file,
.open = default_open,
.llseek = default_file_lseek,
};
/* file ops for the "presence" files */
static ssize_t presence_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
static struct file_operations presence_file_operations = {
.read = presence_read_file,
.write = default_write_file,
.open = default_open,
.llseek = default_file_lseek,
};
/* file ops for the "max bus speed" files */
static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
static struct file_operations max_bus_speed_file_operations = {
.read = max_bus_speed_read_file,
.write = default_write_file,
.open = default_open,
.llseek = default_file_lseek,
};
/* file ops for the "current bus speed" files */
static ssize_t cur_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
static struct file_operations cur_bus_speed_file_operations = {
.read = cur_bus_speed_read_file,
.write = default_write_file,
.open = default_open,
.llseek = default_file_lseek,
};
/* file ops for the "test" files */
static ssize_t test_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos);
static struct file_operations test_file_operations = {
.read = default_read_file,
.write = test_write_file,
.open = default_open,
.llseek = default_file_lseek,
};
static struct inode_operations pcihpfs_dir_inode_operations = {
.create = pcihpfs_create,
.lookup = simple_lookup,
.unlink = pcihpfs_unlink,
.mkdir = pcihpfs_mkdir,
.rmdir = pcihpfs_rmdir,
.mknod = pcihpfs_mknod,
};
static struct super_operations pcihpfs_ops = {
.statfs = simple_statfs,
.drop_inode = generic_delete_inode,
};
static int pcihpfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
struct dentry *root;
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = PCIHPFS_MAGIC;
sb->s_op = &pcihpfs_ops;
inode = pcihpfs_get_inode(sb, S_IFDIR | 0755, 0);
if (!inode) {
dbg("%s: could not get inode!\n",__FUNCTION__);
return -ENOMEM;
}
root = d_alloc_root(inode);
if (!root) {
dbg("%s: could not get root dentry!\n",__FUNCTION__);
iput(inode);
return -ENOMEM;
}
sb->s_root = root;
return 0;
}
static struct super_block *pcihpfs_get_sb(struct file_system_type *fs_type,
int flags, char *dev_name, void *data)
{
return get_sb_single(fs_type, flags, data, pcihpfs_fill_super);
}
static struct file_system_type pcihpfs_type = {
.owner = THIS_MODULE,
.name = "pcihpfs",
.get_sb = pcihpfs_get_sb,
.kill_sb = kill_litter_super,
};
static int get_mount (void)
{
struct vfsmount *mnt;
spin_lock (&mount_lock);
if (pcihpfs_mount) {
mntget(pcihpfs_mount);
++pcihpfs_mount_count;
spin_unlock (&mount_lock);
goto go_ahead;
}
spin_unlock (&mount_lock);
mnt = kern_mount (&pcihpfs_type);
if (IS_ERR(mnt)) {
err ("could not mount the fs...erroring out!\n");
return -ENODEV;
}
spin_lock (&mount_lock);
if (!pcihpfs_mount) {
pcihpfs_mount = mnt;
++pcihpfs_mount_count;
spin_unlock (&mount_lock);
goto go_ahead;
}
mntget(pcihpfs_mount);
++pcihpfs_mount_count;
spin_unlock (&mount_lock);
mntput(mnt);
go_ahead:
dbg("pcihpfs_mount_count = %d\n", pcihpfs_mount_count);
return 0;
}
static void remove_mount (void)
{
struct vfsmount *mnt;
spin_lock (&mount_lock);
mnt = pcihpfs_mount;
--pcihpfs_mount_count;
if (!pcihpfs_mount_count)
pcihpfs_mount = NULL;
spin_unlock (&mount_lock);
mntput(mnt);
dbg("pcihpfs_mount_count = %d\n", pcihpfs_mount_count);
}
/**
* pcihpfs_create_by_name - create a file, given a name
* @name: name of file
* @mode: type of file
* @parent: dentry of directory to create it in
* @dentry: resulting dentry of file
*
* There is a bit of overhead in creating a file - basically, we
* have to hash the name of the file, then look it up. This will
* prevent files of the same name.
* We then call the proper vfs_ function to take care of all the
* file creation details.
* This function handles both regular files and directories.
*/
static int pcihpfs_create_by_name (const char *name, mode_t mode,
struct dentry *parent, struct dentry **dentry)
{
struct dentry *d = NULL;
struct qstr qstr;
int error;
/* If the parent is not specified, we create it in the root.
* We need the root dentry to do this, which is in the super
* block. A pointer to that is in the struct vfsmount that we
* have around.
*/
if (!parent ) {
if (pcihpfs_mount && pcihpfs_mount->mnt_sb) {
parent = pcihpfs_mount->mnt_sb->s_root;
}
}
if (!parent) {
dbg("Ah! can not find a parent!\n");
return -EINVAL;
}
*dentry = NULL;
qstr.name = name;
qstr.len = strlen(name);
qstr.hash = full_name_hash(name,qstr.len);
parent = dget(parent);
down(&parent->d_inode->i_sem);
d = lookup_hash(&qstr,parent);
error = PTR_ERR(d);
if (!IS_ERR(d)) {
switch(mode & S_IFMT) {
case 0:
case S_IFREG:
error = vfs_create(parent->d_inode,d,mode);
break;
case S_IFDIR:
error = vfs_mkdir(parent->d_inode,d,mode);
break;
default:
err("cannot create special files\n");
}
*dentry = d;
}
up(&parent->d_inode->i_sem);
dput(parent);
return error;
}
static struct dentry *fs_create_file (const char *name, mode_t mode,
struct dentry *parent, void *data,
struct file_operations *fops)
{
struct dentry *dentry;
int error;
dbg("creating file '%s'\n",name);
error = pcihpfs_create_by_name(name,mode,parent,&dentry);
if (error) {
dentry = NULL;
} else {
if (dentry->d_inode) {
if (data)
dentry->d_inode->u.generic_ip = data;
if (fops)
dentry->d_inode->i_fop = fops;
}
}
return dentry;
}
static void fs_remove_file (struct dentry *dentry)
{
struct dentry *parent = dentry->d_parent;
if (!parent || !parent->d_inode)
return;
down(&parent->d_inode->i_sem);
if (pcihpfs_positive(dentry)) {
if (dentry->d_inode) {
if (S_ISDIR(dentry->d_inode->i_mode))
vfs_rmdir(parent->d_inode,dentry);
else
vfs_unlink(parent->d_inode,dentry);
}
dput(dentry);
}
up(&parent->d_inode->i_sem);
}
/* Weee, fun with macros... */
#define GET_STATUS(name,type) \
static int get_##name (struct hotplug_slot *slot, type *value) \
......@@ -584,80 +160,27 @@ GET_STATUS(adapter_status, u8)
GET_STATUS(max_bus_speed, enum pci_bus_speed)
GET_STATUS(cur_bus_speed, enum pci_bus_speed)
static ssize_t power_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
static ssize_t power_read_file (struct hotplug_slot *slot, char *buf)
{
struct hotplug_slot *slot = file->private_data;
unsigned char *page;
int retval;
int len;
u8 value;
dbg(" count = %d, offset = %lld\n", count, *offset);
if (*offset < 0)
return -EINVAL;
if (count == 0 || count > 16384)
return 0;
if (*offset != 0)
return 0;
if (slot == NULL) {
dbg("slot == NULL???\n");
return -ENODEV;
}
page = (unsigned char *)__get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
retval = get_power_status (slot, &value);
if (retval)
goto exit;
len = sprintf (page, "%d\n", value);
if (copy_to_user (buf, page, len)) {
retval = -EFAULT;
goto exit;
}
*offset += len;
retval = len;
retval = sprintf (buf, "%d\n", value);
exit:
free_page((unsigned long)page);
return retval;
}
static ssize_t power_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset)
static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf,
size_t count)
{
struct hotplug_slot *slot = file->private_data;
char *buff;
unsigned long lpower;
u8 power;
int retval = 0;
if (*offset < 0)
return -EINVAL;
if (count == 0 || count > 16384)
return 0;
if (*offset != 0)
return 0;
if (slot == NULL) {
dbg("slot == NULL???\n");
return -ENODEV;
}
buff = kmalloc (count + 1, GFP_KERNEL);
if (!buff)
return -ENOMEM;
memset (buff, 0x00, count + 1);
if (copy_from_user ((void *)buff, (void *)ubuff, count)) {
retval = -EFAULT;
goto exit;
}
lpower = simple_strtoul (buff, NULL, 10);
lpower = simple_strtoul (buf, NULL, 10);
power = (u8)(lpower & 0xff);
dbg ("power = %d\n", power);
......@@ -683,87 +206,39 @@ static ssize_t power_write_file (struct file *file, const char *ubuff, size_t co
module_put(slot->ops->owner);
exit:
kfree (buff);
if (retval)
return retval;
return count;
}
static ssize_t attention_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
static struct hotplug_slot_attribute hotplug_slot_attr_power = {
.attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR},
.show = power_read_file,
.store = power_write_file
};
static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf)
{
struct hotplug_slot *slot = file->private_data;
unsigned char *page;
int retval;
int len;
u8 value;
dbg("count = %d, offset = %lld\n", count, *offset);
if (*offset < 0)
return -EINVAL;
if (count <= 0)
return 0;
if (*offset != 0)
return 0;
if (slot == NULL) {
dbg("slot == NULL???\n");
return -ENODEV;
}
page = (unsigned char *)__get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
retval = get_attention_status (slot, &value);
if (retval)
goto exit;
len = sprintf (page, "%d\n", value);
if (copy_to_user (buf, page, len)) {
retval = -EFAULT;
goto exit;
}
*offset += len;
retval = len;
retval = sprintf (buf, "%d\n", value);
exit:
free_page((unsigned long)page);
return retval;
}
static ssize_t attention_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset)
static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf,
size_t count)
{
struct hotplug_slot *slot = file->private_data;
char *buff;
unsigned long lattention;
u8 attention;
int retval = 0;
if (*offset < 0)
return -EINVAL;
if (count == 0 || count > 16384)
return 0;
if (*offset != 0)
return 0;
if (slot == NULL) {
dbg("slot == NULL???\n");
return -ENODEV;
}
buff = kmalloc (count + 1, GFP_KERNEL);
if (!buff)
return -ENOMEM;
memset (buff, 0x00, count + 1);
if (copy_from_user ((void *)buff, (void *)ubuff, count)) {
retval = -EFAULT;
goto exit;
}
lattention = simple_strtoul (buff, NULL, 10);
lattention = simple_strtoul (buf, NULL, 10);
attention = (u8)(lattention & 0xff);
dbg (" - attention = %d\n", attention);
......@@ -776,128 +251,63 @@ static ssize_t attention_write_file (struct file *file, const char *ubuff, size_
module_put(slot->ops->owner);
exit:
kfree (buff);
if (retval)
return retval;
return count;
}
static ssize_t latch_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
static struct hotplug_slot_attribute hotplug_slot_attr_attention = {
.attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR},
.show = attention_read_file,
.store = attention_write_file
};
static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf)
{
struct hotplug_slot *slot = file->private_data;
unsigned char *page;
int retval;
int len;
u8 value;
dbg("count = %d, offset = %lld\n", count, *offset);
if (*offset < 0)
return -EINVAL;
if (count <= 0)
return 0;
if (*offset != 0)
return 0;
if (slot == NULL) {
dbg("slot == NULL???\n");
return -ENODEV;
}
page = (unsigned char *)__get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
retval = get_latch_status (slot, &value);
if (retval)
goto exit;
len = sprintf (page, "%d\n", value);
if (copy_to_user (buf, page, len)) {
retval = -EFAULT;
goto exit;
}
*offset += len;
retval = len;
retval = sprintf (buf, "%d\n", value);
exit:
free_page((unsigned long)page);
return retval;
}
static ssize_t presence_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
static struct hotplug_slot_attribute hotplug_slot_attr_latch = {
.attr = {.name = "latch", .mode = S_IFREG | S_IRUGO | S_IWUSR},
.show = latch_read_file,
};
static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf)
{
struct hotplug_slot *slot = file->private_data;
unsigned char *page;
int retval;
int len;
u8 value;
dbg("count = %d, offset = %lld\n", count, *offset);
if (*offset < 0)
return -EINVAL;
if (count <= 0)
return 0;
if (*offset != 0)
return 0;
if (slot == NULL) {
dbg("slot == NULL???\n");
return -ENODEV;
}
page = (unsigned char *)__get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
retval = get_adapter_status (slot, &value);
if (retval)
goto exit;
len = sprintf (page, "%d\n", value);
if (copy_to_user (buf, page, len)) {
retval = -EFAULT;
goto exit;
}
*offset += len;
retval = len;
retval = sprintf (buf, "%d\n", value);
exit:
free_page((unsigned long)page);
return retval;
}
static struct hotplug_slot_attribute hotplug_slot_attr_presence = {
.attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO | S_IWUSR},
.show = presence_read_file,
};
static char *unknown_speed = "Unknown bus speed";
static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
{
struct hotplug_slot *slot = file->private_data;
unsigned char *page;
char *speed_string;
int retval;
int len = 0;
enum pci_bus_speed value;
dbg ("count = %d, offset = %lld\n", count, *offset);
if (*offset < 0)
return -EINVAL;
if (count <= 0)
return 0;
if (*offset != 0)
return 0;
if (slot == NULL) {
dbg("slot == NULL???\n");
return -ENODEV;
}
page = (unsigned char *)__get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
retval = get_max_bus_speed (slot, &value);
if (retval)
goto exit;
......@@ -907,47 +317,23 @@ static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t cou
else
speed_string = pci_bus_speed_strings[value];
len = sprintf (page, "%s\n", speed_string);
if (copy_to_user (buf, page, len)) {
retval = -EFAULT;
goto exit;
}
*offset += len;
retval = len;
retval = sprintf (buf, "%s\n", speed_string);
exit:
free_page((unsigned long)page);
return retval;
}
static ssize_t cur_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = {
.attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO | S_IWUSR},
.show = max_bus_speed_read_file,
};
static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
{
struct hotplug_slot *slot = file->private_data;
unsigned char *page;
char *speed_string;
int retval;
int len = 0;
enum pci_bus_speed value;
dbg ("count = %d, offset = %lld\n", count, *offset);
if (*offset < 0)
return -EINVAL;
if (count <= 0)
return 0;
if (*offset != 0)
return 0;
if (slot == NULL) {
dbg("slot == NULL???\n");
return -ENODEV;
}
page = (unsigned char *)__get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
retval = get_cur_bus_speed (slot, &value);
if (retval)
goto exit;
......@@ -957,51 +343,25 @@ static ssize_t cur_bus_speed_read_file (struct file *file, char *buf, size_t cou
else
speed_string = pci_bus_speed_strings[value];
len = sprintf (page, "%s\n", speed_string);
if (copy_to_user (buf, page, len)) {
retval = -EFAULT;
goto exit;
}
*offset += len;
retval = len;
retval = sprintf (buf, "%s\n", speed_string);
exit:
free_page((unsigned long)page);
return retval;
}
static ssize_t test_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset)
static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = {
.attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO | S_IWUSR},
.show = cur_bus_speed_read_file,
};
static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf,
size_t count)
{
struct hotplug_slot *slot = file->private_data;
char *buff;
unsigned long ltest;
u32 test;
int retval = 0;
if (*offset < 0)
return -EINVAL;
if (count == 0 || count > 16384)
return 0;
if (*offset != 0)
return 0;
if (slot == NULL) {
dbg("slot == NULL???\n");
return -ENODEV;
}
buff = kmalloc (count + 1, GFP_KERNEL);
if (!buff)
return -ENOMEM;
memset (buff, 0x00, count + 1);
if (copy_from_user ((void *)buff, (void *)ubuff, count)) {
retval = -EFAULT;
goto exit;
}
ltest = simple_strtoul (buff, NULL, 10);
ltest = simple_strtoul (buf, NULL, 10);
test = (u32)(ltest & 0xffffffff);
dbg ("test = %d\n", test);
......@@ -1014,104 +374,130 @@ static ssize_t test_write_file (struct file *file, const char *ubuff, size_t cou
module_put(slot->ops->owner);
exit:
kfree (buff);
if (retval)
return retval;
return count;
}
static int fs_add_slot (struct hotplug_slot *slot)
{
struct hotplug_slot_core *core = slot->core_priv;
int result;
result = get_mount();
if (result)
return result;
static struct hotplug_slot_attribute hotplug_slot_attr_test = {
.attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR},
.store = test_write_file
};
core->dir_dentry = fs_create_file (slot->name,
S_IFDIR | S_IXUGO | S_IRUGO,
NULL, NULL, NULL);
if (core->dir_dentry != NULL) {
static int has_power_file (struct hotplug_slot *slot)
{
if ((!slot) || (!slot->ops))
return -ENODEV;
if ((slot->ops->enable_slot) ||
(slot->ops->disable_slot) ||
(slot->ops->get_power_status))
core->power_dentry =
fs_create_file ("power",
S_IFREG | S_IRUGO | S_IWUSR,
core->dir_dentry, slot,
&power_file_operations);
return 0;
return -ENOENT;
}
static int has_attention_file (struct hotplug_slot *slot)
{
if ((!slot) || (!slot->ops))
return -ENODEV;
if ((slot->ops->set_attention_status) ||
(slot->ops->get_attention_status))
core->attention_dentry =
fs_create_file ("attention",
S_IFREG | S_IRUGO | S_IWUSR,
core->dir_dentry, slot,
&attention_file_operations);
return 0;
return -ENOENT;
}
static int has_latch_file (struct hotplug_slot *slot)
{
if ((!slot) || (!slot->ops))
return -ENODEV;
if (slot->ops->get_latch_status)
core->latch_dentry =
fs_create_file ("latch",
S_IFREG | S_IRUGO,
core->dir_dentry, slot,
&latch_file_operations);
return 0;
return -ENOENT;
}
static int has_adapter_file (struct hotplug_slot *slot)
{
if ((!slot) || (!slot->ops))
return -ENODEV;
if (slot->ops->get_adapter_status)
core->adapter_dentry =
fs_create_file ("adapter",
S_IFREG | S_IRUGO,
core->dir_dentry, slot,
&presence_file_operations);
return 0;
return -ENOENT;
}
static int has_max_bus_speed_file (struct hotplug_slot *slot)
{
if ((!slot) || (!slot->ops))
return -ENODEV;
if (slot->ops->get_max_bus_speed)
core->max_bus_speed_dentry =
fs_create_file ("max_bus_speed",
S_IFREG | S_IRUGO,
core->dir_dentry, slot,
&max_bus_speed_file_operations);
return 0;
return -ENOENT;
}
static int has_cur_bus_speed_file (struct hotplug_slot *slot)
{
if ((!slot) || (!slot->ops))
return -ENODEV;
if (slot->ops->get_cur_bus_speed)
core->cur_bus_speed_dentry =
fs_create_file ("cur_bus_speed",
S_IFREG | S_IRUGO,
core->dir_dentry, slot,
&cur_bus_speed_file_operations);
return 0;
return -ENOENT;
}
static int has_test_file (struct hotplug_slot *slot)
{
if ((!slot) || (!slot->ops))
return -ENODEV;
if (slot->ops->hardware_test)
core->test_dentry =
fs_create_file ("test",
S_IFREG | S_IRUGO | S_IWUSR,
core->dir_dentry, slot,
&test_file_operations);
}
return 0;
return -ENOENT;
}
static int fs_add_slot (struct hotplug_slot *slot)
{
if (has_power_file(slot) == 0)
sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr);
if (has_attention_file(slot) == 0)
sysfs_create_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
if (has_latch_file(slot) == 0)
sysfs_create_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
if (has_adapter_file(slot) == 0)
sysfs_create_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
if (has_max_bus_speed_file(slot) == 0)
sysfs_create_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
if (has_cur_bus_speed_file(slot) == 0)
sysfs_create_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
if (has_test_file(slot) == 0)
sysfs_create_file(&slot->kobj, &hotplug_slot_attr_test.attr);
return 0;
}
static void fs_remove_slot (struct hotplug_slot *slot)
{
struct hotplug_slot_core *core = slot->core_priv;
if (core->dir_dentry) {
if (core->power_dentry)
fs_remove_file (core->power_dentry);
if (core->attention_dentry)
fs_remove_file (core->attention_dentry);
if (core->latch_dentry)
fs_remove_file (core->latch_dentry);
if (core->adapter_dentry)
fs_remove_file (core->adapter_dentry);
if (core->max_bus_speed_dentry)
fs_remove_file (core->max_bus_speed_dentry);
if (core->cur_bus_speed_dentry)
fs_remove_file (core->cur_bus_speed_dentry);
if (core->test_dentry)
fs_remove_file (core->test_dentry);
fs_remove_file (core->dir_dentry);
}
if (has_power_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
if (has_attention_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
remove_mount();
if (has_latch_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
if (has_adapter_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
if (has_max_bus_speed_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
if (has_cur_bus_speed_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
if (has_test_file(slot) == 0)
sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr);
}
static struct hotplug_slot *get_slot_from_name (const char *name)
......@@ -1138,7 +524,6 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
*/
int pci_hp_register (struct hotplug_slot *slot)
{
struct hotplug_slot_core *core;
int result;
if (slot == NULL)
......@@ -1146,20 +531,20 @@ int pci_hp_register (struct hotplug_slot *slot)
if ((slot->info == NULL) || (slot->ops == NULL))
return -EINVAL;
core = kmalloc (sizeof (struct hotplug_slot_core), GFP_KERNEL);
if (!core)
return -ENOMEM;
/* make sure we have not already registered this slot */
spin_lock (&list_lock);
if (get_slot_from_name (slot->name) != NULL) {
spin_unlock (&list_lock);
kfree (core);
return -EINVAL;
}
memset (core, 0, sizeof (struct hotplug_slot_core));
slot->core_priv = core;
strncpy(slot->kobj.name, slot->name, KOBJ_NAME_LEN);
kobj_set_kset_s(slot, hotplug_slots_subsys);
if (kobject_register(&slot->kobj)) {
err("Unable to register kobject");
return -EINVAL;
}
list_add (&slot->slot_list, &pci_hotplug_slot_list);
spin_unlock (&list_lock);
......@@ -1197,68 +582,56 @@ int pci_hp_deregister (struct hotplug_slot *slot)
spin_unlock (&list_lock);
fs_remove_slot (slot);
kfree(slot->core_priv);
dbg ("Removed slot %s from the list\n", slot->name);
kobject_unregister(&slot->kobj);
return 0;
}
static inline void update_dentry_inode_time (struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
if (inode) {
inode->i_mtime = CURRENT_TIME;
dnotify_parent(dentry, DN_MODIFY);
}
}
/**
* pci_hp_change_slot_info - changes the slot's information structure in the core
* @name: the name of the slot whose info has changed
* @slot: pointer to the slot whose info has changed
* @info: pointer to the info copy into the slot's info structure
*
* A slot with @name must have been registered with the pci
* @slot must have been registered with the pci
* hotplug subsystem previously with a call to pci_hp_register().
*
* Returns 0 if successful, anything else for an error.
*/
int pci_hp_change_slot_info (const char *name, struct hotplug_slot_info *info)
int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info)
{
struct hotplug_slot *temp;
struct hotplug_slot_core *core;
if (info == NULL)
return -ENODEV;
spin_lock (&list_lock);
temp = get_slot_from_name (name);
if (temp == NULL) {
spin_unlock (&list_lock);
if ((slot == NULL) || (info == NULL))
return -ENODEV;
}
/*
* check all fields in the info structure, and update timestamps
* for the files referring to the fields that have now changed.
*/
core = temp->core_priv;
if ((core->power_dentry) &&
(temp->info->power_status != info->power_status))
update_dentry_inode_time (core->power_dentry);
if ((core->attention_dentry) &&
(temp->info->attention_status != info->attention_status))
update_dentry_inode_time (core->attention_dentry);
if ((core->latch_dentry) &&
(temp->info->latch_status != info->latch_status))
update_dentry_inode_time (core->latch_dentry);
if ((core->adapter_dentry) &&
(temp->info->adapter_status != info->adapter_status))
update_dentry_inode_time (core->adapter_dentry);
if ((core->cur_bus_speed_dentry) &&
(temp->info->cur_bus_speed != info->cur_bus_speed))
update_dentry_inode_time (core->cur_bus_speed_dentry);
memcpy (temp->info, info, sizeof (struct hotplug_slot_info));
spin_unlock (&list_lock);
if ((has_power_file(slot) == 0) &&
(slot->info->power_status != info->power_status))
sysfs_update_file(&slot->kobj, &hotplug_slot_attr_power.attr);
if ((has_attention_file(slot) == 0) &&
(slot->info->attention_status != info->attention_status))
sysfs_update_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
if ((has_latch_file(slot) == 0) &&
(slot->info->latch_status != info->latch_status))
sysfs_update_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
if ((has_adapter_file(slot) == 0) &&
(slot->info->adapter_status != info->adapter_status))
sysfs_update_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
if ((has_max_bus_speed_file(slot) == 0) &&
(slot->info->max_bus_speed != info->max_bus_speed))
sysfs_update_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
if ((has_cur_bus_speed_file(slot) == 0) &&
(slot->info->cur_bus_speed != info->cur_bus_speed))
sysfs_update_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
return 0;
}
......@@ -1266,32 +639,25 @@ static int __init pci_hotplug_init (void)
{
int result;
spin_lock_init(&mount_lock);
spin_lock_init(&list_lock);
dbg("registering filesystem.\n");
result = register_filesystem(&pcihpfs_type);
kset_set_kset_s(&hotplug_slots_subsys, pci_bus_type.subsys);
result = subsystem_register(&hotplug_slots_subsys);
if (result) {
err("register_filesystem failed with %d\n", result);
err("Register subsys with error %d\n", result);
goto exit;
}
result = cpci_hotplug_init(debug);
if (result) {
err ("cpci_hotplug_init with error %d\n", result);
goto error_fs;
goto err_subsys;
}
#ifdef CONFIG_PROC_FS
/* create mount point for pcihpfs */
slotdir = proc_mkdir(slotdir_name, proc_bus_pci_dir);
#endif
info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
goto exit;
error_fs:
unregister_filesystem(&pcihpfs_type);
err_subsys:
subsystem_unregister(&hotplug_slots_subsys);
exit:
return result;
}
......@@ -1299,13 +665,7 @@ static int __init pci_hotplug_init (void)
static void __exit pci_hotplug_exit (void)
{
cpci_hotplug_exit();
unregister_filesystem(&pcihpfs_type);
#ifdef CONFIG_PROC_FS
if (slotdir)
remove_proc_entry(slotdir_name, proc_bus_pci_dir);
#endif
subsystem_unregister(&hotplug_slots_subsys);
}
module_init(pci_hotplug_init);
......@@ -1320,4 +680,3 @@ MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
EXPORT_SYMBOL_GPL(pci_hp_register);
EXPORT_SYMBOL_GPL(pci_hp_deregister);
EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
/*
* PCI HotPlug Utility functions
*
* Copyright (c) 1995,2001 Compaq Computer Corporation
* Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (c) 2001 IBM Corp.
*
* All rights reserved.
*
* 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.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Send feedback to <greg@kroah.com>
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include "pci_hotplug.h"
#if !defined(CONFIG_HOTPLUG_PCI_MODULE)
#define MY_NAME "pci_hotplug"
#else
#define MY_NAME THIS_MODULE->name
#endif
#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0)
#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
/* local variables */
static int debug;
/*
* This is code that scans the pci buses.
* Every bus and every function is presented to a custom
* function that can act upon it.
*/
static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent)
{
struct list_head *ln;
struct pci_dev *dev;
struct pci_dev_wrapped wrapped_dev;
int result = 0;
dbg("scanning bus %02x\n", wrapped_bus->bus->number);
if (fn->pre_visit_pci_bus) {
result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent);
if (result)
return result;
}
ln = wrapped_bus->bus->devices.next;
while (ln != &wrapped_bus->bus->devices) {
dev = pci_dev_b(ln);
ln = ln->next;
memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
wrapped_dev.dev = dev;
result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus);
if (result)
return result;
}
if (fn->post_visit_pci_bus)
result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent);
return result;
}
static int pci_visit_bridge (struct pci_visit * fn, struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_parent)
{
struct pci_bus *bus;
struct pci_bus_wrapped wrapped_bus;
int result = 0;
dbg("scanning bridge %02x, %02x\n", PCI_SLOT(wrapped_dev->dev->devfn),
PCI_FUNC(wrapped_dev->dev->devfn));
if (fn->visit_pci_dev) {
result = fn->visit_pci_dev(wrapped_dev, wrapped_parent);
if (result)
return result;
}
bus = wrapped_dev->dev->subordinate;
if(bus) {
memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
wrapped_bus.bus = bus;
result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev);
}
return result;
}
int pci_visit_dev (struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_parent)
{
struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL;
int result = 0;
if (!dev)
return 0;
if (fn->pre_visit_pci_dev) {
result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent);
if (result)
return result;
}
switch (dev->class >> 8) {
case PCI_CLASS_BRIDGE_PCI:
result = pci_visit_bridge(fn, wrapped_dev,
wrapped_parent);
if (result)
return result;
break;
default:
dbg("scanning device %02x, %02x\n",
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
if (fn->visit_pci_dev) {
result = fn->visit_pci_dev (wrapped_dev,
wrapped_parent);
if (result)
return result;
}
}
if (fn->post_visit_pci_dev)
result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent);
return result;
}
/**
* pci_is_dev_in_use - query devices' usage
* @dev: PCI device to query
*
* Queries whether a given PCI device is in use by a driver or not.
* Returns 1 if the device is in use, 0 if it is not.
*/
int pci_is_dev_in_use(struct pci_dev *dev)
{
/*
* dev->driver will be set if the device is in use by a new-style
* driver -- otherwise, check the device's regions to see if any
* driver has claimed them.
*/
int i;
int inuse = 0;
if (dev->driver) {
/* Assume driver feels responsible */
return 1;
}
for (i = 0; !dev->driver && !inuse && (i < 6); i++) {
if (!pci_resource_start(dev, i))
continue;
if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
inuse = check_region(pci_resource_start(dev, i),
pci_resource_len(dev, i));
} else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) {
inuse = check_mem_region(pci_resource_start(dev, i),
pci_resource_len(dev, i));
}
}
return inuse;
}
/**
* pci_remove_device_safe - remove an unused hotplug device
* @dev: the device to remove
*
* Delete the device structure from the device lists and
* notify userspace (/sbin/hotplug), but only if the device
* in question is not being used by a driver.
* Returns 0 on success.
*/
int pci_remove_device_safe(struct pci_dev *dev)
{
if (pci_is_dev_in_use(dev)) {
return -EBUSY;
}
pci_remove_device(dev);
return 0;
}
EXPORT_SYMBOL(pci_visit_dev);
EXPORT_SYMBOL(pci_is_dev_in_use);
EXPORT_SYMBOL(pci_remove_device_safe);
......@@ -3,7 +3,8 @@
#
obj-y += access.o probe.o pci.o pool.o quirks.o \
names.o pci-driver.o search.o hotplug.o
names.o pci-driver.o search.o hotplug.o \
pci-sysfs.o
obj-$(CONFIG_PM) += power.o
obj-$(CONFIG_PROC_FS) += proc.o
......
......@@ -2,6 +2,14 @@
#include <linux/module.h>
#include "pci.h"
#undef DEBUG
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
#ifdef CONFIG_HOTPLUG
int pci_hotplug (struct device *dev, char **envp, int num_envp,
......@@ -57,13 +65,179 @@ int pci_hotplug (struct device *dev, char **envp, int num_envp,
return 0;
}
#else
static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent)
{
struct list_head *ln;
struct pci_dev *dev;
struct pci_dev_wrapped wrapped_dev;
int result = 0;
DBG("scanning bus %02x\n", wrapped_bus->bus->number);
if (fn->pre_visit_pci_bus) {
result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent);
if (result)
return result;
}
ln = wrapped_bus->bus->devices.next;
while (ln != &wrapped_bus->bus->devices) {
dev = pci_dev_b(ln);
ln = ln->next;
memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
wrapped_dev.dev = dev;
result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus);
if (result)
return result;
}
if (fn->post_visit_pci_bus)
result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent);
return result;
}
static int pci_visit_bridge (struct pci_visit * fn,
struct pci_dev_wrapped *wrapped_dev,
struct pci_bus_wrapped *wrapped_parent)
{
struct pci_bus *bus;
struct pci_bus_wrapped wrapped_bus;
int result = 0;
DBG("scanning bridge %02x, %02x\n", PCI_SLOT(wrapped_dev->dev->devfn),
PCI_FUNC(wrapped_dev->dev->devfn));
if (fn->visit_pci_dev) {
result = fn->visit_pci_dev(wrapped_dev, wrapped_parent);
if (result)
return result;
}
bus = wrapped_dev->dev->subordinate;
if(bus) {
memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
wrapped_bus.bus = bus;
result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev);
}
return result;
}
/**
* pci_visit_dev - scans the pci buses.
* Every bus and every function is presented to a custom
* function that can act upon it.
*/
int pci_visit_dev (struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev,
struct pci_bus_wrapped *wrapped_parent)
{
struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL;
int result = 0;
if (!dev)
return 0;
if (fn->pre_visit_pci_dev) {
result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent);
if (result)
return result;
}
switch (dev->class >> 8) {
case PCI_CLASS_BRIDGE_PCI:
result = pci_visit_bridge(fn, wrapped_dev,
wrapped_parent);
if (result)
return result;
break;
default:
DBG("scanning device %02x, %02x\n",
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
if (fn->visit_pci_dev) {
result = fn->visit_pci_dev (wrapped_dev,
wrapped_parent);
if (result)
return result;
}
}
if (fn->post_visit_pci_dev)
result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent);
return result;
}
EXPORT_SYMBOL(pci_visit_dev);
/**
* pci_is_dev_in_use - query devices' usage
* @dev: PCI device to query
*
* Queries whether a given PCI device is in use by a driver or not.
* Returns 1 if the device is in use, 0 if it is not.
*/
int pci_is_dev_in_use(struct pci_dev *dev)
{
/*
* dev->driver will be set if the device is in use by a new-style
* driver -- otherwise, check the device's regions to see if any
* driver has claimed them.
*/
int i;
int inuse = 0;
if (dev->driver) {
/* Assume driver feels responsible */
return 1;
}
for (i = 0; !dev->driver && !inuse && (i < 6); i++) {
if (!pci_resource_start(dev, i))
continue;
if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
inuse = check_region(pci_resource_start(dev, i),
pci_resource_len(dev, i));
} else if (pci_resource_flags(dev, i) & IORESOURCE_MEM) {
inuse = check_mem_region(pci_resource_start(dev, i),
pci_resource_len(dev, i));
}
}
return inuse;
}
EXPORT_SYMBOL(pci_is_dev_in_use);
/**
* pci_remove_device_safe - remove an unused hotplug device
* @dev: the device to remove
*
* Delete the device structure from the device lists and
* notify userspace (/sbin/hotplug), but only if the device
* in question is not being used by a driver.
* Returns 0 on success.
*/
int pci_remove_device_safe(struct pci_dev *dev)
{
if (pci_is_dev_in_use(dev)) {
return -EBUSY;
}
pci_remove_device(dev);
return 0;
}
EXPORT_SYMBOL(pci_remove_device_safe);
#else /* CONFIG_HOTPLUG */
int pci_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
return -ENODEV;
}
#endif
#endif /* CONFIG_HOTPLUG */
/**
* pci_insert_device - insert a pci device
......@@ -81,6 +255,8 @@ pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
#ifdef CONFIG_PROC_FS
pci_proc_attach_device(dev);
#endif
/* add sysfs device files */
pci_create_sysfs_dev_files(dev);
}
static void
......
/*
* drivers/pci/pci-sysfs.c
*
* (C) Copyright 2002 Greg Kroah-Hartman
* (C) Copyright 2002 IBM Corp.
*
* File attributes for PCI devices
*
* Modeled after usb's driverfs.c
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include "pci.h"
#if BITS_PER_LONG == 32
#define LONG_FORMAT "\t%08lx"
#else
#define LONG_FORMAT "\t%16lx"
#endif
/* show configuration fields */
#define pci_config_attr(field, format_string) \
static ssize_t \
show_##field (struct device *dev, char *buf) \
{ \
struct pci_dev *pdev; \
\
pdev = to_pci_dev (dev); \
return sprintf (buf, format_string, pdev->field); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
pci_config_attr(vendor, "%04x\n");
pci_config_attr(device, "%04x\n");
pci_config_attr(subsystem_vendor, "%04x\n");
pci_config_attr(subsystem_device, "%04x\n");
pci_config_attr(class, "%06x\n");
pci_config_attr(irq, "%u\n");
/* show resources */
static ssize_t
pci_show_resources(struct device * dev, char * buf)
{
struct pci_dev * pci_dev = to_pci_dev(dev);
char * str = buf;
int i;
for (i = 0; i < DEVICE_COUNT_RESOURCE && pci_resource_start(pci_dev,i); i++) {
str += sprintf(str,LONG_FORMAT LONG_FORMAT LONG_FORMAT "\n",
pci_resource_start(pci_dev,i),
pci_resource_end(pci_dev,i),
pci_resource_flags(pci_dev,i));
}
return (str - buf);
}
static DEVICE_ATTR(resource,S_IRUGO,pci_show_resources,NULL);
void pci_create_sysfs_dev_files (struct pci_dev *pdev)
{
struct device *dev = &pdev->dev;
/* current configuration's attributes */
device_create_file (dev, &dev_attr_vendor);
device_create_file (dev, &dev_attr_device);
device_create_file (dev, &dev_attr_subsystem_vendor);
device_create_file (dev, &dev_attr_subsystem_device);
device_create_file (dev, &dev_attr_class);
device_create_file (dev, &dev_attr_irq);
device_create_file (dev, &dev_attr_resource);
}
......@@ -2,4 +2,4 @@
extern int pci_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size);
extern void pci_create_sysfs_dev_files(struct pci_dev *pdev);
......@@ -373,32 +373,6 @@ static struct seq_operations proc_bus_pci_devices_op = {
struct proc_dir_entry *proc_bus_pci_dir;
/* driverfs files */
static ssize_t pci_show_irq(struct device * dev, char * buf)
{
struct pci_dev * pci_dev = to_pci_dev(dev);
return sprintf(buf,"%u\n",pci_dev->irq);
}
static DEVICE_ATTR(irq,S_IRUGO,pci_show_irq,NULL);
static ssize_t pci_show_resources(struct device * dev, char * buf)
{
struct pci_dev * pci_dev = to_pci_dev(dev);
char * str = buf;
int i;
for (i = 0; i < DEVICE_COUNT_RESOURCE && pci_resource_start(pci_dev,i); i++) {
str += sprintf(str,LONG_FORMAT LONG_FORMAT LONG_FORMAT "\n",
pci_resource_start(pci_dev,i),
pci_resource_end(pci_dev,i),
pci_resource_flags(pci_dev,i));
}
return (str - buf);
}
static DEVICE_ATTR(resource,S_IRUGO,pci_show_resources,NULL);
int pci_proc_attach_device(struct pci_dev *dev)
{
struct pci_bus *bus = dev->bus;
......@@ -422,8 +396,6 @@ int pci_proc_attach_device(struct pci_dev *dev)
e->data = dev;
e->size = PCI_CFG_SPACE_SIZE;
device_create_file(&dev->dev,&dev_attr_irq);
device_create_file(&dev->dev,&dev_attr_resource);
return 0;
}
......
......@@ -37,6 +37,7 @@
#include <linux/backing-dev.h>
#include <linux/kobject.h>
#include <linux/mount.h>
#include <linux/dnotify.h>
#include <asm/uaccess.h>
/* Random magic number */
......@@ -716,6 +717,46 @@ static void hash_and_remove(struct dentry * dir, const char * name)
up(&dir->d_inode->i_sem);
}
/**
* sysfs_update_file - update the modified timestamp on an object attribute.
* @kobj: object we're acting for.
* @attr: attribute descriptor.
*
* Also call dnotify for the dentry, which lots of userspace programs
* use.
*/
int sysfs_update_file(struct kobject * kobj, struct attribute * attr)
{
struct dentry * dir = kobj->dentry;
struct dentry * victim;
int res = -ENOENT;
down(&dir->d_inode->i_sem);
victim = get_dentry(dir, attr->name);
if (!IS_ERR(victim)) {
/* make sure dentry is really there */
if (victim->d_inode &&
(victim->d_parent->d_inode == dir->d_inode)) {
victim->d_inode->i_mtime = CURRENT_TIME;
dnotify_parent(victim, DN_MODIFY);
/**
* Drop reference from initial get_dentry().
*/
dput(victim);
res = 0;
}
/**
* Drop the reference acquired from get_dentry() above.
*/
dput(victim);
}
up(&dir->d_inode->i_sem);
return res;
}
/**
* sysfs_remove_file - remove an object attribute.
......
......@@ -671,6 +671,37 @@ void pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t addr);
extern struct pci_dev *isa_bridge;
#endif
/* Some worker functions that PCI Hotplug drivers find useful */
struct pci_dev_wrapped {
struct pci_dev *dev;
void *data;
};
struct pci_bus_wrapped {
struct pci_bus *bus;
void *data;
};
struct pci_visit {
int (* pre_visit_pci_bus) (struct pci_bus_wrapped *,
struct pci_dev_wrapped *);
int (* post_visit_pci_bus) (struct pci_bus_wrapped *,
struct pci_dev_wrapped *);
int (* pre_visit_pci_dev) (struct pci_dev_wrapped *,
struct pci_bus_wrapped *);
int (* visit_pci_dev) (struct pci_dev_wrapped *,
struct pci_bus_wrapped *);
int (* post_visit_pci_dev) (struct pci_dev_wrapped *,
struct pci_bus_wrapped *);
};
extern int pci_visit_dev(struct pci_visit *fn,
struct pci_dev_wrapped *wrapped_dev,
struct pci_bus_wrapped *wrapped_parent);
extern int pci_is_dev_in_use(struct pci_dev *dev);
extern int pci_remove_device_safe(struct pci_dev *dev);
#endif /* CONFIG_PCI */
/* Include architecture-dependent settings and functions */
......
......@@ -30,6 +30,9 @@ sysfs_remove_dir(struct kobject *);
extern int
sysfs_create_file(struct kobject *, struct attribute *);
extern int
sysfs_update_file(struct kobject *, struct attribute *);
extern void
sysfs_remove_file(struct kobject *, struct attribute *);
......
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