From 6d6ac1c1a3d4f95953aa3b085e8f16692d3a7179 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Mon, 23 Aug 2010 12:25:29 +0200 Subject: cfq-iosched: Documentation help for new tunables Some documentation to provide help with tunables. Signed-off-by: Vivek Goyal Acked-by: Jeff Moyer Signed-off-by: Jens Axboe --- Documentation/block/cfq-iosched.txt | 45 ++++++++++++++++++++++++++++++ Documentation/cgroups/blkio-controller.txt | 28 +++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 Documentation/block/cfq-iosched.txt (limited to 'Documentation') diff --git a/Documentation/block/cfq-iosched.txt b/Documentation/block/cfq-iosched.txt new file mode 100644 index 00000000000..e578feed6d8 --- /dev/null +++ b/Documentation/block/cfq-iosched.txt @@ -0,0 +1,45 @@ +CFQ ioscheduler tunables +======================== + +slice_idle +---------- +This specifies how long CFQ should idle for next request on certain cfq queues +(for sequential workloads) and service trees (for random workloads) before +queue is expired and CFQ selects next queue to dispatch from. + +By default slice_idle is a non-zero value. That means by default we idle on +queues/service trees. This can be very helpful on highly seeky media like +single spindle SATA/SAS disks where we can cut down on overall number of +seeks and see improved throughput. + +Setting slice_idle to 0 will remove all the idling on queues/service tree +level and one should see an overall improved throughput on faster storage +devices like multiple SATA/SAS disks in hardware RAID configuration. The down +side is that isolation provided from WRITES also goes down and notion of +IO priority becomes weaker. + +So depending on storage and workload, it might be useful to set slice_idle=0. +In general I think for SATA/SAS disks and software RAID of SATA/SAS disks +keeping slice_idle enabled should be useful. For any configurations where +there are multiple spindles behind single LUN (Host based hardware RAID +controller or for storage arrays), setting slice_idle=0 might end up in better +throughput and acceptable latencies. + +CFQ IOPS Mode for group scheduling +=================================== +Basic CFQ design is to provide priority based time slices. Higher priority +process gets bigger time slice and lower priority process gets smaller time +slice. Measuring time becomes harder if storage is fast and supports NCQ and +it would be better to dispatch multiple requests from multiple cfq queues in +request queue at a time. In such scenario, it is not possible to measure time +consumed by single queue accurately. + +What is possible though is to measure number of requests dispatched from a +single queue and also allow dispatch from multiple cfq queue at the same time. +This effectively becomes the fairness in terms of IOPS (IO operations per +second). + +If one sets slice_idle=0 and if storage supports NCQ, CFQ internally switches +to IOPS mode and starts providing fairness in terms of number of requests +dispatched. Note that this mode switching takes effect only for group +scheduling. For non-cgroup users nothing should change. diff --git a/Documentation/cgroups/blkio-controller.txt b/Documentation/cgroups/blkio-controller.txt index 48e0b21b005..6919d62591d 100644 --- a/Documentation/cgroups/blkio-controller.txt +++ b/Documentation/cgroups/blkio-controller.txt @@ -217,6 +217,7 @@ Details of cgroup files CFQ sysfs tunable ================= /sys/block//queue/iosched/group_isolation +----------------------------------------------- If group_isolation=1, it provides stronger isolation between groups at the expense of throughput. By default group_isolation is 0. In general that @@ -243,6 +244,33 @@ By default one should run with group_isolation=0. If that is not sufficient and one wants stronger isolation between groups, then set group_isolation=1 but this will come at cost of reduced throughput. +/sys/block//queue/iosched/slice_idle +------------------------------------------ +On a faster hardware CFQ can be slow, especially with sequential workload. +This happens because CFQ idles on a single queue and single queue might not +drive deeper request queue depths to keep the storage busy. In such scenarios +one can try setting slice_idle=0 and that would switch CFQ to IOPS +(IO operations per second) mode on NCQ supporting hardware. + +That means CFQ will not idle between cfq queues of a cfq group and hence be +able to driver higher queue depth and achieve better throughput. That also +means that cfq provides fairness among groups in terms of IOPS and not in +terms of disk time. + +/sys/block//queue/iosched/group_idle +------------------------------------------ +If one disables idling on individual cfq queues and cfq service trees by +setting slice_idle=0, group_idle kicks in. That means CFQ will still idle +on the group in an attempt to provide fairness among groups. + +By default group_idle is same as slice_idle and does not do anything if +slice_idle is enabled. + +One can experience an overall throughput drop if you have created multiple +groups and put applications in that group which are not driving enough +IO to keep disk busy. In that case set group_idle=0, and CFQ will not idle +on individual groups and throughput should improve. + What works ========== - Currently only sync IO queues are support. All the buffered writes are -- cgit v1.2.3-70-g09d2 From 79dd9182db2072d63ccf160bb9a3463b1c952723 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 21 Aug 2010 01:51:44 +0200 Subject: PCI: PCIe: Introduce commad line switch for disabling port services Introduce kernel command line switch pcie_ports= allowing one to disable all of the native PCIe port services, so that PCIe ports are treated like PCI-to-PCI bridges. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- Documentation/kernel-parameters.txt | 4 ++++ drivers/pci/pcie/portdrv.h | 2 ++ drivers/pci/pcie/portdrv_core.c | 3 +++ drivers/pci/pcie/portdrv_pci.c | 15 +++++++++++++++ 4 files changed, 24 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 873b6809009..b9008fc3a53 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2042,6 +2042,10 @@ and is between 256 and 4096 characters. It is defined in the file force Enable ASPM even on devices that claim not to support it. WARNING: Forcing ASPM on may cause system lockups. + pcie_ports= [PCIE] PCIe ports handling: + compat Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe + ports driver. + pcie_pme= [PCIE,PM] Native PCIe PME signaling options: Format: {auto|force}[,nomsi] auto Use native PCIe PME signaling if the BIOS allows the diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 813a5c3427b..966f6e9761c 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -20,6 +20,8 @@ #define get_descriptor_id(type, service) (((type - 4) << 4) | service) +extern bool pcie_ports_disabled; + extern struct bus_type pcie_port_bus_type; extern int pcie_port_device_register(struct pci_dev *dev); #ifdef CONFIG_PM diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index e73effbe402..2bf2fe510e1 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -494,6 +494,9 @@ static void pcie_port_shutdown_service(struct device *dev) {} */ int pcie_port_service_register(struct pcie_port_service_driver *new) { + if (pcie_ports_disabled) + return -ENODEV; + new->driver.name = (char *)new->name; new->driver.bus = &pcie_port_bus_type; new->driver.probe = pcie_port_probe_service; diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 3debed25e46..a04392da6ce 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -29,6 +29,18 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); +/* If this switch is set, PCIe port native services should not be enabled. */ +bool pcie_ports_disabled; + +static int __init pcie_port_setup(char *str) +{ + if (!strncmp(str, "compat", 6)) + pcie_ports_disabled = true; + + return 1; +} +__setup("pcie_ports=", pcie_port_setup); + /* global data */ static int pcie_portdrv_restore_config(struct pci_dev *dev) @@ -301,6 +313,9 @@ static int __init pcie_portdrv_init(void) { int retval; + if (pcie_ports_disabled) + return -EACCES; + dmi_check_system(pcie_portdrv_dmi_table); retval = pcie_port_bus_register(); -- cgit v1.2.3-70-g09d2 From 28eb5f274a305bf3a13b2c80c4804d4515d05c64 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 21 Aug 2010 22:02:38 +0200 Subject: PCI: PCIe: Ask BIOS for control of all native services at once After commit 852972acff8f10f3a15679be2059bb94916cba5d (ACPI: Disable ASPM if the platform won't provide _OSC control for PCIe) control of the PCIe Capability Structure is unconditionally requested by acpi_pci_root_add(), which in principle may cause problems to happen in two ways. First, the BIOS may refuse to give control of the PCIe Capability Structure if it is not asked for any of the _OSC features depending on it at the same time. Second, the BIOS may assume that control of the _OSC features depending on the PCIe Capability Structure will be requested in the future and may behave incorrectly if that doesn't happen. For this reason, control of the PCIe Capability Structure should always be requested along with control of any other _OSC features that may depend on it (ie. PCIe native PME, PCIe native hot-plug, PCIe AER). Rework the PCIe port driver so that (1) it checks which native PCIe port services can be enabled, according to the BIOS, and (2) it requests control of all these services simultaneously. In particular, this causes pcie_portdrv_probe() to fail if the BIOS refuses to grant control of the PCIe Capability Structure, which means that no native PCIe port services can be enabled for the PCIe Root Complex the given port belongs to. If that happens, ASPM is disabled to avoid problems with mishandling it by the part of the PCIe hierarchy for which control of the PCIe Capability Structure has not been received. Make it possible to override this behavior using 'pcie_ports=native' (use the PCIe native services regardless of the BIOS response to the control request), or 'pcie_ports=compat' (do not use the PCIe native services at all). Accordingly, rework the existing PCIe port service drivers so that they don't request control of the services directly. Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- Documentation/kernel-parameters.txt | 13 +++--- drivers/acpi/pci_root.c | 9 ----- drivers/pci/hotplug/acpi_pcihp.c | 4 +- drivers/pci/hotplug/pciehp.h | 12 ------ drivers/pci/hotplug/pciehp_acpi.c | 4 +- drivers/pci/hotplug/pciehp_core.c | 4 +- drivers/pci/pcie/Makefile | 1 + drivers/pci/pcie/aer/aerdrv_acpi.c | 36 ----------------- drivers/pci/pcie/aer/aerdrv_core.c | 14 +------ drivers/pci/pcie/pme/Makefile | 5 +-- drivers/pci/pcie/pme/pcie_pme.c | 64 +++--------------------------- drivers/pci/pcie/pme/pcie_pme.h | 28 ------------- drivers/pci/pcie/pme/pcie_pme_acpi.c | 56 -------------------------- drivers/pci/pcie/portdrv.h | 20 ++++++++++ drivers/pci/pcie/portdrv_acpi.c | 77 ++++++++++++++++++++++++++++++++++++ drivers/pci/pcie/portdrv_core.c | 25 ++++++++++-- drivers/pci/pcie/portdrv_pci.c | 20 +++++++++- 17 files changed, 155 insertions(+), 237 deletions(-) delete mode 100644 drivers/pci/pcie/pme/pcie_pme.h delete mode 100644 drivers/pci/pcie/pme/pcie_pme_acpi.c create mode 100644 drivers/pci/pcie/portdrv_acpi.c (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index b9008fc3a53..8f126e878db 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2043,18 +2043,17 @@ and is between 256 and 4096 characters. It is defined in the file WARNING: Forcing ASPM on may cause system lockups. pcie_ports= [PCIE] PCIe ports handling: + auto Ask the BIOS whether or not to use native PCIe services + associated with PCIe ports (PME, hot-plug, AER). Use + them only if that is allowed by the BIOS. + native Use native PCIe services associated with PCIe ports + unconditionally. compat Treat PCIe ports as PCI-to-PCI bridges, disable the PCIe ports driver. pcie_pme= [PCIE,PM] Native PCIe PME signaling options: - Format: {auto|force}[,nomsi] - auto Use native PCIe PME signaling if the BIOS allows the - kernel to control PCIe config registers of root ports. - force Use native PCIe PME signaling even if the BIOS refuses - to allow the kernel to control the relevant PCIe config - registers. nomsi Do not use MSI for native PCIe PME signaling (this makes - all PCIe root ports use INTx for everything). + all PCIe root ports use INTx for all services). pcmv= [HW,PCMCIA] BadgePAD 4 diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index c3471311252..3ba8d1f44a7 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -568,14 +567,6 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) if (flags != base_flags) acpi_pci_osc_support(root, flags); - flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL; - status = acpi_pci_osc_control_set(root->device->handle, &flags, flags); - - if (ACPI_FAILURE(status)) { - printk(KERN_INFO "Unable to assume PCIe control: Disabling ASPM\n"); - pcie_no_aspm(); - } - pci_acpi_add_bus_pm_notifier(device, root->bus); if (device->wakeup.flags.run_wake) device_set_run_wake(root->bus->bridge, true); diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 3d93d529a7b..3bc72d18b12 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -338,9 +338,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags) acpi_handle chandle, handle; struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; - flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | - OSC_SHPC_NATIVE_HP_CONTROL | - OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); + flags &= OSC_SHPC_NATIVE_HP_CONTROL; if (!flags) { err("Invalid flags %u specified!\n", flags); return -EINVAL; diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 4ed76b47b6d..653de6ff8ac 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -176,19 +176,7 @@ static inline void pciehp_firmware_init(void) { pciehp_acpi_slot_detection_init(); } - -static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev) -{ - int retval; - u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | - OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); - retval = acpi_get_hp_hw_control_from_firmware(dev, flags); - if (retval) - return retval; - return pciehp_acpi_slot_detection_check(dev); -} #else #define pciehp_firmware_init() do {} while (0) -#define pciehp_get_hp_hw_control_from_firmware(dev) 0 #endif /* CONFIG_ACPI */ #endif /* _PCIEHP_H */ diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c index 1f4000a5a10..2574700db46 100644 --- a/drivers/pci/hotplug/pciehp_acpi.c +++ b/drivers/pci/hotplug/pciehp_acpi.c @@ -85,9 +85,7 @@ static int __init dummy_probe(struct pcie_device *dev) acpi_handle handle; struct dummy_slot *slot, *tmp; struct pci_dev *pdev = dev->port; - /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */ - if (pciehp_get_hp_hw_control_from_firmware(pdev)) - return -ENODEV; + pos = pci_pcie_cap(pdev); if (!pos) return -ENODEV; diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 3588ea61b0d..aa5f3ff629f 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -59,7 +59,7 @@ module_param(pciehp_force, bool, 0644); MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); -MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing"); +MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if OSHP is missing"); #define PCIE_MODULE_NAME "pciehp" @@ -235,7 +235,7 @@ static int pciehp_probe(struct pcie_device *dev) dev_info(&dev->device, "Bypassing BIOS check for pciehp use on %s\n", pci_name(dev->port)); - else if (pciehp_get_hp_hw_control_from_firmware(dev->port)) + else if (pciehp_acpi_slot_detection_check(dev->port)) goto err_out_none; ctrl = pcie_init(dev); diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile index ea654545e7c..4d2b18704c4 100644 --- a/drivers/pci/pcie/Makefile +++ b/drivers/pci/pcie/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_PCIEASPM) += aspm.o pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o +pcieportdrv-$(CONFIG_ACPI) += portdrv_acpi.o obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 3a276a0cea9..2bb9b897221 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -19,42 +19,6 @@ #include #include "aerdrv.h" -/** - * aer_osc_setup - run ACPI _OSC method - * @pciedev: pcie_device which AER is being enabled on - * - * @return: Zero on success. Nonzero otherwise. - * - * Invoked when PCIe bus loads AER service driver. To avoid conflict with - * BIOS AER support requires BIOS to yield AER control to OS native driver. - **/ -int aer_osc_setup(struct pcie_device *pciedev) -{ - acpi_status status = AE_NOT_FOUND; - struct pci_dev *pdev = pciedev->port; - acpi_handle handle = NULL; - - if (acpi_pci_disabled) - return -1; - - handle = acpi_find_root_bridge_handle(pdev); - if (handle) { - u32 flags = OSC_PCI_EXPRESS_AER_CONTROL | - OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL; - status = acpi_pci_osc_control_set(handle, &flags, flags); - } - - if (ACPI_FAILURE(status)) { - dev_printk(KERN_DEBUG, &pciedev->device, "AER service couldn't " - "init device: %s\n", - (status == AE_SUPPORT || status == AE_NOT_FOUND) ? - "no _OSC support" : "_OSC failed"); - return -1; - } - - return 0; -} - #ifdef CONFIG_ACPI_APEI static inline int hest_match_pci(struct acpi_hest_aer_common *p, struct pci_dev *pci) diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index fc0b5a93e1d..29e268fadf1 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -772,22 +772,10 @@ void aer_isr(struct work_struct *work) */ int aer_init(struct pcie_device *dev) { - if (pcie_aer_get_firmware_first(dev->port)) { - dev_printk(KERN_DEBUG, &dev->device, - "PCIe errors handled by platform firmware.\n"); - goto out; - } - - if (aer_osc_setup(dev)) - goto out; - - return 0; -out: if (forceload) { dev_printk(KERN_DEBUG, &dev->device, "aerdrv forceload requested.\n"); pcie_aer_force_firmware_first(dev->port, 0); - return 0; } - return -ENXIO; + return 0; } diff --git a/drivers/pci/pcie/pme/Makefile b/drivers/pci/pcie/pme/Makefile index 8b923805308..3c67bf4d26c 100644 --- a/drivers/pci/pcie/pme/Makefile +++ b/drivers/pci/pcie/pme/Makefile @@ -2,7 +2,4 @@ # Makefile for PCI-Express Root Port PME signaling driver # -obj-$(CONFIG_PCIE_PME) += pmedriver.o - -pmedriver-objs := pcie_pme.o -pmedriver-$(CONFIG_ACPI) += pcie_pme_acpi.o +obj-$(CONFIG_PCIE_PME) += pcie_pme.o diff --git a/drivers/pci/pcie/pme/pcie_pme.c b/drivers/pci/pcie/pme/pcie_pme.c index bbdea18693d..9d1361e1a77 100644 --- a/drivers/pci/pcie/pme/pcie_pme.c +++ b/drivers/pci/pcie/pme/pcie_pme.c @@ -24,36 +24,11 @@ #include #include "../../pci.h" -#include "pcie_pme.h" +#include "../portdrv.h" #define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ #define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ -/* - * If set, this switch will prevent the PCIe root port PME service driver from - * being registered. Consequently, the interrupt-based PCIe PME signaling will - * not be used by any PCIe root ports in that case. - */ -static bool pcie_pme_disabled = true; - -/* - * The PCI Express Base Specification 2.0, Section 6.1.8, states the following: - * "In order to maintain compatibility with non-PCI Express-aware system - * software, system power management logic must be configured by firmware to use - * the legacy mechanism of signaling PME by default. PCI Express-aware system - * software must notify the firmware prior to enabling native, interrupt-based - * PME signaling." However, if the platform doesn't provide us with a suitable - * notification mechanism or the notification fails, it is not clear whether or - * not we are supposed to use the interrupt-based PCIe PME signaling. The - * switch below can be used to indicate the desired behaviour. When set, it - * will make the kernel use the interrupt-based PCIe PME signaling regardless of - * the platform notification status, although the kernel will attempt to notify - * the platform anyway. When unset, it will prevent the kernel from using the - * the interrupt-based PCIe PME signaling if the platform notification fails, - * which is the default. - */ -static bool pcie_pme_force_enable; - /* * If this switch is set, MSI will not be used for PCIe PME signaling. This * causes the PCIe port driver to use INTx interrupts only, but it turns out @@ -64,38 +39,13 @@ bool pcie_pme_msi_disabled; static int __init pcie_pme_setup(char *str) { - if (!strncmp(str, "auto", 4)) - pcie_pme_disabled = false; - else if (!strncmp(str, "force", 5)) - pcie_pme_force_enable = true; - - str = strchr(str, ','); - if (str) { - str++; - str += strspn(str, " \t"); - if (*str && !strcmp(str, "nomsi")) - pcie_pme_msi_disabled = true; - } + if (!strncmp(str, "nomsi", 5)) + pcie_pme_msi_disabled = true; return 1; } __setup("pcie_pme=", pcie_pme_setup); -/** - * pcie_pme_platform_setup - Ensure that the kernel controls the PCIe PME. - * @srv: PCIe PME root port service to use for carrying out the check. - * - * Notify the platform that the native PCIe PME is going to be used and return - * 'true' if the control of the PCIe PME registers has been acquired from the - * platform. - */ -static bool pcie_pme_platform_setup(struct pcie_device *srv) -{ - if (!pcie_pme_platform_notify(srv)) - return true; - return pcie_pme_force_enable; -} - struct pcie_pme_service_data { spinlock_t lock; struct pcie_device *srv; @@ -108,7 +58,7 @@ struct pcie_pme_service_data { * @dev: PCIe root port or event collector. * @enable: Enable or disable the interrupt. */ -static void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable) +void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable) { int rtctl_pos; u16 rtctl; @@ -417,9 +367,6 @@ static int pcie_pme_probe(struct pcie_device *srv) struct pcie_pme_service_data *data; int ret; - if (!pcie_pme_platform_setup(srv)) - return -EACCES; - data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -509,8 +456,7 @@ static struct pcie_port_service_driver pcie_pme_driver = { */ static int __init pcie_pme_service_init(void) { - return pcie_pme_disabled ? - -ENODEV : pcie_port_service_register(&pcie_pme_driver); + return pcie_port_service_register(&pcie_pme_driver); } module_init(pcie_pme_service_init); diff --git a/drivers/pci/pcie/pme/pcie_pme.h b/drivers/pci/pcie/pme/pcie_pme.h deleted file mode 100644 index b30d2b7c977..00000000000 --- a/drivers/pci/pcie/pme/pcie_pme.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * drivers/pci/pcie/pme/pcie_pme.h - * - * PCI Express Root Port PME signaling support - * - * Copyright (C) 2009 Rafael J. Wysocki , Novell Inc. - */ - -#ifndef _PCIE_PME_H_ -#define _PCIE_PME_H_ - -struct pcie_device; - -#ifdef CONFIG_ACPI -extern int pcie_pme_acpi_setup(struct pcie_device *srv); - -static inline int pcie_pme_platform_notify(struct pcie_device *srv) -{ - return pcie_pme_acpi_setup(srv); -} -#else /* !CONFIG_ACPI */ -static inline int pcie_pme_platform_notify(struct pcie_device *srv) -{ - return 0; -} -#endif /* !CONFIG_ACPI */ - -#endif diff --git a/drivers/pci/pcie/pme/pcie_pme_acpi.c b/drivers/pci/pcie/pme/pcie_pme_acpi.c deleted file mode 100644 index be20222b12d..00000000000 --- a/drivers/pci/pcie/pme/pcie_pme_acpi.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * PCIe Native PME support, ACPI-related part - * - * Copyright (C) 2009 Rafael J. Wysocki , Novell Inc. - * - * This file is subject to the terms and conditions of the GNU General Public - * License V2. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include -#include -#include -#include -#include -#include - -/** - * pcie_pme_acpi_setup - Request the ACPI BIOS to release control over PCIe PME. - * @srv - PCIe PME service for a root port or event collector. - * - * Invoked when the PCIe bus type loads PCIe PME service driver. To avoid - * conflict with the BIOS PCIe support requires the BIOS to yield PCIe PME - * control to the kernel. - */ -int pcie_pme_acpi_setup(struct pcie_device *srv) -{ - acpi_status status = AE_NOT_FOUND; - struct pci_dev *port = srv->port; - acpi_handle handle; - u32 flags; - int error = 0; - - if (acpi_pci_disabled) - return -ENOSYS; - - dev_info(&port->dev, "Requesting control of PCIe PME from ACPI BIOS\n"); - - handle = acpi_find_root_bridge_handle(port); - if (!handle) - return -EINVAL; - - flags = OSC_PCI_EXPRESS_PME_CONTROL | - OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL; - - status = acpi_pci_osc_control_set(handle, &flags, flags); - if (ACPI_FAILURE(status)) { - dev_info(&port->dev, - "Failed to receive control of PCIe PME service: %s\n", - (status == AE_SUPPORT || status == AE_NOT_FOUND) ? - "no _OSC support" : "ACPI _OSC failed"); - error = -ENODEV; - } - - return error; -} diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 966f6e9761c..7b5aba0a329 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -21,6 +21,7 @@ #define get_descriptor_id(type, service) (((type - 4) << 4) | service) extern bool pcie_ports_disabled; +extern bool pcie_ports_auto; extern struct bus_type pcie_port_bus_type; extern int pcie_port_device_register(struct pci_dev *dev); @@ -32,6 +33,8 @@ extern void pcie_port_device_remove(struct pci_dev *dev); extern int __must_check pcie_port_bus_register(void); extern void pcie_port_bus_unregister(void); +struct pci_dev; + #ifdef CONFIG_PCIE_PME extern bool pcie_pme_msi_disabled; @@ -44,9 +47,26 @@ static inline bool pcie_pme_no_msi(void) { return pcie_pme_msi_disabled; } + +extern void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable); #else /* !CONFIG_PCIE_PME */ static inline void pcie_pme_disable_msi(void) {} static inline bool pcie_pme_no_msi(void) { return false; } +static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {} #endif /* !CONFIG_PCIE_PME */ +#ifdef CONFIG_ACPI +extern int pcie_port_acpi_setup(struct pci_dev *port, int *mask); + +static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask) +{ + return pcie_port_acpi_setup(port, mask); +} +#else /* !CONFIG_ACPI */ +static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask) +{ + return 0; +} +#endif /* !CONFIG_ACPI */ + #endif /* _PORTDRV_H_ */ diff --git a/drivers/pci/pcie/portdrv_acpi.c b/drivers/pci/pcie/portdrv_acpi.c new file mode 100644 index 00000000000..b7c4cb1ccb2 --- /dev/null +++ b/drivers/pci/pcie/portdrv_acpi.c @@ -0,0 +1,77 @@ +/* + * PCIe Port Native Services Support, ACPI-Related Part + * + * Copyright (C) 2010 Rafael J. Wysocki , Novell Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License V2. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include "aer/aerdrv.h" +#include "../pci.h" + +/** + * pcie_port_acpi_setup - Request the BIOS to release control of PCIe services. + * @port: PCIe Port service for a root port or event collector. + * @srv_mask: Bit mask of services that can be enabled for @port. + * + * Invoked when @port is identified as a PCIe port device. To avoid conflicts + * with the BIOS PCIe port native services support requires the BIOS to yield + * control of these services to the kernel. The mask of services that the BIOS + * allows to be enabled for @port is written to @srv_mask. + * + * NOTE: It turns out that we cannot do that for individual port services + * separately, because that would make some systems work incorrectly. + */ +int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask) +{ + acpi_status status; + acpi_handle handle; + u32 flags; + + if (acpi_pci_disabled) + return 0; + + handle = acpi_find_root_bridge_handle(port); + if (!handle) + return -EINVAL; + + flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL + | OSC_PCI_EXPRESS_NATIVE_HP_CONTROL + | OSC_PCI_EXPRESS_PME_CONTROL; + + if (pci_aer_available()) { + if (pcie_aer_get_firmware_first(port)) + dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n"); + else + flags |= OSC_PCI_EXPRESS_AER_CONTROL; + } + + status = acpi_pci_osc_control_set(handle, &flags, + OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); + if (ACPI_FAILURE(status)) { + dev_dbg(&port->dev, "ACPI _OSC request failed (code %d)\n", + status); + return -ENODEV; + } + + dev_info(&port->dev, "ACPI _OSC control granted for 0x%02x\n", flags); + + *srv_mask = PCIE_PORT_SERVICE_VC; + if (flags & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL) + *srv_mask |= PCIE_PORT_SERVICE_HP; + if (flags & OSC_PCI_EXPRESS_PME_CONTROL) + *srv_mask |= PCIE_PORT_SERVICE_PME; + if (flags & OSC_PCI_EXPRESS_AER_CONTROL) + *srv_mask |= PCIE_PORT_SERVICE_AER; + + return 0; +} diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 2bf2fe510e1..d0245c83b62 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include "../pci.h" #include "portdrv.h" @@ -236,23 +238,40 @@ static int get_port_device_capability(struct pci_dev *dev) int services = 0, pos; u16 reg16; u32 reg32; + int cap_mask; + int err; + + err = pcie_port_platform_notify(dev, &cap_mask); + if (pcie_ports_auto) { + if (err) { + pcie_no_aspm(); + return 0; + } + } else { + cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP + | PCIE_PORT_SERVICE_VC; + if (pci_aer_available()) + cap_mask |= PCIE_PORT_SERVICE_AER; + } pos = pci_pcie_cap(dev); pci_read_config_word(dev, pos + PCI_EXP_FLAGS, ®16); /* Hot-Plug Capable */ - if (reg16 & PCI_EXP_FLAGS_SLOT) { + if ((cap_mask & PCIE_PORT_SERVICE_HP) && (reg16 & PCI_EXP_FLAGS_SLOT)) { pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, ®32); if (reg32 & PCI_EXP_SLTCAP_HPC) services |= PCIE_PORT_SERVICE_HP; } /* AER capable */ - if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR)) + if ((cap_mask & PCIE_PORT_SERVICE_AER) + && pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR)) services |= PCIE_PORT_SERVICE_AER; /* VC support */ if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC)) services |= PCIE_PORT_SERVICE_VC; /* Root ports are capable of generating PME too */ - if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) + if ((cap_mask & PCIE_PORT_SERVICE_PME) + && dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) services |= PCIE_PORT_SERVICE_PME; return services; diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index a04392da6ce..8f1338d1c53 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "portdrv.h" #include "aer/aerdrv.h" @@ -32,10 +33,23 @@ MODULE_LICENSE("GPL"); /* If this switch is set, PCIe port native services should not be enabled. */ bool pcie_ports_disabled; +/* + * If this switch is set, ACPI _OSC will be used to determine whether or not to + * enable PCIe port native services. + */ +bool pcie_ports_auto = true; + static int __init pcie_port_setup(char *str) { - if (!strncmp(str, "compat", 6)) + if (!strncmp(str, "compat", 6)) { pcie_ports_disabled = true; + } else if (!strncmp(str, "native", 6)) { + pcie_ports_disabled = false; + pcie_ports_auto = false; + } else if (!strncmp(str, "auto", 4)) { + pcie_ports_disabled = false; + pcie_ports_auto = true; + } return 1; } @@ -313,8 +327,10 @@ static int __init pcie_portdrv_init(void) { int retval; - if (pcie_ports_disabled) + if (pcie_ports_disabled) { + pcie_no_aspm(); return -EACCES; + } dmi_check_system(pcie_portdrv_dmi_table); -- cgit v1.2.3-70-g09d2 From 7c38875a0d0a9b90eee66be79e36995c86acc70c Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Thu, 26 Aug 2010 10:35:43 -0400 Subject: workqueue: Add a workqueue chapter to the tracepoint docbook Add a workqueue chapter to the traceopint docbook. Current book is at: http://www.kernel.org/doc/htmldocs/tracepoint/ Signed-off-by: Jason Baron Signed-off-by: Tejun Heo --- Documentation/DocBook/tracepoint.tmpl | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/tracepoint.tmpl b/Documentation/DocBook/tracepoint.tmpl index e8473eae2a2..b57a9ede322 100644 --- a/Documentation/DocBook/tracepoint.tmpl +++ b/Documentation/DocBook/tracepoint.tmpl @@ -104,4 +104,9 @@ Block IO !Iinclude/trace/events/block.h + + + Workqueue +!Iinclude/trace/events/workqueue.h + -- cgit v1.2.3-70-g09d2 From 048e78a5bc22c27410cb5ca9680c3c7ac400607f Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Thu, 2 Sep 2010 08:35:47 +0200 Subject: ALSA: hda - Add a new hp-laptop model for Conexant 5066, tested on HP G60 This new model adds the following functionality to HP G60: - Automute of internal speakers - Autoswitch of internal/external mics - Remove SPDIF not physically present BugLink: http://launchpad.net/bugs/587388 Cc: stable@kernel.org Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 1 + sound/pci/hda/patch_conexant.c | 57 ++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index ce46fa1e643..37c6aad5e59 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -296,6 +296,7 @@ Conexant 5051 Conexant 5066 ============= laptop Basic Laptop config (default) + hp-laptop HP laptops, e g G60 dell-laptop Dell laptops dell-vostro Dell Vostro olpc-xo-1_5 OLPC XO 1.5 diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 5cdb80edbd7..4f0619908a3 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -116,6 +116,7 @@ struct conexant_spec { unsigned int dell_vostro:1; unsigned int ideapad:1; unsigned int thinkpad:1; + unsigned int hp_laptop:1; unsigned int ext_mic_present; unsigned int recording; @@ -2299,6 +2300,18 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec) } } +/* toggle input of built-in digital mic and mic jack appropriately */ +static void cxt5066_hp_laptop_automic(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_jack_detect(codec, 0x1b); + snd_printdd("CXT5066: external microphone present=%d\n", present); + snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, + present ? 1 : 3); +} + + /* toggle input of built-in digital mic and mic jack appropriately order is: external mic -> dock mic -> interal mic */ static void cxt5066_thinkpad_automic(struct hda_codec *codec) @@ -2407,6 +2420,20 @@ static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res) } } +/* unsolicited event for jack sensing */ +static void cxt5066_hp_laptop_event(struct hda_codec *codec, unsigned int res) +{ + snd_printdd("CXT5066_hp_laptop: unsol event %x (%x)\n", res, res >> 26); + switch (res >> 26) { + case CONEXANT_HP_EVENT: + cxt5066_hp_automute(codec); + break; + case CONEXANT_MIC_EVENT: + cxt5066_hp_laptop_automic(codec); + break; + } +} + /* unsolicited event for jack sensing */ static void cxt5066_thinkpad_event(struct hda_codec *codec, unsigned int res) { @@ -2989,6 +3016,14 @@ static struct hda_verb cxt5066_init_verbs_portd_lo[] = { { } /* end */ }; + +static struct hda_verb cxt5066_init_verbs_hp_laptop[] = { + {0x14, AC_VERB_SET_CONNECT_SEL, 0x0}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, + { } /* end */ +}; + /* initialize jack-sensing, too */ static int cxt5066_init(struct hda_codec *codec) { @@ -3004,6 +3039,8 @@ static int cxt5066_init(struct hda_codec *codec) cxt5066_ideapad_automic(codec); else if (spec->thinkpad) cxt5066_thinkpad_automic(codec); + else if (spec->hp_laptop) + cxt5066_hp_laptop_automic(codec); } cxt5066_set_mic_boost(codec); return 0; @@ -3031,6 +3068,7 @@ enum { CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ + CXT5066_HP_LAPTOP, /* HP Laptop */ CXT5066_MODELS }; @@ -3041,6 +3079,7 @@ static const char *cxt5066_models[CXT5066_MODELS] = { [CXT5066_DELL_VOSTO] = "dell-vostro", [CXT5066_IDEAPAD] = "ideapad", [CXT5066_THINKPAD] = "thinkpad", + [CXT5066_HP_LAPTOP] = "hp-laptop", }; static struct snd_pci_quirk cxt5066_cfg_tbl[] = { @@ -3052,6 +3091,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTO), SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), + SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), @@ -3116,6 +3156,23 @@ static int patch_cxt5066(struct hda_codec *codec) spec->num_init_verbs++; spec->dell_automute = 1; break; + case CXT5066_HP_LAPTOP: + codec->patch_ops.init = cxt5066_init; + codec->patch_ops.unsol_event = cxt5066_hp_laptop_event; + spec->init_verbs[spec->num_init_verbs] = + cxt5066_init_verbs_hp_laptop; + spec->num_init_verbs++; + spec->hp_laptop = 1; + spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; + spec->mixers[spec->num_mixers++] = cxt5066_mixers; + /* no S/PDIF out */ + spec->multiout.dig_out_nid = 0; + /* input source automatically selected */ + spec->input_mux = NULL; + spec->port_d_mode = 0; + spec->mic_boost = 3; /* default 30dB gain */ + break; + case CXT5066_OLPC_XO_1_5: codec->patch_ops.init = cxt5066_olpc_init; codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event; -- cgit v1.2.3-70-g09d2 From ef5dc121d5a0bb1fa477c5395277259f07d318a3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 2 Sep 2010 15:48:16 -0700 Subject: mutex: Fix annotations to include it in kernel-locking docbook Fix kernel-doc notation in linux/mutex.h and kernel/mutex.c, then add these 2 files to the kernel-locking docbook as the Mutex API reference chapter. Add one API function to mutex-design.txt and correct a typo in that file. Signed-off-by: Randy Dunlap Cc: Rusty Russell LKML-Reference: <20100902154816.6cc2f9ad.randy.dunlap@oracle.com> Signed-off-by: Ingo Molnar --- Documentation/DocBook/kernel-locking.tmpl | 6 ++++++ Documentation/mutex-design.txt | 3 ++- include/linux/mutex.h | 8 ++++++++ kernel/mutex.c | 23 +++++++---------------- 4 files changed, 23 insertions(+), 17 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/kernel-locking.tmpl b/Documentation/DocBook/kernel-locking.tmpl index 0b1a3f97f28..a0d479d1e1d 100644 --- a/Documentation/DocBook/kernel-locking.tmpl +++ b/Documentation/DocBook/kernel-locking.tmpl @@ -1961,6 +1961,12 @@ machines due to caching. + + Mutex API reference +!Iinclude/linux/mutex.h +!Ekernel/mutex.c + + Further reading diff --git a/Documentation/mutex-design.txt b/Documentation/mutex-design.txt index c91ccc0720f..38c10fd7f41 100644 --- a/Documentation/mutex-design.txt +++ b/Documentation/mutex-design.txt @@ -9,7 +9,7 @@ firstly, there's nothing wrong with semaphores. But if the simpler mutex semantics are sufficient for your code, then there are a couple of advantages of mutexes: - - 'struct mutex' is smaller on most architectures: .e.g on x86, + - 'struct mutex' is smaller on most architectures: E.g. on x86, 'struct semaphore' is 20 bytes, 'struct mutex' is 16 bytes. A smaller structure size means less RAM footprint, and better CPU-cache utilization. @@ -136,3 +136,4 @@ the APIs of 'struct mutex' have been streamlined: void mutex_lock_nested(struct mutex *lock, unsigned int subclass); int mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass); + int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock); diff --git a/include/linux/mutex.h b/include/linux/mutex.h index 878cab4f5fc..f363bc8fdc7 100644 --- a/include/linux/mutex.h +++ b/include/linux/mutex.h @@ -78,6 +78,14 @@ struct mutex_waiter { # include #else # define __DEBUG_MUTEX_INITIALIZER(lockname) +/** + * mutex_init - initialize the mutex + * @mutex: the mutex to be initialized + * + * Initialize the mutex to unlocked state. + * + * It is not allowed to initialize an already locked mutex. + */ # define mutex_init(mutex) \ do { \ static struct lock_class_key __key; \ diff --git a/kernel/mutex.c b/kernel/mutex.c index 4c0b7b3e6d2..200407c1502 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c @@ -36,15 +36,6 @@ # include #endif -/*** - * mutex_init - initialize the mutex - * @lock: the mutex to be initialized - * @key: the lock_class_key for the class; used by mutex lock debugging - * - * Initialize the mutex to unlocked state. - * - * It is not allowed to initialize an already locked mutex. - */ void __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key) { @@ -68,7 +59,7 @@ EXPORT_SYMBOL(__mutex_init); static __used noinline void __sched __mutex_lock_slowpath(atomic_t *lock_count); -/*** +/** * mutex_lock - acquire the mutex * @lock: the mutex to be acquired * @@ -105,7 +96,7 @@ EXPORT_SYMBOL(mutex_lock); static __used noinline void __sched __mutex_unlock_slowpath(atomic_t *lock_count); -/*** +/** * mutex_unlock - release the mutex * @lock: the mutex to be released * @@ -364,8 +355,8 @@ __mutex_lock_killable_slowpath(atomic_t *lock_count); static noinline int __sched __mutex_lock_interruptible_slowpath(atomic_t *lock_count); -/*** - * mutex_lock_interruptible - acquire the mutex, interruptable +/** + * mutex_lock_interruptible - acquire the mutex, interruptible * @lock: the mutex to be acquired * * Lock the mutex like mutex_lock(), and return 0 if the mutex has @@ -456,15 +447,15 @@ static inline int __mutex_trylock_slowpath(atomic_t *lock_count) return prev == 1; } -/*** - * mutex_trylock - try acquire the mutex, without waiting +/** + * mutex_trylock - try to acquire the mutex, without waiting * @lock: the mutex to be acquired * * Try to acquire the mutex atomically. Returns 1 if the mutex * has been acquired successfully, and 0 on contention. * * NOTE: this function follows the spin_trylock() convention, so - * it is negated to the down_trylock() return values! Be careful + * it is negated from the down_trylock() return values! Be careful * about this when converting semaphore users to mutexes. * * This function must not be used in interrupt context. The -- cgit v1.2.3-70-g09d2 From c956126c137d97acb6f4d56fa9572d0bcc84e4ed Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 9 Sep 2010 16:38:03 -0700 Subject: gpio: doc updates There's been some recent confusion about error checking GPIO numbers. briefly, it should be handled mostly during setup, when gpio_request() is called, and NEVER by expectig gpio_is_valid to report more than never-usable GPIO numbers. [akpm@linux-foundation.org: terminate unterminated comment] Signed-off-by: David Brownell Cc: Eric Miao" Cc: "Ryan Mallon" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/gpio.txt | 22 ++++++++++++++-------- include/asm-generic/gpio.h | 14 +++++++++++++- 2 files changed, 27 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt index d96a6dba574..9633da01ff4 100644 --- a/Documentation/gpio.txt +++ b/Documentation/gpio.txt @@ -109,17 +109,19 @@ use numbers 2000-2063 to identify GPIOs in a bank of I2C GPIO expanders. If you want to initialize a structure with an invalid GPIO number, use some negative number (perhaps "-EINVAL"); that will never be valid. To -test if a number could reference a GPIO, you may use this predicate: +test if such number from such a structure could reference a GPIO, you +may use this predicate: int gpio_is_valid(int number); A number that's not valid will be rejected by calls which may request or free GPIOs (see below). Other numbers may also be rejected; for -example, a number might be valid but unused on a given board. - -Whether a platform supports multiple GPIO controllers is currently a -platform-specific implementation issue. +example, a number might be valid but temporarily unused on a given board. +Whether a platform supports multiple GPIO controllers is a platform-specific +implementation issue, as are whether that support can leave "holes" in the space +of GPIO numbers, and whether new controllers can be added at runtime. Such issues +can affect things including whether adjacent GPIO numbers are both valid. Using GPIOs ----------- @@ -480,12 +482,16 @@ To support this framework, a platform's Kconfig will "select" either ARCH_REQUIRE_GPIOLIB or ARCH_WANT_OPTIONAL_GPIOLIB and arrange that its includes and defines three functions: gpio_get_value(), gpio_set_value(), and gpio_cansleep(). -They may also want to provide a custom value for ARCH_NR_GPIOS. -ARCH_REQUIRE_GPIOLIB means that the gpio-lib code will always get compiled +It may also provide a custom value for ARCH_NR_GPIOS, so that it better +reflects the number of GPIOs in actual use on that platform, without +wasting static table space. (It should count both built-in/SoC GPIOs and +also ones on GPIO expanders. + +ARCH_REQUIRE_GPIOLIB means that the gpiolib code will always get compiled into the kernel on that architecture. -ARCH_WANT_OPTIONAL_GPIOLIB means the gpio-lib code defaults to off and the user +ARCH_WANT_OPTIONAL_GPIOLIB means the gpiolib code defaults to off and the user can enable it and build it into the kernel optionally. If neither of these options are selected, the platform does not support diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index c7376bf80b0..8ca18e26d7e 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -16,15 +16,27 @@ * While the GPIO programming interface defines valid GPIO numbers * to be in the range 0..MAX_INT, this library restricts them to the * smaller range 0..ARCH_NR_GPIOS-1. + * + * ARCH_NR_GPIOS is somewhat arbitrary; it usually reflects the sum of + * builtin/SoC GPIOs plus a number of GPIOs on expanders; the latter is + * actually an estimate of a board-specific value. */ #ifndef ARCH_NR_GPIOS #define ARCH_NR_GPIOS 256 #endif +/* + * "valid" GPIO numbers are nonnegative and may be passed to + * setup routines like gpio_request(). only some valid numbers + * can successfully be requested and used. + * + * Invalid GPIO numbers are useful for indicating no-such-GPIO in + * platform data and other tables. + */ + static inline int gpio_is_valid(int number) { - /* only some non-negative numbers are valid */ return ((unsigned)number) < ARCH_NR_GPIOS; } -- cgit v1.2.3-70-g09d2 From eda603f6cdba4b14dbf80531fab2fe545232e7a0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 11 Sep 2010 15:55:22 -0700 Subject: docbook: warn on unused doc entries When you don't use !E or !I but only !F, then it's very easy to miss including some functions, structs etc. in documentation. To help finding which ones were missed, allow printing out the unused ones as warnings. For example, using this on mac80211 yields a lot of warnings like this: Warning: didn't use docs for DOC: mac80211 workqueue Warning: didn't use docs for ieee80211_max_queues Warning: didn't use docs for ieee80211_bss_change Warning: didn't use docs for ieee80211_bss_conf when generating the documentation for it. Signed-off-by: Johannes Berg Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/kernel-doc-nano-HOWTO.txt | 5 ++ scripts/basic/docproc.c | 129 +++++++++++++++++++++++++++++++- scripts/kernel-doc | 52 ++++++++++++- 3 files changed, 183 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-doc-nano-HOWTO.txt b/Documentation/kernel-doc-nano-HOWTO.txt index 27a52b35d55..3d8a97747f7 100644 --- a/Documentation/kernel-doc-nano-HOWTO.txt +++ b/Documentation/kernel-doc-nano-HOWTO.txt @@ -345,5 +345,10 @@ documentation, in , for the functions listed. section titled
from . Spaces are allowed in
; do not quote the
. +!C is replaced by nothing, but makes the tools check that +all DOC: sections and documented functions, symbols, etc. are used. +This makes sense to use when you use !F/!P only and want to verify +that all documentation is included. + Tim. */ diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c index 79ab973fb43..fc3b18d844a 100644 --- a/scripts/basic/docproc.c +++ b/scripts/basic/docproc.c @@ -34,12 +34,14 @@ * */ +#define _GNU_SOURCE #include #include #include #include #include #include +#include #include #include @@ -54,6 +56,7 @@ typedef void FILEONLY(char * file); FILEONLY *internalfunctions; FILEONLY *externalfunctions; FILEONLY *symbolsonly; +FILEONLY *findall; typedef void FILELINE(char * file, char * line); FILELINE * singlefunctions; @@ -65,12 +68,30 @@ FILELINE * docsection; #define KERNELDOCPATH "scripts/" #define KERNELDOC "kernel-doc" #define DOCBOOK "-docbook" +#define LIST "-list" #define FUNCTION "-function" #define NOFUNCTION "-nofunction" #define NODOCSECTIONS "-no-doc-sections" static char *srctree, *kernsrctree; +static char **all_list = NULL; +static int all_list_len = 0; + +static void consume_symbol(const char *sym) +{ + int i; + + for (i = 0; i < all_list_len; i++) { + if (!all_list[i]) + continue; + if (strcmp(sym, all_list[i])) + continue; + all_list[i] = NULL; + break; + } +} + static void usage (void) { fprintf(stderr, "Usage: docproc {doc|depend} file\n"); @@ -248,6 +269,7 @@ static void docfunctions(char * filename, char * type) struct symfile * sym = &symfilelist[i]; for (j=0; j < sym->symbolcnt; j++) { vec[idx++] = type; + consume_symbol(sym->symbollist[j].name); vec[idx++] = sym->symbollist[j].name; } } @@ -287,6 +309,11 @@ static void singfunc(char * filename, char * line) vec[idx++] = &line[i]; } } + for (i = 0; i < idx; i++) { + if (strcmp(vec[i], FUNCTION)) + continue; + consume_symbol(vec[i + 1]); + } vec[idx++] = filename; vec[idx] = NULL; exec_kernel_doc(vec); @@ -306,6 +333,10 @@ static void docsect(char *filename, char *line) if (*s == '\n') *s = '\0'; + asprintf(&s, "DOC: %s", line); + consume_symbol(s); + free(s); + vec[0] = KERNELDOC; vec[1] = DOCBOOK; vec[2] = FUNCTION; @@ -315,6 +346,84 @@ static void docsect(char *filename, char *line) exec_kernel_doc(vec); } +static void find_all_symbols(char *filename) +{ + char *vec[4]; /* kerneldoc -list file NULL */ + pid_t pid; + int ret, i, count, start; + char real_filename[PATH_MAX + 1]; + int pipefd[2]; + char *data, *str; + size_t data_len = 0; + + vec[0] = KERNELDOC; + vec[1] = LIST; + vec[2] = filename; + vec[3] = NULL; + + if (pipe(pipefd)) { + perror("pipe"); + exit(1); + } + + switch (pid=fork()) { + case -1: + perror("fork"); + exit(1); + case 0: + close(pipefd[0]); + dup2(pipefd[1], 1); + memset(real_filename, 0, sizeof(real_filename)); + strncat(real_filename, kernsrctree, PATH_MAX); + strncat(real_filename, "/" KERNELDOCPATH KERNELDOC, + PATH_MAX - strlen(real_filename)); + execvp(real_filename, vec); + fprintf(stderr, "exec "); + perror(real_filename); + exit(1); + default: + close(pipefd[1]); + data = malloc(4096); + do { + while ((ret = read(pipefd[0], + data + data_len, + 4096)) > 0) { + data_len += ret; + data = realloc(data, data_len + 4096); + } + } while (ret == -EAGAIN); + if (ret != 0) { + perror("read"); + exit(1); + } + waitpid(pid, &ret ,0); + } + if (WIFEXITED(ret)) + exitstatus |= WEXITSTATUS(ret); + else + exitstatus = 0xff; + + count = 0; + /* poor man's strtok, but with counting */ + for (i = 0; i < data_len; i++) { + if (data[i] == '\n') { + count++; + data[i] = '\0'; + } + } + start = all_list_len; + all_list_len += count; + all_list = realloc(all_list, sizeof(char *) * all_list_len); + str = data; + for (i = 0; i < data_len && start != all_list_len; i++) { + if (data[i] == '\0') { + all_list[start] = str; + str = data + i + 1; + start++; + } + } +} + /* * Parse file, calling action specific functions for: * 1) Lines containing !E @@ -322,7 +431,8 @@ static void docsect(char *filename, char *line) * 3) Lines containing !D * 4) Lines containing !F * 5) Lines containing !P - * 6) Default lines - lines not matching the above + * 6) Lines containing !C + * 7) Default lines - lines not matching the above */ static void parse_file(FILE *infile) { @@ -365,6 +475,12 @@ static void parse_file(FILE *infile) s++; docsection(line + 2, s); break; + case 'C': + while (*s && !isspace(*s)) s++; + *s = '\0'; + if (findall) + findall(line+2); + break; default: defaultline(line); } @@ -380,6 +496,7 @@ static void parse_file(FILE *infile) int main(int argc, char *argv[]) { FILE * infile; + int i; srctree = getenv("SRCTREE"); if (!srctree) @@ -415,6 +532,7 @@ int main(int argc, char *argv[]) symbolsonly = find_export_symbols; singlefunctions = noaction2; docsection = noaction2; + findall = find_all_symbols; parse_file(infile); /* Rewind to start from beginning of file again */ @@ -425,8 +543,16 @@ int main(int argc, char *argv[]) symbolsonly = printline; singlefunctions = singfunc; docsection = docsect; + findall = NULL; parse_file(infile); + + for (i = 0; i < all_list_len; i++) { + if (!all_list[i]) + continue; + fprintf(stderr, "Warning: didn't use docs for %s\n", + all_list[i]); + } } else if (strcmp("depend", argv[1]) == 0) { @@ -439,6 +565,7 @@ int main(int argc, char *argv[]) symbolsonly = adddep; singlefunctions = adddep2; docsection = adddep2; + findall = adddep; parse_file(infile); printf("\n"); } diff --git a/scripts/kernel-doc b/scripts/kernel-doc index a68240c188f..cdb6dc1f645 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -44,12 +44,13 @@ use strict; # Note: This only supports 'c'. # usage: -# kernel-doc [ -docbook | -html | -text | -man ] [ -no-doc-sections ] +# kernel-doc [ -docbook | -html | -text | -man | -list ] [ -no-doc-sections ] # [ -function funcname [ -function funcname ...] ] c file(s)s > outputfile # or # [ -nofunction funcname [ -function funcname ...] ] c file(s)s > outputfile # # Set output format using one of -docbook -html -text or -man. Default is man. +# The -list format is for internal use by docproc. # # -no-doc-sections # Do not output DOC: sections @@ -210,9 +211,16 @@ my %highlights_text = ( $type_constant, "\$1", $type_param, "\$1" ); my $blankline_text = ""; +# list mode +my %highlights_list = ( $type_constant, "\$1", + $type_func, "\$1", + $type_struct, "\$1", + $type_param, "\$1" ); +my $blankline_list = ""; sub usage { - print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man ] [ -no-doc-sections ]\n"; + print "Usage: $0 [ -v ] [ -docbook | -html | -text | -man | -list ]\n"; + print " [ -no-doc-sections ]\n"; print " [ -function funcname [ -function funcname ...] ]\n"; print " [ -nofunction funcname [ -nofunction funcname ...] ]\n"; print " c source file(s) > outputfile\n"; @@ -318,6 +326,10 @@ while ($ARGV[0] =~ m/^-(.*)/) { $output_mode = "xml"; %highlights = %highlights_xml; $blankline = $blankline_xml; + } elsif ($cmd eq "-list") { + $output_mode = "list"; + %highlights = %highlights_list; + $blankline = $blankline_list; } elsif ($cmd eq "-gnome") { $output_mode = "gnome"; %highlights = %highlights_gnome; @@ -1361,6 +1373,42 @@ sub output_blockhead_text(%) { } } +## list mode output functions + +sub output_function_list(%) { + my %args = %{$_[0]}; + + print $args{'function'} . "\n"; +} + +# output enum in list +sub output_enum_list(%) { + my %args = %{$_[0]}; + print $args{'enum'} . "\n"; +} + +# output typedef in list +sub output_typedef_list(%) { + my %args = %{$_[0]}; + print $args{'typedef'} . "\n"; +} + +# output struct as list +sub output_struct_list(%) { + my %args = %{$_[0]}; + + print $args{'struct'} . "\n"; +} + +sub output_blockhead_list(%) { + my %args = %{$_[0]}; + my ($parameter, $section); + + foreach $section (@{$args{'sectionlist'}}) { + print "DOC: $section\n"; + } +} + ## # generic output function for all types (function, struct/union, typedef, enum); # calls the generated, variable output_ function name based on -- cgit v1.2.3-70-g09d2 From 39d709392ffc1d05f825191b07b7d865d434f282 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 11 Sep 2010 15:55:26 -0700 Subject: docbook: skip files with no docs since they generate scary warnings Fix docbook templates that reference files that do not contain the expected kernel-doc notation. Fixes these warnings: Warning(arch/x86/include/asm/unaligned.h): no structured comments found Warning(lib/vsprintf.c): no structured comments found These cause errors in the generated html output, like below, so drop these lines. Name arch/x86/include/asm/unaligned.h - Document generation inconsistency Oops Warning The template for this document tried to insert the structured comment from the file arch/x86/include/asm/unaligned.h at this point, but none was found. This dummy section is inserted to allow generation to continue. Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- Documentation/DocBook/device-drivers.tmpl | 1 - Documentation/DocBook/kernel-api.tmpl | 1 - 2 files changed, 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index ecd35e9d441..feca0758391 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl @@ -46,7 +46,6 @@ Atomic and pointer manipulation !Iarch/x86/include/asm/atomic.h -!Iarch/x86/include/asm/unaligned.h Delaying, scheduling, and timer routines diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index a20c6f6fffc..6899f471fb1 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -57,7 +57,6 @@ String Conversions -!Ilib/vsprintf.c !Elib/vsprintf.c String Manipulation -- cgit v1.2.3-70-g09d2