From 2dc034a85d4164b90fa883a1226afb971174bcc5 Mon Sep 17 00:00:00 2001 From: Hans-Jürgen Koch Date: Tue, 19 Feb 2008 21:07:19 +0100 Subject: UIO: arch/arm/Kconfig: Make UIO available on ARM architecture Source drivers/uio/Kconfig to make UIO available in menuconfig if ARCH=arm. Signed-off-by: Hans J Koch Signed-off-by: Greg Kroah-Hartman --- arch/arm/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4039a133006e..1165a8fb99c1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1174,6 +1174,8 @@ source "drivers/dma/Kconfig" source "drivers/dca/Kconfig" +source "drivers/uio/Kconfig" + endmenu source "fs/Kconfig" -- cgit v1.2.3 From 138fe4e069798d9aa948a5402ff15e58f483ee4e Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Date: Wed, 9 Apr 2008 19:50:41 -0700 Subject: Firmware: add iSCSI iBFT Support Add /sysfs/firmware/ibft/[initiator|targetX|ethernetX] directories along with text properties which export the the iSCSI Boot Firmware Table (iBFT) structure. What is iSCSI Boot Firmware Table? It is a mechanism for the iSCSI tools to extract from the machine NICs the iSCSI connection information so that they can automagically mount the iSCSI share/target. Currently the iSCSI information is hard-coded in the initrd. The /sysfs entries are read-only one-name-and-value fields. The usual set of data exposed is: # for a in `find /sys/firmware/ibft/ -type f -print`; do echo -n "$a: "; cat $a; done /sys/firmware/ibft/target0/target-name: iqn.2007.com.intel-sbx44:storage-10gb /sys/firmware/ibft/target0/nic-assoc: 0 /sys/firmware/ibft/target0/chap-type: 0 /sys/firmware/ibft/target0/lun: 00000000 /sys/firmware/ibft/target0/port: 3260 /sys/firmware/ibft/target0/ip-addr: 192.168.79.116 /sys/firmware/ibft/target0/flags: 3 /sys/firmware/ibft/target0/index: 0 /sys/firmware/ibft/ethernet0/mac: 00:11:25:9d:8b:01 /sys/firmware/ibft/ethernet0/vlan: 0 /sys/firmware/ibft/ethernet0/gateway: 192.168.79.254 /sys/firmware/ibft/ethernet0/origin: 0 /sys/firmware/ibft/ethernet0/subnet-mask: 255.255.252.0 /sys/firmware/ibft/ethernet0/ip-addr: 192.168.77.41 /sys/firmware/ibft/ethernet0/flags: 7 /sys/firmware/ibft/ethernet0/index: 0 /sys/firmware/ibft/initiator/initiator-name: iqn.2007-07.com:konrad.initiator /sys/firmware/ibft/initiator/flags: 3 /sys/firmware/ibft/initiator/index: 0 For full details of the IBFT structure please take a look at: ftp://ftp.software.ibm.com/systems/support/system_x_pdf/ibm_iscsi_boot_firmware_table_v1.02.pdf [akpm@linux-foundation.org: fix build] Signed-off-by: Konrad Rzeszutek Cc: Mike Christie Cc: Peter Jones Cc: James Bottomley Cc: Ingo Molnar Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-ibft | 23 + arch/x86/kernel/setup_32.c | 3 + arch/x86/kernel/setup_64.c | 4 + drivers/firmware/Kconfig | 20 + drivers/firmware/Makefile | 2 + drivers/firmware/iscsi_ibft.c | 982 +++++++++++++++++++++++++++++++++++ drivers/firmware/iscsi_ibft_find.c | 84 +++ include/linux/iscsi_ibft.h | 50 ++ 8 files changed, 1168 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-ibft create mode 100644 drivers/firmware/iscsi_ibft.c create mode 100644 drivers/firmware/iscsi_ibft_find.c create mode 100644 include/linux/iscsi_ibft.h (limited to 'arch') diff --git a/Documentation/ABI/testing/sysfs-ibft b/Documentation/ABI/testing/sysfs-ibft new file mode 100644 index 000000000000..c2b7d1154bec --- /dev/null +++ b/Documentation/ABI/testing/sysfs-ibft @@ -0,0 +1,23 @@ +What: /sys/firmware/ibft/initiator +Date: November 2007 +Contact: Konrad Rzeszutek +Description: The /sys/firmware/ibft/initiator directory will contain + files that expose the iSCSI Boot Firmware Table initiator data. + Usually this contains the Initiator name. + +What: /sys/firmware/ibft/targetX +Date: November 2007 +Contact: Konrad Rzeszutek +Description: The /sys/firmware/ibft/targetX directory will contain + files that expose the iSCSI Boot Firmware Table target data. + Usually this contains the target's IP address, boot LUN, + target name, and what NIC it is associated with. It can also + contain the CHAP name (and password), the reverse CHAP + name (and password) + +What: /sys/firmware/ibft/ethernetX +Date: November 2007 +Contact: Konrad Rzeszutek +Description: The /sys/firmware/ibft/ethernetX directory will contain + files that expose the iSCSI Boot Firmware Table NIC data. + This can this can the IP address, MAC, and gateway of the NIC. diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c index 5b0bffb7fcc9..4ef91749959e 100644 --- a/arch/x86/kernel/setup_32.c +++ b/arch/x86/kernel/setup_32.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -689,6 +690,8 @@ void __init setup_bootmem_allocator(void) #endif numa_kva_reserve(); reserve_crashkernel(); + + reserve_ibft_region(); } /* diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c index 674ef3510cdf..216c93bd9993 100644 --- a/arch/x86/kernel/setup_64.c +++ b/arch/x86/kernel/setup_64.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -434,6 +435,9 @@ void __init setup_arch(char **cmdline_p) } #endif reserve_crashkernel(); + + reserve_ibft_region(); + paging_init(); map_vsyscall(); diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 05f02a326f1c..40ffd767647d 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -93,4 +93,24 @@ config DMIID information from userspace through /sys/class/dmi/id/ or if you want DMI-based module auto-loading. +config ISCSI_IBFT_FIND + bool "iSCSI Boot Firmware Table Attributes" + depends on X86 + default n + help + This option enables the kernel to find the region of memory + in which the ISCSI Boot Firmware Table (iBFT) resides. This + is necessary for iSCSI Boot Firmware Table Attributes module to work + properly. + +config ISCSI_IBFT + tristate "iSCSI Boot Firmware Table Attributes module" + depends on ISCSI_IBFT_FIND + default n + help + This option enables support for detection and exposing of iSCSI + Boot Firmware Table (iBFT) via sysfs to userspace. If you wish to + detect iSCSI boot parameters dynamically during system boot, say Y. + Otherwise, say N. + endmenu diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 8d4ebc805a50..4c9147154df8 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -8,3 +8,5 @@ obj-$(CONFIG_EFI_PCDP) += pcdp.o obj-$(CONFIG_DELL_RBU) += dell_rbu.o obj-$(CONFIG_DCDBAS) += dcdbas.o obj-$(CONFIG_DMIID) += dmi-id.o +obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o +obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c new file mode 100644 index 000000000000..8024e3bfd877 --- /dev/null +++ b/drivers/firmware/iscsi_ibft.c @@ -0,0 +1,982 @@ +/* + * Copyright 2007 Red Hat, Inc. + * by Peter Jones + * Copyright 2008 IBM, Inc. + * by Konrad Rzeszutek + * Copyright 2008 + * by Konrad Rzeszutek + * + * This code exposes the iSCSI Boot Format Table to userland via sysfs. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2.0 as published by + * the Free Software Foundation + * + * 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. See the + * GNU General Public License for more details. + * + * Changelog: + * + * 14 Mar 2008 - Konrad Rzeszutek + * Updated comments and copyrights. (v0.4.9) + * + * 11 Feb 2008 - Konrad Rzeszutek + * Converted to using ibft_addr. (v0.4.8) + * + * 8 Feb 2008 - Konrad Rzeszutek + * Combined two functions in one: reserve_ibft_region. (v0.4.7) + * + * 30 Jan 2008 - Konrad Rzeszutek + * Added logic to handle IPv6 addresses. (v0.4.6) + * + * 25 Jan 2008 - Konrad Rzeszutek + * Added logic to handle badly not-to-spec iBFT. (v0.4.5) + * + * 4 Jan 2008 - Konrad Rzeszutek + * Added __init to function declarations. (v0.4.4) + * + * 21 Dec 2007 - Konrad Rzeszutek + * Updated kobject registration, combined unregister functions in one + * and code and style cleanup. (v0.4.3) + * + * 5 Dec 2007 - Konrad Rzeszutek + * Added end-markers to enums and re-organized kobject registration. (v0.4.2) + * + * 4 Dec 2007 - Konrad Rzeszutek + * Created 'device' sysfs link to the NIC and style cleanup. (v0.4.1) + * + * 28 Nov 2007 - Konrad Rzeszutek + * Added sysfs-ibft documentation, moved 'find_ibft' function to + * in its own file and added text attributes for every struct field. (v0.4) + * + * 21 Nov 2007 - Konrad Rzeszutek + * Added text attributes emulating OpenFirmware /proc/device-tree naming. + * Removed binary /sysfs interface (v0.3) + * + * 29 Aug 2007 - Konrad Rzeszutek + * Added functionality in setup.c to reserve iBFT region. (v0.2) + * + * 27 Aug 2007 - Konrad Rzeszutek + * First version exposing iBFT data via a binary /sysfs. (v0.1) + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IBFT_ISCSI_VERSION "0.4.9" +#define IBFT_ISCSI_DATE "2008-Mar-14" + +MODULE_AUTHOR("Peter Jones and \ +Konrad Rzeszutek "); +MODULE_DESCRIPTION("sysfs interface to BIOS iBFT information"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(IBFT_ISCSI_VERSION); + +struct ibft_hdr { + u8 id; + u8 version; + u16 length; + u8 index; + u8 flags; +} __attribute__((__packed__)); + +struct ibft_control { + struct ibft_hdr hdr; + u16 extensions; + u16 initiator_off; + u16 nic0_off; + u16 tgt0_off; + u16 nic1_off; + u16 tgt1_off; +} __attribute__((__packed__)); + +struct ibft_initiator { + struct ibft_hdr hdr; + char isns_server[16]; + char slp_server[16]; + char pri_radius_server[16]; + char sec_radius_server[16]; + u16 initiator_name_len; + u16 initiator_name_off; +} __attribute__((__packed__)); + +struct ibft_nic { + struct ibft_hdr hdr; + char ip_addr[16]; + u8 subnet_mask_prefix; + u8 origin; + char gateway[16]; + char primary_dns[16]; + char secondary_dns[16]; + char dhcp[16]; + u16 vlan; + char mac[6]; + u16 pci_bdf; + u16 hostname_len; + u16 hostname_off; +} __attribute__((__packed__)); + +struct ibft_tgt { + struct ibft_hdr hdr; + char ip_addr[16]; + u16 port; + char lun[8]; + u8 chap_type; + u8 nic_assoc; + u16 tgt_name_len; + u16 tgt_name_off; + u16 chap_name_len; + u16 chap_name_off; + u16 chap_secret_len; + u16 chap_secret_off; + u16 rev_chap_name_len; + u16 rev_chap_name_off; + u16 rev_chap_secret_len; + u16 rev_chap_secret_off; +} __attribute__((__packed__)); + +/* + * The kobject different types and its names. + * +*/ +enum ibft_id { + id_reserved = 0, /* We don't support. */ + id_control = 1, /* Should show up only once and is not exported. */ + id_initiator = 2, + id_nic = 3, + id_target = 4, + id_extensions = 5, /* We don't support. */ + id_end_marker, +}; + +/* + * We do not support the other types, hence the usage of NULL. + * This maps to the enum ibft_id. + */ +static const char *ibft_id_names[] = + {NULL, NULL, "initiator", "ethernet%d", "target%d", NULL, NULL}; + +/* + * The text attributes names for each of the kobjects. +*/ +enum ibft_eth_properties_enum { + ibft_eth_index, + ibft_eth_flags, + ibft_eth_ip_addr, + ibft_eth_subnet_mask, + ibft_eth_origin, + ibft_eth_gateway, + ibft_eth_primary_dns, + ibft_eth_secondary_dns, + ibft_eth_dhcp, + ibft_eth_vlan, + ibft_eth_mac, + /* ibft_eth_pci_bdf - this is replaced by link to the device itself. */ + ibft_eth_hostname, + ibft_eth_end_marker, +}; + +static const char *ibft_eth_properties[] = + {"index", "flags", "ip-addr", "subnet-mask", "origin", "gateway", + "primary-dns", "secondary-dns", "dhcp", "vlan", "mac", "hostname", + NULL}; + +enum ibft_tgt_properties_enum { + ibft_tgt_index, + ibft_tgt_flags, + ibft_tgt_ip_addr, + ibft_tgt_port, + ibft_tgt_lun, + ibft_tgt_chap_type, + ibft_tgt_nic_assoc, + ibft_tgt_name, + ibft_tgt_chap_name, + ibft_tgt_chap_secret, + ibft_tgt_rev_chap_name, + ibft_tgt_rev_chap_secret, + ibft_tgt_end_marker, +}; + +static const char *ibft_tgt_properties[] = + {"index", "flags", "ip-addr", "port", "lun", "chap-type", "nic-assoc", + "target-name", "chap-name", "chap-secret", "rev-chap-name", + "rev-chap-name-secret", NULL}; + +enum ibft_initiator_properties_enum { + ibft_init_index, + ibft_init_flags, + ibft_init_isns_server, + ibft_init_slp_server, + ibft_init_pri_radius_server, + ibft_init_sec_radius_server, + ibft_init_initiator_name, + ibft_init_end_marker, +}; + +static const char *ibft_initiator_properties[] = + {"index", "flags", "isns-server", "slp-server", "pri-radius-server", + "sec-radius-server", "initiator-name", NULL}; + +/* + * The kobject and attribute structures. + */ + +struct ibft_kobject { + struct ibft_table_header *header; + union { + struct ibft_initiator *initiator; + struct ibft_nic *nic; + struct ibft_tgt *tgt; + struct ibft_hdr *hdr; + }; + struct kobject kobj; + struct list_head node; +}; + +struct ibft_attribute { + struct attribute attr; + ssize_t (*show) (struct ibft_kobject *entry, + struct ibft_attribute *attr, char *buf); + union { + struct ibft_initiator *initiator; + struct ibft_nic *nic; + struct ibft_tgt *tgt; + struct ibft_hdr *hdr; + }; + struct kobject *kobj; + int type; /* The enum of the type. This can be any value of: + ibft_eth_properties_enum, ibft_tgt_properties_enum, + or ibft_initiator_properties_enum. */ + struct list_head node; +}; + +static LIST_HEAD(ibft_attr_list); +static LIST_HEAD(ibft_kobject_list); + +static const char nulls[16]; + +/* + * Helper functions to parse data properly. + */ +static ssize_t sprintf_ipaddr(char *buf, u8 *ip) +{ + char *str = buf; + + if (ip[0] == 0 && ip[1] == 0 && ip[2] == 0 && ip[3] == 0 && + ip[4] == 0 && ip[5] == 0 && ip[6] == 0 && ip[7] == 0 && + ip[8] == 0 && ip[9] == 0 && ip[10] == 0xff && ip[11] == 0xff) { + /* + * IPV4 + */ + str += sprintf(buf, NIPQUAD_FMT, ip[12], + ip[13], ip[14], ip[15]); + } else { + /* + * IPv6 + */ + str += sprintf(str, NIP6_FMT, ntohs(ip[0]), ntohs(ip[1]), + ntohs(ip[2]), ntohs(ip[3]), ntohs(ip[4]), + ntohs(ip[5]), ntohs(ip[6]), ntohs(ip[7])); + } + str += sprintf(str, "\n"); + return str - buf; +} + +static ssize_t sprintf_string(char *str, int len, char *buf) +{ + return sprintf(str, "%.*s\n", len, buf); +} + +/* + * Helper function to verify the IBFT header. + */ +static int ibft_verify_hdr(char *t, struct ibft_hdr *hdr, int id, int length) +{ + if (hdr->id != id) { + printk(KERN_ERR "iBFT error: We expected the " \ + "field header.id to have %d but " \ + "found %d instead!\n", id, hdr->id); + return -ENODEV; + } + if (hdr->length != length) { + printk(KERN_ERR "iBFT error: We expected the " \ + "field header.length to have %d but " \ + "found %d instead!\n", length, hdr->length); + return -ENODEV; + } + + return 0; +} + +static void ibft_release(struct kobject *kobj) +{ + struct ibft_kobject *ibft = + container_of(kobj, struct ibft_kobject, kobj); + kfree(ibft); +} + +/* + * Routines for parsing the iBFT data to be human readable. + */ +ssize_t ibft_attr_show_initiator(struct ibft_kobject *entry, + struct ibft_attribute *attr, + char *buf) +{ + struct ibft_initiator *initiator = entry->initiator; + void *ibft_loc = entry->header; + char *str = buf; + + if (!initiator) + return 0; + + switch (attr->type) { + case ibft_init_index: + str += sprintf(str, "%d\n", initiator->hdr.index); + break; + case ibft_init_flags: + str += sprintf(str, "%d\n", initiator->hdr.flags); + break; + case ibft_init_isns_server: + str += sprintf_ipaddr(str, initiator->isns_server); + break; + case ibft_init_slp_server: + str += sprintf_ipaddr(str, initiator->slp_server); + break; + case ibft_init_pri_radius_server: + str += sprintf_ipaddr(str, initiator->pri_radius_server); + break; + case ibft_init_sec_radius_server: + str += sprintf_ipaddr(str, initiator->sec_radius_server); + break; + case ibft_init_initiator_name: + str += sprintf_string(str, initiator->initiator_name_len, + (char *)ibft_loc + + initiator->initiator_name_off); + break; + default: + break; + } + + return str - buf; +} + +ssize_t ibft_attr_show_nic(struct ibft_kobject *entry, + struct ibft_attribute *attr, + char *buf) +{ + struct ibft_nic *nic = entry->nic; + void *ibft_loc = entry->header; + char *str = buf; + char *mac; + int val; + + if (!nic) + return 0; + + switch (attr->type) { + case ibft_eth_index: + str += sprintf(str, "%d\n", nic->hdr.index); + break; + case ibft_eth_flags: + str += sprintf(str, "%d\n", nic->hdr.flags); + break; + case ibft_eth_ip_addr: + str += sprintf_ipaddr(str, nic->ip_addr); + break; + case ibft_eth_subnet_mask: + val = ~((1 << (32-nic->subnet_mask_prefix))-1); + str += sprintf(str, NIPQUAD_FMT, + (u8)(val >> 24), (u8)(val >> 16), + (u8)(val >> 8), (u8)(val)); + break; + case ibft_eth_origin: + str += sprintf(str, "%d\n", nic->origin); + break; + case ibft_eth_gateway: + str += sprintf_ipaddr(str, nic->gateway); + break; + case ibft_eth_primary_dns: + str += sprintf_ipaddr(str, nic->primary_dns); + break; + case ibft_eth_secondary_dns: + str += sprintf_ipaddr(str, nic->secondary_dns); + break; + case ibft_eth_dhcp: + str += sprintf_ipaddr(str, nic->dhcp); + break; + case ibft_eth_vlan: + str += sprintf(str, "%d\n", nic->vlan); + break; + case ibft_eth_mac: + mac = nic->mac; + str += sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x\n", + (u8)mac[0], (u8)mac[1], (u8)mac[2], + (u8)mac[3], (u8)mac[4], (u8)mac[5]); + break; + case ibft_eth_hostname: + str += sprintf_string(str, nic->hostname_len, + (char *)ibft_loc + nic->hostname_off); + break; + default: + break; + } + + return str - buf; +}; + +ssize_t ibft_attr_show_target(struct ibft_kobject *entry, + struct ibft_attribute *attr, + char *buf) +{ + struct ibft_tgt *tgt = entry->tgt; + void *ibft_loc = entry->header; + char *str = buf; + int i; + + if (!tgt) + return 0; + + switch (attr->type) { + case ibft_tgt_index: + str += sprintf(str, "%d\n", tgt->hdr.index); + break; + case ibft_tgt_flags: + str += sprintf(str, "%d\n", tgt->hdr.flags); + break; + case ibft_tgt_ip_addr: + str += sprintf_ipaddr(str, tgt->ip_addr); + break; + case ibft_tgt_port: + str += sprintf(str, "%d\n", tgt->port); + break; + case ibft_tgt_lun: + for (i = 0; i < 8; i++) + str += sprintf(str, "%x", (u8)tgt->lun[i]); + str += sprintf(str, "\n"); + break; + case ibft_tgt_nic_assoc: + str += sprintf(str, "%d\n", tgt->nic_assoc); + break; + case ibft_tgt_chap_type: + str += sprintf(str, "%d\n", tgt->chap_type); + break; + case ibft_tgt_name: + str += sprintf_string(str, tgt->tgt_name_len, + (char *)ibft_loc + tgt->tgt_name_off); + break; + case ibft_tgt_chap_name: + str += sprintf_string(str, tgt->chap_name_len, + (char *)ibft_loc + tgt->chap_name_off); + break; + case ibft_tgt_chap_secret: + str += sprintf_string(str, tgt->chap_secret_len, + (char *)ibft_loc + tgt->chap_secret_off); + break; + case ibft_tgt_rev_chap_name: + str += sprintf_string(str, tgt->rev_chap_name_len, + (char *)ibft_loc + + tgt->rev_chap_name_off); + break; + case ibft_tgt_rev_chap_secret: + str += sprintf_string(str, tgt->rev_chap_secret_len, + (char *)ibft_loc + + tgt->rev_chap_secret_off); + break; + default: + break; + } + + return str - buf; +} + +/* + * The routine called for all sysfs attributes. + */ +static ssize_t ibft_show_attribute(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct ibft_kobject *dev = + container_of(kobj, struct ibft_kobject, kobj); + struct ibft_attribute *ibft_attr = + container_of(attr, struct ibft_attribute, attr); + ssize_t ret = -EIO; + char *str = buf; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (ibft_attr->show) + ret = ibft_attr->show(dev, ibft_attr, str); + + return ret; +} + +static struct sysfs_ops ibft_attr_ops = { + .show = ibft_show_attribute, +}; + +static struct kobj_type ibft_ktype = { + .release = ibft_release, + .sysfs_ops = &ibft_attr_ops, +}; + +static struct kset *ibft_kset; + +static int __init ibft_check_device(void) +{ + int len; + u8 *pos; + u8 csum = 0; + + len = ibft_addr->length; + + /* Sanity checking of iBFT. */ + if (ibft_addr->revision != 1) { + printk(KERN_ERR "iBFT module supports only revision 1, " \ + "while this is %d.\n", ibft_addr->revision); + return -ENOENT; + } + for (pos = (u8 *)ibft_addr; pos < (u8 *)ibft_addr + len; pos++) + csum += *pos; + + if (csum) { + printk(KERN_ERR "iBFT has incorrect checksum (0x%x)!\n", csum); + return -ENOENT; + } + + return 0; +} + +/* + * Helper function for ibft_register_kobjects. + */ +static int __init ibft_create_kobject(struct ibft_table_header *header, + struct ibft_hdr *hdr, + struct list_head *list) +{ + struct ibft_kobject *ibft_kobj = NULL; + struct ibft_nic *nic = (struct ibft_nic *)hdr; + struct pci_dev *pci_dev; + int rc = 0; + + ibft_kobj = kzalloc(sizeof(*ibft_kobj), GFP_KERNEL); + if (!ibft_kobj) + return -ENOMEM; + + ibft_kobj->header = header; + ibft_kobj->hdr = hdr; + + switch (hdr->id) { + case id_initiator: + rc = ibft_verify_hdr("initiator", hdr, id_initiator, + sizeof(*ibft_kobj->initiator)); + break; + case id_nic: + rc = ibft_verify_hdr("ethernet", hdr, id_nic, + sizeof(*ibft_kobj->nic)); + break; + case id_target: + rc = ibft_verify_hdr("target", hdr, id_target, + sizeof(*ibft_kobj->tgt)); + break; + case id_reserved: + case id_control: + case id_extensions: + /* Fields which we don't support. Ignore them */ + rc = 1; + break; + default: + printk(KERN_ERR "iBFT has unknown structure type (%d). " \ + "Report this bug to %.6s!\n", hdr->id, + header->oem_id); + rc = 1; + break; + } + + if (rc) { + /* Skip adding this kobject, but exit with non-fatal error. */ + kfree(ibft_kobj); + goto out_invalid_struct; + } + + ibft_kobj->kobj.kset = ibft_kset; + + rc = kobject_init_and_add(&ibft_kobj->kobj, &ibft_ktype, + NULL, ibft_id_names[hdr->id], hdr->index); + + if (rc) { + kfree(ibft_kobj); + goto out; + } + + kobject_uevent(&ibft_kobj->kobj, KOBJ_ADD); + + if (hdr->id == id_nic) { + /* + * We don't search for the device in other domains than + * zero. This is because on x86 platforms the BIOS + * executes only devices which are in domain 0. Furthermore, the + * iBFT spec doesn't have a domain id field :-( + */ + pci_dev = pci_get_bus_and_slot((nic->pci_bdf & 0xff00) >> 8, + (nic->pci_bdf & 0xff)); + if (pci_dev) { + rc = sysfs_create_link(&ibft_kobj->kobj, + &pci_dev->dev.kobj, "device"); + pci_dev_put(pci_dev); + } + } + + /* Nothing broke so lets add it to the list. */ + list_add_tail(&ibft_kobj->node, list); +out: + return rc; +out_invalid_struct: + /* Unsupported structs are skipped. */ + return 0; +} + +/* + * Scan the IBFT table structure for the NIC and Target fields. When + * found add them on the passed-in list. We do not support the other + * fields at this point, so they are skipped. + */ +static int __init ibft_register_kobjects(struct ibft_table_header *header, + struct list_head *list) +{ + struct ibft_control *control = NULL; + void *ptr, *end; + int rc = 0; + u16 offset; + u16 eot_offset; + + control = (void *)header + sizeof(*header); + end = (void *)control + control->hdr.length; + eot_offset = (void *)header + header->length - + (void *)control - sizeof(*header); + rc = ibft_verify_hdr("control", (struct ibft_hdr *)control, id_control, + sizeof(*control)); + + /* iBFT table safety checking */ + rc |= ((control->hdr.index) ? -ENODEV : 0); + if (rc) { + printk(KERN_ERR "iBFT error: Control header is invalid!\n"); + return rc; + } + for (ptr = &control->initiator_off; ptr < end; ptr += sizeof(u16)) { + offset = *(u16 *)ptr; + if (offset && offset < header->length && offset < eot_offset) { + rc = ibft_create_kobject(header, + (void *)header + offset, + list); + if (rc) + break; + } + } + + return rc; +} + +static void ibft_unregister(struct list_head *attr_list, + struct list_head *kobj_list) +{ + struct ibft_kobject *data = NULL, *n; + struct ibft_attribute *attr = NULL, *m; + + list_for_each_entry_safe(attr, m, attr_list, node) { + sysfs_remove_file(attr->kobj, &attr->attr); + list_del(&attr->node); + kfree(attr); + }; + list_del_init(attr_list); + + list_for_each_entry_safe(data, n, kobj_list, node) { + list_del(&data->node); + if (data->hdr->id == id_nic) + sysfs_remove_link(&data->kobj, "device"); + kobject_put(&data->kobj); + }; + list_del_init(kobj_list); +} + +static int __init ibft_create_attribute(struct ibft_kobject *kobj_data, + int type, + const char *name, + ssize_t (*show)(struct ibft_kobject *, + struct ibft_attribute*, + char *buf), + struct list_head *list) +{ + struct ibft_attribute *attr = NULL; + struct ibft_hdr *hdr = kobj_data->hdr; + + attr = kmalloc(sizeof(*attr), GFP_KERNEL); + if (!attr) + return -ENOMEM; + + attr->attr.name = name; + attr->attr.mode = S_IRUSR; + attr->attr.owner = THIS_MODULE; + + attr->hdr = hdr; + attr->show = show; + attr->kobj = &kobj_data->kobj; + attr->type = type; + + list_add_tail(&attr->node, list); + + return 0; +} + +/* + * Helper routiners to check to determine if the entry is valid + * in the proper iBFT structure. + */ +static int __init ibft_check_nic_for(struct ibft_nic *nic, int entry) +{ + int rc = 0; + + switch (entry) { + case ibft_eth_index: + case ibft_eth_flags: + rc = 1; + break; + case ibft_eth_ip_addr: + if (!memcmp(nic->dhcp, nulls, sizeof(nic->dhcp))) + rc = 1; + break; + case ibft_eth_subnet_mask: + if (!memcmp(nic->dhcp, nulls, sizeof(nic->dhcp))) + rc = 1; + break; + case ibft_eth_origin: + rc = 1; + break; + case ibft_eth_gateway: + if (memcmp(nic->gateway, nulls, sizeof(nic->gateway))) + rc = 1; + break; + case ibft_eth_primary_dns: + if (memcmp(nic->primary_dns, nulls, + sizeof(nic->primary_dns))) + rc = 1; + break; + case ibft_eth_secondary_dns: + if (memcmp(nic->secondary_dns, nulls, + sizeof(nic->secondary_dns))) + rc = 1; + break; + case ibft_eth_dhcp: + if (memcmp(nic->dhcp, nulls, sizeof(nic->dhcp))) + rc = 1; + break; + case ibft_eth_vlan: + case ibft_eth_mac: + rc = 1; + break; + case ibft_eth_hostname: + if (nic->hostname_off) + rc = 1; + break; + default: + break; + } + + return rc; +} + +static int __init ibft_check_tgt_for(struct ibft_tgt *tgt, int entry) +{ + int rc = 0; + + switch (entry) { + case ibft_tgt_index: + case ibft_tgt_flags: + case ibft_tgt_ip_addr: + case ibft_tgt_port: + case ibft_tgt_lun: + case ibft_tgt_nic_assoc: + case ibft_tgt_chap_type: + rc = 1; + case ibft_tgt_name: + if (tgt->tgt_name_len) + rc = 1; + break; + case ibft_tgt_chap_name: + case ibft_tgt_chap_secret: + if (tgt->chap_name_len) + rc = 1; + break; + case ibft_tgt_rev_chap_name: + case ibft_tgt_rev_chap_secret: + if (tgt->rev_chap_name_len) + rc = 1; + break; + default: + break; + } + + return rc; +} + +static int __init ibft_check_initiator_for(struct ibft_initiator *init, + int entry) +{ + int rc = 0; + + switch (entry) { + case ibft_init_index: + case ibft_init_flags: + rc = 1; + break; + case ibft_init_isns_server: + if (memcmp(init->isns_server, nulls, + sizeof(init->isns_server))) + rc = 1; + break; + case ibft_init_slp_server: + if (memcmp(init->slp_server, nulls, + sizeof(init->slp_server))) + rc = 1; + break; + case ibft_init_pri_radius_server: + if (memcmp(init->pri_radius_server, nulls, + sizeof(init->pri_radius_server))) + rc = 1; + break; + case ibft_init_sec_radius_server: + if (memcmp(init->sec_radius_server, nulls, + sizeof(init->sec_radius_server))) + rc = 1; + break; + case ibft_init_initiator_name: + if (init->initiator_name_len) + rc = 1; + break; + default: + break; + } + + return rc; +} + +/* + * Register the attributes for all of the kobjects. + */ +static int __init ibft_register_attributes(struct list_head *kobject_list, + struct list_head *attr_list) +{ + int rc = 0, i = 0; + struct ibft_kobject *data = NULL; + struct ibft_attribute *attr = NULL, *m; + + list_for_each_entry(data, kobject_list, node) { + switch (data->hdr->id) { + case id_nic: + for (i = 0; i < ibft_eth_end_marker && !rc; i++) + if (ibft_check_nic_for(data->nic, i)) + rc = ibft_create_attribute(data, i, + ibft_eth_properties[i], + ibft_attr_show_nic, attr_list); + break; + case id_target: + for (i = 0; i < ibft_tgt_end_marker && !rc; i++) + if (ibft_check_tgt_for(data->tgt, i)) + rc = ibft_create_attribute(data, i, + ibft_tgt_properties[i], + ibft_attr_show_target, + attr_list); + break; + case id_initiator: + for (i = 0; i < ibft_init_end_marker && !rc; i++) + if (ibft_check_initiator_for( + data->initiator, i)) + rc = ibft_create_attribute(data, i, + ibft_initiator_properties[i], + ibft_attr_show_initiator, + attr_list); + break; + default: + break; + } + if (rc) + break; + } + list_for_each_entry_safe(attr, m, attr_list, node) { + rc = sysfs_create_file(attr->kobj, &attr->attr); + if (rc) { + list_del(&attr->node); + kfree(attr); + break; + } + } + + return rc; +} + +/* + * ibft_init() - creates sysfs tree entries for the iBFT data. + */ +static int __init ibft_init(void) +{ + int rc = 0; + + ibft_kset = kset_create_and_add("ibft", NULL, firmware_kobj); + if (!ibft_kset) + return -ENOMEM; + + if (ibft_addr) { + printk(KERN_INFO "iBFT detected at 0x%lx.\n", + virt_to_phys((void *)ibft_addr)); + + rc = ibft_check_device(); + if (rc) + goto out_firmware_unregister; + + /* Scan the IBFT for data and register the kobjects. */ + rc = ibft_register_kobjects(ibft_addr, &ibft_kobject_list); + if (rc) + goto out_free; + + /* Register the attributes */ + rc = ibft_register_attributes(&ibft_kobject_list, + &ibft_attr_list); + if (rc) + goto out_free; + } else + printk(KERN_INFO "No iBFT detected.\n"); + + return 0; + +out_free: + ibft_unregister(&ibft_attr_list, &ibft_kobject_list); +out_firmware_unregister: + kset_unregister(ibft_kset); + return rc; +} + +static void __exit ibft_exit(void) +{ + ibft_unregister(&ibft_attr_list, &ibft_kobject_list); + kset_unregister(ibft_kset); +} + +module_init(ibft_init); +module_exit(ibft_exit); diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c new file mode 100644 index 000000000000..d0e5fa4ea51b --- /dev/null +++ b/drivers/firmware/iscsi_ibft_find.c @@ -0,0 +1,84 @@ +/* + * Copyright 2007 Red Hat, Inc. + * by Peter Jones + * Copyright 2007 IBM, Inc. + * by Konrad Rzeszutek + * Copyright 2008 + * by Konrad Rzeszutek + * + * This code finds the iSCSI Boot Format Table. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2.0 as published by + * the Free Software Foundation + * + * 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. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Physical location of iSCSI Boot Format Table. + */ +struct ibft_table_header *ibft_addr; +EXPORT_SYMBOL_GPL(ibft_addr); + +#define IBFT_SIGN "iBFT" +#define IBFT_SIGN_LEN 4 +#define IBFT_START 0x80000 /* 512kB */ +#define IBFT_END 0x100000 /* 1MB */ +#define VGA_MEM 0xA0000 /* VGA buffer */ +#define VGA_SIZE 0x20000 /* 128kB */ + + +/* + * Routine used to find the iSCSI Boot Format Table. The logical + * kernel address is set in the ibft_addr global variable. + */ +void __init reserve_ibft_region(void) +{ + unsigned long pos; + unsigned int len = 0; + void *virt; + + ibft_addr = 0; + + for (pos = IBFT_START; pos < IBFT_END; pos += 16) { + /* The table can't be inside the VGA BIOS reserved space, + * so skip that area */ + if (pos == VGA_MEM) + pos += VGA_SIZE; + virt = phys_to_virt(pos); + if (memcmp(virt, IBFT_SIGN, IBFT_SIGN_LEN) == 0) { + unsigned long *addr = + (unsigned long *)phys_to_virt(pos + 4); + len = *addr; + /* if the length of the table extends past 1M, + * the table cannot be valid. */ + if (pos + len <= (IBFT_END-1)) { + ibft_addr = (struct ibft_table_header *)virt; + break; + } + } + } + if (ibft_addr) + reserve_bootmem(pos, PAGE_ALIGN(len), BOOTMEM_DEFAULT); +} +EXPORT_SYMBOL_GPL(reserve_ibft_region); diff --git a/include/linux/iscsi_ibft.h b/include/linux/iscsi_ibft.h new file mode 100644 index 000000000000..6092487e2950 --- /dev/null +++ b/include/linux/iscsi_ibft.h @@ -0,0 +1,50 @@ +/* + * Copyright 2007 Red Hat, Inc. + * by Peter Jones + * Copyright 2007 IBM, Inc. + * by Konrad Rzeszutek + * Copyright 2008 + * by Konrad Rzeszutek + * + * This code exposes the iSCSI Boot Format Table to userland via sysfs. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2.0 as published by + * the Free Software Foundation + * + * 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. See the + * GNU General Public License for more details. + */ + +#ifndef ISCSI_IBFT_H +#define ISCSI_IBFT_H + +struct ibft_table_header { + char signature[4]; + u32 length; + u8 revision; + u8 checksum; + char oem_id[6]; + char oem_table_id[8]; + char reserved[24]; +} __attribute__((__packed__)); + +/* + * Logical location of iSCSI Boot Format Table. + * If the value is NULL there is no iBFT on the machine. + */ +extern struct ibft_table_header *ibft_addr; + +/* + * Routine used to find and reserve the iSCSI Boot Format Table. The + * mapped address is set in the ibft_addr variable. + */ +#ifdef CONFIG_ISCSI_IBFT_FIND +extern void __init reserve_ibft_region(void); +#else +static inline void reserve_ibft_region(void) { } +#endif + +#endif /* ISCSI_IBFT_H */ -- cgit v1.2.3 From b844eba292b477cda14582bfc6f535deed57a82d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 23 Mar 2008 20:28:24 +0100 Subject: PM: Remove destroy_suspended_device() After 2.6.24 there was a plan to make the PM core acquire all device semaphores during a suspend/hibernation to protect itself from concurrent operations involving device objects. That proved to be too heavy-handed and we found a better way to achieve the goal, but before it happened, we had introduced the functions device_pm_schedule_removal() and destroy_suspended_device() to allow drivers to "safely" destroy a suspended device and we had adapted some drivers to use them. Now that these functions are no longer necessary, it seems reasonable to remove them and modify their users to use the normal device unregistration instead. Signed-off-by: Rafael J. Wysocki Acked-by: Pavel Machek Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpuid.c | 4 +--- arch/x86/kernel/msr.c | 4 +--- drivers/base/core.c | 29 ----------------------------- drivers/base/power/main.c | 40 ---------------------------------------- drivers/char/hw_random/core.c | 10 +++++----- drivers/char/misc.c | 13 ++++--------- drivers/leds/led-class.c | 11 +++-------- drivers/net/wireless/b43/leds.c | 5 +---- drivers/net/wireless/b43/main.c | 8 ++++---- include/linux/device.h | 14 -------------- include/linux/hw_random.h | 10 +--------- include/linux/leds.h | 10 +--------- include/linux/miscdevice.h | 10 +--------- 13 files changed, 22 insertions(+), 146 deletions(-) (limited to 'arch') diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c index 288e7a6598ac..daff52a62248 100644 --- a/arch/x86/kernel/cpuid.c +++ b/arch/x86/kernel/cpuid.c @@ -154,12 +154,10 @@ static int __cpuinit cpuid_class_cpu_callback(struct notifier_block *nfb, err = cpuid_device_create(cpu); break; case CPU_UP_CANCELED: + case CPU_UP_CANCELED_FROZEN: case CPU_DEAD: cpuid_device_destroy(cpu); break; - case CPU_UP_CANCELED_FROZEN: - destroy_suspended_device(cpuid_class, MKDEV(CPUID_MAJOR, cpu)); - break; } return err ? NOTIFY_BAD : NOTIFY_OK; } diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c index 4dfb40530057..1f3abe048e93 100644 --- a/arch/x86/kernel/msr.c +++ b/arch/x86/kernel/msr.c @@ -162,12 +162,10 @@ static int __cpuinit msr_class_cpu_callback(struct notifier_block *nfb, err = msr_device_create(cpu); break; case CPU_UP_CANCELED: + case CPU_UP_CANCELED_FROZEN: case CPU_DEAD: msr_device_destroy(cpu); break; - case CPU_UP_CANCELED_FROZEN: - destroy_suspended_device(msr_class, MKDEV(MSR_MAJOR, cpu)); - break; } return err ? NOTIFY_BAD : NOTIFY_OK; } diff --git a/drivers/base/core.c b/drivers/base/core.c index adbc01788447..0262fc7c45fc 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1163,35 +1163,6 @@ void device_destroy(struct class *class, dev_t devt) } EXPORT_SYMBOL_GPL(device_destroy); -#ifdef CONFIG_PM_SLEEP -/** - * destroy_suspended_device - asks the PM core to remove a suspended device - * @class: pointer to the struct class that this device was registered with - * @devt: the dev_t of the device that was previously registered - * - * This call notifies the PM core of the necessity to unregister a suspended - * device created with a call to device_create() (devices cannot be - * unregistered directly while suspended, since the PM core holds their - * semaphores at that time). - * - * It can only be called within the scope of a system sleep transition. In - * practice this means it has to be directly or indirectly invoked either by - * a suspend or resume method, or by the PM core (e.g. via - * disable_nonboot_cpus() or enable_nonboot_cpus()). - */ -void destroy_suspended_device(struct class *class, dev_t devt) -{ - struct device *dev; - - dev = class_find_device(class, &devt, __match_devt); - if (dev) { - device_pm_schedule_removal(dev); - put_device(dev); - } -} -EXPORT_SYMBOL_GPL(destroy_suspended_device); -#endif /* CONFIG_PM_SLEEP */ - /** * device_rename - renames a device * @dev: the pointer to the struct device to be renamed diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 5630af302b2f..c4568b82875b 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -50,7 +50,6 @@ LIST_HEAD(dpm_active); static LIST_HEAD(dpm_off); static LIST_HEAD(dpm_off_irq); -static LIST_HEAD(dpm_destroy); static DEFINE_MUTEX(dpm_list_mtx); @@ -104,24 +103,6 @@ void device_pm_remove(struct device *dev) mutex_unlock(&dpm_list_mtx); } -/** - * device_pm_schedule_removal - schedule the removal of a suspended device - * @dev: Device to destroy - * - * Moves the device to the dpm_destroy list for further processing by - * unregister_dropped_devices(). - */ -void device_pm_schedule_removal(struct device *dev) -{ - pr_debug("PM: Preparing for removal: %s:%s\n", - dev->bus ? dev->bus->name : "No Bus", - kobject_name(&dev->kobj)); - mutex_lock(&dpm_list_mtx); - list_move_tail(&dev->power.entry, &dpm_destroy); - mutex_unlock(&dpm_list_mtx); -} -EXPORT_SYMBOL_GPL(device_pm_schedule_removal); - /*------------------------- Resume routines -------------------------*/ /** @@ -245,26 +226,6 @@ static void dpm_resume(void) mutex_unlock(&dpm_list_mtx); } -/** - * unregister_dropped_devices - Unregister devices scheduled for removal - * - * Unregister all devices on the dpm_destroy list. - */ -static void unregister_dropped_devices(void) -{ - mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_destroy)) { - struct list_head *entry = dpm_destroy.next; - struct device *dev = to_device(entry); - - mutex_unlock(&dpm_list_mtx); - /* This also removes the device from the list */ - device_unregister(dev); - mutex_lock(&dpm_list_mtx); - } - mutex_unlock(&dpm_list_mtx); -} - /** * device_resume - Restore state of each device in system. * @@ -275,7 +236,6 @@ void device_resume(void) { might_sleep(); dpm_resume(); - unregister_dropped_devices(); } EXPORT_SYMBOL_GPL(device_resume); diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 349b6edc5794..662d60e44e9a 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -238,11 +238,11 @@ static DEVICE_ATTR(rng_available, S_IRUGO, NULL); -static void unregister_miscdev(bool suspended) +static void unregister_miscdev(void) { device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available); device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current); - __misc_deregister(&rng_miscdev, suspended); + misc_deregister(&rng_miscdev); } static int register_miscdev(void) @@ -317,7 +317,7 @@ out: } EXPORT_SYMBOL_GPL(hwrng_register); -void __hwrng_unregister(struct hwrng *rng, bool suspended) +void hwrng_unregister(struct hwrng *rng) { int err; @@ -336,11 +336,11 @@ void __hwrng_unregister(struct hwrng *rng, bool suspended) } } if (list_empty(&rng_list)) - unregister_miscdev(suspended); + unregister_miscdev(); mutex_unlock(&rng_mutex); } -EXPORT_SYMBOL_GPL(__hwrng_unregister); +EXPORT_SYMBOL_GPL(hwrng_unregister); MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver"); diff --git a/drivers/char/misc.c b/drivers/char/misc.c index a39101feb2ed..4d058dadbfcc 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -232,9 +232,8 @@ int misc_register(struct miscdevice * misc) } /** - * __misc_deregister - unregister a miscellaneous device + * misc_deregister - unregister a miscellaneous device * @misc: device to unregister - * @suspended: to be set if the function is used during suspend/resume * * Unregister a miscellaneous device that was previously * successfully registered with misc_register(). Success @@ -242,7 +241,7 @@ int misc_register(struct miscdevice * misc) * indicates an error. */ -int __misc_deregister(struct miscdevice *misc, bool suspended) +int misc_deregister(struct miscdevice *misc) { int i = misc->minor; @@ -251,11 +250,7 @@ int __misc_deregister(struct miscdevice *misc, bool suspended) mutex_lock(&misc_mtx); list_del(&misc->list); - if (suspended) - destroy_suspended_device(misc_class, - MKDEV(MISC_MAJOR, misc->minor)); - else - device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); + device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); if (i < DYNAMIC_MINORS && i>0) { misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); } @@ -264,7 +259,7 @@ int __misc_deregister(struct miscdevice *misc, bool suspended) } EXPORT_SYMBOL(misc_register); -EXPORT_SYMBOL(__misc_deregister); +EXPORT_SYMBOL(misc_deregister); static int __init misc_init(void) { diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 4a938780dfc3..63aad90247c4 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -139,12 +139,10 @@ EXPORT_SYMBOL_GPL(led_classdev_register); /** * __led_classdev_unregister - unregisters a object of led_properties class. * @led_cdev: the led device to unregister - * @suspended: indicates whether system-wide suspend or resume is in progress * * Unregisters a previously registered via led_classdev_register object. */ -void __led_classdev_unregister(struct led_classdev *led_cdev, - bool suspended) +void led_classdev_unregister(struct led_classdev *led_cdev) { device_remove_file(led_cdev->dev, &dev_attr_brightness); #ifdef CONFIG_LEDS_TRIGGERS @@ -155,16 +153,13 @@ void __led_classdev_unregister(struct led_classdev *led_cdev, up_write(&led_cdev->trigger_lock); #endif - if (suspended) - device_pm_schedule_removal(led_cdev->dev); - else - device_unregister(led_cdev->dev); + device_unregister(led_cdev->dev); down_write(&leds_list_lock); list_del(&led_cdev->node); up_write(&leds_list_lock); } -EXPORT_SYMBOL_GPL(__led_classdev_unregister); +EXPORT_SYMBOL_GPL(led_classdev_unregister); static int __init leds_init(void) { diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 0aac1ff511df..36a9c42df835 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -116,10 +116,7 @@ static void b43_unregister_led(struct b43_led *led) { if (!led->dev) return; - if (led->dev->suspend_in_progress) - led_classdev_unregister_suspended(&led->led_dev); - else - led_classdev_unregister(&led->led_dev); + led_classdev_unregister(&led->led_dev); b43_led_turn_off(led->dev, led->index, led->activelow); led->dev = NULL; } diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index cf5c046c9fa8..943cc851c504 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2804,10 +2804,10 @@ static int b43_rng_read(struct hwrng *rng, u32 * data) return (sizeof(u16)); } -static void b43_rng_exit(struct b43_wl *wl, bool suspended) +static void b43_rng_exit(struct b43_wl *wl) { if (wl->rng_initialized) - __hwrng_unregister(&wl->rng, suspended); + hwrng_unregister(&wl->rng); } static int b43_rng_init(struct b43_wl *wl) @@ -3824,7 +3824,7 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) if (!dev->suspend_in_progress) { b43_leds_exit(dev); - b43_rng_exit(dev->wl, false); + b43_rng_exit(dev->wl); } b43_dma_free(dev); b43_pio_free(dev); @@ -4589,7 +4589,7 @@ static int b43_resume(struct ssb_device *dev) err = b43_wireless_core_start(wldev); if (err) { b43_leds_exit(wldev); - b43_rng_exit(wldev->wl, true); + b43_rng_exit(wldev->wl); b43_wireless_core_exit(wldev); b43err(wl, "Resume failed at core start\n"); goto out; diff --git a/include/linux/device.h b/include/linux/device.h index 441461f5ee20..dc3429e2eb0f 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -545,20 +545,6 @@ extern struct device *device_create(struct class *cls, struct device *parent, dev_t devt, const char *fmt, ...) __attribute__((format(printf, 4, 5))); extern void device_destroy(struct class *cls, dev_t devt); -#ifdef CONFIG_PM_SLEEP -extern void destroy_suspended_device(struct class *cls, dev_t devt); -extern void device_pm_schedule_removal(struct device *); -#else /* !CONFIG_PM_SLEEP */ -static inline void destroy_suspended_device(struct class *cls, dev_t devt) -{ - device_destroy(cls, devt); -} - -static inline void device_pm_schedule_removal(struct device *dev) -{ - device_unregister(dev); -} -#endif /* !CONFIG_PM_SLEEP */ /* * Platform "fixup" functions - allow the platform to have their say diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h index 42131820bb89..85d11916e9ea 100644 --- a/include/linux/hw_random.h +++ b/include/linux/hw_random.h @@ -44,15 +44,7 @@ struct hwrng { /** Register a new Hardware Random Number Generator driver. */ extern int hwrng_register(struct hwrng *rng); /** Unregister a Hardware Random Number Generator driver. */ -extern void __hwrng_unregister(struct hwrng *rng, bool suspended); -static inline void hwrng_unregister(struct hwrng *rng) -{ - __hwrng_unregister(rng, false); -} -static inline void hwrng_unregister_suspended(struct hwrng *rng) -{ - __hwrng_unregister(rng, true); -} +extern void hwrng_unregister(struct hwrng *rng); #endif /* __KERNEL__ */ #endif /* LINUX_HWRANDOM_H_ */ diff --git a/include/linux/leds.h b/include/linux/leds.h index 0201f6f51cea..b07e3d400bd6 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -59,15 +59,7 @@ struct led_classdev { extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev); -extern void __led_classdev_unregister(struct led_classdev *led_cdev, bool sus); -static inline void led_classdev_unregister(struct led_classdev *lcd) -{ - __led_classdev_unregister(lcd, false); -} -static inline void led_classdev_unregister_suspended(struct led_classdev *lcd) -{ - __led_classdev_unregister(lcd, true); -} +extern void led_classdev_unregister(struct led_classdev *lcd); extern void led_classdev_suspend(struct led_classdev *led_cdev); extern void led_classdev_resume(struct led_classdev *led_cdev); diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index 24b30b9b4f8a..26433ec520b3 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -43,15 +43,7 @@ struct miscdevice { }; extern int misc_register(struct miscdevice * misc); -extern int __misc_deregister(struct miscdevice *misc, bool suspended); -static inline int misc_deregister(struct miscdevice *misc) -{ - return __misc_deregister(misc, false); -} -static inline int misc_deregister_suspended(struct miscdevice *misc) -{ - return __misc_deregister(misc, true); -} +extern int misc_deregister(struct miscdevice *misc); #define MODULE_ALIAS_MISCDEV(minor) \ MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR) \ -- cgit v1.2.3