From fd468c74bd4d6949736810a80d6ca05eb20fba84 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 14 Nov 2013 01:19:29 +0000 Subject: net_tstamp: Add SIOCGHWTSTAMP ioctl to match SIOCSHWTSTAMP SIOCSHWTSTAMP returns the real configuration to the application using it, but there is currently no way for any other application to find out the configuration non-destructively. Add a new ioctl for this, making it unprivileged. Signed-off-by: Ben Hutchings --- Documentation/networking/timestamping.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt index 98097d8cb910..661d3c316a17 100644 --- a/Documentation/networking/timestamping.txt +++ b/Documentation/networking/timestamping.txt @@ -85,7 +85,7 @@ Filled in if SOF_TIMESTAMPING_SYS_HARDWARE is set. Requires support by the network device and will be empty without that support. -SIOCSHWTSTAMP: +SIOCSHWTSTAMP, SIOCGHWTSTAMP: Hardware time stamping must also be initialized for each device driver that is expected to do hardware time stamping. The parameter is defined in @@ -115,6 +115,10 @@ Only a processes with admin rights may change the configuration. User space is responsible to ensure that multiple processes don't interfere with each other and that the settings are reset. +Any process can read the actual configuration by passing this +structure to ioctl(SIOCGHWTSTAMP) in the same way. However, this has +not been implemented in all drivers. + /* possible values for hwtstamp_config->tx_type */ enum { /* @@ -157,7 +161,8 @@ DEVICE IMPLEMENTATION A driver which supports hardware time stamping must support the SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with -the actual values as described in the section on SIOCSHWTSTAMP. +the actual values as described in the section on SIOCSHWTSTAMP. It +should also support SIOCGHWTSTAMP. Time stamps for received packets must be stored in the skb. To get a pointer to the shared time stamp structure of the skb call skb_hwtstamps(). Then -- cgit v1.2.3 From a4bcc795e9cc84902b86edbfbb755ecb38d11f91 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 22 Nov 2013 20:10:24 +0000 Subject: net_tstamp,doc: Add test program for SIOC{G,S}HWTSTAMP Signed-off-by: Ben Hutchings --- Documentation/networking/timestamping/.gitignore | 1 + Documentation/networking/timestamping/Makefile | 5 +- .../networking/timestamping/hwtstamp_config.c | 134 +++++++++++++++++++++ 3 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 Documentation/networking/timestamping/hwtstamp_config.c (limited to 'Documentation') diff --git a/Documentation/networking/timestamping/.gitignore b/Documentation/networking/timestamping/.gitignore index 71e81eb2e22f..a380159765ce 100644 --- a/Documentation/networking/timestamping/.gitignore +++ b/Documentation/networking/timestamping/.gitignore @@ -1 +1,2 @@ timestamping +hwtstamp_config diff --git a/Documentation/networking/timestamping/Makefile b/Documentation/networking/timestamping/Makefile index e79973443e9f..d934afc8306a 100644 --- a/Documentation/networking/timestamping/Makefile +++ b/Documentation/networking/timestamping/Makefile @@ -2,12 +2,13 @@ obj- := dummy.o # List of programs to build -hostprogs-y := timestamping +hostprogs-y := timestamping hwtstamp_config # Tell kbuild to always build the programs always := $(hostprogs-y) HOSTCFLAGS_timestamping.o += -I$(objtree)/usr/include +HOSTCFLAGS_hwtstamp_config.o += -I$(objtree)/usr/include clean: - rm -f timestamping + rm -f timestamping hwtstamp_config diff --git a/Documentation/networking/timestamping/hwtstamp_config.c b/Documentation/networking/timestamping/hwtstamp_config.c new file mode 100644 index 000000000000..e8b685a7f15f --- /dev/null +++ b/Documentation/networking/timestamping/hwtstamp_config.c @@ -0,0 +1,134 @@ +/* Test program for SIOC{G,S}HWTSTAMP + * Copyright 2013 Solarflare Communications + * Author: Ben Hutchings + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +static int +lookup_value(const char **names, int size, const char *name) +{ + int value; + + for (value = 0; value < size; value++) + if (names[value] && strcasecmp(names[value], name) == 0) + return value; + + return -1; +} + +static const char * +lookup_name(const char **names, int size, int value) +{ + return (value >= 0 && value < size) ? names[value] : NULL; +} + +static void list_names(FILE *f, const char **names, int size) +{ + int value; + + for (value = 0; value < size; value++) + if (names[value]) + fprintf(f, " %s\n", names[value]); +} + +static const char *tx_types[] = { +#define TX_TYPE(name) [HWTSTAMP_TX_ ## name] = #name + TX_TYPE(OFF), + TX_TYPE(ON), + TX_TYPE(ONESTEP_SYNC) +#undef TX_TYPE +}; +#define N_TX_TYPES ((int)(sizeof(tx_types) / sizeof(tx_types[0]))) + +static const char *rx_filters[] = { +#define RX_FILTER(name) [HWTSTAMP_FILTER_ ## name] = #name + RX_FILTER(NONE), + RX_FILTER(ALL), + RX_FILTER(SOME), + RX_FILTER(PTP_V1_L4_EVENT), + RX_FILTER(PTP_V1_L4_SYNC), + RX_FILTER(PTP_V1_L4_DELAY_REQ), + RX_FILTER(PTP_V2_L4_EVENT), + RX_FILTER(PTP_V2_L4_SYNC), + RX_FILTER(PTP_V2_L4_DELAY_REQ), + RX_FILTER(PTP_V2_L2_EVENT), + RX_FILTER(PTP_V2_L2_SYNC), + RX_FILTER(PTP_V2_L2_DELAY_REQ), + RX_FILTER(PTP_V2_EVENT), + RX_FILTER(PTP_V2_SYNC), + RX_FILTER(PTP_V2_DELAY_REQ), +#undef RX_FILTER +}; +#define N_RX_FILTERS ((int)(sizeof(rx_filters) / sizeof(rx_filters[0]))) + +static void usage(void) +{ + fputs("Usage: hwtstamp_config if_name [tx_type rx_filter]\n" + "tx_type is any of (case-insensitive):\n", + stderr); + list_names(stderr, tx_types, N_TX_TYPES); + fputs("rx_filter is any of (case-insensitive):\n", stderr); + list_names(stderr, rx_filters, N_RX_FILTERS); +} + +int main(int argc, char **argv) +{ + struct ifreq ifr; + struct hwtstamp_config config; + const char *name; + int sock; + + if ((argc != 2 && argc != 4) || (strlen(argv[1]) >= IFNAMSIZ)) { + usage(); + return 2; + } + + if (argc == 4) { + config.flags = 0; + config.tx_type = lookup_value(tx_types, N_TX_TYPES, argv[2]); + config.rx_filter = lookup_value(rx_filters, N_RX_FILTERS, argv[3]); + if (config.tx_type < 0 || config.rx_filter < 0) { + usage(); + return 2; + } + } + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + perror("socket"); + return 1; + } + + strcpy(ifr.ifr_name, argv[1]); + ifr.ifr_data = (caddr_t)&config; + + if (ioctl(sock, (argc == 2) ? SIOCGHWTSTAMP : SIOCSHWTSTAMP, &ifr)) { + perror("ioctl"); + return 1; + } + + printf("flags = %#x\n", config.flags); + name = lookup_name(tx_types, N_TX_TYPES, config.tx_type); + if (name) + printf("tx_type = %s\n", name); + else + printf("tx_type = %d\n", config.tx_type); + name = lookup_name(rx_filters, N_RX_FILTERS, config.rx_filter); + if (name) + printf("rx_filter = %s\n", name); + else + printf("rx_filter = %d\n", config.rx_filter); + + return 0; +} -- cgit v1.2.3 From 202317a573b20d77a9abb7c16a3fd5b40cef3d9d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Nov 2013 21:54:37 +0100 Subject: ACPI / scan: Add acpi_device objects for all device nodes in the namespace Modify the ACPI namespace scanning code to register a struct acpi_device object for every namespace node representing a device, processor and so on, even if the device represented by that namespace node is reported to be not present and not functional by _STA. There are multiple reasons to do that. First of all, it avoids quite a lot of overhead when struct acpi_device objects are deleted every time acpi_bus_trim() is run and then added again by a subsequent acpi_bus_scan() for the same scope, although the namespace objects they correspond to stay in memory all the time (which always is the case on a vast majority of systems). Second, it will allow user space to see that there are namespace nodes representing devices that are not present at the moment and may be added to the system. It will also allow user space to evaluate _SUN for those nodes to check what physical slots the "missing" devices may be put into and it will make sense to add a sysfs attribute for _STA evaluation after this change (that will be useful for thermal management on some systems). Next, it will help to consolidate the ACPI hotplug handling among subsystems by making it possible to store hotplug-related information in struct acpi_device objects in a standard common way. Finally, it will help to avoid a race condition related to the deletion of ACPI namespace nodes. Namely, namespace nodes may be deleted as a result of a table unload triggered by _EJ0 or _DCK. If a hotplug notification for one of those nodes is triggered right before the deletion and it executes a hotplug callback via acpi_hotplug_execute(), the ACPI handle passed to that callback may be stale when the callback actually runs. One way to work around that is to always pass struct acpi_device pointers to hotplug callbacks after doing a get_device() on the objects in question which eliminates the use-after-free possibility (the ACPI handles in those objects are invalidated by acpi_scan_drop_device(), so they will trigger ACPICA errors on attempts to use them). Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- Documentation/acpi/namespace.txt | 9 +--- drivers/acpi/device_pm.c | 22 ++++++-- drivers/acpi/dock.c | 9 ++-- drivers/acpi/internal.h | 3 ++ drivers/acpi/pci_root.c | 5 +- drivers/acpi/scan.c | 107 ++++++++++++++++++------------------- drivers/pci/hotplug/acpiphp_glue.c | 2 +- drivers/xen/xen-acpi-cpuhotplug.c | 8 +-- drivers/xen/xen-acpi-memhotplug.c | 7 +-- include/acpi/acpi_bus.h | 9 +++- 10 files changed, 97 insertions(+), 84 deletions(-) (limited to 'Documentation') diff --git a/Documentation/acpi/namespace.txt b/Documentation/acpi/namespace.txt index 260f6a3661fa..1860cb3865c6 100644 --- a/Documentation/acpi/namespace.txt +++ b/Documentation/acpi/namespace.txt @@ -235,10 +235,6 @@ Wysocki . named object's type in the second column). In that case the object's directory in sysfs will contain the 'path' attribute whose value is the full path to the node from the namespace root. - struct acpi_device objects are created for the ACPI namespace nodes - whose _STA control methods return PRESENT or FUNCTIONING. The power - resource nodes or nodes without _STA are assumed to be both PRESENT - and FUNCTIONING. F: The struct acpi_device object is created for a fixed hardware feature (as indicated by the fixed feature flag's name in the second @@ -340,7 +336,7 @@ Wysocki . | +-------------+-------+----------------+ | | | | +- - - - - - - +- - - - - - +- - - - - - - -+ - | +-| * PNP0C0D:00 | \_SB_.LID0 | acpi:PNP0C0D: | + | +-| PNP0C0D:00 | \_SB_.LID0 | acpi:PNP0C0D: | | | +- - - - - - - +- - - - - - +- - - - - - - -+ | | | | +------------+------------+-----------------------+ @@ -390,6 +386,3 @@ Wysocki . attribute (as described earlier in this document). NOTE: N/A indicates the device object does not have the 'path' or the 'modalias' attribute. - NOTE: The PNP0C0D device listed above is highlighted (marked by "*") - to indicate it will be created only when its _STA methods return - PRESENT or FUNCTIONING. diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index b3480cf7db1a..d49f1e464703 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -256,6 +256,8 @@ int acpi_bus_init_power(struct acpi_device *device) return -EINVAL; device->power.state = ACPI_STATE_UNKNOWN; + if (!acpi_device_is_present(device)) + return 0; result = acpi_device_get_power(device, &state); if (result) @@ -302,15 +304,18 @@ int acpi_device_fix_up_power(struct acpi_device *device) return ret; } -int acpi_bus_update_power(acpi_handle handle, int *state_p) +int acpi_device_update_power(struct acpi_device *device, int *state_p) { - struct acpi_device *device; int state; int result; - result = acpi_bus_get_device(handle, &device); - if (result) + if (device->power.state == ACPI_STATE_UNKNOWN) { + result = acpi_bus_init_power(device); + if (!result && state_p) + *state_p = device->power.state; + return result; + } result = acpi_device_get_power(device, &state); if (result) @@ -338,6 +343,15 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p) return 0; } + +int acpi_bus_update_power(acpi_handle handle, int *state_p) +{ + struct acpi_device *device; + int result; + + result = acpi_bus_get_device(handle, &device); + return result ? result : acpi_device_update_power(device, state_p); +} EXPORT_SYMBOL_GPL(acpi_bus_update_power); bool acpi_bus_power_manageable(acpi_handle handle) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index dcd73ccb514c..de032010da3c 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -323,14 +323,11 @@ static int dock_present(struct dock_station *ds) */ static void dock_create_acpi_device(acpi_handle handle) { - struct acpi_device *device; + struct acpi_device *device = NULL; int ret; - if (acpi_bus_get_device(handle, &device)) { - /* - * no device created for this object, - * so we should create one. - */ + acpi_bus_get_device(handle, &device); + if (!acpi_device_enumerated(device)) { ret = acpi_bus_scan(handle); if (ret) pr_debug("error adding bus, %x\n", -ret); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index d8606498bf6f..809b8082c134 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -90,6 +90,7 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); int acpi_bind_one(struct device *dev, acpi_handle handle); int acpi_unbind_one(struct device *dev); void acpi_bus_device_eject(void *data, u32 ost_src); +bool acpi_device_is_present(struct acpi_device *adev); /* -------------------------------------------------------------------------- Power Resource @@ -107,6 +108,8 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state); int acpi_power_on_resources(struct acpi_device *device, int state); int acpi_power_transition(struct acpi_device *device, int state); +int acpi_device_update_power(struct acpi_device *device, int *state_p); + int acpi_wakeup_device_init(void); void acpi_early_processor_set_pdc(void); diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 20360e480bd8..4076491c6ded 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -634,9 +634,10 @@ void __init acpi_pci_root_init(void) static void handle_root_bridge_insertion(acpi_handle handle) { - struct acpi_device *device; + struct acpi_device *device = NULL; - if (!acpi_bus_get_device(handle, &device)) { + acpi_bus_get_device(handle, &device); + if (acpi_device_enumerated(device)) { dev_printk(KERN_DEBUG, &device->dev, "acpi device already exists; ignoring notify\n"); return; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ad2522015e5e..bc52192785f1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -259,7 +259,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) acpi_bus_trim(device); - /* Device node has been unregistered. */ put_device(&device->dev); device = NULL; @@ -328,7 +327,7 @@ void acpi_bus_device_eject(void *data, u32 ost_src) static void acpi_scan_bus_device_check(void *data, u32 ost_source) { acpi_handle handle = data; - struct acpi_device *device = NULL; + struct acpi_device *device; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; int error; @@ -336,8 +335,9 @@ static void acpi_scan_bus_device_check(void *data, u32 ost_source) mutex_lock(&acpi_scan_lock); if (ost_source != ACPI_NOTIFY_BUS_CHECK) { + device = NULL; acpi_bus_get_device(handle, &device); - if (device) { + if (acpi_device_enumerated(device)) { dev_warn(&device->dev, "Attempt to re-insert\n"); goto out; } @@ -347,9 +347,10 @@ static void acpi_scan_bus_device_check(void *data, u32 ost_source) acpi_handle_warn(handle, "Namespace scan failure\n"); goto out; } - error = acpi_bus_get_device(handle, &device); - if (error) { - acpi_handle_warn(handle, "Missing device node object\n"); + device = NULL; + acpi_bus_get_device(handle, &device); + if (!acpi_device_enumerated(device)) { + acpi_handle_warn(handle, "Device not enumerated\n"); goto out; } ost_code = ACPI_OST_SC_SUCCESS; @@ -1111,20 +1112,6 @@ int acpi_device_add(struct acpi_device *device, return result; } -static void acpi_device_unregister(struct acpi_device *device) -{ - acpi_detach_data(device->handle, acpi_scan_drop_device); - acpi_device_del(device); - /* - * Transition the device to D3cold to drop the reference counts of all - * power resources the device depends on and turn off the ones that have - * no more references. - */ - acpi_device_set_power(device, ACPI_STATE_D3_COLD); - device->handle = NULL; - put_device(&device->dev); -} - /* -------------------------------------------------------------------------- Driver Management -------------------------------------------------------------------------- */ @@ -1703,6 +1690,8 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, acpi_set_pnp_ids(handle, &device->pnp, type); acpi_bus_get_flags(device); device->flags.match_driver = false; + device->flags.initialized = true; + device->flags.visited = false; device_initialize(&device->dev); dev_set_uevent_suppress(&device->dev, true); } @@ -1787,6 +1776,15 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, return 0; } +bool acpi_device_is_present(struct acpi_device *adev) +{ + if (adev->status.present || adev->status.functional) + return true; + + adev->flags.initialized = false; + return false; +} + static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler, char *idstr, const struct acpi_device_id **matchid) @@ -1880,18 +1878,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, acpi_scan_init_hotplug(handle, type); - if (!(sta & ACPI_STA_DEVICE_PRESENT) && - !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { - struct acpi_device_wakeup wakeup; - - if (acpi_has_method(handle, "_PRW")) { - acpi_bus_extract_wakeup_device_power_package(handle, - &wakeup); - acpi_power_resources_list_free(&wakeup.resources); - } - return AE_CTRL_DEPTH; - } - acpi_add_single_object(&device, handle, type, sta); if (!device) return AE_CTRL_DEPTH; @@ -1930,32 +1916,50 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, void *not_used, void **ret_not_used) { struct acpi_device *device; - unsigned long long sta_not_used; + unsigned long long sta; int ret; /* * Ignore errors ignored by acpi_bus_check_add() to avoid terminating * namespace walks prematurely. */ - if (acpi_bus_type_and_status(handle, &ret, &sta_not_used)) + if (acpi_bus_type_and_status(handle, &ret, &sta)) return AE_OK; if (acpi_bus_get_device(handle, &device)) return AE_CTRL_DEPTH; + STRUCT_TO_INT(device->status) = sta; + /* Skip devices that are not present. */ + if (!acpi_device_is_present(device)) + goto err; + if (device->handler) return AE_OK; + if (!device->flags.initialized) { + acpi_bus_update_power(device, NULL); + device->flags.initialized = true; + } ret = acpi_scan_attach_handler(device); if (ret < 0) - return AE_CTRL_DEPTH; + goto err; device->flags.match_driver = true; if (ret > 0) - return AE_OK; + goto ok; ret = device_attach(&device->dev); - return ret >= 0 ? AE_OK : AE_CTRL_DEPTH; + if (ret < 0) + goto err; + + ok: + device->flags.visited = true; + return AE_OK; + + err: + device->flags.visited = false; + return AE_CTRL_DEPTH; } /** @@ -2007,21 +2011,17 @@ static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used, } else { device_release_driver(&device->dev); } + /* + * Most likely, the device is going away, so put it into D3cold + * before that. + */ + acpi_device_set_power(device, ACPI_STATE_D3_COLD); + device->flags.initialized = false; + device->flags.visited = false; } return AE_OK; } -static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used, - void *not_used, void **ret_not_used) -{ - struct acpi_device *device = NULL; - - if (!acpi_bus_get_device(handle, &device)) - acpi_device_unregister(device); - - return AE_OK; -} - /** * acpi_bus_trim - Remove ACPI device node and all of its descendants * @start: Root of the ACPI device nodes subtree to remove. @@ -2037,13 +2037,6 @@ void acpi_bus_trim(struct acpi_device *start) acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL, acpi_bus_device_detach, NULL, NULL); acpi_bus_device_detach(start->handle, 0, NULL, NULL); - /* - * Execute acpi_bus_remove() as a post-order callback to remove device - * nodes in the given namespace scope. - */ - acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL, - acpi_bus_remove, NULL, NULL); - acpi_bus_remove(start->handle, 0, NULL, NULL); } EXPORT_SYMBOL_GPL(acpi_bus_trim); @@ -2121,7 +2114,9 @@ int __init acpi_scan_init(void) result = acpi_bus_scan_fixed(); if (result) { - acpi_device_unregister(acpi_root); + acpi_detach_data(acpi_root->handle, acpi_scan_drop_device); + acpi_device_del(acpi_root); + put_device(&acpi_root->dev); goto out; } diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 1cf605f67673..67be6bab7535 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -489,7 +489,7 @@ static void acpiphp_bus_add(acpi_handle handle) acpi_bus_scan(handle); acpi_bus_get_device(handle, &adev); - if (adev) + if (acpi_device_enumerated(adev)) acpi_device_set_power(adev, ACPI_STATE_D0); } diff --git a/drivers/xen/xen-acpi-cpuhotplug.c b/drivers/xen/xen-acpi-cpuhotplug.c index 8dae6c13063a..73496c3d18ae 100644 --- a/drivers/xen/xen-acpi-cpuhotplug.c +++ b/drivers/xen/xen-acpi-cpuhotplug.c @@ -269,7 +269,8 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, if (!is_processor_present(handle)) break; - if (!acpi_bus_get_device(handle, &device)) + acpi_bus_get_device(handle, &device); + if (acpi_device_enumerated(device)) break; result = acpi_bus_scan(handle); @@ -277,8 +278,9 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, pr_err(PREFIX "Unable to add the device\n"); break; } - result = acpi_bus_get_device(handle, &device); - if (result) { + device = NULL; + acpi_bus_get_device(handle, &device); + if (!acpi_device_enumerated(device)) { pr_err(PREFIX "Missing device object\n"); break; } diff --git a/drivers/xen/xen-acpi-memhotplug.c b/drivers/xen/xen-acpi-memhotplug.c index 9083f1e474f8..9b056f06691f 100644 --- a/drivers/xen/xen-acpi-memhotplug.c +++ b/drivers/xen/xen-acpi-memhotplug.c @@ -169,7 +169,7 @@ static int acpi_memory_get_device(acpi_handle handle, acpi_scan_lock_acquire(); acpi_bus_get_device(handle, &device); - if (device) + if (acpi_device_enumerated(device)) goto end; /* @@ -182,8 +182,9 @@ static int acpi_memory_get_device(acpi_handle handle, result = -EINVAL; goto out; } - result = acpi_bus_get_device(handle, &device); - if (result) { + device = NULL; + acpi_bus_get_device(handle, &device); + if (!acpi_device_enumerated(device)) { pr_warn(PREFIX "Missing device object\n"); result = -EINVAL; goto out; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 9fe5f63155ed..e748dbfca9d5 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -169,7 +169,9 @@ struct acpi_device_flags { u32 ejectable:1; u32 power_manageable:1; u32 match_driver:1; - u32 reserved:27; + u32 initialized:1; + u32 visited:1; + u32 reserved:25; }; /* File System */ @@ -386,6 +388,11 @@ int acpi_match_device_ids(struct acpi_device *device, int acpi_create_dir(struct acpi_device *); void acpi_remove_dir(struct acpi_device *); +static inline bool acpi_device_enumerated(struct acpi_device *adev) +{ + return adev && adev->flags.initialized && adev->flags.visited; +} + typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -- cgit v1.2.3 From 3bc942f372af383f49d56aab599469561a5e39ec Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 22 Nov 2013 18:20:44 -0500 Subject: memcg: rename cgroup_event to mem_cgroup_event cgroup_event is only available in memcg now. Let's brand it that way. While at it, add a comment encouraging deprecation of the feature and remove the respective section from cgroup documentation. This patch is cosmetic. v3: Typo update as per Li Zefan. v2: Index in cgroups.txt updated accordingly as suggested by Li Zefan. Signed-off-by: Tejun Heo Acked-by: Li Zefan Acked-by: Kirill A. Shutemov Acked-by: Michal Hocko --- Documentation/cgroups/cgroups.txt | 20 -------------- mm/memcontrol.c | 57 +++++++++++++++++++++++++-------------- 2 files changed, 37 insertions(+), 40 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt index 638bf17ff869..821de56d1580 100644 --- a/Documentation/cgroups/cgroups.txt +++ b/Documentation/cgroups/cgroups.txt @@ -24,7 +24,6 @@ CONTENTS: 2.1 Basic Usage 2.2 Attaching processes 2.3 Mounting hierarchies by name - 2.4 Notification API 3. Kernel API 3.1 Overview 3.2 Synchronization @@ -472,25 +471,6 @@ you give a subsystem a name. The name of the subsystem appears as part of the hierarchy description in /proc/mounts and /proc//cgroups. -2.4 Notification API --------------------- - -There is mechanism which allows to get notifications about changing -status of a cgroup. - -To register a new notification handler you need to: - - create a file descriptor for event notification using eventfd(2); - - open a control file to be monitored (e.g. memory.usage_in_bytes); - - write " " to cgroup.event_control. - Interpretation of args is defined by control file implementation; - -eventfd will be woken up by control file implementation or when the -cgroup is removed. - -To unregister a notification handler just close eventfd. - -NOTE: Support of notifications should be implemented for the control -file. See documentation for the subsystem. 3. Kernel API ============= diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 42f2843af1a7..ec8582b3a232 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -231,7 +231,7 @@ struct mem_cgroup_eventfd_list { /* * cgroup_event represents events which userspace want to receive. */ -struct cgroup_event { +struct mem_cgroup_event { /* * memcg which the event belongs to. */ @@ -6001,15 +6001,28 @@ static void kmem_cgroup_css_offline(struct mem_cgroup *memcg) } #endif +/* + * DO NOT USE IN NEW FILES. + * + * "cgroup.event_control" implementation. + * + * This is way over-engineered. It tries to support fully configurable + * events for each user. Such level of flexibility is completely + * unnecessary especially in the light of the planned unified hierarchy. + * + * Please deprecate this and replace with something simpler if at all + * possible. + */ + /* * Unregister event and free resources. * * Gets called from workqueue. */ -static void cgroup_event_remove(struct work_struct *work) +static void memcg_event_remove(struct work_struct *work) { - struct cgroup_event *event = container_of(work, struct cgroup_event, - remove); + struct mem_cgroup_event *event = + container_of(work, struct mem_cgroup_event, remove); struct mem_cgroup *memcg = event->memcg; remove_wait_queue(event->wqh, &event->wait); @@ -6029,11 +6042,11 @@ static void cgroup_event_remove(struct work_struct *work) * * Called with wqh->lock held and interrupts disabled. */ -static int cgroup_event_wake(wait_queue_t *wait, unsigned mode, - int sync, void *key) +static int memcg_event_wake(wait_queue_t *wait, unsigned mode, + int sync, void *key) { - struct cgroup_event *event = container_of(wait, - struct cgroup_event, wait); + struct mem_cgroup_event *event = + container_of(wait, struct mem_cgroup_event, wait); struct mem_cgroup *memcg = event->memcg; unsigned long flags = (unsigned long)key; @@ -6062,27 +6075,29 @@ static int cgroup_event_wake(wait_queue_t *wait, unsigned mode, return 0; } -static void cgroup_event_ptable_queue_proc(struct file *file, +static void memcg_event_ptable_queue_proc(struct file *file, wait_queue_head_t *wqh, poll_table *pt) { - struct cgroup_event *event = container_of(pt, - struct cgroup_event, pt); + struct mem_cgroup_event *event = + container_of(pt, struct mem_cgroup_event, pt); event->wqh = wqh; add_wait_queue(wqh, &event->wait); } /* + * DO NOT USE IN NEW FILES. + * * Parse input and register new cgroup event handler. * * Input must be in format ' '. * Interpretation of args is defined by control file implementation. */ -static int cgroup_write_event_control(struct cgroup_subsys_state *css, - struct cftype *cft, const char *buffer) +static int memcg_write_event_control(struct cgroup_subsys_state *css, + struct cftype *cft, const char *buffer) { struct mem_cgroup *memcg = mem_cgroup_from_css(css); - struct cgroup_event *event; + struct mem_cgroup_event *event; struct cgroup_subsys_state *cfile_css; unsigned int efd, cfd; struct fd efile; @@ -6107,9 +6122,9 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *css, event->memcg = memcg; INIT_LIST_HEAD(&event->list); - init_poll_funcptr(&event->pt, cgroup_event_ptable_queue_proc); - init_waitqueue_func_entry(&event->wait, cgroup_event_wake); - INIT_WORK(&event->remove, cgroup_event_remove); + init_poll_funcptr(&event->pt, memcg_event_ptable_queue_proc); + init_waitqueue_func_entry(&event->wait, memcg_event_wake); + INIT_WORK(&event->remove, memcg_event_remove); efile = fdget(efd); if (!efile.file) { @@ -6140,6 +6155,8 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *css, * to be done via struct cftype but cgroup core no longer knows * about these events. The following is crude but the whole thing * is for compatibility anyway. + * + * DO NOT ADD NEW FILES. */ name = cfile.file->f_dentry->d_name.name; @@ -6251,8 +6268,8 @@ static struct cftype mem_cgroup_files[] = { .read_u64 = mem_cgroup_hierarchy_read, }, { - .name = "cgroup.event_control", - .write_string = cgroup_write_event_control, + .name = "cgroup.event_control", /* XXX: for compat */ + .write_string = memcg_write_event_control, .flags = CFTYPE_NO_PREFIX, .mode = S_IWUGO, }, @@ -6585,7 +6602,7 @@ static void mem_cgroup_invalidate_reclaim_iterators(struct mem_cgroup *memcg) static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) { struct mem_cgroup *memcg = mem_cgroup_from_css(css); - struct cgroup_event *event, *tmp; + struct mem_cgroup_event *event, *tmp; /* * Unregister events and notify userspace. -- cgit v1.2.3 From 4f024f3797c43cb4b73cd2c50cec728842d0e49e Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Fri, 11 Oct 2013 15:44:27 -0700 Subject: block: Abstract out bvec iterator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Immutable biovecs are going to require an explicit iterator. To implement immutable bvecs, a later patch is going to add a bi_bvec_done member to this struct; for now, this patch effectively just renames things. Signed-off-by: Kent Overstreet Cc: Jens Axboe Cc: Geert Uytterhoeven Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: "Ed L. Cashin" Cc: Nick Piggin Cc: Lars Ellenberg Cc: Jiri Kosina Cc: Matthew Wilcox Cc: Geoff Levand Cc: Yehuda Sadeh Cc: Sage Weil Cc: Alex Elder Cc: ceph-devel@vger.kernel.org Cc: Joshua Morris Cc: Philip Kelleher Cc: Rusty Russell Cc: "Michael S. Tsirkin" Cc: Konrad Rzeszutek Wilk Cc: Jeremy Fitzhardinge Cc: Neil Brown Cc: Alasdair Kergon Cc: Mike Snitzer Cc: dm-devel@redhat.com Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux390@de.ibm.com Cc: Boaz Harrosh Cc: Benny Halevy Cc: "James E.J. Bottomley" Cc: Greg Kroah-Hartman Cc: "Nicholas A. Bellinger" Cc: Alexander Viro Cc: Chris Mason Cc: "Theodore Ts'o" Cc: Andreas Dilger Cc: Jaegeuk Kim Cc: Steven Whitehouse Cc: Dave Kleikamp Cc: Joern Engel Cc: Prasad Joshi Cc: Trond Myklebust Cc: KONISHI Ryusuke Cc: Mark Fasheh Cc: Joel Becker Cc: Ben Myers Cc: xfs@oss.sgi.com Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Len Brown Cc: Pavel Machek Cc: "Rafael J. Wysocki" Cc: Herton Ronaldo Krzesinski Cc: Ben Hutchings Cc: Andrew Morton Cc: Guo Chao Cc: Tejun Heo Cc: Asai Thambi S P Cc: Selvan Mani Cc: Sam Bradshaw Cc: Wei Yongjun Cc: "Roger Pau Monné" Cc: Jan Beulich Cc: Stefano Stabellini Cc: Ian Campbell Cc: Sebastian Ott Cc: Christian Borntraeger Cc: Minchan Kim Cc: Jiang Liu Cc: Nitin Gupta Cc: Jerome Marchand Cc: Joe Perches Cc: Peng Tao Cc: Andy Adamson Cc: fanchaoting Cc: Jie Liu Cc: Sunil Mushran Cc: "Martin K. Petersen" Cc: Namjae Jeon Cc: Pankaj Kumar Cc: Dan Magenheimer Cc: Mel Gorman 6 --- Documentation/block/biodoc.txt | 7 +-- arch/m68k/emu/nfblock.c | 2 +- arch/powerpc/sysdev/axonram.c | 3 +- block/blk-core.c | 36 ++++++------ block/blk-flush.c | 2 +- block/blk-lib.c | 12 ++-- block/blk-map.c | 6 +- block/blk-merge.c | 4 +- block/blk-mq.c | 2 +- block/blk-throttle.c | 14 ++--- block/elevator.c | 2 +- drivers/block/aoe/aoecmd.c | 6 +- drivers/block/brd.c | 4 +- drivers/block/drbd/drbd_actlog.c | 2 +- drivers/block/drbd/drbd_bitmap.c | 2 +- drivers/block/drbd/drbd_receiver.c | 6 +- drivers/block/drbd/drbd_req.c | 6 +- drivers/block/drbd/drbd_req.h | 2 +- drivers/block/floppy.c | 4 +- drivers/block/loop.c | 4 +- drivers/block/mtip32xx/mtip32xx.c | 7 ++- drivers/block/nvme-core.c | 25 ++++---- drivers/block/pktcdvd.c | 54 +++++++++-------- drivers/block/ps3disk.c | 2 +- drivers/block/ps3vram.c | 2 +- drivers/block/rbd.c | 21 +++---- drivers/block/rsxx/dev.c | 6 +- drivers/block/rsxx/dma.c | 4 +- drivers/block/umem.c | 9 +-- drivers/block/xen-blkback/blkback.c | 2 +- drivers/block/xen-blkfront.c | 2 +- drivers/md/bcache/btree.c | 4 +- drivers/md/bcache/debug.c | 2 +- drivers/md/bcache/io.c | 26 ++++----- drivers/md/bcache/journal.c | 12 ++-- drivers/md/bcache/movinggc.c | 4 +- drivers/md/bcache/request.c | 58 +++++++++--------- drivers/md/bcache/super.c | 16 ++--- drivers/md/bcache/util.c | 4 +- drivers/md/bcache/writeback.c | 6 +- drivers/md/bcache/writeback.h | 2 +- drivers/md/dm-bio-record.h | 12 ++-- drivers/md/dm-bufio.c | 2 +- drivers/md/dm-cache-policy-mq.c | 4 +- drivers/md/dm-cache-target.c | 22 +++---- drivers/md/dm-crypt.c | 19 +++--- drivers/md/dm-delay.c | 7 ++- drivers/md/dm-flakey.c | 7 ++- drivers/md/dm-io.c | 6 +- drivers/md/dm-linear.c | 3 +- drivers/md/dm-raid1.c | 16 ++--- drivers/md/dm-region-hash.c | 3 +- drivers/md/dm-snap.c | 18 +++--- drivers/md/dm-stripe.c | 13 +++-- drivers/md/dm-switch.c | 4 +- drivers/md/dm-thin.c | 22 +++---- drivers/md/dm-verity.c | 8 +-- drivers/md/dm.c | 25 ++++---- drivers/md/faulty.c | 19 +++--- drivers/md/linear.c | 12 ++-- drivers/md/md.c | 10 ++-- drivers/md/multipath.c | 13 +++-- drivers/md/raid0.c | 16 ++--- drivers/md/raid1.c | 75 ++++++++++++------------ drivers/md/raid10.c | 91 ++++++++++++++++------------- drivers/md/raid5.c | 72 ++++++++++++----------- drivers/s390/block/dcssblk.c | 5 +- drivers/s390/block/xpram.c | 9 +-- drivers/scsi/osd/osd_initiator.c | 2 +- drivers/staging/lustre/lustre/llite/lloop.c | 12 ++-- drivers/staging/zram/zram_drv.c | 14 +++-- drivers/target/target_core_iblock.c | 2 +- fs/bio-integrity.c | 8 +-- fs/bio.c | 56 +++++++++--------- fs/btrfs/check-integrity.c | 8 +-- fs/btrfs/compression.c | 17 +++--- fs/btrfs/extent_io.c | 14 ++--- fs/btrfs/file-item.c | 19 +++--- fs/btrfs/inode.c | 22 +++---- fs/btrfs/raid56.c | 22 +++---- fs/btrfs/scrub.c | 12 ++-- fs/btrfs/volumes.c | 12 ++-- fs/buffer.c | 12 ++-- fs/direct-io.c | 4 +- fs/ext4/page-io.c | 4 +- fs/f2fs/data.c | 2 +- fs/f2fs/segment.c | 2 +- fs/gfs2/lops.c | 2 +- fs/gfs2/ops_fstype.c | 2 +- fs/hfsplus/wrapper.c | 2 +- fs/jfs/jfs_logmgr.c | 12 ++-- fs/jfs/jfs_metapage.c | 9 +-- fs/logfs/dev_bdev.c | 20 +++---- fs/mpage.c | 2 +- fs/nfs/blocklayout/blocklayout.c | 9 +-- fs/nilfs2/segbuf.c | 3 +- fs/ocfs2/cluster/heartbeat.c | 2 +- fs/xfs/xfs_aops.c | 2 +- fs/xfs/xfs_buf.c | 4 +- include/linux/bio.h | 16 ++--- include/linux/blk_types.h | 19 +++--- include/trace/events/bcache.h | 26 ++++----- include/trace/events/block.h | 26 ++++----- include/trace/events/f2fs.h | 4 +- kernel/power/block_io.c | 2 +- kernel/trace/blktrace.c | 15 ++--- mm/page_io.c | 10 ++-- 107 files changed, 700 insertions(+), 638 deletions(-) (limited to 'Documentation') diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt index 8df5e8e6dceb..2101e718670d 100644 --- a/Documentation/block/biodoc.txt +++ b/Documentation/block/biodoc.txt @@ -447,14 +447,13 @@ struct bio_vec { * main unit of I/O for the block layer and lower layers (ie drivers) */ struct bio { - sector_t bi_sector; struct bio *bi_next; /* request queue link */ struct block_device *bi_bdev; /* target device */ unsigned long bi_flags; /* status, command, etc */ unsigned long bi_rw; /* low bits: r/w, high: priority */ unsigned int bi_vcnt; /* how may bio_vec's */ - unsigned int bi_idx; /* current index into bio_vec array */ + struct bvec_iter bi_iter; /* current index into bio_vec array */ unsigned int bi_size; /* total size in bytes */ unsigned short bi_phys_segments; /* segments after physaddr coalesce*/ @@ -480,7 +479,7 @@ With this multipage bio design: - Code that traverses the req list can find all the segments of a bio by using rq_for_each_segment. This handles the fact that a request has multiple bios, each of which can have multiple segments. -- Drivers which can't process a large bio in one shot can use the bi_idx +- Drivers which can't process a large bio in one shot can use the bi_iter field to keep track of the next bio_vec entry to process. (e.g a 1MB bio_vec needs to be handled in max 128kB chunks for IDE) [TBD: Should preferably also have a bi_voffset and bi_vlen to avoid modifying @@ -589,7 +588,7 @@ driver should not modify these values. The block layer sets up the nr_sectors and current_nr_sectors fields (based on the corresponding hard_xxx values and the number of bytes transferred) and updates it on every transfer that invokes end_that_request_first. It does the same for the -buffer, bio, bio->bi_idx fields too. +buffer, bio, bio->bi_iter fields too. The buffer field is just a virtual address mapping of the current segment of the i/o buffer in cases where the buffer resides in low-memory. For high diff --git a/arch/m68k/emu/nfblock.c b/arch/m68k/emu/nfblock.c index 0721858fbd1e..0a9d0b3c794b 100644 --- a/arch/m68k/emu/nfblock.c +++ b/arch/m68k/emu/nfblock.c @@ -64,7 +64,7 @@ static void nfhd_make_request(struct request_queue *queue, struct bio *bio) struct nfhd_device *dev = queue->queuedata; struct bio_vec *bvec; int i, dir, len, shift; - sector_t sec = bio->bi_sector; + sector_t sec = bio->bi_iter.bi_sector; dir = bio_data_dir(bio); shift = dev->bshift; diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index 1c16141c031c..f33bcbaa6a07 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -113,7 +113,8 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) unsigned int transfered; unsigned short idx; - phys_mem = bank->io_addr + (bio->bi_sector << AXON_RAM_SECTOR_SHIFT); + phys_mem = bank->io_addr + (bio->bi_iter.bi_sector << + AXON_RAM_SECTOR_SHIFT); phys_end = bank->io_addr + bank->size; transfered = 0; bio_for_each_segment(vec, bio, idx) { diff --git a/block/blk-core.c b/block/blk-core.c index 8bdd0121212a..5c2ab2c74066 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -130,7 +130,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio, bio_advance(bio, nbytes); /* don't actually finish bio if it's part of flush sequence */ - if (bio->bi_size == 0 && !(rq->cmd_flags & REQ_FLUSH_SEQ)) + if (bio->bi_iter.bi_size == 0 && !(rq->cmd_flags & REQ_FLUSH_SEQ)) bio_endio(bio, error); } @@ -1326,7 +1326,7 @@ void blk_add_request_payload(struct request *rq, struct page *page, bio->bi_io_vec->bv_offset = 0; bio->bi_io_vec->bv_len = len; - bio->bi_size = len; + bio->bi_iter.bi_size = len; bio->bi_vcnt = 1; bio->bi_phys_segments = 1; @@ -1351,7 +1351,7 @@ bool bio_attempt_back_merge(struct request_queue *q, struct request *req, req->biotail->bi_next = bio; req->biotail = bio; - req->__data_len += bio->bi_size; + req->__data_len += bio->bi_iter.bi_size; req->ioprio = ioprio_best(req->ioprio, bio_prio(bio)); blk_account_io_start(req, false); @@ -1380,8 +1380,8 @@ bool bio_attempt_front_merge(struct request_queue *q, struct request *req, * not touch req->buffer either... */ req->buffer = bio_data(bio); - req->__sector = bio->bi_sector; - req->__data_len += bio->bi_size; + req->__sector = bio->bi_iter.bi_sector; + req->__data_len += bio->bi_iter.bi_size; req->ioprio = ioprio_best(req->ioprio, bio_prio(bio)); blk_account_io_start(req, false); @@ -1459,7 +1459,7 @@ void init_request_from_bio(struct request *req, struct bio *bio) req->cmd_flags |= REQ_FAILFAST_MASK; req->errors = 0; - req->__sector = bio->bi_sector; + req->__sector = bio->bi_iter.bi_sector; req->ioprio = bio_prio(bio); blk_rq_bio_prep(req->q, req, bio); } @@ -1583,12 +1583,12 @@ static inline void blk_partition_remap(struct bio *bio) if (bio_sectors(bio) && bdev != bdev->bd_contains) { struct hd_struct *p = bdev->bd_part; - bio->bi_sector += p->start_sect; + bio->bi_iter.bi_sector += p->start_sect; bio->bi_bdev = bdev->bd_contains; trace_block_bio_remap(bdev_get_queue(bio->bi_bdev), bio, bdev->bd_dev, - bio->bi_sector - p->start_sect); + bio->bi_iter.bi_sector - p->start_sect); } } @@ -1654,7 +1654,7 @@ static inline int bio_check_eod(struct bio *bio, unsigned int nr_sectors) /* Test device or partition size, when known. */ maxsector = i_size_read(bio->bi_bdev->bd_inode) >> 9; if (maxsector) { - sector_t sector = bio->bi_sector; + sector_t sector = bio->bi_iter.bi_sector; if (maxsector < nr_sectors || maxsector - nr_sectors < sector) { /* @@ -1690,7 +1690,7 @@ generic_make_request_checks(struct bio *bio) "generic_make_request: Trying to access " "nonexistent block-device %s (%Lu)\n", bdevname(bio->bi_bdev, b), - (long long) bio->bi_sector); + (long long) bio->bi_iter.bi_sector); goto end_io; } @@ -1704,9 +1704,9 @@ generic_make_request_checks(struct bio *bio) } part = bio->bi_bdev->bd_part; - if (should_fail_request(part, bio->bi_size) || + if (should_fail_request(part, bio->bi_iter.bi_size) || should_fail_request(&part_to_disk(part)->part0, - bio->bi_size)) + bio->bi_iter.bi_size)) goto end_io; /* @@ -1865,7 +1865,7 @@ void submit_bio(int rw, struct bio *bio) if (rw & WRITE) { count_vm_events(PGPGOUT, count); } else { - task_io_account_read(bio->bi_size); + task_io_account_read(bio->bi_iter.bi_size); count_vm_events(PGPGIN, count); } @@ -1874,7 +1874,7 @@ void submit_bio(int rw, struct bio *bio) printk(KERN_DEBUG "%s(%d): %s block %Lu on %s (%u sectors)\n", current->comm, task_pid_nr(current), (rw & WRITE) ? "WRITE" : "READ", - (unsigned long long)bio->bi_sector, + (unsigned long long)bio->bi_iter.bi_sector, bdevname(bio->bi_bdev, b), count); } @@ -2007,7 +2007,7 @@ unsigned int blk_rq_err_bytes(const struct request *rq) for (bio = rq->bio; bio; bio = bio->bi_next) { if ((bio->bi_rw & ff) != ff) break; - bytes += bio->bi_size; + bytes += bio->bi_iter.bi_size; } /* this could lead to infinite loop */ @@ -2378,9 +2378,9 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes) total_bytes = 0; while (req->bio) { struct bio *bio = req->bio; - unsigned bio_bytes = min(bio->bi_size, nr_bytes); + unsigned bio_bytes = min(bio->bi_iter.bi_size, nr_bytes); - if (bio_bytes == bio->bi_size) + if (bio_bytes == bio->bi_iter.bi_size) req->bio = bio->bi_next; req_bio_endio(req, bio, bio_bytes, error); @@ -2728,7 +2728,7 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq, rq->nr_phys_segments = bio_phys_segments(q, bio); rq->buffer = bio_data(bio); } - rq->__data_len = bio->bi_size; + rq->__data_len = bio->bi_iter.bi_size; rq->bio = rq->biotail = bio; if (bio->bi_bdev) diff --git a/block/blk-flush.c b/block/blk-flush.c index fb6f3c0ffa49..9288aaf35c21 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -548,7 +548,7 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask, * copied from blk_rq_pos(rq). */ if (error_sector) - *error_sector = bio->bi_sector; + *error_sector = bio->bi_iter.bi_sector; bio_put(bio); return ret; diff --git a/block/blk-lib.c b/block/blk-lib.c index 9b5b561cb928..2da76c999ef3 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -108,12 +108,12 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector, req_sects = end_sect - sector; } - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_end_io = bio_batch_end_io; bio->bi_bdev = bdev; bio->bi_private = &bb; - bio->bi_size = req_sects << 9; + bio->bi_iter.bi_size = req_sects << 9; nr_sects -= req_sects; sector = end_sect; @@ -174,7 +174,7 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, break; } - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_end_io = bio_batch_end_io; bio->bi_bdev = bdev; bio->bi_private = &bb; @@ -184,11 +184,11 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, bio->bi_io_vec->bv_len = bdev_logical_block_size(bdev); if (nr_sects > max_write_same_sectors) { - bio->bi_size = max_write_same_sectors << 9; + bio->bi_iter.bi_size = max_write_same_sectors << 9; nr_sects -= max_write_same_sectors; sector += max_write_same_sectors; } else { - bio->bi_size = nr_sects << 9; + bio->bi_iter.bi_size = nr_sects << 9; nr_sects = 0; } @@ -240,7 +240,7 @@ int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, break; } - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_bdev = bdev; bio->bi_end_io = bio_batch_end_io; bio->bi_private = &bb; diff --git a/block/blk-map.c b/block/blk-map.c index 623e1cd4cffe..ae4ae1047fd9 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -20,7 +20,7 @@ int blk_rq_append_bio(struct request_queue *q, struct request *rq, rq->biotail->bi_next = bio; rq->biotail = bio; - rq->__data_len += bio->bi_size; + rq->__data_len += bio->bi_iter.bi_size; } return 0; } @@ -76,7 +76,7 @@ static int __blk_rq_map_user(struct request_queue *q, struct request *rq, ret = blk_rq_append_bio(q, rq, bio); if (!ret) - return bio->bi_size; + return bio->bi_iter.bi_size; /* if it was boucned we must call the end io function */ bio_endio(bio, 0); @@ -220,7 +220,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, if (IS_ERR(bio)) return PTR_ERR(bio); - if (bio->bi_size != len) { + if (bio->bi_iter.bi_size != len) { /* * Grab an extra reference to this bio, as bio_unmap_user() * expects to be able to drop it twice as it happens on the diff --git a/block/blk-merge.c b/block/blk-merge.c index 1ffc58977835..03bc083c28cf 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -543,9 +543,9 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio) int blk_try_merge(struct request *rq, struct bio *bio) { - if (blk_rq_pos(rq) + blk_rq_sectors(rq) == bio->bi_sector) + if (blk_rq_pos(rq) + blk_rq_sectors(rq) == bio->bi_iter.bi_sector) return ELEVATOR_BACK_MERGE; - else if (blk_rq_pos(rq) - bio_sectors(bio) == bio->bi_sector) + else if (blk_rq_pos(rq) - bio_sectors(bio) == bio->bi_iter.bi_sector) return ELEVATOR_FRONT_MERGE; return ELEVATOR_NO_MERGE; } diff --git a/block/blk-mq.c b/block/blk-mq.c index cdc629cf075b..e4fbcc3fd2db 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -301,7 +301,7 @@ void blk_mq_complete_request(struct request *rq, int error) struct bio *next = bio->bi_next; bio->bi_next = NULL; - bytes += bio->bi_size; + bytes += bio->bi_iter.bi_size; blk_mq_bio_endio(rq, bio, error); bio = next; } diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 06534049afba..20f820037775 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -877,14 +877,14 @@ static bool tg_with_in_bps_limit(struct throtl_grp *tg, struct bio *bio, do_div(tmp, HZ); bytes_allowed = tmp; - if (tg->bytes_disp[rw] + bio->bi_size <= bytes_allowed) { + if (tg->bytes_disp[rw] + bio->bi_iter.bi_size <= bytes_allowed) { if (wait) *wait = 0; return 1; } /* Calc approx time to dispatch */ - extra_bytes = tg->bytes_disp[rw] + bio->bi_size - bytes_allowed; + extra_bytes = tg->bytes_disp[rw] + bio->bi_iter.bi_size - bytes_allowed; jiffy_wait = div64_u64(extra_bytes * HZ, tg->bps[rw]); if (!jiffy_wait) @@ -987,7 +987,7 @@ static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio) bool rw = bio_data_dir(bio); /* Charge the bio to the group */ - tg->bytes_disp[rw] += bio->bi_size; + tg->bytes_disp[rw] += bio->bi_iter.bi_size; tg->io_disp[rw]++; /* @@ -1003,8 +1003,8 @@ static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio) */ if (!(bio->bi_rw & REQ_THROTTLED)) { bio->bi_rw |= REQ_THROTTLED; - throtl_update_dispatch_stats(tg_to_blkg(tg), bio->bi_size, - bio->bi_rw); + throtl_update_dispatch_stats(tg_to_blkg(tg), + bio->bi_iter.bi_size, bio->bi_rw); } } @@ -1508,7 +1508,7 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio) if (tg) { if (!tg->has_rules[rw]) { throtl_update_dispatch_stats(tg_to_blkg(tg), - bio->bi_size, bio->bi_rw); + bio->bi_iter.bi_size, bio->bi_rw); goto out_unlock_rcu; } } @@ -1564,7 +1564,7 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio) /* out-of-limit, queue to @tg */ throtl_log(sq, "[%c] bio. bdisp=%llu sz=%u bps=%llu iodisp=%u iops=%u queued=%d/%d", rw == READ ? 'R' : 'W', - tg->bytes_disp[rw], bio->bi_size, tg->bps[rw], + tg->bytes_disp[rw], bio->bi_iter.bi_size, tg->bps[rw], tg->io_disp[rw], tg->iops[rw], sq->nr_queued[READ], sq->nr_queued[WRITE]); diff --git a/block/elevator.c b/block/elevator.c index b7ff2861b6bd..42c45a7d6714 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -440,7 +440,7 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio) /* * See if our hash lookup can find a potential backmerge. */ - __rq = elv_rqhash_find(q, bio->bi_sector); + __rq = elv_rqhash_find(q, bio->bi_iter.bi_sector); if (__rq && elv_rq_merge_ok(__rq, bio)) { *req = __rq; return ELEVATOR_BACK_MERGE; diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index d2515435e23f..877ba119b3f8 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -929,8 +929,8 @@ bufinit(struct buf *buf, struct request *rq, struct bio *bio) memset(buf, 0, sizeof(*buf)); buf->rq = rq; buf->bio = bio; - buf->resid = bio->bi_size; - buf->sector = bio->bi_sector; + buf->resid = bio->bi_iter.bi_size; + buf->sector = bio->bi_iter.bi_sector; bio_pageinc(bio); buf->bv = bio_iovec(bio); buf->bv_resid = buf->bv->bv_len; @@ -1152,7 +1152,7 @@ aoe_end_request(struct aoedev *d, struct request *rq, int fastfail) do { bio = rq->bio; bok = !fastfail && test_bit(BIO_UPTODATE, &bio->bi_flags); - } while (__blk_end_request(rq, bok ? 0 : -EIO, bio->bi_size)); + } while (__blk_end_request(rq, bok ? 0 : -EIO, bio->bi_iter.bi_size)); /* cf. http://lkml.org/lkml/2006/10/31/28 */ if (!fastfail) diff --git a/drivers/block/brd.c b/drivers/block/brd.c index d91f1a56e861..66f5aaae15a2 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -333,13 +333,13 @@ static void brd_make_request(struct request_queue *q, struct bio *bio) int i; int err = -EIO; - sector = bio->bi_sector; + sector = bio->bi_iter.bi_sector; if (bio_end_sector(bio) > get_capacity(bdev->bd_disk)) goto out; if (unlikely(bio->bi_rw & REQ_DISCARD)) { err = 0; - discard_from_brd(brd, sector, bio->bi_size); + discard_from_brd(brd, sector, bio->bi_iter.bi_size); goto out; } diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 28c73ca320a8..a9b13f2cc420 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -159,7 +159,7 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev, bio = bio_alloc_drbd(GFP_NOIO); bio->bi_bdev = bdev->md_bdev; - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; err = -EIO; if (bio_add_page(bio, page, size, 0) != size) goto out; diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index b12c11ec4bd2..597f111df67b 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -1028,7 +1028,7 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must } else page = b->bm_pages[page_nr]; bio->bi_bdev = mdev->ldev->md_bdev; - bio->bi_sector = on_disk_sector; + bio->bi_iter.bi_sector = on_disk_sector; /* bio_add_page of a single page to an empty bio will always succeed, * according to api. Do we want to assert that? */ bio_add_page(bio, page, len, 0); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 6fa6673b36b3..5326c22cdb9d 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1333,7 +1333,7 @@ next_bio: goto fail; } /* > peer_req->i.sector, unless this is the first bio */ - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_bdev = mdev->ldev->backing_bdev; bio->bi_rw = rw; bio->bi_private = peer_req; @@ -1353,7 +1353,7 @@ next_bio: dev_err(DEV, "bio_add_page failed for len=%u, " "bi_vcnt=0 (bi_sector=%llu)\n", - len, (unsigned long long)bio->bi_sector); + len, (uint64_t)bio->bi_iter.bi_sector); err = -ENOSPC; goto fail; } @@ -1615,7 +1615,7 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, mdev->recv_cnt += data_size>>9; bio = req->master_bio; - D_ASSERT(sector == bio->bi_sector); + D_ASSERT(sector == bio->bi_iter.bi_sector); bio_for_each_segment(bvec, bio, i) { void *mapped = kmap(bvec->bv_page) + bvec->bv_offset; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index fec7bef44994..104a040f24de 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -77,8 +77,8 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev, req->epoch = 0; drbd_clear_interval(&req->i); - req->i.sector = bio_src->bi_sector; - req->i.size = bio_src->bi_size; + req->i.sector = bio_src->bi_iter.bi_sector; + req->i.size = bio_src->bi_iter.bi_size; req->i.local = true; req->i.waiting = false; @@ -1280,7 +1280,7 @@ void drbd_make_request(struct request_queue *q, struct bio *bio) /* * what we "blindly" assume: */ - D_ASSERT(IS_ALIGNED(bio->bi_size, 512)); + D_ASSERT(IS_ALIGNED(bio->bi_iter.bi_size, 512)); inc_ap_bio(mdev); __drbd_make_request(mdev, bio, start_time); diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 978cb1addc98..28e15d91197a 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -269,7 +269,7 @@ static inline void drbd_req_make_private_bio(struct drbd_request *req, struct bi /* Short lived temporary struct on the stack. * We could squirrel the error to be returned into - * bio->bi_size, or similar. But that would be too ugly. */ + * bio->bi_iter.bi_size, or similar. But that would be too ugly. */ struct bio_and_error { struct bio *bio; int error; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 000abe2f105c..6a86fe7b730f 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3775,9 +3775,9 @@ static int __floppy_read_block_0(struct block_device *bdev) bio_vec.bv_len = size; bio_vec.bv_offset = 0; bio.bi_vcnt = 1; - bio.bi_size = size; + bio.bi_iter.bi_size = size; bio.bi_bdev = bdev; - bio.bi_sector = 0; + bio.bi_iter.bi_sector = 0; bio.bi_flags = (1 << BIO_QUIET); init_completion(&complete); bio.bi_private = &complete; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index c8dac7305244..f5e39989adde 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -415,7 +415,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio) loff_t pos; int ret; - pos = ((loff_t) bio->bi_sector << 9) + lo->lo_offset; + pos = ((loff_t) bio->bi_iter.bi_sector << 9) + lo->lo_offset; if (bio_rw(bio) == WRITE) { struct file *file = lo->lo_backing_file; @@ -444,7 +444,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio) goto out; } ret = file->f_op->fallocate(file, mode, pos, - bio->bi_size); + bio->bi_iter.bi_size); if (unlikely(ret && ret != -EINVAL && ret != -EOPNOTSUPP)) ret = -EIO; diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 050c71267f14..69e9eb5a6b34 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -3993,7 +3993,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) } if (unlikely(bio->bi_rw & REQ_DISCARD)) { - bio_endio(bio, mtip_send_trim(dd, bio->bi_sector, + bio_endio(bio, mtip_send_trim(dd, bio->bi_iter.bi_sector, bio_sectors(bio))); return; } @@ -4006,7 +4006,8 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) if (bio_data_dir(bio) == WRITE && bio_sectors(bio) <= 64 && dd->unal_qdepth) { - if (bio->bi_sector % 8 != 0) /* Unaligned on 4k boundaries */ + if (bio->bi_iter.bi_sector % 8 != 0) + /* Unaligned on 4k boundaries */ unaligned = 1; else if (bio_sectors(bio) % 8 != 0) /* Aligned but not 4k/8k */ unaligned = 1; @@ -4035,7 +4036,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) /* Issue the read/write. */ mtip_hw_submit_io(dd, - bio->bi_sector, + bio->bi_iter.bi_sector, bio_sectors(bio), nents, tag, diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 26d03fa0bf26..53d217381873 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -468,7 +468,7 @@ static struct nvme_bio_pair *nvme_bio_split(struct bio *bio, int idx, { struct nvme_bio_pair *bp; - BUG_ON(len > bio->bi_size); + BUG_ON(len > bio->bi_iter.bi_size); BUG_ON(idx > bio->bi_vcnt); bp = kmalloc(sizeof(*bp), GFP_ATOMIC); @@ -479,11 +479,11 @@ static struct nvme_bio_pair *nvme_bio_split(struct bio *bio, int idx, bp->b1 = *bio; bp->b2 = *bio; - bp->b1.bi_size = len; - bp->b2.bi_size -= len; + bp->b1.bi_iter.bi_size = len; + bp->b2.bi_iter.bi_size -= len; bp->b1.bi_vcnt = idx; - bp->b2.bi_idx = idx; - bp->b2.bi_sector += len >> 9; + bp->b2.bi_iter.bi_idx = idx; + bp->b2.bi_iter.bi_sector += len >> 9; if (offset) { bp->bv1 = kmalloc(bio->bi_max_vecs * sizeof(struct bio_vec), @@ -552,11 +552,12 @@ static int nvme_map_bio(struct nvme_queue *nvmeq, struct nvme_iod *iod, { struct bio_vec *bvec, *bvprv = NULL; struct scatterlist *sg = NULL; - int i, length = 0, nsegs = 0, split_len = bio->bi_size; + int i, length = 0, nsegs = 0, split_len = bio->bi_iter.bi_size; if (nvmeq->dev->stripe_size) split_len = nvmeq->dev->stripe_size - - ((bio->bi_sector << 9) & (nvmeq->dev->stripe_size - 1)); + ((bio->bi_iter.bi_sector << 9) & + (nvmeq->dev->stripe_size - 1)); sg_init_table(iod->sg, psegs); bio_for_each_segment(bvec, bio, i) { @@ -584,7 +585,7 @@ static int nvme_map_bio(struct nvme_queue *nvmeq, struct nvme_iod *iod, if (dma_map_sg(nvmeq->q_dmadev, iod->sg, iod->nents, dma_dir) == 0) return -ENOMEM; - BUG_ON(length != bio->bi_size); + BUG_ON(length != bio->bi_iter.bi_size); return length; } @@ -608,8 +609,8 @@ static int nvme_submit_discard(struct nvme_queue *nvmeq, struct nvme_ns *ns, iod->npages = 0; range->cattr = cpu_to_le32(0); - range->nlb = cpu_to_le32(bio->bi_size >> ns->lba_shift); - range->slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_sector)); + range->nlb = cpu_to_le32(bio->bi_iter.bi_size >> ns->lba_shift); + range->slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_iter.bi_sector)); memset(cmnd, 0, sizeof(*cmnd)); cmnd->dsm.opcode = nvme_cmd_dsm; @@ -674,7 +675,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns, } result = -ENOMEM; - iod = nvme_alloc_iod(psegs, bio->bi_size, GFP_ATOMIC); + iod = nvme_alloc_iod(psegs, bio->bi_iter.bi_size, GFP_ATOMIC); if (!iod) goto nomem; iod->private = bio; @@ -723,7 +724,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns, cmnd->rw.nsid = cpu_to_le32(ns->ns_id); length = nvme_setup_prps(nvmeq->dev, &cmnd->common, iod, length, GFP_ATOMIC); - cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_sector)); + cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_iter.bi_sector)); cmnd->rw.length = cpu_to_le16((length >> ns->lba_shift) - 1); cmnd->rw.control = cpu_to_le16(control); cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index ff8668c5efb1..ce986bacf7b7 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -651,7 +651,7 @@ static struct pkt_rb_node *pkt_rbtree_find(struct pktcdvd_device *pd, sector_t s for (;;) { tmp = rb_entry(n, struct pkt_rb_node, rb_node); - if (s <= tmp->bio->bi_sector) + if (s <= tmp->bio->bi_iter.bi_sector) next = n->rb_left; else next = n->rb_right; @@ -660,12 +660,12 @@ static struct pkt_rb_node *pkt_rbtree_find(struct pktcdvd_device *pd, sector_t s n = next; } - if (s > tmp->bio->bi_sector) { + if (s > tmp->bio->bi_iter.bi_sector) { tmp = pkt_rbtree_next(tmp); if (!tmp) return NULL; } - BUG_ON(s > tmp->bio->bi_sector); + BUG_ON(s > tmp->bio->bi_iter.bi_sector); return tmp; } @@ -676,13 +676,13 @@ static void pkt_rbtree_insert(struct pktcdvd_device *pd, struct pkt_rb_node *nod { struct rb_node **p = &pd->bio_queue.rb_node; struct rb_node *parent = NULL; - sector_t s = node->bio->bi_sector; + sector_t s = node->bio->bi_iter.bi_sector; struct pkt_rb_node *tmp; while (*p) { parent = *p; tmp = rb_entry(parent, struct pkt_rb_node, rb_node); - if (s < tmp->bio->bi_sector) + if (s < tmp->bio->bi_iter.bi_sector) p = &(*p)->rb_left; else p = &(*p)->rb_right; @@ -857,7 +857,8 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd) spin_lock(&pd->iosched.lock); bio = bio_list_peek(&pd->iosched.write_queue); spin_unlock(&pd->iosched.lock); - if (bio && (bio->bi_sector == pd->iosched.last_write)) + if (bio && (bio->bi_iter.bi_sector == + pd->iosched.last_write)) need_write_seek = 0; if (need_write_seek && reads_queued) { if (atomic_read(&pd->cdrw.pending_bios) > 0) { @@ -888,7 +889,8 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd) continue; if (bio_data_dir(bio) == READ) - pd->iosched.successive_reads += bio->bi_size >> 10; + pd->iosched.successive_reads += + bio->bi_iter.bi_size >> 10; else { pd->iosched.successive_reads = 0; pd->iosched.last_write = bio_end_sector(bio); @@ -978,7 +980,7 @@ static void pkt_end_io_read(struct bio *bio, int err) pkt_dbg(2, pd, "bio=%p sec0=%llx sec=%llx err=%d\n", bio, (unsigned long long)pkt->sector, - (unsigned long long)bio->bi_sector, err); + (unsigned long long)bio->bi_iter.bi_sector, err); if (err) atomic_inc(&pkt->io_errors); @@ -1026,8 +1028,9 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) memset(written, 0, sizeof(written)); spin_lock(&pkt->lock); bio_list_for_each(bio, &pkt->orig_bios) { - int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9); - int num_frames = bio->bi_size / CD_FRAMESIZE; + int first_frame = (bio->bi_iter.bi_sector - pkt->sector) / + (CD_FRAMESIZE >> 9); + int num_frames = bio->bi_iter.bi_size / CD_FRAMESIZE; pd->stats.secs_w += num_frames * (CD_FRAMESIZE >> 9); BUG_ON(first_frame < 0); BUG_ON(first_frame + num_frames > pkt->frames); @@ -1053,7 +1056,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) bio = pkt->r_bios[f]; bio_reset(bio); - bio->bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9); + bio->bi_iter.bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9); bio->bi_bdev = pd->bdev; bio->bi_end_io = pkt_end_io_read; bio->bi_private = pkt; @@ -1150,8 +1153,8 @@ static int pkt_start_recovery(struct packet_data *pkt) bio_reset(pkt->bio); pkt->bio->bi_bdev = pd->bdev; pkt->bio->bi_rw = REQ_WRITE; - pkt->bio->bi_sector = new_sector; - pkt->bio->bi_size = pkt->frames * CD_FRAMESIZE; + pkt->bio->bi_iter.bi_sector = new_sector; + pkt->bio->bi_iter.bi_size = pkt->frames * CD_FRAMESIZE; pkt->bio->bi_vcnt = pkt->frames; pkt->bio->bi_end_io = pkt_end_io_packet_write; @@ -1213,7 +1216,7 @@ static int pkt_handle_queue(struct pktcdvd_device *pd) node = first_node; while (node) { bio = node->bio; - zone = get_zone(bio->bi_sector, pd); + zone = get_zone(bio->bi_iter.bi_sector, pd); list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) { if (p->sector == zone) { bio = NULL; @@ -1252,14 +1255,14 @@ try_next_bio: pkt_dbg(2, pd, "looking for zone %llx\n", (unsigned long long)zone); while ((node = pkt_rbtree_find(pd, zone)) != NULL) { bio = node->bio; - pkt_dbg(2, pd, "found zone=%llx\n", - (unsigned long long)get_zone(bio->bi_sector, pd)); - if (get_zone(bio->bi_sector, pd) != zone) + pkt_dbg(2, pd, "found zone=%llx\n", (unsigned long long) + get_zone(bio->bi_iter.bi_sector, pd)); + if (get_zone(bio->bi_iter.bi_sector, pd) != zone) break; pkt_rbtree_erase(pd, node); spin_lock(&pkt->lock); bio_list_add(&pkt->orig_bios, bio); - pkt->write_size += bio->bi_size / CD_FRAMESIZE; + pkt->write_size += bio->bi_iter.bi_size / CD_FRAMESIZE; spin_unlock(&pkt->lock); } /* check write congestion marks, and if bio_queue_size is @@ -1293,7 +1296,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) struct bio_vec *bvec = pkt->w_bio->bi_io_vec; bio_reset(pkt->w_bio); - pkt->w_bio->bi_sector = pkt->sector; + pkt->w_bio->bi_iter.bi_sector = pkt->sector; pkt->w_bio->bi_bdev = pd->bdev; pkt->w_bio->bi_end_io = pkt_end_io_packet_write; pkt->w_bio->bi_private = pkt; @@ -2370,20 +2373,20 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) if (!test_bit(PACKET_WRITABLE, &pd->flags)) { pkt_notice(pd, "WRITE for ro device (%llu)\n", - (unsigned long long)bio->bi_sector); + (unsigned long long)bio->bi_iter.bi_sector); goto end_io; } - if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) { + if (!bio->bi_iter.bi_size || (bio->bi_iter.bi_size % CD_FRAMESIZE)) { pkt_err(pd, "wrong bio size\n"); goto end_io; } blk_queue_bounce(q, &bio); - zone = get_zone(bio->bi_sector, pd); + zone = get_zone(bio->bi_iter.bi_sector, pd); pkt_dbg(2, pd, "start = %6llx stop = %6llx\n", - (unsigned long long)bio->bi_sector, + (unsigned long long)bio->bi_iter.bi_sector, (unsigned long long)bio_end_sector(bio)); /* Check if we have to split the bio */ @@ -2395,7 +2398,7 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) last_zone = get_zone(bio_end_sector(bio) - 1, pd); if (last_zone != zone) { BUG_ON(last_zone != zone + pd->settings.size); - first_sectors = last_zone - bio->bi_sector; + first_sectors = last_zone - bio->bi_iter.bi_sector; bp = bio_split(bio, first_sectors); BUG_ON(!bp); pkt_make_request(q, &bp->bio1); @@ -2417,7 +2420,8 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) if ((pkt->state == PACKET_WAITING_STATE) || (pkt->state == PACKET_READ_WAIT_STATE)) { bio_list_add(&pkt->orig_bios, bio); - pkt->write_size += bio->bi_size / CD_FRAMESIZE; + pkt->write_size += + bio->bi_iter.bi_size / CD_FRAMESIZE; if ((pkt->write_size >= pkt->frames) && (pkt->state == PACKET_WAITING_STATE)) { atomic_inc(&pkt->run_sm); diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index d754a88d7585..464be78a0836 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -104,7 +104,7 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, dev_dbg(&dev->sbd.core, "%s:%u: bio %u: %u segs %u sectors from %lu\n", __func__, __LINE__, i, bio_segments(iter.bio), - bio_sectors(iter.bio), iter.bio->bi_sector); + bio_sectors(iter.bio), iter.bio->bi_iter.bi_sector); size = bvec->bv_len; buf = bvec_kmap_irq(bvec, &flags); diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 06a2e53e5f37..320bbfc9b902 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -553,7 +553,7 @@ static struct bio *ps3vram_do_bio(struct ps3_system_bus_device *dev, struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); int write = bio_data_dir(bio) == WRITE; const char *op = write ? "write" : "read"; - loff_t offset = bio->bi_sector << 9; + loff_t offset = bio->bi_iter.bi_sector << 9; int error = 0; struct bio_vec *bvec; unsigned int i; diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index cb1db2979d3d..a8f4fe2d4d1b 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1183,14 +1183,14 @@ static struct bio *bio_clone_range(struct bio *bio_src, /* Handle the easy case for the caller */ - if (!offset && len == bio_src->bi_size) + if (!offset && len == bio_src->bi_iter.bi_size) return bio_clone(bio_src, gfpmask); if (WARN_ON_ONCE(!len)) return NULL; - if (WARN_ON_ONCE(len > bio_src->bi_size)) + if (WARN_ON_ONCE(len > bio_src->bi_iter.bi_size)) return NULL; - if (WARN_ON_ONCE(offset > bio_src->bi_size - len)) + if (WARN_ON_ONCE(offset > bio_src->bi_iter.bi_size - len)) return NULL; /* Find first affected segment... */ @@ -1220,7 +1220,8 @@ static struct bio *bio_clone_range(struct bio *bio_src, return NULL; /* ENOMEM */ bio->bi_bdev = bio_src->bi_bdev; - bio->bi_sector = bio_src->bi_sector + (offset >> SECTOR_SHIFT); + bio->bi_iter.bi_sector = bio_src->bi_iter.bi_sector + + (offset >> SECTOR_SHIFT); bio->bi_rw = bio_src->bi_rw; bio->bi_flags |= 1 << BIO_CLONED; @@ -1239,8 +1240,7 @@ static struct bio *bio_clone_range(struct bio *bio_src, } bio->bi_vcnt = vcnt; - bio->bi_size = len; - bio->bi_idx = 0; + bio->bi_iter.bi_size = len; return bio; } @@ -1271,7 +1271,7 @@ static struct bio *bio_chain_clone_range(struct bio **bio_src, /* Build up a chain of clone bios up to the limit */ - if (!bi || off >= bi->bi_size || !len) + if (!bi || off >= bi->bi_iter.bi_size || !len) return NULL; /* Nothing to clone */ end = &chain; @@ -1283,7 +1283,7 @@ static struct bio *bio_chain_clone_range(struct bio **bio_src, rbd_warn(NULL, "bio_chain exhausted with %u left", len); goto out_err; /* EINVAL; ran out of bio's */ } - bi_size = min_t(unsigned int, bi->bi_size - off, len); + bi_size = min_t(unsigned int, bi->bi_iter.bi_size - off, len); bio = bio_clone_range(bi, off, bi_size, gfpmask); if (!bio) goto out_err; /* ENOMEM */ @@ -1292,7 +1292,7 @@ static struct bio *bio_chain_clone_range(struct bio **bio_src, end = &bio->bi_next; off += bi_size; - if (off == bi->bi_size) { + if (off == bi->bi_iter.bi_size) { bi = bi->bi_next; off = 0; } @@ -2186,7 +2186,8 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request, if (type == OBJ_REQUEST_BIO) { bio_list = data_desc; - rbd_assert(img_offset == bio_list->bi_sector << SECTOR_SHIFT); + rbd_assert(img_offset == + bio_list->bi_iter.bi_sector << SECTOR_SHIFT); } else { rbd_assert(type == OBJ_REQUEST_PAGES); pages = data_desc; diff --git a/drivers/block/rsxx/dev.c b/drivers/block/rsxx/dev.c index 2284f5d3a54a..2839d37e5af7 100644 --- a/drivers/block/rsxx/dev.c +++ b/drivers/block/rsxx/dev.c @@ -174,7 +174,7 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio) if (!card) goto req_err; - if (bio->bi_sector + (bio->bi_size >> 9) > get_capacity(card->gendisk)) + if (bio_end_sector(bio) > get_capacity(card->gendisk)) goto req_err; if (unlikely(card->halt)) { @@ -187,7 +187,7 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio) goto req_err; } - if (bio->bi_size == 0) { + if (bio->bi_iter.bi_size == 0) { dev_err(CARD_TO_DEV(card), "size zero BIO!\n"); goto req_err; } @@ -208,7 +208,7 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio) dev_dbg(CARD_TO_DEV(card), "BIO[%c]: meta: %p addr8: x%llx size: %d\n", bio_data_dir(bio) ? 'W' : 'R', bio_meta, - (u64)bio->bi_sector << 9, bio->bi_size); + (u64)bio->bi_iter.bi_sector << 9, bio->bi_iter.bi_size); st = rsxx_dma_queue_bio(card, bio, &bio_meta->pending_dmas, bio_dma_done_cb, bio_meta); diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index fc88ba3e1bd2..3716633be3c2 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -696,7 +696,7 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, int st; int i; - addr8 = bio->bi_sector << 9; /* sectors are 512 bytes */ + addr8 = bio->bi_iter.bi_sector << 9; /* sectors are 512 bytes */ atomic_set(n_dmas, 0); for (i = 0; i < card->n_targets; i++) { @@ -705,7 +705,7 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, } if (bio->bi_rw & REQ_DISCARD) { - bv_len = bio->bi_size; + bv_len = bio->bi_iter.bi_size; while (bv_len > 0) { tgt = rsxx_get_dma_tgt(card, addr8); diff --git a/drivers/block/umem.c b/drivers/block/umem.c index ad70868f8a96..dab4f1afeae9 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -352,8 +352,8 @@ static int add_bio(struct cardinfo *card) bio = card->currentbio; if (!bio && card->bio) { card->currentbio = card->bio; - card->current_idx = card->bio->bi_idx; - card->current_sector = card->bio->bi_sector; + card->current_idx = card->bio->bi_iter.bi_idx; + card->current_sector = card->bio->bi_iter.bi_sector; card->bio = card->bio->bi_next; if (card->bio == NULL) card->biotail = &card->bio; @@ -451,7 +451,7 @@ static void process_page(unsigned long data) if (page->idx >= bio->bi_vcnt) { page->bio = bio->bi_next; if (page->bio) - page->idx = page->bio->bi_idx; + page->idx = page->bio->bi_iter.bi_idx; } pci_unmap_page(card->dev, desc->data_dma_handle, @@ -532,7 +532,8 @@ static void mm_make_request(struct request_queue *q, struct bio *bio) { struct cardinfo *card = q->queuedata; pr_debug("mm_make_request %llu %u\n", - (unsigned long long)bio->bi_sector, bio->bi_size); + (unsigned long long)bio->bi_iter.bi_sector, + bio->bi_iter.bi_size); spin_lock_irq(&card->lock); *card->biotail = bio; diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 6620b73d0490..4b97b86da926 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -1257,7 +1257,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, bio->bi_bdev = preq.bdev; bio->bi_private = pending_req; bio->bi_end_io = end_block_io_op; - bio->bi_sector = preq.sector_number; + bio->bi_iter.bi_sector = preq.sector_number; } preq.sector_number += seg[i].nsec; diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 432db1b59b00..80e86307dd4b 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1547,7 +1547,7 @@ static int blkif_recover(struct blkfront_info *info) for (i = 0; i < pending; i++) { offset = (i * segs * PAGE_SIZE) >> 9; size = min((unsigned int)(segs * PAGE_SIZE) >> 9, - (unsigned int)(bio->bi_size >> 9) - offset); + (unsigned int)bio_sectors(bio) - offset); cloned_bio = bio_clone(bio, GFP_NOIO); BUG_ON(cloned_bio == NULL); bio_trim(cloned_bio, offset, size); diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 5e2765aadce1..038a6d2aced3 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -299,7 +299,7 @@ void bch_btree_node_read(struct btree *b) bio = bch_bbio_alloc(b->c); bio->bi_rw = REQ_META|READ_SYNC; - bio->bi_size = KEY_SIZE(&b->key) << 9; + bio->bi_iter.bi_size = KEY_SIZE(&b->key) << 9; bio->bi_end_io = btree_node_read_endio; bio->bi_private = &cl; @@ -395,7 +395,7 @@ static void do_btree_node_write(struct btree *b) b->bio->bi_end_io = btree_node_write_endio; b->bio->bi_private = cl; b->bio->bi_rw = REQ_META|WRITE_SYNC|REQ_FUA; - b->bio->bi_size = set_blocks(i, b->c) * block_bytes(b->c); + b->bio->bi_iter.bi_size = set_blocks(i, b->c) * block_bytes(b->c); bch_bio_map(b->bio, i); /* diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c index 264fcfbd6290..92b3fd468a03 100644 --- a/drivers/md/bcache/debug.c +++ b/drivers/md/bcache/debug.c @@ -195,7 +195,7 @@ void bch_data_verify(struct cached_dev *dc, struct bio *bio) dc->disk.c, "verify failed at dev %s sector %llu", bdevname(dc->bdev, name), - (uint64_t) bio->bi_sector); + (uint64_t) bio->bi_iter.bi_sector); kunmap_atomic(p1); } diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index 9056632995b1..cc4ba2da5fb6 100644 --- a/drivers/md/bcache/io.c +++ b/drivers/md/bcache/io.c @@ -21,18 +21,18 @@ static void bch_bi_idx_hack_endio(struct bio *bio, int error) static void bch_generic_make_request_hack(struct bio *bio) { - if (bio->bi_idx) { + if (bio->bi_iter.bi_idx) { struct bio *clone = bio_alloc(GFP_NOIO, bio_segments(bio)); memcpy(clone->bi_io_vec, bio_iovec(bio), bio_segments(bio) * sizeof(struct bio_vec)); - clone->bi_sector = bio->bi_sector; + clone->bi_iter.bi_sector = bio->bi_iter.bi_sector; clone->bi_bdev = bio->bi_bdev; clone->bi_rw = bio->bi_rw; clone->bi_vcnt = bio_segments(bio); - clone->bi_size = bio->bi_size; + clone->bi_iter.bi_size = bio->bi_iter.bi_size; clone->bi_private = bio; clone->bi_end_io = bch_bi_idx_hack_endio; @@ -72,7 +72,7 @@ static void bch_generic_make_request_hack(struct bio *bio) struct bio *bch_bio_split(struct bio *bio, int sectors, gfp_t gfp, struct bio_set *bs) { - unsigned idx = bio->bi_idx, vcnt = 0, nbytes = sectors << 9; + unsigned idx = bio->bi_iter.bi_idx, vcnt = 0, nbytes = sectors << 9; struct bio_vec *bv; struct bio *ret = NULL; @@ -90,7 +90,7 @@ struct bio *bch_bio_split(struct bio *bio, int sectors, } bio_for_each_segment(bv, bio, idx) { - vcnt = idx - bio->bi_idx; + vcnt = idx - bio->bi_iter.bi_idx; if (!nbytes) { ret = bio_alloc_bioset(gfp, vcnt, bs); @@ -119,15 +119,15 @@ struct bio *bch_bio_split(struct bio *bio, int sectors, } out: ret->bi_bdev = bio->bi_bdev; - ret->bi_sector = bio->bi_sector; - ret->bi_size = sectors << 9; + ret->bi_iter.bi_sector = bio->bi_iter.bi_sector; + ret->bi_iter.bi_size = sectors << 9; ret->bi_rw = bio->bi_rw; ret->bi_vcnt = vcnt; ret->bi_max_vecs = vcnt; - bio->bi_sector += sectors; - bio->bi_size -= sectors << 9; - bio->bi_idx = idx; + bio->bi_iter.bi_sector += sectors; + bio->bi_iter.bi_size -= sectors << 9; + bio->bi_iter.bi_idx = idx; if (bio_integrity(bio)) { if (bio_integrity_clone(ret, bio, gfp)) { @@ -162,7 +162,7 @@ static unsigned bch_bio_max_sectors(struct bio *bio) bio_for_each_segment(bv, bio, i) { struct bvec_merge_data bvm = { .bi_bdev = bio->bi_bdev, - .bi_sector = bio->bi_sector, + .bi_sector = bio->bi_iter.bi_sector, .bi_size = ret << 9, .bi_rw = bio->bi_rw, }; @@ -272,8 +272,8 @@ void __bch_submit_bbio(struct bio *bio, struct cache_set *c) { struct bbio *b = container_of(bio, struct bbio, bio); - bio->bi_sector = PTR_OFFSET(&b->key, 0); - bio->bi_bdev = PTR_CACHE(c, &b->key, 0)->bdev; + bio->bi_iter.bi_sector = PTR_OFFSET(&b->key, 0); + bio->bi_bdev = PTR_CACHE(c, &b->key, 0)->bdev; b->submit_time_us = local_clock_us(); closure_bio_submit(bio, bio->bi_private, PTR_CACHE(c, &b->key, 0)); diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c index ecdaa671bd50..7eafdf09a0ae 100644 --- a/drivers/md/bcache/journal.c +++ b/drivers/md/bcache/journal.c @@ -51,10 +51,10 @@ reread: left = ca->sb.bucket_size - offset; len = min_t(unsigned, left, PAGE_SECTORS * 8); bio_reset(bio); - bio->bi_sector = bucket + offset; + bio->bi_iter.bi_sector = bucket + offset; bio->bi_bdev = ca->bdev; bio->bi_rw = READ; - bio->bi_size = len << 9; + bio->bi_iter.bi_size = len << 9; bio->bi_end_io = journal_read_endio; bio->bi_private = &cl; @@ -437,13 +437,13 @@ static void do_journal_discard(struct cache *ca) atomic_set(&ja->discard_in_flight, DISCARD_IN_FLIGHT); bio_init(bio); - bio->bi_sector = bucket_to_sector(ca->set, + bio->bi_iter.bi_sector = bucket_to_sector(ca->set, ca->sb.d[ja->discard_idx]); bio->bi_bdev = ca->bdev; bio->bi_rw = REQ_WRITE|REQ_DISCARD; bio->bi_max_vecs = 1; bio->bi_io_vec = bio->bi_inline_vecs; - bio->bi_size = bucket_bytes(ca); + bio->bi_iter.bi_size = bucket_bytes(ca); bio->bi_end_io = journal_discard_endio; closure_get(&ca->set->cl); @@ -608,10 +608,10 @@ static void journal_write_unlocked(struct closure *cl) atomic_long_add(sectors, &ca->meta_sectors_written); bio_reset(bio); - bio->bi_sector = PTR_OFFSET(k, i); + bio->bi_iter.bi_sector = PTR_OFFSET(k, i); bio->bi_bdev = ca->bdev; bio->bi_rw = REQ_WRITE|REQ_SYNC|REQ_META|REQ_FLUSH|REQ_FUA; - bio->bi_size = sectors << 9; + bio->bi_iter.bi_size = sectors << 9; bio->bi_end_io = journal_write_endio; bio->bi_private = w; diff --git a/drivers/md/bcache/movinggc.c b/drivers/md/bcache/movinggc.c index 7c1275e66025..581f95df8265 100644 --- a/drivers/md/bcache/movinggc.c +++ b/drivers/md/bcache/movinggc.c @@ -82,7 +82,7 @@ static void moving_init(struct moving_io *io) bio_get(bio); bio_set_prio(bio, IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)); - bio->bi_size = KEY_SIZE(&io->w->key) << 9; + bio->bi_iter.bi_size = KEY_SIZE(&io->w->key) << 9; bio->bi_max_vecs = DIV_ROUND_UP(KEY_SIZE(&io->w->key), PAGE_SECTORS); bio->bi_private = &io->cl; @@ -98,7 +98,7 @@ static void write_moving(struct closure *cl) if (!op->error) { moving_init(io); - io->bio.bio.bi_sector = KEY_START(&io->w->key); + io->bio.bio.bi_iter.bi_sector = KEY_START(&io->w->key); op->write_prio = 1; op->bio = &io->bio.bio; diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 78bab4154e97..47a9bbc75124 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -261,7 +261,7 @@ static void bch_data_invalidate(struct closure *cl) struct bio *bio = op->bio; pr_debug("invalidating %i sectors from %llu", - bio_sectors(bio), (uint64_t) bio->bi_sector); + bio_sectors(bio), (uint64_t) bio->bi_iter.bi_sector); while (bio_sectors(bio)) { unsigned sectors = min(bio_sectors(bio), @@ -270,11 +270,11 @@ static void bch_data_invalidate(struct closure *cl) if (bch_keylist_realloc(&op->insert_keys, 0, op->c)) goto out; - bio->bi_sector += sectors; - bio->bi_size -= sectors << 9; + bio->bi_iter.bi_sector += sectors; + bio->bi_iter.bi_size -= sectors << 9; bch_keylist_add(&op->insert_keys, - &KEY(op->inode, bio->bi_sector, sectors)); + &KEY(op->inode, bio->bi_iter.bi_sector, sectors)); } op->insert_data_done = true; @@ -364,7 +364,7 @@ static void bch_data_insert_start(struct closure *cl) k = op->insert_keys.top; bkey_init(k); SET_KEY_INODE(k, op->inode); - SET_KEY_OFFSET(k, bio->bi_sector); + SET_KEY_OFFSET(k, bio->bi_iter.bi_sector); if (!bch_alloc_sectors(op->c, k, bio_sectors(bio), op->write_point, op->write_prio, @@ -522,7 +522,7 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio) (bio->bi_rw & REQ_WRITE))) goto skip; - if (bio->bi_sector & (c->sb.block_size - 1) || + if (bio->bi_iter.bi_sector & (c->sb.block_size - 1) || bio_sectors(bio) & (c->sb.block_size - 1)) { pr_debug("skipping unaligned io"); goto skip; @@ -546,8 +546,8 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio) spin_lock(&dc->io_lock); - hlist_for_each_entry(i, iohash(dc, bio->bi_sector), hash) - if (i->last == bio->bi_sector && + hlist_for_each_entry(i, iohash(dc, bio->bi_iter.bi_sector), hash) + if (i->last == bio->bi_iter.bi_sector && time_before(jiffies, i->jiffies)) goto found; @@ -556,8 +556,8 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio) add_sequential(task); i->sequential = 0; found: - if (i->sequential + bio->bi_size > i->sequential) - i->sequential += bio->bi_size; + if (i->sequential + bio->bi_iter.bi_size > i->sequential) + i->sequential += bio->bi_iter.bi_size; i->last = bio_end_sector(bio); i->jiffies = jiffies + msecs_to_jiffies(5000); @@ -650,15 +650,15 @@ static int cache_lookup_fn(struct btree_op *op, struct btree *b, struct bkey *k) struct bkey *bio_key; unsigned ptr; - if (bkey_cmp(k, &KEY(s->iop.inode, bio->bi_sector, 0)) <= 0) + if (bkey_cmp(k, &KEY(s->iop.inode, bio->bi_iter.bi_sector, 0)) <= 0) return MAP_CONTINUE; if (KEY_INODE(k) != s->iop.inode || - KEY_START(k) > bio->bi_sector) { + KEY_START(k) > bio->bi_iter.bi_sector) { unsigned bio_sectors = bio_sectors(bio); unsigned sectors = KEY_INODE(k) == s->iop.inode ? min_t(uint64_t, INT_MAX, - KEY_START(k) - bio->bi_sector) + KEY_START(k) - bio->bi_iter.bi_sector) : INT_MAX; int ret = s->d->cache_miss(b, s, bio, sectors); @@ -681,13 +681,13 @@ static int cache_lookup_fn(struct btree_op *op, struct btree *b, struct bkey *k) s->read_dirty_data = true; n = bch_bio_split(bio, min_t(uint64_t, INT_MAX, - KEY_OFFSET(k) - bio->bi_sector), + KEY_OFFSET(k) - bio->bi_iter.bi_sector), GFP_NOIO, s->d->bio_split); bio_key = &container_of(n, struct bbio, bio)->key; bch_bkey_copy_single_ptr(bio_key, k, ptr); - bch_cut_front(&KEY(s->iop.inode, n->bi_sector, 0), bio_key); + bch_cut_front(&KEY(s->iop.inode, n->bi_iter.bi_sector, 0), bio_key); bch_cut_back(&KEY(s->iop.inode, bio_end_sector(n), 0), bio_key); n->bi_end_io = bch_cache_read_endio; @@ -714,7 +714,7 @@ static void cache_lookup(struct closure *cl) struct bio *bio = &s->bio.bio; int ret = bch_btree_map_keys(&s->op, s->iop.c, - &KEY(s->iop.inode, bio->bi_sector, 0), + &KEY(s->iop.inode, bio->bi_iter.bi_sector, 0), cache_lookup_fn, MAP_END_KEY); if (ret == -EAGAIN) continue_at(cl, cache_lookup, bcache_wq); @@ -872,9 +872,9 @@ static void cached_dev_read_done(struct closure *cl) if (s->iop.bio) { bio_reset(s->iop.bio); - s->iop.bio->bi_sector = s->cache_miss->bi_sector; + s->iop.bio->bi_iter.bi_sector = s->cache_miss->bi_iter.bi_sector; s->iop.bio->bi_bdev = s->cache_miss->bi_bdev; - s->iop.bio->bi_size = s->insert_bio_sectors << 9; + s->iop.bio->bi_iter.bi_size = s->insert_bio_sectors << 9; bch_bio_map(s->iop.bio, NULL); bio_copy_data(s->cache_miss, s->iop.bio); @@ -937,7 +937,7 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s, s->insert_bio_sectors = min(sectors, bio_sectors(bio) + reada); s->iop.replace_key = KEY(s->iop.inode, - bio->bi_sector + s->insert_bio_sectors, + bio->bi_iter.bi_sector + s->insert_bio_sectors, s->insert_bio_sectors); ret = bch_btree_insert_check_key(b, &s->op, &s->iop.replace_key); @@ -957,9 +957,9 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s, if (!cache_bio) goto out_submit; - cache_bio->bi_sector = miss->bi_sector; - cache_bio->bi_bdev = miss->bi_bdev; - cache_bio->bi_size = s->insert_bio_sectors << 9; + cache_bio->bi_iter.bi_sector = miss->bi_iter.bi_sector; + cache_bio->bi_bdev = miss->bi_bdev; + cache_bio->bi_iter.bi_size = s->insert_bio_sectors << 9; cache_bio->bi_end_io = request_endio; cache_bio->bi_private = &s->cl; @@ -1009,7 +1009,7 @@ static void cached_dev_write(struct cached_dev *dc, struct search *s) { struct closure *cl = &s->cl; struct bio *bio = &s->bio.bio; - struct bkey start = KEY(dc->disk.id, bio->bi_sector, 0); + struct bkey start = KEY(dc->disk.id, bio->bi_iter.bi_sector, 0); struct bkey end = KEY(dc->disk.id, bio_end_sector(bio), 0); bch_keybuf_check_overlapping(&s->iop.c->moving_gc_keys, &start, &end); @@ -1104,13 +1104,13 @@ static void cached_dev_make_request(struct request_queue *q, struct bio *bio) part_stat_unlock(); bio->bi_bdev = dc->bdev; - bio->bi_sector += dc->sb.data_offset; + bio->bi_iter.bi_sector += dc->sb.data_offset; if (cached_dev_get(dc)) { s = search_alloc(bio, d); trace_bcache_request_start(s->d, bio); - if (!bio->bi_size) { + if (!bio->bi_iter.bi_size) { /* * can't call bch_journal_meta from under * generic_make_request @@ -1197,9 +1197,9 @@ static int flash_dev_cache_miss(struct btree *b, struct search *s, sectors -= j; } - bio_advance(bio, min(sectors << 9, bio->bi_size)); + bio_advance(bio, min(sectors << 9, bio->bi_iter.bi_size)); - if (!bio->bi_size) + if (!bio->bi_iter.bi_size) return MAP_DONE; return MAP_CONTINUE; @@ -1233,7 +1233,7 @@ static void flash_dev_make_request(struct request_queue *q, struct bio *bio) trace_bcache_request_start(s->d, bio); - if (!bio->bi_size) { + if (!bio->bi_iter.bi_size) { /* * can't call bch_journal_meta from under * generic_make_request @@ -1243,7 +1243,7 @@ static void flash_dev_make_request(struct request_queue *q, struct bio *bio) bcache_wq); } else if (rw) { bch_keybuf_check_overlapping(&s->iop.c->moving_gc_keys, - &KEY(d->id, bio->bi_sector, 0), + &KEY(d->id, bio->bi_iter.bi_sector, 0), &KEY(d->id, bio_end_sector(bio), 0)); s->iop.bypass = (bio->bi_rw & REQ_DISCARD) != 0; diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 1d9ee67d14ec..60fb6044b953 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -233,9 +233,9 @@ static void __write_super(struct cache_sb *sb, struct bio *bio) struct cache_sb *out = page_address(bio->bi_io_vec[0].bv_page); unsigned i; - bio->bi_sector = SB_SECTOR; - bio->bi_rw = REQ_SYNC|REQ_META; - bio->bi_size = SB_SIZE; + bio->bi_iter.bi_sector = SB_SECTOR; + bio->bi_rw = REQ_SYNC|REQ_META; + bio->bi_iter.bi_size = SB_SIZE; bch_bio_map(bio, NULL); out->offset = cpu_to_le64(sb->offset); @@ -347,7 +347,7 @@ static void uuid_io(struct cache_set *c, unsigned long rw, struct bio *bio = bch_bbio_alloc(c); bio->bi_rw = REQ_SYNC|REQ_META|rw; - bio->bi_size = KEY_SIZE(k) << 9; + bio->bi_iter.bi_size = KEY_SIZE(k) << 9; bio->bi_end_io = uuid_endio; bio->bi_private = cl; @@ -503,10 +503,10 @@ static void prio_io(struct cache *ca, uint64_t bucket, unsigned long rw) closure_init_stack(cl); - bio->bi_sector = bucket * ca->sb.bucket_size; - bio->bi_bdev = ca->bdev; - bio->bi_rw = REQ_SYNC|REQ_META|rw; - bio->bi_size = bucket_bytes(ca); + bio->bi_iter.bi_sector = bucket * ca->sb.bucket_size; + bio->bi_bdev = ca->bdev; + bio->bi_rw = REQ_SYNC|REQ_META|rw; + bio->bi_iter.bi_size = bucket_bytes(ca); bio->bi_end_io = prio_endio; bio->bi_private = ca; diff --git a/drivers/md/bcache/util.c b/drivers/md/bcache/util.c index 462214eeacbe..c57621e49dc0 100644 --- a/drivers/md/bcache/util.c +++ b/drivers/md/bcache/util.c @@ -218,10 +218,10 @@ uint64_t bch_next_delay(struct bch_ratelimit *d, uint64_t done) void bch_bio_map(struct bio *bio, void *base) { - size_t size = bio->bi_size; + size_t size = bio->bi_iter.bi_size; struct bio_vec *bv = bio->bi_io_vec; - BUG_ON(!bio->bi_size); + BUG_ON(!bio->bi_iter.bi_size); BUG_ON(bio->bi_vcnt); bv->bv_offset = base ? ((unsigned long) base) % PAGE_SIZE : 0; diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index 99053b1251be..04657e93f4fd 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -113,7 +113,7 @@ static void dirty_init(struct keybuf_key *w) if (!io->dc->writeback_percent) bio_set_prio(bio, IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)); - bio->bi_size = KEY_SIZE(&w->key) << 9; + bio->bi_iter.bi_size = KEY_SIZE(&w->key) << 9; bio->bi_max_vecs = DIV_ROUND_UP(KEY_SIZE(&w->key), PAGE_SECTORS); bio->bi_private = w; bio->bi_io_vec = bio->bi_inline_vecs; @@ -186,7 +186,7 @@ static void write_dirty(struct closure *cl) dirty_init(w); io->bio.bi_rw = WRITE; - io->bio.bi_sector = KEY_START(&w->key); + io->bio.bi_iter.bi_sector = KEY_START(&w->key); io->bio.bi_bdev = io->dc->bdev; io->bio.bi_end_io = dirty_endio; @@ -255,7 +255,7 @@ static void read_dirty(struct cached_dev *dc) io->dc = dc; dirty_init(w); - io->bio.bi_sector = PTR_OFFSET(&w->key, 0); + io->bio.bi_iter.bi_sector = PTR_OFFSET(&w->key, 0); io->bio.bi_bdev = PTR_CACHE(dc->disk.c, &w->key, 0)->bdev; io->bio.bi_rw = READ; diff --git a/drivers/md/bcache/writeback.h b/drivers/md/bcache/writeback.h index c9ddcf4614b9..e2f8598937ac 100644 --- a/drivers/md/bcache/writeback.h +++ b/drivers/md/bcache/writeback.h @@ -50,7 +50,7 @@ static inline bool should_writeback(struct cached_dev *dc, struct bio *bio, return false; if (dc->partial_stripes_expensive && - bcache_dev_stripe_dirty(dc, bio->bi_sector, + bcache_dev_stripe_dirty(dc, bio->bi_iter.bi_sector, bio_sectors(bio))) return true; diff --git a/drivers/md/dm-bio-record.h b/drivers/md/dm-bio-record.h index 3a8cfa2645c7..5ace48ee9f58 100644 --- a/drivers/md/dm-bio-record.h +++ b/drivers/md/dm-bio-record.h @@ -40,10 +40,10 @@ static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio) { unsigned i; - bd->bi_sector = bio->bi_sector; + bd->bi_sector = bio->bi_iter.bi_sector; bd->bi_bdev = bio->bi_bdev; - bd->bi_size = bio->bi_size; - bd->bi_idx = bio->bi_idx; + bd->bi_size = bio->bi_iter.bi_size; + bd->bi_idx = bio->bi_iter.bi_idx; bd->bi_flags = bio->bi_flags; for (i = 0; i < bio->bi_vcnt; i++) { @@ -56,10 +56,10 @@ static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio) { unsigned i; - bio->bi_sector = bd->bi_sector; + bio->bi_iter.bi_sector = bd->bi_sector; bio->bi_bdev = bd->bi_bdev; - bio->bi_size = bd->bi_size; - bio->bi_idx = bd->bi_idx; + bio->bi_iter.bi_size = bd->bi_size; + bio->bi_iter.bi_idx = bd->bi_idx; bio->bi_flags = bd->bi_flags; for (i = 0; i < bio->bi_vcnt; i++) { diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 173cbb20d104..4113b6044b80 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -538,7 +538,7 @@ static void use_inline_bio(struct dm_buffer *b, int rw, sector_t block, bio_init(&b->bio); b->bio.bi_io_vec = b->bio_vec; b->bio.bi_max_vecs = DM_BUFIO_INLINE_VECS; - b->bio.bi_sector = block << b->c->sectors_per_block_bits; + b->bio.bi_iter.bi_sector = block << b->c->sectors_per_block_bits; b->bio.bi_bdev = b->c->bdev; b->bio.bi_end_io = end_io; diff --git a/drivers/md/dm-cache-policy-mq.c b/drivers/md/dm-cache-policy-mq.c index 416b7b752a6e..bfba97dcde2d 100644 --- a/drivers/md/dm-cache-policy-mq.c +++ b/drivers/md/dm-cache-policy-mq.c @@ -72,7 +72,7 @@ static enum io_pattern iot_pattern(struct io_tracker *t) static void iot_update_stats(struct io_tracker *t, struct bio *bio) { - if (bio->bi_sector == from_oblock(t->last_end_oblock) + 1) + if (bio->bi_iter.bi_sector == from_oblock(t->last_end_oblock) + 1) t->nr_seq_samples++; else { /* @@ -87,7 +87,7 @@ static void iot_update_stats(struct io_tracker *t, struct bio *bio) t->nr_rand_samples++; } - t->last_end_oblock = to_oblock(bio->bi_sector + bio_sectors(bio) - 1); + t->last_end_oblock = to_oblock(bio_end_sector(bio) - 1); } static void iot_check_for_pattern_switch(struct io_tracker *t) diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 9efcf1059b99..86f9c83eb30c 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -664,15 +664,17 @@ static void remap_to_origin(struct cache *cache, struct bio *bio) static void remap_to_cache(struct cache *cache, struct bio *bio, dm_cblock_t cblock) { - sector_t bi_sector = bio->bi_sector; + sector_t bi_sector = bio->bi_iter.bi_sector; bio->bi_bdev = cache->cache_dev->bdev; if (!block_size_is_power_of_two(cache)) - bio->bi_sector = (from_cblock(cblock) * cache->sectors_per_block) + - sector_div(bi_sector, cache->sectors_per_block); + bio->bi_iter.bi_sector = + (from_cblock(cblock) * cache->sectors_per_block) + + sector_div(bi_sector, cache->sectors_per_block); else - bio->bi_sector = (from_cblock(cblock) << cache->sectors_per_block_shift) | - (bi_sector & (cache->sectors_per_block - 1)); + bio->bi_iter.bi_sector = + (from_cblock(cblock) << cache->sectors_per_block_shift) | + (bi_sector & (cache->sectors_per_block - 1)); } static void check_if_tick_bio_needed(struct cache *cache, struct bio *bio) @@ -712,7 +714,7 @@ static void remap_to_cache_dirty(struct cache *cache, struct bio *bio, static dm_oblock_t get_bio_block(struct cache *cache, struct bio *bio) { - sector_t block_nr = bio->bi_sector; + sector_t block_nr = bio->bi_iter.bi_sector; if (!block_size_is_power_of_two(cache)) (void) sector_div(block_nr, cache->sectors_per_block); @@ -1027,7 +1029,7 @@ static void issue_overwrite(struct dm_cache_migration *mg, struct bio *bio) static bool bio_writes_complete_block(struct cache *cache, struct bio *bio) { return (bio_data_dir(bio) == WRITE) && - (bio->bi_size == (cache->sectors_per_block << SECTOR_SHIFT)); + (bio->bi_iter.bi_size == (cache->sectors_per_block << SECTOR_SHIFT)); } static void avoid_copy(struct dm_cache_migration *mg) @@ -1252,7 +1254,7 @@ static void process_flush_bio(struct cache *cache, struct bio *bio) size_t pb_data_size = get_per_bio_data_size(cache); struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size); - BUG_ON(bio->bi_size); + BUG_ON(bio->bi_iter.bi_size); if (!pb->req_nr) remap_to_origin(cache, bio); else @@ -1275,9 +1277,9 @@ static void process_flush_bio(struct cache *cache, struct bio *bio) */ static void process_discard_bio(struct cache *cache, struct bio *bio) { - dm_block_t start_block = dm_sector_div_up(bio->bi_sector, + dm_block_t start_block = dm_sector_div_up(bio->bi_iter.bi_sector, cache->discard_block_size); - dm_block_t end_block = bio->bi_sector + bio_sectors(bio); + dm_block_t end_block = bio_end_sector(bio); dm_block_t b; end_block = block_div(end_block, cache->discard_block_size); diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 81b0fa660452..1e2e5465d28e 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -828,8 +828,8 @@ static void crypt_convert_init(struct crypt_config *cc, ctx->bio_out = bio_out; ctx->offset_in = 0; ctx->offset_out = 0; - ctx->idx_in = bio_in ? bio_in->bi_idx : 0; - ctx->idx_out = bio_out ? bio_out->bi_idx : 0; + ctx->idx_in = bio_in ? bio_in->bi_iter.bi_idx : 0; + ctx->idx_out = bio_out ? bio_out->bi_iter.bi_idx : 0; ctx->cc_sector = sector + cc->iv_offset; init_completion(&ctx->restart); } @@ -1021,7 +1021,7 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size, size -= len; } - if (!clone->bi_size) { + if (!clone->bi_iter.bi_size) { bio_put(clone); return NULL; } @@ -1161,7 +1161,7 @@ static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp) crypt_inc_pending(io); clone_init(io, clone); - clone->bi_sector = cc->start + io->sector; + clone->bi_iter.bi_sector = cc->start + io->sector; generic_make_request(clone); return 0; @@ -1209,7 +1209,7 @@ static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async) /* crypt_convert should have filled the clone bio */ BUG_ON(io->ctx.idx_out < clone->bi_vcnt); - clone->bi_sector = cc->start + io->sector; + clone->bi_iter.bi_sector = cc->start + io->sector; if (async) kcryptd_queue_io(io); @@ -1224,7 +1224,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io) struct dm_crypt_io *new_io; int crypt_finished; unsigned out_of_pages = 0; - unsigned remaining = io->base_bio->bi_size; + unsigned remaining = io->base_bio->bi_iter.bi_size; sector_t sector = io->sector; int r; @@ -1248,7 +1248,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io) io->ctx.bio_out = clone; io->ctx.idx_out = 0; - remaining -= clone->bi_size; + remaining -= clone->bi_iter.bi_size; sector += bio_sectors(clone); crypt_inc_pending(io); @@ -1869,11 +1869,12 @@ static int crypt_map(struct dm_target *ti, struct bio *bio) if (unlikely(bio->bi_rw & (REQ_FLUSH | REQ_DISCARD))) { bio->bi_bdev = cc->dev->bdev; if (bio_sectors(bio)) - bio->bi_sector = cc->start + dm_target_offset(ti, bio->bi_sector); + bio->bi_iter.bi_sector = cc->start + + dm_target_offset(ti, bio->bi_iter.bi_sector); return DM_MAPIO_REMAPPED; } - io = crypt_io_alloc(cc, bio, dm_target_offset(ti, bio->bi_sector)); + io = crypt_io_alloc(cc, bio, dm_target_offset(ti, bio->bi_iter.bi_sector)); if (bio_data_dir(io->base_bio) == READ) { if (kcryptd_io_read(io, GFP_NOWAIT)) diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c index 496d5f3646a5..84c860191a2e 100644 --- a/drivers/md/dm-delay.c +++ b/drivers/md/dm-delay.c @@ -281,14 +281,15 @@ static int delay_map(struct dm_target *ti, struct bio *bio) if ((bio_data_dir(bio) == WRITE) && (dc->dev_write)) { bio->bi_bdev = dc->dev_write->bdev; if (bio_sectors(bio)) - bio->bi_sector = dc->start_write + - dm_target_offset(ti, bio->bi_sector); + bio->bi_iter.bi_sector = dc->start_write + + dm_target_offset(ti, bio->bi_iter.bi_sector); return delay_bio(dc, dc->write_delay, bio); } bio->bi_bdev = dc->dev_read->bdev; - bio->bi_sector = dc->start_read + dm_target_offset(ti, bio->bi_sector); + bio->bi_iter.bi_sector = dc->start_read + + dm_target_offset(ti, bio->bi_iter.bi_sector); return delay_bio(dc, dc->read_delay, bio); } diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c index c80a0ec5f126..b257e46876d3 100644 --- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -248,7 +248,8 @@ static void flakey_map_bio(struct dm_target *ti, struct bio *bio) bio->bi_bdev = fc->dev->bdev; if (bio_sectors(bio)) - bio->bi_sector = flakey_map_sector(ti, bio->bi_sector); + bio->bi_iter.bi_sector = + flakey_map_sector(ti, bio->bi_iter.bi_sector); } static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc) @@ -265,8 +266,8 @@ static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc) DMDEBUG("Corrupting data bio=%p by writing %u to byte %u " "(rw=%c bi_rw=%lu bi_sector=%llu cur_bytes=%u)\n", bio, fc->corrupt_bio_value, fc->corrupt_bio_byte, - (bio_data_dir(bio) == WRITE) ? 'w' : 'r', - bio->bi_rw, (unsigned long long)bio->bi_sector, bio_bytes); + (bio_data_dir(bio) == WRITE) ? 'w' : 'r', bio->bi_rw, + (unsigned long long)bio->bi_iter.bi_sector, bio_bytes); } } diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 2a20986a2fec..01558b093307 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -304,14 +304,14 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, dm_sector_div_up(remaining, (PAGE_SIZE >> SECTOR_SHIFT))); bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios); - bio->bi_sector = where->sector + (where->count - remaining); + bio->bi_iter.bi_sector = where->sector + (where->count - remaining); bio->bi_bdev = where->bdev; bio->bi_end_io = endio; store_io_and_region_in_bio(bio, io, region); if (rw & REQ_DISCARD) { num_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining); - bio->bi_size = num_sectors << SECTOR_SHIFT; + bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT; remaining -= num_sectors; } else if (rw & REQ_WRITE_SAME) { /* @@ -320,7 +320,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, dp->get_page(dp, &page, &len, &offset); bio_add_page(bio, page, logical_block_size, offset); num_sectors = min_t(sector_t, q->limits.max_write_same_sectors, remaining); - bio->bi_size = num_sectors << SECTOR_SHIFT; + bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT; offset = 0; remaining -= num_sectors; diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 4f99d267340c..53e848c10939 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c @@ -85,7 +85,8 @@ static void linear_map_bio(struct dm_target *ti, struct bio *bio) bio->bi_bdev = lc->dev->bdev; if (bio_sectors(bio)) - bio->bi_sector = linear_map_sector(ti, bio->bi_sector); + bio->bi_iter.bi_sector = + linear_map_sector(ti, bio->bi_iter.bi_sector); } static int linear_map(struct dm_target *ti, struct bio *bio) diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 9584443c5614..9f6d8e6baa7d 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -432,7 +432,7 @@ static int mirror_available(struct mirror_set *ms, struct bio *bio) region_t region = dm_rh_bio_to_region(ms->rh, bio); if (log->type->in_sync(log, region, 0)) - return choose_mirror(ms, bio->bi_sector) ? 1 : 0; + return choose_mirror(ms, bio->bi_iter.bi_sector) ? 1 : 0; return 0; } @@ -442,15 +442,15 @@ static int mirror_available(struct mirror_set *ms, struct bio *bio) */ static sector_t map_sector(struct mirror *m, struct bio *bio) { - if (unlikely(!bio->bi_size)) + if (unlikely(!bio->bi_iter.bi_size)) return 0; - return m->offset + dm_target_offset(m->ms->ti, bio->bi_sector); + return m->offset + dm_target_offset(m->ms->ti, bio->bi_iter.bi_sector); } static void map_bio(struct mirror *m, struct bio *bio) { bio->bi_bdev = m->dev->bdev; - bio->bi_sector = map_sector(m, bio); + bio->bi_iter.bi_sector = map_sector(m, bio); } static void map_region(struct dm_io_region *io, struct mirror *m, @@ -527,7 +527,7 @@ static void read_async_bio(struct mirror *m, struct bio *bio) struct dm_io_request io_req = { .bi_rw = READ, .mem.type = DM_IO_BVEC, - .mem.ptr.bvec = bio->bi_io_vec + bio->bi_idx, + .mem.ptr.bvec = bio->bi_io_vec + bio->bi_iter.bi_idx, .notify.fn = read_callback, .notify.context = bio, .client = m->ms->io_client, @@ -559,7 +559,7 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads) * We can only read balance if the region is in sync. */ if (likely(region_in_sync(ms, region, 1))) - m = choose_mirror(ms, bio->bi_sector); + m = choose_mirror(ms, bio->bi_iter.bi_sector); else if (m && atomic_read(&m->error_count)) m = NULL; @@ -630,7 +630,7 @@ static void do_write(struct mirror_set *ms, struct bio *bio) struct dm_io_request io_req = { .bi_rw = WRITE | (bio->bi_rw & WRITE_FLUSH_FUA), .mem.type = DM_IO_BVEC, - .mem.ptr.bvec = bio->bi_io_vec + bio->bi_idx, + .mem.ptr.bvec = bio->bi_io_vec + bio->bi_iter.bi_idx, .notify.fn = write_callback, .notify.context = bio, .client = ms->io_client, @@ -1181,7 +1181,7 @@ static int mirror_map(struct dm_target *ti, struct bio *bio) * The region is in-sync and we can perform reads directly. * Store enough information so we can retry if it fails. */ - m = choose_mirror(ms, bio->bi_sector); + m = choose_mirror(ms, bio->bi_iter.bi_sector); if (unlikely(!m)) return -EIO; diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c index 69732e03eb34..b929fd5f4984 100644 --- a/drivers/md/dm-region-hash.c +++ b/drivers/md/dm-region-hash.c @@ -126,7 +126,8 @@ EXPORT_SYMBOL_GPL(dm_rh_region_to_sector); region_t dm_rh_bio_to_region(struct dm_region_hash *rh, struct bio *bio) { - return dm_rh_sector_to_region(rh, bio->bi_sector - rh->target_begin); + return dm_rh_sector_to_region(rh, bio->bi_iter.bi_sector - + rh->target_begin); } EXPORT_SYMBOL_GPL(dm_rh_bio_to_region); diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index aec57d76db5d..3ded8c729dfb 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -1562,11 +1562,10 @@ static void remap_exception(struct dm_snapshot *s, struct dm_exception *e, struct bio *bio, chunk_t chunk) { bio->bi_bdev = s->cow->bdev; - bio->bi_sector = chunk_to_sector(s->store, - dm_chunk_number(e->new_chunk) + - (chunk - e->old_chunk)) + - (bio->bi_sector & - s->store->chunk_mask); + bio->bi_iter.bi_sector = + chunk_to_sector(s->store, dm_chunk_number(e->new_chunk) + + (chunk - e->old_chunk)) + + (bio->bi_iter.bi_sector & s->store->chunk_mask); } static int snapshot_map(struct dm_target *ti, struct bio *bio) @@ -1584,7 +1583,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) return DM_MAPIO_REMAPPED; } - chunk = sector_to_chunk(s->store, bio->bi_sector); + chunk = sector_to_chunk(s->store, bio->bi_iter.bi_sector); /* Full snapshots are not usable */ /* To get here the table must be live so s->active is always set. */ @@ -1645,7 +1644,8 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) r = DM_MAPIO_SUBMITTED; if (!pe->started && - bio->bi_size == (s->store->chunk_size << SECTOR_SHIFT)) { + bio->bi_iter.bi_size == + (s->store->chunk_size << SECTOR_SHIFT)) { pe->started = 1; up_write(&s->lock); start_full_bio(pe, bio); @@ -1701,7 +1701,7 @@ static int snapshot_merge_map(struct dm_target *ti, struct bio *bio) return DM_MAPIO_REMAPPED; } - chunk = sector_to_chunk(s->store, bio->bi_sector); + chunk = sector_to_chunk(s->store, bio->bi_iter.bi_sector); down_write(&s->lock); @@ -2038,7 +2038,7 @@ static int do_origin(struct dm_dev *origin, struct bio *bio) down_read(&_origins_lock); o = __lookup_origin(origin->bdev); if (o) - r = __origin_write(&o->snapshots, bio->bi_sector, bio); + r = __origin_write(&o->snapshots, bio->bi_iter.bi_sector, bio); up_read(&_origins_lock); return r; diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 73c1712dad96..d1600d2aa2e2 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -259,13 +259,15 @@ static int stripe_map_range(struct stripe_c *sc, struct bio *bio, { sector_t begin, end; - stripe_map_range_sector(sc, bio->bi_sector, target_stripe, &begin); + stripe_map_range_sector(sc, bio->bi_iter.bi_sector, + target_stripe, &begin); stripe_map_range_sector(sc, bio_end_sector(bio), target_stripe, &end); if (begin < end) { bio->bi_bdev = sc->stripe[target_stripe].dev->bdev; - bio->bi_sector = begin + sc->stripe[target_stripe].physical_start; - bio->bi_size = to_bytes(end - begin); + bio->bi_iter.bi_sector = begin + + sc->stripe[target_stripe].physical_start; + bio->bi_iter.bi_size = to_bytes(end - begin); return DM_MAPIO_REMAPPED; } else { /* The range doesn't map to the target stripe */ @@ -293,9 +295,10 @@ static int stripe_map(struct dm_target *ti, struct bio *bio) return stripe_map_range(sc, bio, target_bio_nr); } - stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector); + stripe_map_sector(sc, bio->bi_iter.bi_sector, + &stripe, &bio->bi_iter.bi_sector); - bio->bi_sector += sc->stripe[stripe].physical_start; + bio->bi_iter.bi_sector += sc->stripe[stripe].physical_start; bio->bi_bdev = sc->stripe[stripe].dev->bdev; return DM_MAPIO_REMAPPED; diff --git a/drivers/md/dm-switch.c b/drivers/md/dm-switch.c index ff9ac4be4721..09a688b3d48c 100644 --- a/drivers/md/dm-switch.c +++ b/drivers/md/dm-switch.c @@ -311,11 +311,11 @@ error: static int switch_map(struct dm_target *ti, struct bio *bio) { struct switch_ctx *sctx = ti->private; - sector_t offset = dm_target_offset(ti, bio->bi_sector); + sector_t offset = dm_target_offset(ti, bio->bi_iter.bi_sector); unsigned path_nr = switch_get_path_nr(sctx, offset); bio->bi_bdev = sctx->path_list[path_nr].dmdev->bdev; - bio->bi_sector = sctx->path_list[path_nr].start + offset; + bio->bi_iter.bi_sector = sctx->path_list[path_nr].start + offset; return DM_MAPIO_REMAPPED; } diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 2c0cf511ec23..a65402480c8c 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -413,7 +413,7 @@ static bool block_size_is_power_of_two(struct pool *pool) static dm_block_t get_bio_block(struct thin_c *tc, struct bio *bio) { struct pool *pool = tc->pool; - sector_t block_nr = bio->bi_sector; + sector_t block_nr = bio->bi_iter.bi_sector; if (block_size_is_power_of_two(pool)) block_nr >>= pool->sectors_per_block_shift; @@ -426,14 +426,15 @@ static dm_block_t get_bio_block(struct thin_c *tc, struct bio *bio) static void remap(struct thin_c *tc, struct bio *bio, dm_block_t block) { struct pool *pool = tc->pool; - sector_t bi_sector = bio->bi_sector; + sector_t bi_sector = bio->bi_iter.bi_sector; bio->bi_bdev = tc->pool_dev->bdev; if (block_size_is_power_of_two(pool)) - bio->bi_sector = (block << pool->sectors_per_block_shift) | - (bi_sector & (pool->sectors_per_block - 1)); + bio->bi_iter.bi_sector = + (block << pool->sectors_per_block_shift) | + (bi_sector & (pool->sectors_per_block - 1)); else - bio->bi_sector = (block * pool->sectors_per_block) + + bio->bi_iter.bi_sector = (block * pool->sectors_per_block) + sector_div(bi_sector, pool->sectors_per_block); } @@ -721,7 +722,8 @@ static void process_prepared(struct pool *pool, struct list_head *head, */ static int io_overlaps_block(struct pool *pool, struct bio *bio) { - return bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT); + return bio->bi_iter.bi_size == + (pool->sectors_per_block << SECTOR_SHIFT); } static int io_overwrites_block(struct pool *pool, struct bio *bio) @@ -1130,7 +1132,7 @@ static void process_shared_bio(struct thin_c *tc, struct bio *bio, if (bio_detain(pool, &key, bio, &cell)) return; - if (bio_data_dir(bio) == WRITE && bio->bi_size) + if (bio_data_dir(bio) == WRITE && bio->bi_iter.bi_size) break_sharing(tc, bio, block, &key, lookup_result, cell); else { struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook)); @@ -1153,7 +1155,7 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block /* * Remap empty bios (flushes) immediately, without provisioning. */ - if (!bio->bi_size) { + if (!bio->bi_iter.bi_size) { inc_all_io_entry(pool, bio); cell_defer_no_holder(tc, cell); @@ -1253,7 +1255,7 @@ static void process_bio_read_only(struct thin_c *tc, struct bio *bio) r = dm_thin_find_block(tc->td, block, 1, &lookup_result); switch (r) { case 0: - if (lookup_result.shared && (rw == WRITE) && bio->bi_size) + if (lookup_result.shared && (rw == WRITE) && bio->bi_iter.bi_size) bio_io_error(bio); else { inc_all_io_entry(tc->pool, bio); @@ -2867,7 +2869,7 @@ out_unlock: static int thin_map(struct dm_target *ti, struct bio *bio) { - bio->bi_sector = dm_target_offset(ti, bio->bi_sector); + bio->bi_iter.bi_sector = dm_target_offset(ti, bio->bi_iter.bi_sector); return thin_bio_map(ti, bio); } diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c index 4b7941db3aff..132b3154d466 100644 --- a/drivers/md/dm-verity.c +++ b/drivers/md/dm-verity.c @@ -493,9 +493,9 @@ static int verity_map(struct dm_target *ti, struct bio *bio) struct dm_verity_io *io; bio->bi_bdev = v->data_dev->bdev; - bio->bi_sector = verity_map_sector(v, bio->bi_sector); + bio->bi_iter.bi_sector = verity_map_sector(v, bio->bi_iter.bi_sector); - if (((unsigned)bio->bi_sector | bio_sectors(bio)) & + if (((unsigned)bio->bi_iter.bi_sector | bio_sectors(bio)) & ((1 << (v->data_dev_block_bits - SECTOR_SHIFT)) - 1)) { DMERR_LIMIT("unaligned io"); return -EIO; @@ -514,8 +514,8 @@ static int verity_map(struct dm_target *ti, struct bio *bio) io->v = v; io->orig_bi_end_io = bio->bi_end_io; io->orig_bi_private = bio->bi_private; - io->block = bio->bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT); - io->n_blocks = bio->bi_size >> v->data_dev_block_bits; + io->block = bio->bi_iter.bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT); + io->n_blocks = bio->bi_iter.bi_size >> v->data_dev_block_bits; bio->bi_end_io = verity_end_io; bio->bi_private = io; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 0704c523a76b..ccd064ea4fe6 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -575,7 +575,7 @@ static void start_io_acct(struct dm_io *io) atomic_inc_return(&md->pending[rw])); if (unlikely(dm_stats_used(&md->stats))) - dm_stats_account_io(&md->stats, bio->bi_rw, bio->bi_sector, + dm_stats_account_io(&md->stats, bio->bi_rw, bio->bi_iter.bi_sector, bio_sectors(bio), false, 0, &io->stats_aux); } @@ -593,7 +593,7 @@ static void end_io_acct(struct dm_io *io) part_stat_unlock(); if (unlikely(dm_stats_used(&md->stats))) - dm_stats_account_io(&md->stats, bio->bi_rw, bio->bi_sector, + dm_stats_account_io(&md->stats, bio->bi_rw, bio->bi_iter.bi_sector, bio_sectors(bio), true, duration, &io->stats_aux); /* @@ -742,7 +742,7 @@ static void dec_pending(struct dm_io *io, int error) if (io_error == DM_ENDIO_REQUEUE) return; - if ((bio->bi_rw & REQ_FLUSH) && bio->bi_size) { + if ((bio->bi_rw & REQ_FLUSH) && bio->bi_iter.bi_size) { /* * Preflush done for flush with data, reissue * without REQ_FLUSH. @@ -797,7 +797,7 @@ static void end_clone_bio(struct bio *clone, int error) struct dm_rq_clone_bio_info *info = clone->bi_private; struct dm_rq_target_io *tio = info->tio; struct bio *bio = info->orig; - unsigned int nr_bytes = info->orig->bi_size; + unsigned int nr_bytes = info->orig->bi_iter.bi_size; bio_put(clone); @@ -1128,7 +1128,7 @@ static void __map_bio(struct dm_target_io *tio) * this io. */ atomic_inc(&tio->io->io_count); - sector = clone->bi_sector; + sector = clone->bi_iter.bi_sector; r = ti->type->map(ti, clone); if (r == DM_MAPIO_REMAPPED) { /* the bio has been remapped so dispatch it */ @@ -1160,13 +1160,13 @@ struct clone_info { static void bio_setup_sector(struct bio *bio, sector_t sector, sector_t len) { - bio->bi_sector = sector; - bio->bi_size = to_bytes(len); + bio->bi_iter.bi_sector = sector; + bio->bi_iter.bi_size = to_bytes(len); } static void bio_setup_bv(struct bio *bio, unsigned short idx, unsigned short bv_count) { - bio->bi_idx = idx; + bio->bi_iter.bi_idx = idx; bio->bi_vcnt = idx + bv_count; bio->bi_flags &= ~(1 << BIO_SEG_VALID); } @@ -1202,7 +1202,7 @@ static void clone_split_bio(struct dm_target_io *tio, struct bio *bio, clone->bi_rw = bio->bi_rw; clone->bi_vcnt = 1; clone->bi_io_vec->bv_offset = offset; - clone->bi_io_vec->bv_len = clone->bi_size; + clone->bi_io_vec->bv_len = clone->bi_iter.bi_size; clone->bi_flags |= 1 << BIO_CLONED; clone_bio_integrity(bio, clone, idx, len, offset, 1); @@ -1222,7 +1222,8 @@ static void clone_bio(struct dm_target_io *tio, struct bio *bio, bio_setup_sector(clone, sector, len); bio_setup_bv(clone, idx, bv_count); - if (idx != bio->bi_idx || clone->bi_size < bio->bi_size) + if (idx != bio->bi_iter.bi_idx || + clone->bi_iter.bi_size < bio->bi_iter.bi_size) trim = 1; clone_bio_integrity(bio, clone, idx, len, 0, trim); } @@ -1510,8 +1511,8 @@ static void __split_and_process_bio(struct mapped_device *md, ci.io->bio = bio; ci.io->md = md; spin_lock_init(&ci.io->endio_lock); - ci.sector = bio->bi_sector; - ci.idx = bio->bi_idx; + ci.sector = bio->bi_iter.bi_sector; + ci.idx = bio->bi_iter.bi_idx; start_io_acct(ci.io); diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index 3193aefe982b..e8b4574956c7 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -74,8 +74,8 @@ static void faulty_fail(struct bio *bio, int error) { struct bio *b = bio->bi_private; - b->bi_size = bio->bi_size; - b->bi_sector = bio->bi_sector; + b->bi_iter.bi_size = bio->bi_iter.bi_size; + b->bi_iter.bi_sector = bio->bi_iter.bi_sector; bio_put(bio); @@ -185,26 +185,31 @@ static void make_request(struct mddev *mddev, struct bio *bio) return; } - if (check_sector(conf, bio->bi_sector, bio_end_sector(bio), WRITE)) + if (check_sector(conf, bio->bi_iter.bi_sector, + bio_end_sector(bio), WRITE)) failit = 1; if (check_mode(conf, WritePersistent)) { - add_sector(conf, bio->bi_sector, WritePersistent); + add_sector(conf, bio->bi_iter.bi_sector, + WritePersistent); failit = 1; } if (check_mode(conf, WriteTransient)) failit = 1; } else { /* read request */ - if (check_sector(conf, bio->bi_sector, bio_end_sector(bio), READ)) + if (check_sector(conf, bio->bi_iter.bi_sector, + bio_end_sector(bio), READ)) failit = 1; if (check_mode(conf, ReadTransient)) failit = 1; if (check_mode(conf, ReadPersistent)) { - add_sector(conf, bio->bi_sector, ReadPersistent); + add_sector(conf, bio->bi_iter.bi_sector, + ReadPersistent); failit = 1; } if (check_mode(conf, ReadFixable)) { - add_sector(conf, bio->bi_sector, ReadFixable); + add_sector(conf, bio->bi_iter.bi_sector, + ReadFixable); failit = 1; } } diff --git a/drivers/md/linear.c b/drivers/md/linear.c index f03fabd2b37b..fb3b0d04edfb 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -297,19 +297,19 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio) } rcu_read_lock(); - tmp_dev = which_dev(mddev, bio->bi_sector); + tmp_dev = which_dev(mddev, bio->bi_iter.bi_sector); start_sector = tmp_dev->end_sector - tmp_dev->rdev->sectors; - if (unlikely(bio->bi_sector >= (tmp_dev->end_sector) - || (bio->bi_sector < start_sector))) { + if (unlikely(bio->bi_iter.bi_sector >= (tmp_dev->end_sector) + || (bio->bi_iter.bi_sector < start_sector))) { char b[BDEVNAME_SIZE]; printk(KERN_ERR "md/linear:%s: make_request: Sector %llu out of bounds on " "dev %s: %llu sectors, offset %llu\n", mdname(mddev), - (unsigned long long)bio->bi_sector, + (unsigned long long)bio->bi_iter.bi_sector, bdevname(tmp_dev->rdev->bdev, b), (unsigned long long)tmp_dev->rdev->sectors, (unsigned long long)start_sector); @@ -326,7 +326,7 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio) rcu_read_unlock(); - bp = bio_split(bio, end_sector - bio->bi_sector); + bp = bio_split(bio, end_sector - bio->bi_iter.bi_sector); linear_make_request(mddev, &bp->bio1); linear_make_request(mddev, &bp->bio2); @@ -335,7 +335,7 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio) } bio->bi_bdev = tmp_dev->rdev->bdev; - bio->bi_sector = bio->bi_sector - start_sector + bio->bi_iter.bi_sector = bio->bi_iter.bi_sector - start_sector + tmp_dev->rdev->data_offset; rcu_read_unlock(); diff --git a/drivers/md/md.c b/drivers/md/md.c index 739b1ec54e28..b07fed398fd7 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -393,7 +393,7 @@ static void md_submit_flush_data(struct work_struct *ws) struct mddev *mddev = container_of(ws, struct mddev, flush_work); struct bio *bio = mddev->flush_bio; - if (bio->bi_size == 0) + if (bio->bi_iter.bi_size == 0) /* an empty barrier - all done */ bio_endio(bio, 0); else { @@ -754,7 +754,7 @@ void md_super_write(struct mddev *mddev, struct md_rdev *rdev, struct bio *bio = bio_alloc_mddev(GFP_NOIO, 1, mddev); bio->bi_bdev = rdev->meta_bdev ? rdev->meta_bdev : rdev->bdev; - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio_add_page(bio, page, size, 0); bio->bi_private = rdev; bio->bi_end_io = super_written; @@ -785,13 +785,13 @@ int sync_page_io(struct md_rdev *rdev, sector_t sector, int size, bio->bi_bdev = (metadata_op && rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev; if (metadata_op) - bio->bi_sector = sector + rdev->sb_start; + bio->bi_iter.bi_sector = sector + rdev->sb_start; else if (rdev->mddev->reshape_position != MaxSector && (rdev->mddev->reshape_backwards == (sector >= rdev->mddev->reshape_position))) - bio->bi_sector = sector + rdev->new_data_offset; + bio->bi_iter.bi_sector = sector + rdev->new_data_offset; else - bio->bi_sector = sector + rdev->data_offset; + bio->bi_iter.bi_sector = sector + rdev->data_offset; bio_add_page(bio, page, size, 0); submit_bio_wait(rw, bio); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 1642eae75a33..849ad39f547b 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -100,7 +100,7 @@ static void multipath_end_request(struct bio *bio, int error) md_error (mp_bh->mddev, rdev); printk(KERN_ERR "multipath: %s: rescheduling sector %llu\n", bdevname(rdev->bdev,b), - (unsigned long long)bio->bi_sector); + (unsigned long long)bio->bi_iter.bi_sector); multipath_reschedule_retry(mp_bh); } else multipath_end_bh_io(mp_bh, error); @@ -132,7 +132,7 @@ static void multipath_make_request(struct mddev *mddev, struct bio * bio) multipath = conf->multipaths + mp_bh->path; mp_bh->bio = *bio; - mp_bh->bio.bi_sector += multipath->rdev->data_offset; + mp_bh->bio.bi_iter.bi_sector += multipath->rdev->data_offset; mp_bh->bio.bi_bdev = multipath->rdev->bdev; mp_bh->bio.bi_rw |= REQ_FAILFAST_TRANSPORT; mp_bh->bio.bi_end_io = multipath_end_request; @@ -355,21 +355,22 @@ static void multipathd(struct md_thread *thread) spin_unlock_irqrestore(&conf->device_lock, flags); bio = &mp_bh->bio; - bio->bi_sector = mp_bh->master_bio->bi_sector; + bio->bi_iter.bi_sector = mp_bh->master_bio->bi_iter.bi_sector; if ((mp_bh->path = multipath_map (conf))<0) { printk(KERN_ALERT "multipath: %s: unrecoverable IO read" " error for block %llu\n", bdevname(bio->bi_bdev,b), - (unsigned long long)bio->bi_sector); + (unsigned long long)bio->bi_iter.bi_sector); multipath_end_bh_io(mp_bh, -EIO); } else { printk(KERN_ERR "multipath: %s: redirecting sector %llu" " to another IO path\n", bdevname(bio->bi_bdev,b), - (unsigned long long)bio->bi_sector); + (unsigned long long)bio->bi_iter.bi_sector); *bio = *(mp_bh->master_bio); - bio->bi_sector += conf->multipaths[mp_bh->path].rdev->data_offset; + bio->bi_iter.bi_sector += + conf->multipaths[mp_bh->path].rdev->data_offset; bio->bi_bdev = conf->multipaths[mp_bh->path].rdev->bdev; bio->bi_rw |= REQ_FAILFAST_TRANSPORT; bio->bi_end_io = multipath_end_request; diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index c4d420b7d2f4..e38d1d3226f3 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -501,10 +501,11 @@ static inline int is_io_in_chunk_boundary(struct mddev *mddev, unsigned int chunk_sects, struct bio *bio) { if (likely(is_power_of_2(chunk_sects))) { - return chunk_sects >= ((bio->bi_sector & (chunk_sects-1)) + return chunk_sects >= + ((bio->bi_iter.bi_sector & (chunk_sects-1)) + bio_sectors(bio)); } else{ - sector_t sector = bio->bi_sector; + sector_t sector = bio->bi_iter.bi_sector; return chunk_sects >= (sector_div(sector, chunk_sects) + bio_sectors(bio)); } @@ -524,7 +525,7 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio) chunk_sects = mddev->chunk_sectors; if (unlikely(!is_io_in_chunk_boundary(mddev, chunk_sects, bio))) { - sector_t sector = bio->bi_sector; + sector_t sector = bio->bi_iter.bi_sector; struct bio_pair *bp; /* Sanity check -- queue functions should prevent this happening */ if (bio_segments(bio) > 1) @@ -544,12 +545,12 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio) return; } - sector_offset = bio->bi_sector; + sector_offset = bio->bi_iter.bi_sector; zone = find_zone(mddev->private, §or_offset); - tmp_dev = map_sector(mddev, zone, bio->bi_sector, + tmp_dev = map_sector(mddev, zone, bio->bi_iter.bi_sector, §or_offset); bio->bi_bdev = tmp_dev->bdev; - bio->bi_sector = sector_offset + zone->dev_start + + bio->bi_iter.bi_sector = sector_offset + zone->dev_start + tmp_dev->data_offset; if (unlikely((bio->bi_rw & REQ_DISCARD) && @@ -566,7 +567,8 @@ bad_map: printk("md/raid0:%s: make_request bug: can't convert block across chunks" " or bigger than %dk %llu %d\n", mdname(mddev), chunk_sects / 2, - (unsigned long long)bio->bi_sector, bio_sectors(bio) / 2); + (unsigned long long)bio->bi_iter.bi_sector, + bio_sectors(bio) / 2); bio_io_error(bio); return; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 1e5a540995e9..db3b9d7314f1 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -229,7 +229,7 @@ static void call_bio_endio(struct r1bio *r1_bio) int done; struct r1conf *conf = r1_bio->mddev->private; sector_t start_next_window = r1_bio->start_next_window; - sector_t bi_sector = bio->bi_sector; + sector_t bi_sector = bio->bi_iter.bi_sector; if (bio->bi_phys_segments) { unsigned long flags; @@ -265,9 +265,8 @@ static void raid_end_bio_io(struct r1bio *r1_bio) if (!test_and_set_bit(R1BIO_Returned, &r1_bio->state)) { pr_debug("raid1: sync end %s on sectors %llu-%llu\n", (bio_data_dir(bio) == WRITE) ? "write" : "read", - (unsigned long long) bio->bi_sector, - (unsigned long long) bio->bi_sector + - bio_sectors(bio) - 1); + (unsigned long long) bio->bi_iter.bi_sector, + (unsigned long long) bio_end_sector(bio) - 1); call_bio_endio(r1_bio); } @@ -466,9 +465,8 @@ static void raid1_end_write_request(struct bio *bio, int error) struct bio *mbio = r1_bio->master_bio; pr_debug("raid1: behind end write sectors" " %llu-%llu\n", - (unsigned long long) mbio->bi_sector, - (unsigned long long) mbio->bi_sector + - bio_sectors(mbio) - 1); + (unsigned long long) mbio->bi_iter.bi_sector, + (unsigned long long) bio_end_sector(mbio) - 1); call_bio_endio(r1_bio); } } @@ -875,7 +873,7 @@ static bool need_to_wait_for_sync(struct r1conf *conf, struct bio *bio) else if ((conf->next_resync - RESYNC_WINDOW_SECTORS >= bio_end_sector(bio)) || (conf->next_resync + NEXT_NORMALIO_DISTANCE - <= bio->bi_sector)) + <= bio->bi_iter.bi_sector)) wait = false; else wait = true; @@ -913,19 +911,19 @@ static sector_t wait_barrier(struct r1conf *conf, struct bio *bio) if (bio && bio_data_dir(bio) == WRITE) { if (conf->next_resync + NEXT_NORMALIO_DISTANCE - <= bio->bi_sector) { + <= bio->bi_iter.bi_sector) { if (conf->start_next_window == MaxSector) conf->start_next_window = conf->next_resync + NEXT_NORMALIO_DISTANCE; if ((conf->start_next_window + NEXT_NORMALIO_DISTANCE) - <= bio->bi_sector) + <= bio->bi_iter.bi_sector) conf->next_window_requests++; else conf->current_window_requests++; } - if (bio->bi_sector >= conf->start_next_window) + if (bio->bi_iter.bi_sector >= conf->start_next_window) sector = conf->start_next_window; } @@ -1028,7 +1026,8 @@ do_sync_io: if (bvecs[i].bv_page) put_page(bvecs[i].bv_page); kfree(bvecs); - pr_debug("%dB behind alloc failed, doing sync I/O\n", bio->bi_size); + pr_debug("%dB behind alloc failed, doing sync I/O\n", + bio->bi_iter.bi_size); } struct raid1_plug_cb { @@ -1108,7 +1107,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) if (bio_data_dir(bio) == WRITE && bio_end_sector(bio) > mddev->suspend_lo && - bio->bi_sector < mddev->suspend_hi) { + bio->bi_iter.bi_sector < mddev->suspend_hi) { /* As the suspend_* range is controlled by * userspace, we want an interruptible * wait. @@ -1119,7 +1118,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) prepare_to_wait(&conf->wait_barrier, &w, TASK_INTERRUPTIBLE); if (bio_end_sector(bio) <= mddev->suspend_lo || - bio->bi_sector >= mddev->suspend_hi) + bio->bi_iter.bi_sector >= mddev->suspend_hi) break; schedule(); } @@ -1141,7 +1140,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) r1_bio->sectors = bio_sectors(bio); r1_bio->state = 0; r1_bio->mddev = mddev; - r1_bio->sector = bio->bi_sector; + r1_bio->sector = bio->bi_iter.bi_sector; /* We might need to issue multiple reads to different * devices if there are bad blocks around, so we keep @@ -1181,12 +1180,13 @@ read_again: r1_bio->read_disk = rdisk; read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev); - bio_trim(read_bio, r1_bio->sector - bio->bi_sector, + bio_trim(read_bio, r1_bio->sector - bio->bi_iter.bi_sector, max_sectors); r1_bio->bios[rdisk] = read_bio; - read_bio->bi_sector = r1_bio->sector + mirror->rdev->data_offset; + read_bio->bi_iter.bi_sector = r1_bio->sector + + mirror->rdev->data_offset; read_bio->bi_bdev = mirror->rdev->bdev; read_bio->bi_end_io = raid1_end_read_request; read_bio->bi_rw = READ | do_sync; @@ -1198,7 +1198,7 @@ read_again: */ sectors_handled = (r1_bio->sector + max_sectors - - bio->bi_sector); + - bio->bi_iter.bi_sector); r1_bio->sectors = max_sectors; spin_lock_irq(&conf->device_lock); if (bio->bi_phys_segments == 0) @@ -1219,7 +1219,8 @@ read_again: r1_bio->sectors = bio_sectors(bio) - sectors_handled; r1_bio->state = 0; r1_bio->mddev = mddev; - r1_bio->sector = bio->bi_sector + sectors_handled; + r1_bio->sector = bio->bi_iter.bi_sector + + sectors_handled; goto read_again; } else generic_make_request(read_bio); @@ -1322,7 +1323,7 @@ read_again: if (r1_bio->bios[j]) rdev_dec_pending(conf->mirrors[j].rdev, mddev); r1_bio->state = 0; - allow_barrier(conf, start_next_window, bio->bi_sector); + allow_barrier(conf, start_next_window, bio->bi_iter.bi_sector); md_wait_for_blocked_rdev(blocked_rdev, mddev); start_next_window = wait_barrier(conf, bio); /* @@ -1349,7 +1350,7 @@ read_again: bio->bi_phys_segments++; spin_unlock_irq(&conf->device_lock); } - sectors_handled = r1_bio->sector + max_sectors - bio->bi_sector; + sectors_handled = r1_bio->sector + max_sectors - bio->bi_iter.bi_sector; atomic_set(&r1_bio->remaining, 1); atomic_set(&r1_bio->behind_remaining, 0); @@ -1361,7 +1362,7 @@ read_again: continue; mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - bio_trim(mbio, r1_bio->sector - bio->bi_sector, max_sectors); + bio_trim(mbio, r1_bio->sector - bio->bi_iter.bi_sector, max_sectors); if (first_clone) { /* do behind I/O ? @@ -1395,7 +1396,7 @@ read_again: r1_bio->bios[i] = mbio; - mbio->bi_sector = (r1_bio->sector + + mbio->bi_iter.bi_sector = (r1_bio->sector + conf->mirrors[i].rdev->data_offset); mbio->bi_bdev = conf->mirrors[i].rdev->bdev; mbio->bi_end_io = raid1_end_write_request; @@ -1435,7 +1436,7 @@ read_again: r1_bio->sectors = bio_sectors(bio) - sectors_handled; r1_bio->state = 0; r1_bio->mddev = mddev; - r1_bio->sector = bio->bi_sector + sectors_handled; + r1_bio->sector = bio->bi_iter.bi_sector + sectors_handled; goto retry_write; } @@ -1959,14 +1960,14 @@ static int process_checks(struct r1bio *r1_bio) /* fixup the bio for reuse */ bio_reset(b); b->bi_vcnt = vcnt; - b->bi_size = r1_bio->sectors << 9; - b->bi_sector = r1_bio->sector + + b->bi_iter.bi_size = r1_bio->sectors << 9; + b->bi_iter.bi_sector = r1_bio->sector + conf->mirrors[i].rdev->data_offset; b->bi_bdev = conf->mirrors[i].rdev->bdev; b->bi_end_io = end_sync_read; b->bi_private = r1_bio; - size = b->bi_size; + size = b->bi_iter.bi_size; for (j = 0; j < vcnt ; j++) { struct bio_vec *bi; bi = &b->bi_io_vec[j]; @@ -2221,11 +2222,11 @@ static int narrow_write_error(struct r1bio *r1_bio, int i) } wbio->bi_rw = WRITE; - wbio->bi_sector = r1_bio->sector; - wbio->bi_size = r1_bio->sectors << 9; + wbio->bi_iter.bi_sector = r1_bio->sector; + wbio->bi_iter.bi_size = r1_bio->sectors << 9; bio_trim(wbio, sector - r1_bio->sector, sectors); - wbio->bi_sector += rdev->data_offset; + wbio->bi_iter.bi_sector += rdev->data_offset; wbio->bi_bdev = rdev->bdev; if (submit_bio_wait(WRITE, wbio) == 0) /* failure! */ @@ -2339,7 +2340,8 @@ read_more: } r1_bio->read_disk = disk; bio = bio_clone_mddev(r1_bio->master_bio, GFP_NOIO, mddev); - bio_trim(bio, r1_bio->sector - bio->bi_sector, max_sectors); + bio_trim(bio, r1_bio->sector - bio->bi_iter.bi_sector, + max_sectors); r1_bio->bios[r1_bio->read_disk] = bio; rdev = conf->mirrors[disk].rdev; printk_ratelimited(KERN_ERR @@ -2348,7 +2350,7 @@ read_more: mdname(mddev), (unsigned long long)r1_bio->sector, bdevname(rdev->bdev, b)); - bio->bi_sector = r1_bio->sector + rdev->data_offset; + bio->bi_iter.bi_sector = r1_bio->sector + rdev->data_offset; bio->bi_bdev = rdev->bdev; bio->bi_end_io = raid1_end_read_request; bio->bi_rw = READ | do_sync; @@ -2357,7 +2359,7 @@ read_more: /* Drat - have to split this up more */ struct bio *mbio = r1_bio->master_bio; int sectors_handled = (r1_bio->sector + max_sectors - - mbio->bi_sector); + - mbio->bi_iter.bi_sector); r1_bio->sectors = max_sectors; spin_lock_irq(&conf->device_lock); if (mbio->bi_phys_segments == 0) @@ -2375,7 +2377,8 @@ read_more: r1_bio->state = 0; set_bit(R1BIO_ReadError, &r1_bio->state); r1_bio->mddev = mddev; - r1_bio->sector = mbio->bi_sector + sectors_handled; + r1_bio->sector = mbio->bi_iter.bi_sector + + sectors_handled; goto read_more; } else @@ -2599,7 +2602,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipp } if (bio->bi_end_io) { atomic_inc(&rdev->nr_pending); - bio->bi_sector = sector_nr + rdev->data_offset; + bio->bi_iter.bi_sector = sector_nr + rdev->data_offset; bio->bi_bdev = rdev->bdev; bio->bi_private = r1_bio; } @@ -2699,7 +2702,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipp continue; /* remove last page from this bio */ bio->bi_vcnt--; - bio->bi_size -= len; + bio->bi_iter.bi_size -= len; bio->bi_flags &= ~(1<< BIO_SEG_VALID); } goto bio_full; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index c504e8389e69..dbf3b63c2754 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1182,7 +1182,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) /* If this request crosses a chunk boundary, we need to * split it. This will only happen for 1 PAGE (or less) requests. */ - if (unlikely((bio->bi_sector & chunk_mask) + bio_sectors(bio) + if (unlikely((bio->bi_iter.bi_sector & chunk_mask) + bio_sectors(bio) > chunk_sects && (conf->geo.near_copies < conf->geo.raid_disks || conf->prev.near_copies < conf->prev.raid_disks))) { @@ -1193,8 +1193,8 @@ static void make_request(struct mddev *mddev, struct bio * bio) /* This is a one page bio that upper layers * refuse to split for us, so we need to split it. */ - bp = bio_split(bio, - chunk_sects - (bio->bi_sector & (chunk_sects - 1)) ); + bp = bio_split(bio, chunk_sects - + (bio->bi_iter.bi_sector & (chunk_sects - 1))); /* Each of these 'make_request' calls will call 'wait_barrier'. * If the first succeeds but the second blocks due to the resync @@ -1221,7 +1221,8 @@ static void make_request(struct mddev *mddev, struct bio * bio) bad_map: printk("md/raid10:%s: make_request bug: can't convert block across chunks" " or bigger than %dk %llu %d\n", mdname(mddev), chunk_sects/2, - (unsigned long long)bio->bi_sector, bio_sectors(bio) / 2); + (unsigned long long)bio->bi_iter.bi_sector, + bio_sectors(bio) / 2); bio_io_error(bio); return; @@ -1238,24 +1239,25 @@ static void make_request(struct mddev *mddev, struct bio * bio) sectors = bio_sectors(bio); while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && - bio->bi_sector < conf->reshape_progress && - bio->bi_sector + sectors > conf->reshape_progress) { + bio->bi_iter.bi_sector < conf->reshape_progress && + bio->bi_iter.bi_sector + sectors > conf->reshape_progress) { /* IO spans the reshape position. Need to wait for * reshape to pass */ allow_barrier(conf); wait_event(conf->wait_barrier, - conf->reshape_progress <= bio->bi_sector || - conf->reshape_progress >= bio->bi_sector + sectors); + conf->reshape_progress <= bio->bi_iter.bi_sector || + conf->reshape_progress >= bio->bi_iter.bi_sector + + sectors); wait_barrier(conf); } if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && bio_data_dir(bio) == WRITE && (mddev->reshape_backwards - ? (bio->bi_sector < conf->reshape_safe && - bio->bi_sector + sectors > conf->reshape_progress) - : (bio->bi_sector + sectors > conf->reshape_safe && - bio->bi_sector < conf->reshape_progress))) { + ? (bio->bi_iter.bi_sector < conf->reshape_safe && + bio->bi_iter.bi_sector + sectors > conf->reshape_progress) + : (bio->bi_iter.bi_sector + sectors > conf->reshape_safe && + bio->bi_iter.bi_sector < conf->reshape_progress))) { /* Need to update reshape_position in metadata */ mddev->reshape_position = conf->reshape_progress; set_bit(MD_CHANGE_DEVS, &mddev->flags); @@ -1273,7 +1275,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) r10_bio->sectors = sectors; r10_bio->mddev = mddev; - r10_bio->sector = bio->bi_sector; + r10_bio->sector = bio->bi_iter.bi_sector; r10_bio->state = 0; /* We might need to issue multiple reads to different @@ -1302,13 +1304,13 @@ read_again: slot = r10_bio->read_slot; read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev); - bio_trim(read_bio, r10_bio->sector - bio->bi_sector, + bio_trim(read_bio, r10_bio->sector - bio->bi_iter.bi_sector, max_sectors); r10_bio->devs[slot].bio = read_bio; r10_bio->devs[slot].rdev = rdev; - read_bio->bi_sector = r10_bio->devs[slot].addr + + read_bio->bi_iter.bi_sector = r10_bio->devs[slot].addr + choose_data_offset(r10_bio, rdev); read_bio->bi_bdev = rdev->bdev; read_bio->bi_end_io = raid10_end_read_request; @@ -1320,7 +1322,7 @@ read_again: * need another r10_bio. */ sectors_handled = (r10_bio->sectors + max_sectors - - bio->bi_sector); + - bio->bi_iter.bi_sector); r10_bio->sectors = max_sectors; spin_lock_irq(&conf->device_lock); if (bio->bi_phys_segments == 0) @@ -1341,7 +1343,8 @@ read_again: r10_bio->sectors = bio_sectors(bio) - sectors_handled; r10_bio->state = 0; r10_bio->mddev = mddev; - r10_bio->sector = bio->bi_sector + sectors_handled; + r10_bio->sector = bio->bi_iter.bi_sector + + sectors_handled; goto read_again; } else generic_make_request(read_bio); @@ -1499,7 +1502,8 @@ retry_write: bio->bi_phys_segments++; spin_unlock_irq(&conf->device_lock); } - sectors_handled = r10_bio->sector + max_sectors - bio->bi_sector; + sectors_handled = r10_bio->sector + max_sectors - + bio->bi_iter.bi_sector; atomic_set(&r10_bio->remaining, 1); bitmap_startwrite(mddev->bitmap, r10_bio->sector, r10_bio->sectors, 0); @@ -1510,11 +1514,11 @@ retry_write: if (r10_bio->devs[i].bio) { struct md_rdev *rdev = conf->mirrors[d].rdev; mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - bio_trim(mbio, r10_bio->sector - bio->bi_sector, + bio_trim(mbio, r10_bio->sector - bio->bi_iter.bi_sector, max_sectors); r10_bio->devs[i].bio = mbio; - mbio->bi_sector = (r10_bio->devs[i].addr+ + mbio->bi_iter.bi_sector = (r10_bio->devs[i].addr+ choose_data_offset(r10_bio, rdev)); mbio->bi_bdev = rdev->bdev; @@ -1553,11 +1557,11 @@ retry_write: rdev = conf->mirrors[d].rdev; } mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - bio_trim(mbio, r10_bio->sector - bio->bi_sector, + bio_trim(mbio, r10_bio->sector - bio->bi_iter.bi_sector, max_sectors); r10_bio->devs[i].repl_bio = mbio; - mbio->bi_sector = (r10_bio->devs[i].addr + + mbio->bi_iter.bi_sector = (r10_bio->devs[i].addr + choose_data_offset( r10_bio, rdev)); mbio->bi_bdev = rdev->bdev; @@ -1591,7 +1595,7 @@ retry_write: r10_bio->sectors = bio_sectors(bio) - sectors_handled; r10_bio->mddev = mddev; - r10_bio->sector = bio->bi_sector + sectors_handled; + r10_bio->sector = bio->bi_iter.bi_sector + sectors_handled; r10_bio->state = 0; goto retry_write; } @@ -2124,10 +2128,10 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) bio_reset(tbio); tbio->bi_vcnt = vcnt; - tbio->bi_size = r10_bio->sectors << 9; + tbio->bi_iter.bi_size = r10_bio->sectors << 9; tbio->bi_rw = WRITE; tbio->bi_private = r10_bio; - tbio->bi_sector = r10_bio->devs[i].addr; + tbio->bi_iter.bi_sector = r10_bio->devs[i].addr; for (j=0; j < vcnt ; j++) { tbio->bi_io_vec[j].bv_offset = 0; @@ -2144,7 +2148,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) atomic_inc(&r10_bio->remaining); md_sync_acct(conf->mirrors[d].rdev->bdev, bio_sectors(tbio)); - tbio->bi_sector += conf->mirrors[d].rdev->data_offset; + tbio->bi_iter.bi_sector += conf->mirrors[d].rdev->data_offset; tbio->bi_bdev = conf->mirrors[d].rdev->bdev; generic_make_request(tbio); } @@ -2614,8 +2618,8 @@ static int narrow_write_error(struct r10bio *r10_bio, int i) sectors = sect_to_write; /* Write at 'sector' for 'sectors' */ wbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - bio_trim(wbio, sector - bio->bi_sector, sectors); - wbio->bi_sector = (r10_bio->devs[i].addr+ + bio_trim(wbio, sector - bio->bi_iter.bi_sector, sectors); + wbio->bi_iter.bi_sector = (r10_bio->devs[i].addr+ choose_data_offset(r10_bio, rdev) + (sector - r10_bio->sector)); wbio->bi_bdev = rdev->bdev; @@ -2687,10 +2691,10 @@ read_more: (unsigned long long)r10_bio->sector); bio = bio_clone_mddev(r10_bio->master_bio, GFP_NOIO, mddev); - bio_trim(bio, r10_bio->sector - bio->bi_sector, max_sectors); + bio_trim(bio, r10_bio->sector - bio->bi_iter.bi_sector, max_sectors); r10_bio->devs[slot].bio = bio; r10_bio->devs[slot].rdev = rdev; - bio->bi_sector = r10_bio->devs[slot].addr + bio->bi_iter.bi_sector = r10_bio->devs[slot].addr + choose_data_offset(r10_bio, rdev); bio->bi_bdev = rdev->bdev; bio->bi_rw = READ | do_sync; @@ -2701,7 +2705,7 @@ read_more: struct bio *mbio = r10_bio->master_bio; int sectors_handled = r10_bio->sector + max_sectors - - mbio->bi_sector; + - mbio->bi_iter.bi_sector; r10_bio->sectors = max_sectors; spin_lock_irq(&conf->device_lock); if (mbio->bi_phys_segments == 0) @@ -2719,7 +2723,7 @@ read_more: set_bit(R10BIO_ReadError, &r10_bio->state); r10_bio->mddev = mddev; - r10_bio->sector = mbio->bi_sector + r10_bio->sector = mbio->bi_iter.bi_sector + sectors_handled; goto read_more; @@ -3157,7 +3161,8 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, bio->bi_end_io = end_sync_read; bio->bi_rw = READ; from_addr = r10_bio->devs[j].addr; - bio->bi_sector = from_addr + rdev->data_offset; + bio->bi_iter.bi_sector = from_addr + + rdev->data_offset; bio->bi_bdev = rdev->bdev; atomic_inc(&rdev->nr_pending); /* and we write to 'i' (if not in_sync) */ @@ -3181,7 +3186,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, bio->bi_private = r10_bio; bio->bi_end_io = end_sync_write; bio->bi_rw = WRITE; - bio->bi_sector = to_addr + bio->bi_iter.bi_sector = to_addr + rdev->data_offset; bio->bi_bdev = rdev->bdev; atomic_inc(&r10_bio->remaining); @@ -3210,7 +3215,8 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, bio->bi_private = r10_bio; bio->bi_end_io = end_sync_write; bio->bi_rw = WRITE; - bio->bi_sector = to_addr + rdev->data_offset; + bio->bi_iter.bi_sector = to_addr + + rdev->data_offset; bio->bi_bdev = rdev->bdev; atomic_inc(&r10_bio->remaining); break; @@ -3328,7 +3334,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, bio->bi_private = r10_bio; bio->bi_end_io = end_sync_read; bio->bi_rw = READ; - bio->bi_sector = sector + + bio->bi_iter.bi_sector = sector + conf->mirrors[d].rdev->data_offset; bio->bi_bdev = conf->mirrors[d].rdev->bdev; count++; @@ -3350,7 +3356,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, bio->bi_private = r10_bio; bio->bi_end_io = end_sync_write; bio->bi_rw = WRITE; - bio->bi_sector = sector + + bio->bi_iter.bi_sector = sector + conf->mirrors[d].replacement->data_offset; bio->bi_bdev = conf->mirrors[d].replacement->bdev; count++; @@ -3397,7 +3403,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, bio2 = bio2->bi_next) { /* remove last page from this bio */ bio2->bi_vcnt--; - bio2->bi_size -= len; + bio2->bi_iter.bi_size -= len; bio2->bi_flags &= ~(1<< BIO_SEG_VALID); } goto bio_full; @@ -4417,7 +4423,7 @@ read_more: read_bio = bio_alloc_mddev(GFP_KERNEL, RESYNC_PAGES, mddev); read_bio->bi_bdev = rdev->bdev; - read_bio->bi_sector = (r10_bio->devs[r10_bio->read_slot].addr + read_bio->bi_iter.bi_sector = (r10_bio->devs[r10_bio->read_slot].addr + rdev->data_offset); read_bio->bi_private = r10_bio; read_bio->bi_end_io = end_sync_read; @@ -4425,7 +4431,7 @@ read_more: read_bio->bi_flags &= ~(BIO_POOL_MASK - 1); read_bio->bi_flags |= 1 << BIO_UPTODATE; read_bio->bi_vcnt = 0; - read_bio->bi_size = 0; + read_bio->bi_iter.bi_size = 0; r10_bio->master_bio = read_bio; r10_bio->read_slot = r10_bio->devs[r10_bio->read_slot].devnum; @@ -4451,7 +4457,8 @@ read_more: bio_reset(b); b->bi_bdev = rdev2->bdev; - b->bi_sector = r10_bio->devs[s/2].addr + rdev2->new_data_offset; + b->bi_iter.bi_sector = r10_bio->devs[s/2].addr + + rdev2->new_data_offset; b->bi_private = r10_bio; b->bi_end_io = end_reshape_write; b->bi_rw = WRITE; @@ -4478,7 +4485,7 @@ read_more: bio2 = bio2->bi_next) { /* Remove last page from this bio */ bio2->bi_vcnt--; - bio2->bi_size -= len; + bio2->bi_iter.bi_size -= len; bio2->bi_flags &= ~(1<bi_sector + sectors < sector + STRIPE_SECTORS) + if (bio->bi_iter.bi_sector + sectors < sector + STRIPE_SECTORS) return bio->bi_next; else return NULL; @@ -225,7 +225,7 @@ static void return_io(struct bio *return_bi) return_bi = bi->bi_next; bi->bi_next = NULL; - bi->bi_size = 0; + bi->bi_iter.bi_size = 0; trace_block_bio_complete(bdev_get_queue(bi->bi_bdev), bi, 0); bio_endio(bi, 0); @@ -854,10 +854,10 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) bi->bi_rw, i); atomic_inc(&sh->count); if (use_new_offset(conf, sh)) - bi->bi_sector = (sh->sector + bi->bi_iter.bi_sector = (sh->sector + rdev->new_data_offset); else - bi->bi_sector = (sh->sector + bi->bi_iter.bi_sector = (sh->sector + rdev->data_offset); if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) bi->bi_rw |= REQ_NOMERGE; @@ -865,7 +865,7 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) bi->bi_vcnt = 1; bi->bi_io_vec[0].bv_len = STRIPE_SIZE; bi->bi_io_vec[0].bv_offset = 0; - bi->bi_size = STRIPE_SIZE; + bi->bi_iter.bi_size = STRIPE_SIZE; /* * If this is discard request, set bi_vcnt 0. We don't * want to confuse SCSI because SCSI will replace payload @@ -901,15 +901,15 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) rbi->bi_rw, i); atomic_inc(&sh->count); if (use_new_offset(conf, sh)) - rbi->bi_sector = (sh->sector + rbi->bi_iter.bi_sector = (sh->sector + rrdev->new_data_offset); else - rbi->bi_sector = (sh->sector + rbi->bi_iter.bi_sector = (sh->sector + rrdev->data_offset); rbi->bi_vcnt = 1; rbi->bi_io_vec[0].bv_len = STRIPE_SIZE; rbi->bi_io_vec[0].bv_offset = 0; - rbi->bi_size = STRIPE_SIZE; + rbi->bi_iter.bi_size = STRIPE_SIZE; /* * If this is discard request, set bi_vcnt 0. We don't * want to confuse SCSI because SCSI will replace payload @@ -944,10 +944,10 @@ async_copy_data(int frombio, struct bio *bio, struct page *page, struct async_submit_ctl submit; enum async_tx_flags flags = 0; - if (bio->bi_sector >= sector) - page_offset = (signed)(bio->bi_sector - sector) * 512; + if (bio->bi_iter.bi_sector >= sector) + page_offset = (signed)(bio->bi_iter.bi_sector - sector) * 512; else - page_offset = (signed)(sector - bio->bi_sector) * -512; + page_offset = (signed)(sector - bio->bi_iter.bi_sector) * -512; if (frombio) flags |= ASYNC_TX_FENCE; @@ -1014,7 +1014,7 @@ static void ops_complete_biofill(void *stripe_head_ref) BUG_ON(!dev->read); rbi = dev->read; dev->read = NULL; - while (rbi && rbi->bi_sector < + while (rbi && rbi->bi_iter.bi_sector < dev->sector + STRIPE_SECTORS) { rbi2 = r5_next_bio(rbi, dev->sector); if (!raid5_dec_bi_active_stripes(rbi)) { @@ -1050,7 +1050,7 @@ static void ops_run_biofill(struct stripe_head *sh) dev->read = rbi = dev->toread; dev->toread = NULL; spin_unlock_irq(&sh->stripe_lock); - while (rbi && rbi->bi_sector < + while (rbi && rbi->bi_iter.bi_sector < dev->sector + STRIPE_SECTORS) { tx = async_copy_data(0, rbi, dev->page, dev->sector, tx); @@ -1392,7 +1392,7 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx) wbi = dev->written = chosen; spin_unlock_irq(&sh->stripe_lock); - while (wbi && wbi->bi_sector < + while (wbi && wbi->bi_iter.bi_sector < dev->sector + STRIPE_SECTORS) { if (wbi->bi_rw & REQ_FUA) set_bit(R5_WantFUA, &dev->flags); @@ -2616,7 +2616,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in int firstwrite=0; pr_debug("adding bi b#%llu to stripe s#%llu\n", - (unsigned long long)bi->bi_sector, + (unsigned long long)bi->bi_iter.bi_sector, (unsigned long long)sh->sector); /* @@ -2634,12 +2634,12 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in firstwrite = 1; } else bip = &sh->dev[dd_idx].toread; - while (*bip && (*bip)->bi_sector < bi->bi_sector) { - if (bio_end_sector(*bip) > bi->bi_sector) + while (*bip && (*bip)->bi_iter.bi_sector < bi->bi_iter.bi_sector) { + if (bio_end_sector(*bip) > bi->bi_iter.bi_sector) goto overlap; bip = & (*bip)->bi_next; } - if (*bip && (*bip)->bi_sector < bio_end_sector(bi)) + if (*bip && (*bip)->bi_iter.bi_sector < bio_end_sector(bi)) goto overlap; BUG_ON(*bip && bi->bi_next && (*bip) != bi->bi_next); @@ -2653,7 +2653,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in sector_t sector = sh->dev[dd_idx].sector; for (bi=sh->dev[dd_idx].towrite; sector < sh->dev[dd_idx].sector + STRIPE_SECTORS && - bi && bi->bi_sector <= sector; + bi && bi->bi_iter.bi_sector <= sector; bi = r5_next_bio(bi, sh->dev[dd_idx].sector)) { if (bio_end_sector(bi) >= sector) sector = bio_end_sector(bi); @@ -2663,7 +2663,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in } pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n", - (unsigned long long)(*bip)->bi_sector, + (unsigned long long)(*bip)->bi_iter.bi_sector, (unsigned long long)sh->sector, dd_idx); spin_unlock_irq(&sh->stripe_lock); @@ -2738,7 +2738,7 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) wake_up(&conf->wait_for_overlap); - while (bi && bi->bi_sector < + while (bi && bi->bi_iter.bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); clear_bit(BIO_UPTODATE, &bi->bi_flags); @@ -2757,7 +2757,7 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, bi = sh->dev[i].written; sh->dev[i].written = NULL; if (bi) bitmap_end = 1; - while (bi && bi->bi_sector < + while (bi && bi->bi_iter.bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector); clear_bit(BIO_UPTODATE, &bi->bi_flags); @@ -2781,7 +2781,7 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, spin_unlock_irq(&sh->stripe_lock); if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) wake_up(&conf->wait_for_overlap); - while (bi && bi->bi_sector < + while (bi && bi->bi_iter.bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); @@ -3005,7 +3005,7 @@ static void handle_stripe_clean_event(struct r5conf *conf, clear_bit(R5_UPTODATE, &dev->flags); wbi = dev->written; dev->written = NULL; - while (wbi && wbi->bi_sector < + while (wbi && wbi->bi_iter.bi_sector < dev->sector + STRIPE_SECTORS) { wbi2 = r5_next_bio(wbi, dev->sector); if (!raid5_dec_bi_active_stripes(wbi)) { @@ -4097,7 +4097,7 @@ static int raid5_mergeable_bvec(struct request_queue *q, static int in_chunk_boundary(struct mddev *mddev, struct bio *bio) { - sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); + sector_t sector = bio->bi_iter.bi_sector + get_start_sect(bio->bi_bdev); unsigned int chunk_sectors = mddev->chunk_sectors; unsigned int bio_sectors = bio_sectors(bio); @@ -4234,9 +4234,9 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio) /* * compute position */ - align_bi->bi_sector = raid5_compute_sector(conf, raid_bio->bi_sector, - 0, - &dd_idx, NULL); + align_bi->bi_iter.bi_sector = + raid5_compute_sector(conf, raid_bio->bi_iter.bi_sector, + 0, &dd_idx, NULL); end_sector = bio_end_sector(align_bi); rcu_read_lock(); @@ -4261,7 +4261,8 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio) align_bi->bi_flags &= ~(1 << BIO_SEG_VALID); if (!bio_fits_rdev(align_bi) || - is_badblock(rdev, align_bi->bi_sector, bio_sectors(align_bi), + is_badblock(rdev, align_bi->bi_iter.bi_sector, + bio_sectors(align_bi), &first_bad, &bad_sectors)) { /* too big in some way, or has a known bad block */ bio_put(align_bi); @@ -4270,7 +4271,7 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio) } /* No reshape active, so we can trust rdev->data_offset */ - align_bi->bi_sector += rdev->data_offset; + align_bi->bi_iter.bi_sector += rdev->data_offset; spin_lock_irq(&conf->device_lock); wait_event_lock_irq(conf->wait_for_stripe, @@ -4282,7 +4283,7 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio) if (mddev->gendisk) trace_block_bio_remap(bdev_get_queue(align_bi->bi_bdev), align_bi, disk_devt(mddev->gendisk), - raid_bio->bi_sector); + raid_bio->bi_iter.bi_sector); generic_make_request(align_bi); return 1; } else { @@ -4465,8 +4466,8 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi) /* Skip discard while reshape is happening */ return; - logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1); - last_sector = bi->bi_sector + (bi->bi_size>>9); + logical_sector = bi->bi_iter.bi_sector & ~((sector_t)STRIPE_SECTORS-1); + last_sector = bi->bi_iter.bi_sector + (bi->bi_iter.bi_size>>9); bi->bi_next = NULL; bi->bi_phys_segments = 1; /* over-loaded to count active stripes */ @@ -4570,7 +4571,7 @@ static void make_request(struct mddev *mddev, struct bio * bi) return; } - logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1); + logical_sector = bi->bi_iter.bi_sector & ~((sector_t)STRIPE_SECTORS-1); last_sector = bio_end_sector(bi); bi->bi_next = NULL; bi->bi_phys_segments = 1; /* over-loaded to count active stripes */ @@ -5054,7 +5055,8 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio) int remaining; int handled = 0; - logical_sector = raid_bio->bi_sector & ~((sector_t)STRIPE_SECTORS-1); + logical_sector = raid_bio->bi_iter.bi_sector & + ~((sector_t)STRIPE_SECTORS-1); sector = raid5_compute_sector(conf, logical_sector, 0, &dd_idx, NULL); last_sector = bio_end_sector(raid_bio); diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 6eca019bcf30..16814a8457f8 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -819,7 +819,8 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) dev_info = bio->bi_bdev->bd_disk->private_data; if (dev_info == NULL) goto fail; - if ((bio->bi_sector & 7) != 0 || (bio->bi_size & 4095) != 0) + if ((bio->bi_iter.bi_sector & 7) != 0 || + (bio->bi_iter.bi_size & 4095) != 0) /* Request is not page-aligned. */ goto fail; if (bio_end_sector(bio) > get_capacity(bio->bi_bdev->bd_disk)) { @@ -842,7 +843,7 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) } } - index = (bio->bi_sector >> 3); + index = (bio->bi_iter.bi_sector >> 3); bio_for_each_segment(bvec, bio, i) { page_addr = (unsigned long) page_address(bvec->bv_page) + bvec->bv_offset; diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 464dd29d06c0..dd4e73fdb323 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -190,15 +190,16 @@ static void xpram_make_request(struct request_queue *q, struct bio *bio) unsigned long bytes; int i; - if ((bio->bi_sector & 7) != 0 || (bio->bi_size & 4095) != 0) + if ((bio->bi_iter.bi_sector & 7) != 0 || + (bio->bi_iter.bi_size & 4095) != 0) /* Request is not page-aligned. */ goto fail; - if ((bio->bi_size >> 12) > xdev->size) + if ((bio->bi_iter.bi_size >> 12) > xdev->size) /* Request size is no page-aligned. */ goto fail; - if ((bio->bi_sector >> 3) > 0xffffffffU - xdev->offset) + if ((bio->bi_iter.bi_sector >> 3) > 0xffffffffU - xdev->offset) goto fail; - index = (bio->bi_sector >> 3) + xdev->offset; + index = (bio->bi_iter.bi_sector >> 3) + xdev->offset; bio_for_each_segment(bvec, bio, i) { page_addr = (unsigned long) kmap(bvec->bv_page) + bvec->bv_offset; diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index aa66361ed44b..bac04c2335aa 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -731,7 +731,7 @@ static int _osd_req_list_objects(struct osd_request *or, bio->bi_rw &= ~REQ_WRITE; or->in.bio = bio; - or->in.total_bytes = bio->bi_size; + or->in.total_bytes = bio->bi_iter.bi_size; return 0; } diff --git a/drivers/staging/lustre/lustre/llite/lloop.c b/drivers/staging/lustre/lustre/llite/lloop.c index e2421ea61352..53741be754b4 100644 --- a/drivers/staging/lustre/lustre/llite/lloop.c +++ b/drivers/staging/lustre/lustre/llite/lloop.c @@ -220,7 +220,7 @@ static int do_bio_lustrebacked(struct lloop_device *lo, struct bio *head) for (bio = head; bio != NULL; bio = bio->bi_next) { LASSERT(rw == bio->bi_rw); - offset = (pgoff_t)(bio->bi_sector << 9) + lo->lo_offset; + offset = (pgoff_t)(bio->bi_iter.bi_sector << 9) + lo->lo_offset; bio_for_each_segment(bvec, bio, i) { BUG_ON(bvec->bv_offset != 0); BUG_ON(bvec->bv_len != PAGE_CACHE_SIZE); @@ -313,7 +313,8 @@ static unsigned int loop_get_bio(struct lloop_device *lo, struct bio **req) bio = &lo->lo_bio; while (*bio && (*bio)->bi_rw == rw) { CDEBUG(D_INFO, "bio sector %llu size %u count %u vcnt%u \n", - (unsigned long long)(*bio)->bi_sector, (*bio)->bi_size, + (unsigned long long)(*bio)->bi_iter.bi_sector, + (*bio)->bi_iter.bi_size, page_count, (*bio)->bi_vcnt); if (page_count + (*bio)->bi_vcnt > LLOOP_MAX_SEGMENTS) break; @@ -347,7 +348,8 @@ static void loop_make_request(struct request_queue *q, struct bio *old_bio) goto err; CDEBUG(D_INFO, "submit bio sector %llu size %u\n", - (unsigned long long)old_bio->bi_sector, old_bio->bi_size); + (unsigned long long)old_bio->bi_iter.bi_sector, + old_bio->bi_iter.bi_size); spin_lock_irq(&lo->lo_lock); inactive = (lo->lo_state != LLOOP_BOUND); @@ -367,7 +369,7 @@ static void loop_make_request(struct request_queue *q, struct bio *old_bio) loop_add_bio(lo, old_bio); return; err: - cfs_bio_io_error(old_bio, old_bio->bi_size); + cfs_bio_io_error(old_bio, old_bio->bi_iter.bi_size); } @@ -378,7 +380,7 @@ static inline void loop_handle_bio(struct lloop_device *lo, struct bio *bio) while (bio) { struct bio *tmp = bio->bi_next; bio->bi_next = NULL; - cfs_bio_endio(bio, bio->bi_size, ret); + cfs_bio_endio(bio, bio->bi_iter.bi_size, ret); bio = tmp; } } diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c index 79ce363b2ea9..e9e6f984092b 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/staging/zram/zram_drv.c @@ -171,13 +171,14 @@ static inline int valid_io_request(struct zram *zram, struct bio *bio) u64 start, end, bound; /* unaligned request */ - if (unlikely(bio->bi_sector & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1))) + if (unlikely(bio->bi_iter.bi_sector & + (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1))) return 0; - if (unlikely(bio->bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1))) + if (unlikely(bio->bi_iter.bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1))) return 0; - start = bio->bi_sector; - end = start + (bio->bi_size >> SECTOR_SHIFT); + start = bio->bi_iter.bi_sector; + end = start + (bio->bi_iter.bi_size >> SECTOR_SHIFT); bound = zram->disksize >> SECTOR_SHIFT; /* out of range range */ if (unlikely(start >= bound || end > bound || start > end)) @@ -684,8 +685,9 @@ static void __zram_make_request(struct zram *zram, struct bio *bio, int rw) break; } - index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT; - offset = (bio->bi_sector & (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT; + index = bio->bi_iter.bi_sector >> SECTORS_PER_PAGE_SHIFT; + offset = (bio->bi_iter.bi_sector & + (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT; bio_for_each_segment(bvec, bio, i) { int max_transfer_size = PAGE_SIZE - offset; diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index c87959f12760..2d29356d0c85 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -319,7 +319,7 @@ iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num) bio->bi_bdev = ib_dev->ibd_bd; bio->bi_private = cmd; bio->bi_end_io = &iblock_bio_done; - bio->bi_sector = lba; + bio->bi_iter.bi_sector = lba; return bio; } diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index fc60b31453ee..08e3d1388c65 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c @@ -215,9 +215,9 @@ unsigned int bio_integrity_tag_size(struct bio *bio) { struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - BUG_ON(bio->bi_size == 0); + BUG_ON(bio->bi_iter.bi_size == 0); - return bi->tag_size * (bio->bi_size / bi->sector_size); + return bi->tag_size * (bio->bi_iter.bi_size / bi->sector_size); } EXPORT_SYMBOL(bio_integrity_tag_size); @@ -300,7 +300,7 @@ static void bio_integrity_generate(struct bio *bio) struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); struct blk_integrity_exchg bix; struct bio_vec *bv; - sector_t sector = bio->bi_sector; + sector_t sector = bio->bi_iter.bi_sector; unsigned int i, sectors, total; void *prot_buf = bio->bi_integrity->bip_buf; @@ -387,7 +387,7 @@ int bio_integrity_prep(struct bio *bio) bip->bip_owns_buf = 1; bip->bip_buf = buf; bip->bip_size = len; - bip->bip_sector = bio->bi_sector; + bip->bip_sector = bio->bi_iter.bi_sector; /* Map it */ offset = offset_in_page(buf); diff --git a/fs/bio.c b/fs/bio.c index 33d79a4eb92d..a402ad6e753f 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -532,13 +532,13 @@ void __bio_clone(struct bio *bio, struct bio *bio_src) * most users will be overriding ->bi_bdev with a new target, * so we don't set nor calculate new physical/hw segment counts here */ - bio->bi_sector = bio_src->bi_sector; + bio->bi_iter.bi_sector = bio_src->bi_iter.bi_sector; bio->bi_bdev = bio_src->bi_bdev; bio->bi_flags |= 1 << BIO_CLONED; bio->bi_rw = bio_src->bi_rw; bio->bi_vcnt = bio_src->bi_vcnt; - bio->bi_size = bio_src->bi_size; - bio->bi_idx = bio_src->bi_idx; + bio->bi_iter.bi_size = bio_src->bi_iter.bi_size; + bio->bi_iter.bi_idx = bio_src->bi_iter.bi_idx; } EXPORT_SYMBOL(__bio_clone); @@ -612,7 +612,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page if (unlikely(bio_flagged(bio, BIO_CLONED))) return 0; - if (((bio->bi_size + len) >> 9) > max_sectors) + if (((bio->bi_iter.bi_size + len) >> 9) > max_sectors) return 0; /* @@ -635,8 +635,9 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page simulate merging updated prev_bvec as new bvec. */ .bi_bdev = bio->bi_bdev, - .bi_sector = bio->bi_sector, - .bi_size = bio->bi_size - prev_bv_len, + .bi_sector = bio->bi_iter.bi_sector, + .bi_size = bio->bi_iter.bi_size - + prev_bv_len, .bi_rw = bio->bi_rw, }; @@ -684,8 +685,8 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page if (q->merge_bvec_fn) { struct bvec_merge_data bvm = { .bi_bdev = bio->bi_bdev, - .bi_sector = bio->bi_sector, - .bi_size = bio->bi_size, + .bi_sector = bio->bi_iter.bi_sector, + .bi_size = bio->bi_iter.bi_size, .bi_rw = bio->bi_rw, }; @@ -708,7 +709,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page bio->bi_vcnt++; bio->bi_phys_segments++; done: - bio->bi_size += len; + bio->bi_iter.bi_size += len; return len; } @@ -807,22 +808,22 @@ void bio_advance(struct bio *bio, unsigned bytes) if (bio_integrity(bio)) bio_integrity_advance(bio, bytes); - bio->bi_sector += bytes >> 9; - bio->bi_size -= bytes; + bio->bi_iter.bi_sector += bytes >> 9; + bio->bi_iter.bi_size -= bytes; if (bio->bi_rw & BIO_NO_ADVANCE_ITER_MASK) return; while (bytes) { - if (unlikely(bio->bi_idx >= bio->bi_vcnt)) { + if (unlikely(bio->bi_iter.bi_idx >= bio->bi_vcnt)) { WARN_ONCE(1, "bio idx %d >= vcnt %d\n", - bio->bi_idx, bio->bi_vcnt); + bio->bi_iter.bi_idx, bio->bi_vcnt); break; } if (bytes >= bio_iovec(bio)->bv_len) { bytes -= bio_iovec(bio)->bv_len; - bio->bi_idx++; + bio->bi_iter.bi_idx++; } else { bio_iovec(bio)->bv_len -= bytes; bio_iovec(bio)->bv_offset += bytes; @@ -1485,7 +1486,7 @@ struct bio *bio_map_kern(struct request_queue *q, void *data, unsigned int len, if (IS_ERR(bio)) return bio; - if (bio->bi_size == len) + if (bio->bi_iter.bi_size == len) return bio; /* @@ -1763,16 +1764,16 @@ struct bio_pair *bio_split(struct bio *bi, int first_sectors) return bp; trace_block_split(bdev_get_queue(bi->bi_bdev), bi, - bi->bi_sector + first_sectors); + bi->bi_iter.bi_sector + first_sectors); BUG_ON(bio_segments(bi) > 1); atomic_set(&bp->cnt, 3); bp->error = 0; bp->bio1 = *bi; bp->bio2 = *bi; - bp->bio2.bi_sector += first_sectors; - bp->bio2.bi_size -= first_sectors << 9; - bp->bio1.bi_size = first_sectors << 9; + bp->bio2.bi_iter.bi_sector += first_sectors; + bp->bio2.bi_iter.bi_size -= first_sectors << 9; + bp->bio1.bi_iter.bi_size = first_sectors << 9; if (bi->bi_vcnt != 0) { bp->bv1 = *bio_iovec(bi); @@ -1821,21 +1822,22 @@ void bio_trim(struct bio *bio, int offset, int size) int sofar = 0; size <<= 9; - if (offset == 0 && size == bio->bi_size) + if (offset == 0 && size == bio->bi_iter.bi_size) return; clear_bit(BIO_SEG_VALID, &bio->bi_flags); bio_advance(bio, offset << 9); - bio->bi_size = size; + bio->bi_iter.bi_size = size; /* avoid any complications with bi_idx being non-zero*/ - if (bio->bi_idx) { - memmove(bio->bi_io_vec, bio->bi_io_vec+bio->bi_idx, - (bio->bi_vcnt - bio->bi_idx) * sizeof(struct bio_vec)); - bio->bi_vcnt -= bio->bi_idx; - bio->bi_idx = 0; + if (bio->bi_iter.bi_idx) { + memmove(bio->bi_io_vec, bio->bi_io_vec+bio->bi_iter.bi_idx, + (bio->bi_vcnt - bio->bi_iter.bi_idx) * + sizeof(struct bio_vec)); + bio->bi_vcnt -= bio->bi_iter.bi_idx; + bio->bi_iter.bi_idx = 0; } /* Make sure vcnt and last bv are not too big */ bio_for_each_segment(bvec, bio, i) { @@ -1871,7 +1873,7 @@ sector_t bio_sector_offset(struct bio *bio, unsigned short index, sector_sz = queue_logical_block_size(bio->bi_bdev->bd_disk->queue); sectors = 0; - if (index >= bio->bi_idx) + if (index >= bio->bi_iter.bi_idx) index = bio->bi_vcnt - 1; bio_for_each_segment_all(bv, bio, i) { diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index 131d82800b3a..cb05e1c842c5 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -1695,7 +1695,7 @@ static int btrfsic_read_block(struct btrfsic_state *state, return -1; } bio->bi_bdev = block_ctx->dev->bdev; - bio->bi_sector = dev_bytenr >> 9; + bio->bi_iter.bi_sector = dev_bytenr >> 9; for (j = i; j < num_pages; j++) { ret = bio_add_page(bio, block_ctx->pagev[j], @@ -3013,7 +3013,7 @@ static void __btrfsic_submit_bio(int rw, struct bio *bio) int bio_is_patched; char **mapped_datav; - dev_bytenr = 512 * bio->bi_sector; + dev_bytenr = 512 * bio->bi_iter.bi_sector; bio_is_patched = 0; if (dev_state->state->print_mask & BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH) @@ -3021,8 +3021,8 @@ static void __btrfsic_submit_bio(int rw, struct bio *bio) "submit_bio(rw=0x%x, bi_vcnt=%u," " bi_sector=%llu (bytenr %llu), bi_bdev=%p)\n", rw, bio->bi_vcnt, - (unsigned long long)bio->bi_sector, dev_bytenr, - bio->bi_bdev); + (unsigned long long)bio->bi_iter.bi_sector, + dev_bytenr, bio->bi_bdev); mapped_datav = kmalloc(sizeof(*mapped_datav) * bio->bi_vcnt, GFP_NOFS); diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index eac6784e43d7..f5cdeb4b5538 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -172,7 +172,8 @@ static void end_compressed_bio_read(struct bio *bio, int err) goto out; inode = cb->inode; - ret = check_compressed_csum(inode, cb, (u64)bio->bi_sector << 9); + ret = check_compressed_csum(inode, cb, + (u64)bio->bi_iter.bi_sector << 9); if (ret) goto csum_failed; @@ -370,7 +371,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, for (pg_index = 0; pg_index < cb->nr_pages; pg_index++) { page = compressed_pages[pg_index]; page->mapping = inode->i_mapping; - if (bio->bi_size) + if (bio->bi_iter.bi_size) ret = io_tree->ops->merge_bio_hook(WRITE, page, 0, PAGE_CACHE_SIZE, bio, 0); @@ -504,7 +505,7 @@ static noinline int add_ra_bio_pages(struct inode *inode, if (!em || last_offset < em->start || (last_offset + PAGE_CACHE_SIZE > extent_map_end(em)) || - (em->block_start >> 9) != cb->orig_bio->bi_sector) { + (em->block_start >> 9) != cb->orig_bio->bi_iter.bi_sector) { free_extent_map(em); unlock_extent(tree, last_offset, end); unlock_page(page); @@ -550,7 +551,7 @@ next: * in it. We don't actually do IO on those pages but allocate new ones * to hold the compressed pages on disk. * - * bio->bi_sector points to the compressed extent on disk + * bio->bi_iter.bi_sector points to the compressed extent on disk * bio->bi_io_vec points to all of the inode pages * bio->bi_vcnt is a count of pages * @@ -571,7 +572,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, struct page *page; struct block_device *bdev; struct bio *comp_bio; - u64 cur_disk_byte = (u64)bio->bi_sector << 9; + u64 cur_disk_byte = (u64)bio->bi_iter.bi_sector << 9; u64 em_len; u64 em_start; struct extent_map *em; @@ -657,7 +658,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, page->mapping = inode->i_mapping; page->index = em_start >> PAGE_CACHE_SHIFT; - if (comp_bio->bi_size) + if (comp_bio->bi_iter.bi_size) ret = tree->ops->merge_bio_hook(READ, page, 0, PAGE_CACHE_SIZE, comp_bio, 0); @@ -685,8 +686,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, comp_bio, sums); BUG_ON(ret); /* -ENOMEM */ } - sums += (comp_bio->bi_size + root->sectorsize - 1) / - root->sectorsize; + sums += (comp_bio->bi_iter.bi_size + + root->sectorsize - 1) / root->sectorsize; ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0); diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 8b5f9e1d1f0e..bcb6f1b780d6 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1984,7 +1984,7 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start, bio = btrfs_io_bio_alloc(GFP_NOFS, 1); if (!bio) return -EIO; - bio->bi_size = 0; + bio->bi_iter.bi_size = 0; map_length = length; ret = btrfs_map_block(fs_info, WRITE, logical, @@ -1995,7 +1995,7 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start, } BUG_ON(mirror_num != bbio->mirror_num); sector = bbio->stripes[mirror_num-1].physical >> 9; - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; dev = bbio->stripes[mirror_num-1].dev; kfree(bbio); if (!dev || !dev->bdev || !dev->writeable) { @@ -2268,9 +2268,9 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset, return -EIO; } bio->bi_end_io = failed_bio->bi_end_io; - bio->bi_sector = failrec->logical >> 9; + bio->bi_iter.bi_sector = failrec->logical >> 9; bio->bi_bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; - bio->bi_size = 0; + bio->bi_iter.bi_size = 0; btrfs_failed_bio = btrfs_io_bio(failed_bio); if (btrfs_failed_bio->csum) { @@ -2412,7 +2412,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err) struct inode *inode = page->mapping->host; pr_debug("end_bio_extent_readpage: bi_sector=%llu, err=%d, " - "mirror=%lu\n", (u64)bio->bi_sector, err, + "mirror=%lu\n", (u64)bio->bi_iter.bi_sector, err, io_bio->mirror_num); tree = &BTRFS_I(inode)->io_tree; @@ -2543,7 +2543,7 @@ btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, if (bio) { bio->bi_bdev = bdev; - bio->bi_sector = first_sector; + bio->bi_iter.bi_sector = first_sector; btrfs_bio = btrfs_io_bio(bio); btrfs_bio->csum = NULL; btrfs_bio->csum_allocated = NULL; @@ -2637,7 +2637,7 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree, if (bio_ret && *bio_ret) { bio = *bio_ret; if (old_compressed) - contig = bio->bi_sector == sector; + contig = bio->bi_iter.bi_sector == sector; else contig = bio_end_sector(bio) == sector; diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 6f3848860283..84a46a42d262 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -182,7 +182,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, if (!path) return -ENOMEM; - nblocks = bio->bi_size >> inode->i_sb->s_blocksize_bits; + nblocks = bio->bi_iter.bi_size >> inode->i_sb->s_blocksize_bits; if (!dst) { if (nblocks * csum_size > BTRFS_BIO_INLINE_CSUM_SIZE) { btrfs_bio->csum_allocated = kmalloc(nblocks * csum_size, @@ -201,7 +201,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, csum = (u8 *)dst; } - if (bio->bi_size > PAGE_CACHE_SIZE * 8) + if (bio->bi_iter.bi_size > PAGE_CACHE_SIZE * 8) path->reada = 2; WARN_ON(bio->bi_vcnt <= 0); @@ -217,7 +217,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, path->skip_locking = 1; } - disk_bytenr = (u64)bio->bi_sector << 9; + disk_bytenr = (u64)bio->bi_iter.bi_sector << 9; if (dio) offset = logical_offset; while (bio_index < bio->bi_vcnt) { @@ -302,7 +302,7 @@ int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, struct btrfs_dio_private *dip, struct bio *bio, u64 offset) { - int len = (bio->bi_sector << 9) - dip->disk_bytenr; + int len = (bio->bi_iter.bi_sector << 9) - dip->disk_bytenr; u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); int ret; @@ -447,11 +447,12 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, u64 offset; WARN_ON(bio->bi_vcnt <= 0); - sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS); + sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_iter.bi_size), + GFP_NOFS); if (!sums) return -ENOMEM; - sums->len = bio->bi_size; + sums->len = bio->bi_iter.bi_size; INIT_LIST_HEAD(&sums->list); if (contig) @@ -461,7 +462,7 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, ordered = btrfs_lookup_ordered_extent(inode, offset); BUG_ON(!ordered); /* Logic error */ - sums->bytenr = (u64)bio->bi_sector << 9; + sums->bytenr = (u64)bio->bi_iter.bi_sector << 9; index = 0; while (bio_index < bio->bi_vcnt) { @@ -476,7 +477,7 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, btrfs_add_ordered_sum(inode, ordered, sums); btrfs_put_ordered_extent(ordered); - bytes_left = bio->bi_size - total_bytes; + bytes_left = bio->bi_iter.bi_size - total_bytes; sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left), GFP_NOFS); @@ -484,7 +485,7 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, sums->len = bytes_left; ordered = btrfs_lookup_ordered_extent(inode, offset); BUG_ON(!ordered); /* Logic error */ - sums->bytenr = ((u64)bio->bi_sector << 9) + + sums->bytenr = ((u64)bio->bi_iter.bi_sector << 9) + total_bytes; index = 0; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index d6630dc130ba..7ab0e94ad492 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1577,7 +1577,7 @@ int btrfs_merge_bio_hook(int rw, struct page *page, unsigned long offset, unsigned long bio_flags) { struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; - u64 logical = (u64)bio->bi_sector << 9; + u64 logical = (u64)bio->bi_iter.bi_sector << 9; u64 length = 0; u64 map_length; int ret; @@ -1585,7 +1585,7 @@ int btrfs_merge_bio_hook(int rw, struct page *page, unsigned long offset, if (bio_flags & EXTENT_BIO_COMPRESSED) return 0; - length = bio->bi_size; + length = bio->bi_iter.bi_size; map_length = length; ret = btrfs_map_block(root->fs_info, rw, logical, &map_length, NULL, 0); @@ -6894,7 +6894,8 @@ static void btrfs_end_dio_bio(struct bio *bio, int err) printk(KERN_ERR "btrfs direct IO failed ino %llu rw %lu " "sector %#Lx len %u err no %d\n", btrfs_ino(dip->inode), bio->bi_rw, - (unsigned long long)bio->bi_sector, bio->bi_size, err); + (unsigned long long)bio->bi_iter.bi_sector, + bio->bi_iter.bi_size, err); dip->errors = 1; /* @@ -6985,7 +6986,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, struct bio *bio; struct bio *orig_bio = dip->orig_bio; struct bio_vec *bvec = orig_bio->bi_io_vec; - u64 start_sector = orig_bio->bi_sector; + u64 start_sector = orig_bio->bi_iter.bi_sector; u64 file_offset = dip->logical_offset; u64 submit_len = 0; u64 map_length; @@ -6993,7 +6994,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, int ret = 0; int async_submit = 0; - map_length = orig_bio->bi_size; + map_length = orig_bio->bi_iter.bi_size; ret = btrfs_map_block(root->fs_info, rw, start_sector << 9, &map_length, NULL, 0); if (ret) { @@ -7001,7 +7002,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, return -EIO; } - if (map_length >= orig_bio->bi_size) { + if (map_length >= orig_bio->bi_iter.bi_size) { bio = orig_bio; goto submit; } @@ -7053,7 +7054,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, bio->bi_private = dip; bio->bi_end_io = btrfs_end_dio_bio; - map_length = orig_bio->bi_size; + map_length = orig_bio->bi_iter.bi_size; ret = btrfs_map_block(root->fs_info, rw, start_sector << 9, &map_length, NULL, 0); @@ -7111,7 +7112,8 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio, if (!skip_sum && !write) { csum_size = btrfs_super_csum_size(root->fs_info->super_copy); - sum_len = dio_bio->bi_size >> inode->i_sb->s_blocksize_bits; + sum_len = dio_bio->bi_iter.bi_size >> + inode->i_sb->s_blocksize_bits; sum_len *= csum_size; } else { sum_len = 0; @@ -7126,8 +7128,8 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio, dip->private = dio_bio->bi_private; dip->inode = inode; dip->logical_offset = file_offset; - dip->bytes = dio_bio->bi_size; - dip->disk_bytenr = (u64)dio_bio->bi_sector << 9; + dip->bytes = dio_bio->bi_iter.bi_size; + dip->disk_bytenr = (u64)dio_bio->bi_iter.bi_sector << 9; io_bio->bi_private = dip; dip->errors = 0; dip->orig_bio = io_bio; diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 24ac21840a9a..9af0b25d991a 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -1032,8 +1032,8 @@ static int rbio_add_io_page(struct btrfs_raid_bio *rbio, /* see if we can add this page onto our existing bio */ if (last) { - last_end = (u64)last->bi_sector << 9; - last_end += last->bi_size; + last_end = (u64)last->bi_iter.bi_sector << 9; + last_end += last->bi_iter.bi_size; /* * we can't merge these if they are from different @@ -1053,9 +1053,9 @@ static int rbio_add_io_page(struct btrfs_raid_bio *rbio, if (!bio) return -ENOMEM; - bio->bi_size = 0; + bio->bi_iter.bi_size = 0; bio->bi_bdev = stripe->dev->bdev; - bio->bi_sector = disk_start >> 9; + bio->bi_iter.bi_sector = disk_start >> 9; set_bit(BIO_UPTODATE, &bio->bi_flags); bio_add_page(bio, page, PAGE_CACHE_SIZE, 0); @@ -1111,7 +1111,7 @@ static void index_rbio_pages(struct btrfs_raid_bio *rbio) spin_lock_irq(&rbio->bio_list_lock); bio_list_for_each(bio, &rbio->bio_list) { - start = (u64)bio->bi_sector << 9; + start = (u64)bio->bi_iter.bi_sector << 9; stripe_offset = start - rbio->raid_map[0]; page_index = stripe_offset >> PAGE_CACHE_SHIFT; @@ -1272,7 +1272,7 @@ cleanup: static int find_bio_stripe(struct btrfs_raid_bio *rbio, struct bio *bio) { - u64 physical = bio->bi_sector; + u64 physical = bio->bi_iter.bi_sector; u64 stripe_start; int i; struct btrfs_bio_stripe *stripe; @@ -1298,7 +1298,7 @@ static int find_bio_stripe(struct btrfs_raid_bio *rbio, static int find_logical_bio_stripe(struct btrfs_raid_bio *rbio, struct bio *bio) { - u64 logical = bio->bi_sector; + u64 logical = bio->bi_iter.bi_sector; u64 stripe_start; int i; @@ -1602,8 +1602,8 @@ static int plug_cmp(void *priv, struct list_head *a, struct list_head *b) plug_list); struct btrfs_raid_bio *rb = container_of(b, struct btrfs_raid_bio, plug_list); - u64 a_sector = ra->bio_list.head->bi_sector; - u64 b_sector = rb->bio_list.head->bi_sector; + u64 a_sector = ra->bio_list.head->bi_iter.bi_sector; + u64 b_sector = rb->bio_list.head->bi_iter.bi_sector; if (a_sector < b_sector) return -1; @@ -1691,7 +1691,7 @@ int raid56_parity_write(struct btrfs_root *root, struct bio *bio, if (IS_ERR(rbio)) return PTR_ERR(rbio); bio_list_add(&rbio->bio_list, bio); - rbio->bio_list_bytes = bio->bi_size; + rbio->bio_list_bytes = bio->bi_iter.bi_size; /* * don't plug on full rbios, just get them out the door @@ -2044,7 +2044,7 @@ int raid56_parity_recover(struct btrfs_root *root, struct bio *bio, rbio->read_rebuild = 1; bio_list_add(&rbio->bio_list, bio); - rbio->bio_list_bytes = bio->bi_size; + rbio->bio_list_bytes = bio->bi_iter.bi_size; rbio->faila = find_logical_bio_stripe(rbio, bio); if (rbio->faila == -1) { diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 1fd3f33c330a..bb9a928fa3a8 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1308,7 +1308,7 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info, continue; } bio->bi_bdev = page->dev->bdev; - bio->bi_sector = page->physical >> 9; + bio->bi_iter.bi_sector = page->physical >> 9; bio_add_page(bio, page->page, PAGE_SIZE, 0); if (btrfsic_submit_bio_wait(READ, bio)) @@ -1427,7 +1427,7 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, if (!bio) return -EIO; bio->bi_bdev = page_bad->dev->bdev; - bio->bi_sector = page_bad->physical >> 9; + bio->bi_iter.bi_sector = page_bad->physical >> 9; ret = bio_add_page(bio, page_good->page, PAGE_SIZE, 0); if (PAGE_SIZE != ret) { @@ -1520,7 +1520,7 @@ again: bio->bi_private = sbio; bio->bi_end_io = scrub_wr_bio_end_io; bio->bi_bdev = sbio->dev->bdev; - bio->bi_sector = sbio->physical >> 9; + bio->bi_iter.bi_sector = sbio->physical >> 9; sbio->err = 0; } else if (sbio->physical + sbio->page_count * PAGE_SIZE != spage->physical_for_dev_replace || @@ -1926,7 +1926,7 @@ again: bio->bi_private = sbio; bio->bi_end_io = scrub_bio_end_io; bio->bi_bdev = sbio->dev->bdev; - bio->bi_sector = sbio->physical >> 9; + bio->bi_iter.bi_sector = sbio->physical >> 9; sbio->err = 0; } else if (sbio->physical + sbio->page_count * PAGE_SIZE != spage->physical || @@ -3371,8 +3371,8 @@ static int write_page_nocow(struct scrub_ctx *sctx, spin_unlock(&sctx->stat_lock); return -ENOMEM; } - bio->bi_size = 0; - bio->bi_sector = physical_for_dev_replace >> 9; + bio->bi_iter.bi_size = 0; + bio->bi_iter.bi_sector = physical_for_dev_replace >> 9; bio->bi_bdev = dev->bdev; ret = bio_add_page(bio, page, PAGE_CACHE_SIZE, 0); if (ret != PAGE_CACHE_SIZE) { diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 92303f42baaa..f2130de0ddc2 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5411,7 +5411,7 @@ static int bio_size_ok(struct block_device *bdev, struct bio *bio, if (!q->merge_bvec_fn) return 1; - bvm.bi_size = bio->bi_size - prev->bv_len; + bvm.bi_size = bio->bi_iter.bi_size - prev->bv_len; if (q->merge_bvec_fn(q, &bvm, prev) < prev->bv_len) return 0; return 1; @@ -5426,7 +5426,7 @@ static void submit_stripe_bio(struct btrfs_root *root, struct btrfs_bio *bbio, bio->bi_private = bbio; btrfs_io_bio(bio)->stripe_index = dev_nr; bio->bi_end_io = btrfs_end_bio; - bio->bi_sector = physical >> 9; + bio->bi_iter.bi_sector = physical >> 9; #ifdef DEBUG { struct rcu_string *name; @@ -5464,7 +5464,7 @@ again: while (bvec <= (first_bio->bi_io_vec + first_bio->bi_vcnt - 1)) { if (bio_add_page(bio, bvec->bv_page, bvec->bv_len, bvec->bv_offset) < bvec->bv_len) { - u64 len = bio->bi_size; + u64 len = bio->bi_iter.bi_size; atomic_inc(&bbio->stripes_pending); submit_stripe_bio(root, bbio, bio, physical, dev_nr, @@ -5486,7 +5486,7 @@ static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical) bio->bi_private = bbio->private; bio->bi_end_io = bbio->end_io; btrfs_io_bio(bio)->mirror_num = bbio->mirror_num; - bio->bi_sector = logical >> 9; + bio->bi_iter.bi_sector = logical >> 9; kfree(bbio); bio_endio(bio, -EIO); } @@ -5497,7 +5497,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, { struct btrfs_device *dev; struct bio *first_bio = bio; - u64 logical = (u64)bio->bi_sector << 9; + u64 logical = (u64)bio->bi_iter.bi_sector << 9; u64 length = 0; u64 map_length; u64 *raid_map = NULL; @@ -5506,7 +5506,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, int total_devs = 1; struct btrfs_bio *bbio = NULL; - length = bio->bi_size; + length = bio->bi_iter.bi_size; map_length = length; ret = __btrfs_map_block(root->fs_info, rw, logical, &map_length, &bbio, diff --git a/fs/buffer.c b/fs/buffer.c index 6024877335ca..1c04ec66974e 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2982,11 +2982,11 @@ static void guard_bh_eod(int rw, struct bio *bio, struct buffer_head *bh) * let it through, and the IO layer will turn it into * an EIO. */ - if (unlikely(bio->bi_sector >= maxsector)) + if (unlikely(bio->bi_iter.bi_sector >= maxsector)) return; - maxsector -= bio->bi_sector; - bytes = bio->bi_size; + maxsector -= bio->bi_iter.bi_sector; + bytes = bio->bi_iter.bi_size; if (likely((bytes >> 9) <= maxsector)) return; @@ -2994,7 +2994,7 @@ static void guard_bh_eod(int rw, struct bio *bio, struct buffer_head *bh) bytes = maxsector << 9; /* Truncate the bio.. */ - bio->bi_size = bytes; + bio->bi_iter.bi_size = bytes; bio->bi_io_vec[0].bv_len = bytes; /* ..and clear the end of the buffer for reads */ @@ -3029,14 +3029,14 @@ int _submit_bh(int rw, struct buffer_head *bh, unsigned long bio_flags) */ bio = bio_alloc(GFP_NOIO, 1); - bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9); + bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio->bi_bdev = bh->b_bdev; bio->bi_io_vec[0].bv_page = bh->b_page; bio->bi_io_vec[0].bv_len = bh->b_size; bio->bi_io_vec[0].bv_offset = bh_offset(bh); bio->bi_vcnt = 1; - bio->bi_size = bh->b_size; + bio->bi_iter.bi_size = bh->b_size; bio->bi_end_io = end_bio_bh_io_sync; bio->bi_private = bh; diff --git a/fs/direct-io.c b/fs/direct-io.c index 0e04142d5962..160a5489a939 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -375,7 +375,7 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio, bio = bio_alloc(GFP_KERNEL, nr_vecs); bio->bi_bdev = bdev; - bio->bi_sector = first_sector; + bio->bi_iter.bi_sector = first_sector; if (dio->is_async) bio->bi_end_io = dio_bio_end_aio; else @@ -719,7 +719,7 @@ static inline int dio_send_cur_page(struct dio *dio, struct dio_submit *sdio, if (sdio->bio) { loff_t cur_offset = sdio->cur_page_fs_offset; loff_t bio_next_offset = sdio->logical_offset_in_bio + - sdio->bio->bi_size; + sdio->bio->bi_iter.bi_size; /* * See whether this new request is contiguous with the old. diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index a31e4da14508..ab95508e3d40 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -298,7 +298,7 @@ ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end) static void ext4_end_bio(struct bio *bio, int error) { ext4_io_end_t *io_end = bio->bi_private; - sector_t bi_sector = bio->bi_sector; + sector_t bi_sector = bio->bi_iter.bi_sector; BUG_ON(!io_end); bio->bi_end_io = NULL; @@ -366,7 +366,7 @@ static int io_submit_init_bio(struct ext4_io_submit *io, bio = bio_alloc(GFP_NOIO, min(nvecs, BIO_MAX_PAGES)); if (!bio) return -ENOMEM; - bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9); + bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio->bi_bdev = bh->b_bdev; bio->bi_end_io = ext4_end_bio; bio->bi_private = ext4_get_io_end(io->io_end); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index a4949096cf4c..a2c8de8ba6ce 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -386,7 +386,7 @@ int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page, bio = f2fs_bio_alloc(bdev, 1); /* Initialize the bio */ - bio->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr); + bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr); bio->bi_end_io = read_end_io; if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) { diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index a90c6bc0d129..36e8afd8e1e4 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -682,7 +682,7 @@ retry: bio_blocks = MAX_BIO_BLOCKS(max_hw_blocks(sbi)); sbi->bio[type] = f2fs_bio_alloc(bdev, bio_blocks); - sbi->bio[type]->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr); + sbi->bio[type]->bi_iter.bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr); sbi->bio[type]->bi_private = priv; /* * The end_io will be assigned at the sumbission phase. diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 010b9fb9fec6..985da945f0b5 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -272,7 +272,7 @@ static struct bio *gfs2_log_alloc_bio(struct gfs2_sbd *sdp, u64 blkno) nrvecs = max(nrvecs/2, 1U); } - bio->bi_sector = blkno * (sb->s_blocksize >> 9); + bio->bi_iter.bi_sector = blkno * (sb->s_blocksize >> 9); bio->bi_bdev = sb->s_bdev; bio->bi_end_io = gfs2_end_log_write; bio->bi_private = sdp; diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 82303b474958..16194da91652 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -224,7 +224,7 @@ static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector, int silent) lock_page(page); bio = bio_alloc(GFP_NOFS, 1); - bio->bi_sector = sector * (sb->s_blocksize >> 9); + bio->bi_iter.bi_sector = sector * (sb->s_blocksize >> 9); bio->bi_bdev = sb->s_bdev; bio_add_page(bio, page, PAGE_SIZE, 0); diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c index e9a97a0d4314..3f999649587f 100644 --- a/fs/hfsplus/wrapper.c +++ b/fs/hfsplus/wrapper.c @@ -63,7 +63,7 @@ int hfsplus_submit_bio(struct super_block *sb, sector_t sector, sector &= ~((io_size >> HFSPLUS_SECTOR_SHIFT) - 1); bio = bio_alloc(GFP_NOIO, 1); - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_bdev = sb->s_bdev; if (!(rw & WRITE) && data) diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index 360d27c48887..8d811e02b4b9 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -1998,20 +1998,20 @@ static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp) bio = bio_alloc(GFP_NOFS, 1); - bio->bi_sector = bp->l_blkno << (log->l2bsize - 9); + bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9); bio->bi_bdev = log->bdev; bio->bi_io_vec[0].bv_page = bp->l_page; bio->bi_io_vec[0].bv_len = LOGPSIZE; bio->bi_io_vec[0].bv_offset = bp->l_offset; bio->bi_vcnt = 1; - bio->bi_size = LOGPSIZE; + bio->bi_iter.bi_size = LOGPSIZE; bio->bi_end_io = lbmIODone; bio->bi_private = bp; /*check if journaling to disk has been disabled*/ if (log->no_integrity) { - bio->bi_size = 0; + bio->bi_iter.bi_size = 0; lbmIODone(bio, 0); } else { submit_bio(READ_SYNC, bio); @@ -2144,21 +2144,21 @@ static void lbmStartIO(struct lbuf * bp) jfs_info("lbmStartIO\n"); bio = bio_alloc(GFP_NOFS, 1); - bio->bi_sector = bp->l_blkno << (log->l2bsize - 9); + bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9); bio->bi_bdev = log->bdev; bio->bi_io_vec[0].bv_page = bp->l_page; bio->bi_io_vec[0].bv_len = LOGPSIZE; bio->bi_io_vec[0].bv_offset = bp->l_offset; bio->bi_vcnt = 1; - bio->bi_size = LOGPSIZE; + bio->bi_iter.bi_size = LOGPSIZE; bio->bi_end_io = lbmIODone; bio->bi_private = bp; /* check if journaling to disk has been disabled */ if (log->no_integrity) { - bio->bi_size = 0; + bio->bi_iter.bi_size = 0; lbmIODone(bio, 0); } else { submit_bio(WRITE_SYNC, bio); diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index d165cde0c68d..49ba7ff1bbb9 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -416,7 +416,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) * count from hitting zero before we're through */ inc_io(page); - if (!bio->bi_size) + if (!bio->bi_iter.bi_size) goto dump_bio; submit_bio(WRITE, bio); nr_underway++; @@ -438,7 +438,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) bio = bio_alloc(GFP_NOFS, 1); bio->bi_bdev = inode->i_sb->s_bdev; - bio->bi_sector = pblock << (inode->i_blkbits - 9); + bio->bi_iter.bi_sector = pblock << (inode->i_blkbits - 9); bio->bi_end_io = metapage_write_end_io; bio->bi_private = page; @@ -452,7 +452,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) if (bio) { if (bio_add_page(bio, page, bio_bytes, bio_offset) < bio_bytes) goto add_failed; - if (!bio->bi_size) + if (!bio->bi_iter.bi_size) goto dump_bio; submit_bio(WRITE, bio); @@ -517,7 +517,8 @@ static int metapage_readpage(struct file *fp, struct page *page) bio = bio_alloc(GFP_NOFS, 1); bio->bi_bdev = inode->i_sb->s_bdev; - bio->bi_sector = pblock << (inode->i_blkbits - 9); + bio->bi_iter.bi_sector = + pblock << (inode->i_blkbits - 9); bio->bi_end_io = metapage_read_end_io; bio->bi_private = page; len = xlen << inode->i_blkbits; diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index e6df3be3b31b..76279e11982d 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c @@ -26,9 +26,9 @@ static int sync_request(struct page *page, struct block_device *bdev, int rw) bio_vec.bv_len = PAGE_SIZE; bio_vec.bv_offset = 0; bio.bi_vcnt = 1; - bio.bi_size = PAGE_SIZE; bio.bi_bdev = bdev; - bio.bi_sector = page->index * (PAGE_SIZE >> 9); + bio.bi_iter.bi_sector = page->index * (PAGE_SIZE >> 9); + bio.bi_iter.bi_size = PAGE_SIZE; return submit_bio_wait(rw, &bio); } @@ -92,9 +92,9 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, if (i >= max_pages) { /* Block layer cannot split bios :( */ bio->bi_vcnt = i; - bio->bi_size = i * PAGE_SIZE; + bio->bi_iter.bi_size = i * PAGE_SIZE; bio->bi_bdev = super->s_bdev; - bio->bi_sector = ofs >> 9; + bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = writeseg_end_io; atomic_inc(&super->s_pending_writes); @@ -119,9 +119,9 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, unlock_page(page); } bio->bi_vcnt = nr_pages; - bio->bi_size = nr_pages * PAGE_SIZE; + bio->bi_iter.bi_size = nr_pages * PAGE_SIZE; bio->bi_bdev = super->s_bdev; - bio->bi_sector = ofs >> 9; + bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = writeseg_end_io; atomic_inc(&super->s_pending_writes); @@ -184,9 +184,9 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index, if (i >= max_pages) { /* Block layer cannot split bios :( */ bio->bi_vcnt = i; - bio->bi_size = i * PAGE_SIZE; + bio->bi_iter.bi_size = i * PAGE_SIZE; bio->bi_bdev = super->s_bdev; - bio->bi_sector = ofs >> 9; + bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = erase_end_io; atomic_inc(&super->s_pending_writes); @@ -205,9 +205,9 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index, bio->bi_io_vec[i].bv_offset = 0; } bio->bi_vcnt = nr_pages; - bio->bi_size = nr_pages * PAGE_SIZE; + bio->bi_iter.bi_size = nr_pages * PAGE_SIZE; bio->bi_bdev = super->s_bdev; - bio->bi_sector = ofs >> 9; + bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = erase_end_io; atomic_inc(&super->s_pending_writes); diff --git a/fs/mpage.c b/fs/mpage.c index dd6d5878f4d9..4979ffa60aaa 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -93,7 +93,7 @@ mpage_alloc(struct block_device *bdev, if (bio) { bio->bi_bdev = bdev; - bio->bi_sector = first_sector; + bio->bi_iter.bi_sector = first_sector; } return bio; } diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index da768923bf7c..56ff823ca82e 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -134,8 +134,8 @@ bl_submit_bio(int rw, struct bio *bio) if (bio) { get_parallel(bio->bi_private); dprintk("%s submitting %s bio %u@%llu\n", __func__, - rw == READ ? "read" : "write", - bio->bi_size, (unsigned long long)bio->bi_sector); + rw == READ ? "read" : "write", bio->bi_iter.bi_size, + (unsigned long long)bio->bi_iter.bi_sector); submit_bio(rw, bio); } return NULL; @@ -156,7 +156,8 @@ static struct bio *bl_alloc_init_bio(int npg, sector_t isect, } if (bio) { - bio->bi_sector = isect - be->be_f_offset + be->be_v_offset; + bio->bi_iter.bi_sector = isect - be->be_f_offset + + be->be_v_offset; bio->bi_bdev = be->be_mdev; bio->bi_end_io = end_io; bio->bi_private = par; @@ -511,7 +512,7 @@ bl_do_readpage_sync(struct page *page, struct pnfs_block_extent *be, isect = (page->index << PAGE_CACHE_SECTOR_SHIFT) + (offset / SECTOR_SIZE); - bio->bi_sector = isect - be->be_f_offset + be->be_v_offset; + bio->bi_iter.bi_sector = isect - be->be_f_offset + be->be_v_offset; bio->bi_bdev = be->be_mdev; bio->bi_end_io = bl_read_single_end_io; diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index 2d8be51f90dc..dc3a9efdaab8 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c @@ -416,7 +416,8 @@ static struct bio *nilfs_alloc_seg_bio(struct the_nilfs *nilfs, sector_t start, } if (likely(bio)) { bio->bi_bdev = nilfs->ns_bdev; - bio->bi_sector = start << (nilfs->ns_blocksize_bits - 9); + bio->bi_iter.bi_sector = + start << (nilfs->ns_blocksize_bits - 9); } return bio; } diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 73920ffda05b..bf482dfed14f 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -413,7 +413,7 @@ static struct bio *o2hb_setup_one_bio(struct o2hb_region *reg, } /* Must put everything in 512 byte sectors for the bio... */ - bio->bi_sector = (reg->hr_start_block + cs) << (bits - 9); + bio->bi_iter.bi_sector = (reg->hr_start_block + cs) << (bits - 9); bio->bi_bdev = reg->hr_bdev; bio->bi_private = wc; bio->bi_end_io = o2hb_bio_end_io; diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 71c8c9d2b882..1b19b9cd692a 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -407,7 +407,7 @@ xfs_alloc_ioend_bio( struct bio *bio = bio_alloc(GFP_NOIO, nvecs); ASSERT(bio->bi_private == NULL); - bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9); + bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio->bi_bdev = bh->b_bdev; return bio; } diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index c7f0b77dcb00..5f3ea443ebbe 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -1255,7 +1255,7 @@ next_chunk: bio = bio_alloc(GFP_NOIO, nr_pages); bio->bi_bdev = bp->b_target->bt_bdev; - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_end_io = xfs_buf_bio_end_io; bio->bi_private = bp; @@ -1277,7 +1277,7 @@ next_chunk: total_nr_pages--; } - if (likely(bio->bi_size)) { + if (likely(bio->bi_iter.bi_size)) { if (xfs_buf_is_vmapped(bp)) { flush_kernel_vmap_range(bp->b_addr, xfs_buf_vmap_len(bp)); diff --git a/include/linux/bio.h b/include/linux/bio.h index 060ff695085c..e2e0bc642ed1 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -62,19 +62,19 @@ * on highmem page vectors */ #define bio_iovec_idx(bio, idx) (&((bio)->bi_io_vec[(idx)])) -#define bio_iovec(bio) bio_iovec_idx((bio), (bio)->bi_idx) +#define bio_iovec(bio) bio_iovec_idx((bio), (bio)->bi_iter.bi_idx) #define bio_page(bio) bio_iovec((bio))->bv_page #define bio_offset(bio) bio_iovec((bio))->bv_offset -#define bio_segments(bio) ((bio)->bi_vcnt - (bio)->bi_idx) -#define bio_sectors(bio) ((bio)->bi_size >> 9) -#define bio_end_sector(bio) ((bio)->bi_sector + bio_sectors((bio))) +#define bio_segments(bio) ((bio)->bi_vcnt - (bio)->bi_iter.bi_idx) +#define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9) +#define bio_end_sector(bio) ((bio)->bi_iter.bi_sector + bio_sectors((bio))) static inline unsigned int bio_cur_bytes(struct bio *bio) { if (bio->bi_vcnt) return bio_iovec(bio)->bv_len; else /* dataless requests such as discard */ - return bio->bi_size; + return bio->bi_iter.bi_size; } static inline void *bio_data(struct bio *bio) @@ -108,7 +108,7 @@ static inline void *bio_data(struct bio *bio) */ #define __BVEC_END(bio) bio_iovec_idx((bio), (bio)->bi_vcnt - 1) -#define __BVEC_START(bio) bio_iovec_idx((bio), (bio)->bi_idx) +#define __BVEC_START(bio) bio_iovec_idx((bio), (bio)->bi_iter.bi_idx) /* Default implementation of BIOVEC_PHYS_MERGEABLE */ #define __BIOVEC_PHYS_MERGEABLE(vec1, vec2) \ @@ -150,7 +150,7 @@ static inline void *bio_data(struct bio *bio) i++) #define bio_for_each_segment(bvl, bio, i) \ - for (i = (bio)->bi_idx; \ + for (i = (bio)->bi_iter.bi_idx; \ bvl = bio_iovec_idx((bio), (i)), i < (bio)->bi_vcnt; \ i++) @@ -365,7 +365,7 @@ static inline char *__bio_kmap_irq(struct bio *bio, unsigned short idx, #define __bio_kunmap_irq(buf, flags) bvec_kunmap_irq(buf, flags) #define bio_kmap_irq(bio, flags) \ - __bio_kmap_irq((bio), (bio)->bi_idx, (flags)) + __bio_kmap_irq((bio), (bio)->bi_iter.bi_idx, (flags)) #define bio_kunmap_irq(buf,flags) __bio_kunmap_irq(buf, flags) /* diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 238ef0ed62f8..29b5b84d8a29 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -28,13 +28,19 @@ struct bio_vec { unsigned int bv_offset; }; +struct bvec_iter { + sector_t bi_sector; /* device address in 512 byte + sectors */ + unsigned int bi_size; /* residual I/O count */ + + unsigned int bi_idx; /* current index into bvl_vec */ +}; + /* * main unit of I/O for the block layer and lower layers (ie drivers and * stacking drivers) */ struct bio { - sector_t bi_sector; /* device address in 512 byte - sectors */ struct bio *bi_next; /* request queue link */ struct block_device *bi_bdev; unsigned long bi_flags; /* status, command, etc */ @@ -42,16 +48,13 @@ struct bio { * top bits priority */ - unsigned short bi_vcnt; /* how many bio_vec's */ - unsigned short bi_idx; /* current index into bvl_vec */ + struct bvec_iter bi_iter; /* Number of segments in this BIO after * physical address coalescing is performed. */ unsigned int bi_phys_segments; - unsigned int bi_size; /* residual I/O count */ - /* * To keep track of the max segment size, we account for the * sizes of the first and last mergeable segments in this bio. @@ -74,11 +77,13 @@ struct bio { struct bio_integrity_payload *bi_integrity; /* data integrity */ #endif + unsigned short bi_vcnt; /* how many bio_vec's */ + /* * Everything starting with bi_max_vecs will be preserved by bio_reset() */ - unsigned int bi_max_vecs; /* max bvl_vecs we can hold */ + unsigned short bi_max_vecs; /* max bvl_vecs we can hold */ atomic_t bi_cnt; /* pin count */ diff --git a/include/trace/events/bcache.h b/include/trace/events/bcache.h index e2b9576d00e2..095c6e4fe1e8 100644 --- a/include/trace/events/bcache.h +++ b/include/trace/events/bcache.h @@ -24,10 +24,10 @@ DECLARE_EVENT_CLASS(bcache_request, __entry->dev = bio->bi_bdev->bd_dev; __entry->orig_major = d->disk->major; __entry->orig_minor = d->disk->first_minor; - __entry->sector = bio->bi_sector; - __entry->orig_sector = bio->bi_sector - 16; - __entry->nr_sector = bio->bi_size >> 9; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + __entry->sector = bio->bi_iter.bi_sector; + __entry->orig_sector = bio->bi_iter.bi_sector - 16; + __entry->nr_sector = bio->bi_iter.bi_size >> 9; + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); ), TP_printk("%d,%d %s %llu + %u (from %d,%d @ %llu)", @@ -99,9 +99,9 @@ DECLARE_EVENT_CLASS(bcache_bio, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; - __entry->nr_sector = bio->bi_size >> 9; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + __entry->sector = bio->bi_iter.bi_sector; + __entry->nr_sector = bio->bi_iter.bi_size >> 9; + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); ), TP_printk("%d,%d %s %llu + %u", @@ -134,9 +134,9 @@ TRACE_EVENT(bcache_read, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; - __entry->nr_sector = bio->bi_size >> 9; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + __entry->sector = bio->bi_iter.bi_sector; + __entry->nr_sector = bio->bi_iter.bi_size >> 9; + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); __entry->cache_hit = hit; __entry->bypass = bypass; ), @@ -162,9 +162,9 @@ TRACE_EVENT(bcache_write, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; - __entry->nr_sector = bio->bi_size >> 9; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + __entry->sector = bio->bi_iter.bi_sector; + __entry->nr_sector = bio->bi_iter.bi_size >> 9; + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); __entry->writeback = writeback; __entry->bypass = bypass; ), diff --git a/include/trace/events/block.h b/include/trace/events/block.h index 4c2301d2ef1a..e76ae19a8d6f 100644 --- a/include/trace/events/block.h +++ b/include/trace/events/block.h @@ -243,9 +243,9 @@ TRACE_EVENT(block_bio_bounce, TP_fast_assign( __entry->dev = bio->bi_bdev ? bio->bi_bdev->bd_dev : 0; - __entry->sector = bio->bi_sector; + __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio_sectors(bio); - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); memcpy(__entry->comm, current->comm, TASK_COMM_LEN); ), @@ -280,10 +280,10 @@ TRACE_EVENT(block_bio_complete, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; + __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio_sectors(bio); __entry->error = error; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); ), TP_printk("%d,%d %s %llu + %u [%d]", @@ -308,9 +308,9 @@ DECLARE_EVENT_CLASS(block_bio_merge, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; + __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio_sectors(bio); - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); memcpy(__entry->comm, current->comm, TASK_COMM_LEN); ), @@ -375,9 +375,9 @@ TRACE_EVENT(block_bio_queue, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; + __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio_sectors(bio); - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); memcpy(__entry->comm, current->comm, TASK_COMM_LEN); ), @@ -403,7 +403,7 @@ DECLARE_EVENT_CLASS(block_get_rq, TP_fast_assign( __entry->dev = bio ? bio->bi_bdev->bd_dev : 0; - __entry->sector = bio ? bio->bi_sector : 0; + __entry->sector = bio ? bio->bi_iter.bi_sector : 0; __entry->nr_sector = bio ? bio_sectors(bio) : 0; blk_fill_rwbs(__entry->rwbs, bio ? bio->bi_rw : 0, __entry->nr_sector); @@ -538,9 +538,9 @@ TRACE_EVENT(block_split, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; + __entry->sector = bio->bi_iter.bi_sector; __entry->new_sector = new_sector; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); memcpy(__entry->comm, current->comm, TASK_COMM_LEN); ), @@ -579,11 +579,11 @@ TRACE_EVENT(block_bio_remap, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; + __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio_sectors(bio); __entry->old_dev = dev; __entry->old_sector = from; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); ), TP_printk("%d,%d %s %llu + %u <- (%d,%d) %llu", diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index e0dc355fa317..bd3ee4fbe7a7 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -616,8 +616,8 @@ TRACE_EVENT(f2fs_do_submit_bio, __entry->dev = sb->s_dev; __entry->btype = btype; __entry->sync = sync; - __entry->sector = bio->bi_sector; - __entry->size = bio->bi_size; + __entry->sector = bio->bi_iter.bi_sector; + __entry->size = bio->bi_iter.bi_size; ), TP_printk("dev = (%d,%d), type = %s, io = %s, sector = %lld, size = %u", diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c index d09dd10c5a5e..9a58bc258810 100644 --- a/kernel/power/block_io.c +++ b/kernel/power/block_io.c @@ -32,7 +32,7 @@ static int submit(int rw, struct block_device *bdev, sector_t sector, struct bio *bio; bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1); - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_bdev = bdev; bio->bi_end_io = end_swap_bio_read; diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index f785aef65799..b418cb0d7242 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -781,8 +781,8 @@ static void blk_add_trace_bio(struct request_queue *q, struct bio *bio, if (!error && !bio_flagged(bio, BIO_UPTODATE)) error = EIO; - __blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, what, - error, 0, NULL); + __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, + bio->bi_rw, what, error, 0, NULL); } static void blk_add_trace_bio_bounce(void *ignore, @@ -885,8 +885,9 @@ static void blk_add_trace_split(void *ignore, if (bt) { __be64 rpdu = cpu_to_be64(pdu); - __blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, - BLK_TA_SPLIT, !bio_flagged(bio, BIO_UPTODATE), + __blk_add_trace(bt, bio->bi_iter.bi_sector, + bio->bi_iter.bi_size, bio->bi_rw, BLK_TA_SPLIT, + !bio_flagged(bio, BIO_UPTODATE), sizeof(rpdu), &rpdu); } } @@ -918,9 +919,9 @@ static void blk_add_trace_bio_remap(void *ignore, r.device_to = cpu_to_be32(bio->bi_bdev->bd_dev); r.sector_from = cpu_to_be64(from); - __blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, - BLK_TA_REMAP, !bio_flagged(bio, BIO_UPTODATE), - sizeof(r), &r); + __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, + bio->bi_rw, BLK_TA_REMAP, + !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r); } /** diff --git a/mm/page_io.c b/mm/page_io.c index 8c79a4764be0..f14eded987fa 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -31,13 +31,13 @@ static struct bio *get_swap_bio(gfp_t gfp_flags, bio = bio_alloc(gfp_flags, 1); if (bio) { - bio->bi_sector = map_swap_page(page, &bio->bi_bdev); - bio->bi_sector <<= PAGE_SHIFT - 9; + bio->bi_iter.bi_sector = map_swap_page(page, &bio->bi_bdev); + bio->bi_iter.bi_sector <<= PAGE_SHIFT - 9; bio->bi_io_vec[0].bv_page = page; bio->bi_io_vec[0].bv_len = PAGE_SIZE; bio->bi_io_vec[0].bv_offset = 0; bio->bi_vcnt = 1; - bio->bi_size = PAGE_SIZE; + bio->bi_iter.bi_size = PAGE_SIZE; bio->bi_end_io = end_io; } return bio; @@ -62,7 +62,7 @@ void end_swap_bio_write(struct bio *bio, int err) printk(KERN_ALERT "Write-error on swap-device (%u:%u:%Lu)\n", imajor(bio->bi_bdev->bd_inode), iminor(bio->bi_bdev->bd_inode), - (unsigned long long)bio->bi_sector); + (unsigned long long)bio->bi_iter.bi_sector); ClearPageReclaim(page); } end_page_writeback(page); @@ -80,7 +80,7 @@ void end_swap_bio_read(struct bio *bio, int err) printk(KERN_ALERT "Read-error on swap-device (%u:%u:%Lu)\n", imajor(bio->bi_bdev->bd_inode), iminor(bio->bi_bdev->bd_inode), - (unsigned long long)bio->bi_sector); + (unsigned long long)bio->bi_iter.bi_sector); goto out; } -- cgit v1.2.3 From 4550dd6c6b062fc5e5b647296d55da22616123c3 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Wed, 7 Aug 2013 14:26:21 -0700 Subject: block: Immutable bio vecs This adds a mechanism by which we can advance a bio by an arbitrary number of bytes without modifying the biovec: bio->bi_iter.bi_bvec_done indicates the number of bytes completed in the current bvec. Various driver code still needs to be updated to not refer to the bvec directly before we can use this for interesting things, like efficient bio splitting. Signed-off-by: Kent Overstreet Cc: Jens Axboe Cc: Lars Ellenberg Cc: Paul Clements Cc: drbd-user@lists.linbit.com Cc: nbd-general@lists.sourceforge.net --- Documentation/block/biovecs.txt | 111 ++++++++++++++++++++++++++++++++++++++++ drivers/block/drbd/drbd_main.c | 4 +- drivers/block/nbd.c | 2 +- fs/bio.c | 27 +--------- include/linux/bio.h | 81 ++++++++++++++++++++++++++--- include/linux/blk_types.h | 3 ++ include/linux/blkdev.h | 4 +- 7 files changed, 194 insertions(+), 38 deletions(-) create mode 100644 Documentation/block/biovecs.txt (limited to 'Documentation') diff --git a/Documentation/block/biovecs.txt b/Documentation/block/biovecs.txt new file mode 100644 index 000000000000..74a32ad52f53 --- /dev/null +++ b/Documentation/block/biovecs.txt @@ -0,0 +1,111 @@ + +Immutable biovecs and biovec iterators: +======================================= + +Kent Overstreet + +As of 3.13, biovecs should never be modified after a bio has been submitted. +Instead, we have a new struct bvec_iter which represents a range of a biovec - +the iterator will be modified as the bio is completed, not the biovec. + +More specifically, old code that needed to partially complete a bio would +update bi_sector and bi_size, and advance bi_idx to the next biovec. If it +ended up partway through a biovec, it would increment bv_offset and decrement +bv_len by the number of bytes completed in that biovec. + +In the new scheme of things, everything that must be mutated in order to +partially complete a bio is segregated into struct bvec_iter: bi_sector, +bi_size and bi_idx have been moved there; and instead of modifying bv_offset +and bv_len, struct bvec_iter has bi_bvec_done, which represents the number of +bytes completed in the current bvec. + +There are a bunch of new helper macros for hiding the gory details - in +particular, presenting the illusion of partially completed biovecs so that +normal code doesn't have to deal with bi_bvec_done. + + * Driver code should no longer refer to biovecs directly; we now have + bio_iovec() and bio_iovec_iter() macros that return literal struct biovecs, + constructed from the raw biovecs but taking into account bi_bvec_done and + bi_size. + + bio_for_each_segment() has been updated to take a bvec_iter argument + instead of an integer (that corresponded to bi_idx); for a lot of code the + conversion just required changing the types of the arguments to + bio_for_each_segment(). + + * Advancing a bvec_iter is done with bio_advance_iter(); bio_advance() is a + wrapper around bio_advance_iter() that operates on bio->bi_iter, and also + advances the bio integrity's iter if present. + + There is a lower level advance function - bvec_iter_advance() - which takes + a pointer to a biovec, not a bio; this is used by the bio integrity code. + +What's all this get us? +======================= + +Having a real iterator, and making biovecs immutable, has a number of +advantages: + + * Before, iterating over bios was very awkward when you weren't processing + exactly one bvec at a time - for example, bio_copy_data() in fs/bio.c, + which copies the contents of one bio into another. Because the biovecs + wouldn't necessarily be the same size, the old code was tricky convoluted - + it had to walk two different bios at the same time, keeping both bi_idx and + and offset into the current biovec for each. + + The new code is much more straightforward - have a look. This sort of + pattern comes up in a lot of places; a lot of drivers were essentially open + coding bvec iterators before, and having common implementation considerably + simplifies a lot of code. + + * Before, any code that might need to use the biovec after the bio had been + completed (perhaps to copy the data somewhere else, or perhaps to resubmit + it somewhere else if there was an error) had to save the entire bvec array + - again, this was being done in a fair number of places. + + * Biovecs can be shared between multiple bios - a bvec iter can represent an + arbitrary range of an existing biovec, both starting and ending midway + through biovecs. This is what enables efficient splitting of arbitrary + bios. Note that this means we _only_ use bi_size to determine when we've + reached the end of a bio, not bi_vcnt - and the bio_iovec() macro takes + bi_size into account when constructing biovecs. + + * Splitting bios is now much simpler. The old bio_split() didn't even work on + bios with more than a single bvec! Now, we can efficiently split arbitrary + size bios - because the new bio can share the old bio's biovec. + + Care must be taken to ensure the biovec isn't freed while the split bio is + still using it, in case the original bio completes first, though. Using + bio_chain() when splitting bios helps with this. + + * Submitting partially completed bios is now perfectly fine - this comes up + occasionally in stacking block drivers and various code (e.g. md and + bcache) had some ugly workarounds for this. + + It used to be the case that submitting a partially completed bio would work + fine to _most_ devices, but since accessing the raw bvec array was the + norm, not all drivers would respect bi_idx and those would break. Now, + since all drivers _must_ go through the bvec iterator - and have been + audited to make sure they are - submitting partially completed bios is + perfectly fine. + +Other implications: +=================== + + * Almost all usage of bi_idx is now incorrect and has been removed; instead, + where previously you would have used bi_idx you'd now use a bvec_iter, + probably passing it to one of the helper macros. + + I.e. instead of using bio_iovec_idx() (or bio->bi_iovec[bio->bi_idx]), you + now use bio_iter_iovec(), which takes a bvec_iter and returns a + literal struct bio_vec - constructed on the fly from the raw biovec but + taking into account bi_bvec_done (and bi_size). + + * bi_vcnt can't be trusted or relied upon by driver code - i.e. anything that + doesn't actually own the bio. The reason is twofold: firstly, it's not + actually needed for iterating over the bio anymore - we only use bi_size. + Secondly, when cloning a bio and reusing (a portion of) the original bio's + biovec, in order to calculate bi_vcnt for the new bio we'd have to iterate + over all the biovecs in the new bio - which is silly as it's not needed. + + So, don't use bi_vcnt anymore. diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index f4e5440aba05..929468e1512a 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1546,7 +1546,7 @@ static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio) err = _drbd_no_send_page(mdev, bvec.bv_page, bvec.bv_offset, bvec.bv_len, - bio_iter_last(bio, iter) + bio_iter_last(bvec, iter) ? 0 : MSG_MORE); if (err) return err; @@ -1565,7 +1565,7 @@ static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio) err = _drbd_send_page(mdev, bvec.bv_page, bvec.bv_offset, bvec.bv_len, - bio_iter_last(bio, iter) ? 0 : MSG_MORE); + bio_iter_last(bvec, iter) ? 0 : MSG_MORE); if (err) return err; } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index aa362f493216..55298db36b2d 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -278,7 +278,7 @@ static int nbd_send_req(struct nbd_device *nbd, struct request *req) */ rq_for_each_segment(bvec, req, iter) { flags = 0; - if (!rq_iter_last(req, iter)) + if (!rq_iter_last(bvec, iter)) flags = MSG_MORE; dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", nbd->disk->disk_name, req, bvec.bv_len); diff --git a/fs/bio.c b/fs/bio.c index 8b7f14a95503..07b4b7afa695 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -532,13 +532,11 @@ void __bio_clone(struct bio *bio, struct bio *bio_src) * most users will be overriding ->bi_bdev with a new target, * so we don't set nor calculate new physical/hw segment counts here */ - bio->bi_iter.bi_sector = bio_src->bi_iter.bi_sector; bio->bi_bdev = bio_src->bi_bdev; bio->bi_flags |= 1 << BIO_CLONED; bio->bi_rw = bio_src->bi_rw; bio->bi_vcnt = bio_src->bi_vcnt; - bio->bi_iter.bi_size = bio_src->bi_iter.bi_size; - bio->bi_iter.bi_idx = bio_src->bi_iter.bi_idx; + bio->bi_iter = bio_src->bi_iter; } EXPORT_SYMBOL(__bio_clone); @@ -808,28 +806,7 @@ void bio_advance(struct bio *bio, unsigned bytes) if (bio_integrity(bio)) bio_integrity_advance(bio, bytes); - bio->bi_iter.bi_sector += bytes >> 9; - bio->bi_iter.bi_size -= bytes; - - if (bio->bi_rw & BIO_NO_ADVANCE_ITER_MASK) - return; - - while (bytes) { - if (unlikely(bio->bi_iter.bi_idx >= bio->bi_vcnt)) { - WARN_ONCE(1, "bio idx %d >= vcnt %d\n", - bio->bi_iter.bi_idx, bio->bi_vcnt); - break; - } - - if (bytes >= bio_iovec(bio).bv_len) { - bytes -= bio_iovec(bio).bv_len; - bio->bi_iter.bi_idx++; - } else { - bio_iovec(bio).bv_len -= bytes; - bio_iovec(bio).bv_offset += bytes; - bytes = 0; - } - } + bio_advance_iter(bio, &bio->bi_iter, bytes); } EXPORT_SYMBOL(bio_advance); diff --git a/include/linux/bio.h b/include/linux/bio.h index c16adb5f69f8..04e592e74c92 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -64,11 +64,38 @@ #define bio_iovec_idx(bio, idx) (&((bio)->bi_io_vec[(idx)])) #define __bio_iovec(bio) bio_iovec_idx((bio), (bio)->bi_iter.bi_idx) -#define bio_iter_iovec(bio, iter) ((bio)->bi_io_vec[(iter).bi_idx]) +#define __bvec_iter_bvec(bvec, iter) (&(bvec)[(iter).bi_idx]) -#define bio_page(bio) (bio_iovec((bio)).bv_page) -#define bio_offset(bio) (bio_iovec((bio)).bv_offset) -#define bio_iovec(bio) (*__bio_iovec(bio)) +#define bvec_iter_page(bvec, iter) \ + (__bvec_iter_bvec((bvec), (iter))->bv_page) + +#define bvec_iter_len(bvec, iter) \ + min((iter).bi_size, \ + __bvec_iter_bvec((bvec), (iter))->bv_len - (iter).bi_bvec_done) + +#define bvec_iter_offset(bvec, iter) \ + (__bvec_iter_bvec((bvec), (iter))->bv_offset + (iter).bi_bvec_done) + +#define bvec_iter_bvec(bvec, iter) \ +((struct bio_vec) { \ + .bv_page = bvec_iter_page((bvec), (iter)), \ + .bv_len = bvec_iter_len((bvec), (iter)), \ + .bv_offset = bvec_iter_offset((bvec), (iter)), \ +}) + +#define bio_iter_iovec(bio, iter) \ + bvec_iter_bvec((bio)->bi_io_vec, (iter)) + +#define bio_iter_page(bio, iter) \ + bvec_iter_page((bio)->bi_io_vec, (iter)) +#define bio_iter_len(bio, iter) \ + bvec_iter_len((bio)->bi_io_vec, (iter)) +#define bio_iter_offset(bio, iter) \ + bvec_iter_offset((bio)->bi_io_vec, (iter)) + +#define bio_page(bio) bio_iter_page((bio), (bio)->bi_iter) +#define bio_offset(bio) bio_iter_offset((bio), (bio)->bi_iter) +#define bio_iovec(bio) bio_iter_iovec((bio), (bio)->bi_iter) #define bio_segments(bio) ((bio)->bi_vcnt - (bio)->bi_iter.bi_idx) #define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9) @@ -145,16 +172,54 @@ static inline void *bio_data(struct bio *bio) bvl = bio_iovec_idx((bio), (i)), i < (bio)->bi_vcnt; \ i++) +static inline void bvec_iter_advance(struct bio_vec *bv, struct bvec_iter *iter, + unsigned bytes) +{ + WARN_ONCE(bytes > iter->bi_size, + "Attempted to advance past end of bvec iter\n"); + + while (bytes) { + unsigned len = min(bytes, bvec_iter_len(bv, *iter)); + + bytes -= len; + iter->bi_size -= len; + iter->bi_bvec_done += len; + + if (iter->bi_bvec_done == __bvec_iter_bvec(bv, *iter)->bv_len) { + iter->bi_bvec_done = 0; + iter->bi_idx++; + } + } +} + +#define for_each_bvec(bvl, bio_vec, iter, start) \ + for ((iter) = start; \ + (bvl) = bvec_iter_bvec((bio_vec), (iter)), \ + (iter).bi_size; \ + bvec_iter_advance((bio_vec), &(iter), (bvl).bv_len)) + + +static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter, + unsigned bytes) +{ + iter->bi_sector += bytes >> 9; + + if (bio->bi_rw & BIO_NO_ADVANCE_ITER_MASK) + iter->bi_size -= bytes; + else + bvec_iter_advance(bio->bi_io_vec, iter, bytes); +} + #define __bio_for_each_segment(bvl, bio, iter, start) \ for (iter = (start); \ - bvl = bio_iter_iovec((bio), (iter)), \ - (iter).bi_idx < (bio)->bi_vcnt; \ - (iter).bi_idx++) + (iter).bi_size && \ + ((bvl = bio_iter_iovec((bio), (iter))), 1); \ + bio_advance_iter((bio), &(iter), (bvl).bv_len)) #define bio_for_each_segment(bvl, bio, iter) \ __bio_for_each_segment(bvl, bio, iter, (bio)->bi_iter) -#define bio_iter_last(bio, iter) ((iter).bi_idx == (bio)->bi_vcnt - 1) +#define bio_iter_last(bvec, iter) ((iter).bi_size == (bvec).bv_len) /* * get a reference to a bio, so it won't disappear. the intended use is diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 29b5b84d8a29..d369f8f6af79 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -34,6 +34,9 @@ struct bvec_iter { unsigned int bi_size; /* residual I/O count */ unsigned int bi_idx; /* current index into bvl_vec */ + + unsigned int bi_bvec_done; /* number of bytes completed in + current bvec */ }; /* diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 337b92a54658..02cb6f0ea71d 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -750,9 +750,9 @@ struct req_iterator { __rq_for_each_bio(_iter.bio, _rq) \ bio_for_each_segment(bvl, _iter.bio, _iter.iter) -#define rq_iter_last(rq, _iter) \ +#define rq_iter_last(bvec, _iter) \ (_iter.bio->bi_next == NULL && \ - bio_iter_last(_iter.bio, _iter.iter)) + bio_iter_last(bvec, _iter.iter)) #ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE # error "You should define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform" -- cgit v1.2.3 From 8caa07c0e565a15f49f290ca4c6a3adf968ddd38 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 29 Oct 2013 11:39:00 +0000 Subject: iio: core: Implement devm_iio_device_{register,unregister} Add device managed devm_iio_device_{register,unregister}() to automatically unregister IIO drivers thus leading to simplified IIO driver code. Signed-off-by: Sachin Kamat Cc: Lars-Peter Clausen Tested-by: Lars-Peter Clausen Reviewed-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- Documentation/driver-model/devres.txt | 2 ++ drivers/iio/industrialio-core.c | 59 +++++++++++++++++++++++++++++++++++ include/linux/iio/iio.h | 3 ++ 3 files changed, 64 insertions(+) (limited to 'Documentation') diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index fcb34a5697ea..ffeab1dded0a 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -242,6 +242,8 @@ IIO devm_iio_device_free() devm_iio_trigger_alloc() devm_iio_trigger_free() + devm_iio_device_register() + devm_iio_device_unregister() IO region devm_request_region() diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 18f72e3d0ed6..1c280b50c74b 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1161,6 +1161,65 @@ void iio_device_unregister(struct iio_dev *indio_dev) mutex_unlock(&indio_dev->info_exist_lock); } EXPORT_SYMBOL(iio_device_unregister); + +static void devm_iio_device_unreg(struct device *dev, void *res) +{ + iio_device_unregister(*(struct iio_dev **)res); +} + +/** + * devm_iio_device_register - Resource-managed iio_device_register() + * @dev: Device to allocate iio_dev for + * @indio_dev: Device structure filled by the device driver + * + * Managed iio_device_register. The IIO device registered with this + * function is automatically unregistered on driver detach. This function + * calls iio_device_register() internally. Refer to that function for more + * information. + * + * If an iio_dev registered with this function needs to be unregistered + * separately, devm_iio_device_unregister() must be used. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev) +{ + struct iio_dev **ptr; + int ret; + + ptr = devres_alloc(devm_iio_device_unreg, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + *ptr = indio_dev; + ret = iio_device_register(indio_dev); + if (!ret) + devres_add(dev, ptr); + else + devres_free(ptr); + + return ret; +} +EXPORT_SYMBOL_GPL(devm_iio_device_register); + +/** + * devm_iio_device_unregister - Resource-managed iio_device_unregister() + * @dev: Device this iio_dev belongs to + * @indio_dev: the iio_dev associated with the device + * + * Unregister iio_dev registered with devm_iio_device_register(). + */ +void devm_iio_device_unregister(struct device *dev, struct iio_dev *indio_dev) +{ + int rc; + + rc = devres_release(dev, devm_iio_device_unreg, + devm_iio_device_match, indio_dev); + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_iio_device_unregister); + subsys_initcall(iio_init); module_exit(iio_exit); diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 256a90a1bea6..a8cabda4d108 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -510,6 +510,9 @@ int iio_device_register(struct iio_dev *indio_dev); **/ void iio_device_unregister(struct iio_dev *indio_dev); +int devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev); +void devm_iio_device_unregister(struct device *dev, struct iio_dev *indio_dev); + /** * iio_push_event() - try to add event to the list for userspace reading * @indio_dev: IIO device structure -- cgit v1.2.3 From 8175bff5b47eae171a393f5bd67673de50630973 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Fri, 25 Oct 2013 10:10:00 +0100 Subject: iio:light:tsl2563: Add DT support Add Device Tree support for the TSL2563 driver, document the binding and add AMS-TAOS Inc. to the list of vendor prefixes. Signed-off-by: Sebastian Reichel Acked-by: Kumar Gala Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/light/tsl2563.txt | 19 +++++++++++++++++++ Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + drivers/iio/light/tsl2563.c | 4 ++++ 3 files changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/light/tsl2563.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/light/tsl2563.txt b/Documentation/devicetree/bindings/iio/light/tsl2563.txt new file mode 100644 index 000000000000..f91e809e736e --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/tsl2563.txt @@ -0,0 +1,19 @@ +* AMS TAOS TSL2563 ambient light sensor + +Required properties: + + - compatible : should be "amstaos,tsl2563" + - reg : the I2C address of the sensor + +Optional properties: + + - amstaos,cover-comp-gain : integer used as multiplier for gain + compensation (default = 1) + +Example: + +tsl2563@29 { + compatible = "amstaos,tsl2563"; + reg = <0x29>; + amstaos,cover-comp-gain = <16>; +}; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 04eab45dd148..b65a44041ec1 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -9,6 +9,7 @@ aeroflexgaisler Aeroflex Gaisler AB ak Asahi Kasei Corp. altr Altera Corp. amcc Applied Micro Circuits Corporation (APM, formally AMCC) +amstaos AMS-Taos Inc. apm Applied Micro Circuits Corporation (APM) arm ARM Ltd. atmel Atmel Corporation diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index 5e5d9dea22c5..0c6e459c86b1 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -714,6 +714,7 @@ static int tsl2563_probe(struct i2c_client *client, struct iio_dev *indio_dev; struct tsl2563_chip *chip; struct tsl2563_platform_data *pdata = client->dev.platform_data; + struct device_node *np = client->dev.of_node; int err = 0; u8 id = 0; @@ -750,6 +751,9 @@ static int tsl2563_probe(struct i2c_client *client, if (pdata) chip->cover_comp_gain = pdata->cover_comp_gain; + else if (np) + of_property_read_u32(np, "amstaos,cover-comp-gain", + &chip->cover_comp_gain); else chip->cover_comp_gain = 1; -- cgit v1.2.3 From 27b832427e060d4e963c610d07860e5dbe1daafa Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 1 Nov 2013 05:35:00 +0000 Subject: iio:magnetometer:hmc5843 - add basic dt support Compatible string, documenation and an optional gpio for the dataready pin. Signed-off-by: NeilBrown Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/magnetometer/hmc5843.txt | 17 +++++++++++++++++ drivers/staging/iio/magnetometer/hmc5843.c | 7 +++++++ 2 files changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/hmc5843.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/magnetometer/hmc5843.txt b/Documentation/devicetree/bindings/iio/magnetometer/hmc5843.txt new file mode 100644 index 000000000000..90d5f34db04e --- /dev/null +++ b/Documentation/devicetree/bindings/iio/magnetometer/hmc5843.txt @@ -0,0 +1,17 @@ +* Honeywell HMC5843 magnetometer sensor + +Required properties: + + - compatible : should be "honeywell,hmc5843" + - reg : the I2C address of the magnetometer - typically 0x1e + +Optional properties: + + - gpios : should be device tree identifier of the magnetometer DRDY pin + +Example: + +hmc5843@1e { + compatible = "honeywell,hmc5843" + reg = <0x1e>; +}; diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c index 99421f90d189..bdb018878296 100644 --- a/drivers/staging/iio/magnetometer/hmc5843.c +++ b/drivers/staging/iio/magnetometer/hmc5843.c @@ -624,10 +624,17 @@ static const struct i2c_device_id hmc5843_id[] = { }; MODULE_DEVICE_TABLE(i2c, hmc5843_id); +static const struct of_device_id hmc5843_of_match[] = { + { .compatible = "honeywell,hmc5843" }, + {} +}; +MODULE_DEVICE_TABLE(of, hmc5843_of_match); + static struct i2c_driver hmc5843_driver = { .driver = { .name = "hmc5843", .pm = HMC5843_PM_OPS, + .of_match_table = of_match_ptr(hmc5843_of_match), }, .id_table = hmc5843_id, .probe = hmc5843_probe, -- cgit v1.2.3 From 31d610f19670825a0058b70f44570e9ab21a0011 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Mon, 11 Nov 2013 19:19:47 +0100 Subject: pinctrl: imx1-core populate subdevices Support gpio devicetree subnodes to allow a more detailed DT hardware description. Signed-off-by: Markus Pargmann Signed-off-by: Linus Walleij --- .../bindings/pinctrl/fsl,imx27-pinctrl.txt | 22 ++++++++++++++++++++++ drivers/pinctrl/pinctrl-imx1-core.c | 7 +++++++ 2 files changed, 29 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx27-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx27-pinctrl.txt index 353eca0efbf8..d1706ea82572 100644 --- a/Documentation/devicetree/bindings/pinctrl/fsl,imx27-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx27-pinctrl.txt @@ -52,12 +52,25 @@ Required properties for pin configuration node: CONFIG can be 0 or 1, meaning Pullup disable/enable. +The iomux controller has gpio child nodes which are embedded in the iomux +control registers. They have to be defined as child nodes of the iomux device +node. If gpio subnodes are defined "#address-cells", "#size-cells" and "ranges" +properties for the iomux device node are required. Example: iomuxc: iomuxc@10015000 { compatible = "fsl,imx27-iomuxc"; reg = <0x10015000 0x600>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gpio1: gpio@10015000 { + ... + }; + + ... uart { pinctrl_uart1: uart-1 { @@ -83,6 +96,15 @@ The above example using macros: iomuxc: iomuxc@10015000 { compatible = "fsl,imx27-iomuxc"; reg = <0x10015000 0x600>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gpio1: gpio@10015000 { + ... + }; + + ... uart { pinctrl_uart1: uart-1 { diff --git a/drivers/pinctrl/pinctrl-imx1-core.c b/drivers/pinctrl/pinctrl-imx1-core.c index f77914ac081a..17aecde1b51d 100644 --- a/drivers/pinctrl/pinctrl-imx1-core.c +++ b/drivers/pinctrl/pinctrl-imx1-core.c @@ -638,6 +638,13 @@ int imx1_pinctrl_core_probe(struct platform_device *pdev, return -EINVAL; } + ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + if (ret) { + pinctrl_unregister(ipctl->pctl); + dev_err(&pdev->dev, "Failed to populate subdevices\n"); + return ret; + } + dev_info(&pdev->dev, "initialized IMX pinctrl driver\n"); return 0; -- cgit v1.2.3 From b4a87c9b966f71922e54a336e90b485a5fba19b8 Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Wed, 6 Nov 2013 09:52:15 +0100 Subject: pinctrl: pinctrl-imx: add imx25 pinctrl driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is mostly cut and paste from the imx35 pinctrl driver. The data was generated using sed and awk on arch/arm/plat-mxc/include/mach/iomux-mx25.h. Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Stephen Warren Cc: Ian Campbell Cc: devicetree@vger.kernel.org Cc: Shawn Guo Cc: Sascha Hauer Cc: linux-arm-kernel@lists.infradead.org Cc: Russell King Cc: Linus Walleij Cc: Eric Bénard Signed-off-by: Denis Carikli Acked-by: Sascha Hauer Signed-off-by: Linus Walleij --- .../bindings/pinctrl/fsl,imx25-pinctrl.txt | 23 ++ drivers/pinctrl/Kconfig | 9 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-imx25.c | 351 +++++++++++++++++++++ 4 files changed, 384 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,imx25-pinctrl.txt create mode 100644 drivers/pinctrl/pinctrl-imx25.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx25-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx25-pinctrl.txt new file mode 100644 index 000000000000..fd653bde18d5 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx25-pinctrl.txt @@ -0,0 +1,23 @@ +* Freescale IMX25 IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +CONFIG bits definition: +PAD_CTL_HYS (1 << 8) +PAD_CTL_PKE (1 << 7) +PAD_CTL_PUE (1 << 6) +PAD_CTL_PUS_100K_DOWN (0 << 4) +PAD_CTL_PUS_47K_UP (1 << 4) +PAD_CTL_PUS_100K_UP (2 << 4) +PAD_CTL_PUS_22K_UP (3 << 4) +PAD_CTL_ODE_CMOS (0 << 3) +PAD_CTL_ODE_OPENDRAIN (1 << 3) +PAD_CTL_DSE_NOMINAL (0 << 1) +PAD_CTL_DSE_HIGH (1 << 1) +PAD_CTL_DSE_MAX (2 << 1) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) + +Refer to imx25-pinfunc.h in device tree source folder for all available +imx25 PIN_FUNC_ID. diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index e216a46f4194..5e4418f4282b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -121,6 +121,15 @@ config PINCTRL_IMX27 help Say Y here to enable the imx27 pinctrl driver + +config PINCTRL_IMX25 + bool "IMX25 pinctrl driver" + depends on OF + depends on SOC_IMX25 + select PINCTRL_IMX + help + Say Y here to enable the imx25 pinctrl driver + config PINCTRL_IMX35 bool "IMX35 pinctrl driver" depends on SOC_IMX35 diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 4f7be2921aa5..dcb01a4ef653 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_PINCTRL_IMX6SL) += pinctrl-imx6sl.o obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o +obj-$(CONFIG_PINCTRL_IMX25) += pinctrl-imx25.o obj-$(CONFIG_PINCTRL_IMX28) += pinctrl-imx28.o obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o obj-$(CONFIG_PINCTRL_STN8815) += pinctrl-nomadik-stn8815.o diff --git a/drivers/pinctrl/pinctrl-imx25.c b/drivers/pinctrl/pinctrl-imx25.c new file mode 100644 index 000000000000..1aae1b61c4dc --- /dev/null +++ b/drivers/pinctrl/pinctrl-imx25.c @@ -0,0 +1,351 @@ +/* + * imx25 pinctrl driver. + * + * Copyright 2013 Eukréa Electromatique + * + * This driver was mostly copied from the imx51 pinctrl driver which has: + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro, Inc. + * + * Author: Denis Carikli + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pinctrl-imx.h" + +enum imx25_pads { + MX25_PAD_RESERVE0 = 1, + MX25_PAD_RESERVE1 = 2, + MX25_PAD_A10 = 3, + MX25_PAD_A13 = 4, + MX25_PAD_A14 = 5, + MX25_PAD_A15 = 6, + MX25_PAD_A16 = 7, + MX25_PAD_A17 = 8, + MX25_PAD_A18 = 9, + MX25_PAD_A19 = 10, + MX25_PAD_A20 = 11, + MX25_PAD_A21 = 12, + MX25_PAD_A22 = 13, + MX25_PAD_A23 = 14, + MX25_PAD_A24 = 15, + MX25_PAD_A25 = 16, + MX25_PAD_EB0 = 17, + MX25_PAD_EB1 = 18, + MX25_PAD_OE = 19, + MX25_PAD_CS0 = 20, + MX25_PAD_CS1 = 21, + MX25_PAD_CS4 = 22, + MX25_PAD_CS5 = 23, + MX25_PAD_NF_CE0 = 24, + MX25_PAD_ECB = 25, + MX25_PAD_LBA = 26, + MX25_PAD_BCLK = 27, + MX25_PAD_RW = 28, + MX25_PAD_NFWE_B = 29, + MX25_PAD_NFRE_B = 30, + MX25_PAD_NFALE = 31, + MX25_PAD_NFCLE = 32, + MX25_PAD_NFWP_B = 33, + MX25_PAD_NFRB = 34, + MX25_PAD_D15 = 35, + MX25_PAD_D14 = 36, + MX25_PAD_D13 = 37, + MX25_PAD_D12 = 38, + MX25_PAD_D11 = 39, + MX25_PAD_D10 = 40, + MX25_PAD_D9 = 41, + MX25_PAD_D8 = 42, + MX25_PAD_D7 = 43, + MX25_PAD_D6 = 44, + MX25_PAD_D5 = 45, + MX25_PAD_D4 = 46, + MX25_PAD_D3 = 47, + MX25_PAD_D2 = 48, + MX25_PAD_D1 = 49, + MX25_PAD_D0 = 50, + MX25_PAD_LD0 = 51, + MX25_PAD_LD1 = 52, + MX25_PAD_LD2 = 53, + MX25_PAD_LD3 = 54, + MX25_PAD_LD4 = 55, + MX25_PAD_LD5 = 56, + MX25_PAD_LD6 = 57, + MX25_PAD_LD7 = 58, + MX25_PAD_LD8 = 59, + MX25_PAD_LD9 = 60, + MX25_PAD_LD10 = 61, + MX25_PAD_LD11 = 62, + MX25_PAD_LD12 = 63, + MX25_PAD_LD13 = 64, + MX25_PAD_LD14 = 65, + MX25_PAD_LD15 = 66, + MX25_PAD_HSYNC = 67, + MX25_PAD_VSYNC = 68, + MX25_PAD_LSCLK = 69, + MX25_PAD_OE_ACD = 70, + MX25_PAD_CONTRAST = 71, + MX25_PAD_PWM = 72, + MX25_PAD_CSI_D2 = 73, + MX25_PAD_CSI_D3 = 74, + MX25_PAD_CSI_D4 = 75, + MX25_PAD_CSI_D5 = 76, + MX25_PAD_CSI_D6 = 77, + MX25_PAD_CSI_D7 = 78, + MX25_PAD_CSI_D8 = 79, + MX25_PAD_CSI_D9 = 80, + MX25_PAD_CSI_MCLK = 81, + MX25_PAD_CSI_VSYNC = 82, + MX25_PAD_CSI_HSYNC = 83, + MX25_PAD_CSI_PIXCLK = 84, + MX25_PAD_I2C1_CLK = 85, + MX25_PAD_I2C1_DAT = 86, + MX25_PAD_CSPI1_MOSI = 87, + MX25_PAD_CSPI1_MISO = 88, + MX25_PAD_CSPI1_SS0 = 89, + MX25_PAD_CSPI1_SS1 = 90, + MX25_PAD_CSPI1_SCLK = 91, + MX25_PAD_CSPI1_RDY = 92, + MX25_PAD_UART1_RXD = 93, + MX25_PAD_UART1_TXD = 94, + MX25_PAD_UART1_RTS = 95, + MX25_PAD_UART1_CTS = 96, + MX25_PAD_UART2_RXD = 97, + MX25_PAD_UART2_TXD = 98, + MX25_PAD_UART2_RTS = 99, + MX25_PAD_UART2_CTS = 100, + MX25_PAD_SD1_CMD = 101, + MX25_PAD_SD1_CLK = 102, + MX25_PAD_SD1_DATA0 = 103, + MX25_PAD_SD1_DATA1 = 104, + MX25_PAD_SD1_DATA2 = 105, + MX25_PAD_SD1_DATA3 = 106, + MX25_PAD_KPP_ROW0 = 107, + MX25_PAD_KPP_ROW1 = 108, + MX25_PAD_KPP_ROW2 = 109, + MX25_PAD_KPP_ROW3 = 110, + MX25_PAD_KPP_COL0 = 111, + MX25_PAD_KPP_COL1 = 112, + MX25_PAD_KPP_COL2 = 113, + MX25_PAD_KPP_COL3 = 114, + MX25_PAD_FEC_MDC = 115, + MX25_PAD_FEC_MDIO = 116, + MX25_PAD_FEC_TDATA0 = 117, + MX25_PAD_FEC_TDATA1 = 118, + MX25_PAD_FEC_TX_EN = 119, + MX25_PAD_FEC_RDATA0 = 120, + MX25_PAD_FEC_RDATA1 = 121, + MX25_PAD_FEC_RX_DV = 122, + MX25_PAD_FEC_TX_CLK = 123, + MX25_PAD_RTCK = 124, + MX25_PAD_DE_B = 125, + MX25_PAD_GPIO_A = 126, + MX25_PAD_GPIO_B = 127, + MX25_PAD_GPIO_C = 128, + MX25_PAD_GPIO_D = 129, + MX25_PAD_GPIO_E = 130, + MX25_PAD_GPIO_F = 131, + MX25_PAD_EXT_ARMCLK = 132, + MX25_PAD_UPLL_BYPCLK = 133, + MX25_PAD_VSTBY_REQ = 134, + MX25_PAD_VSTBY_ACK = 135, + MX25_PAD_POWER_FAIL = 136, + MX25_PAD_CLKO = 137, + MX25_PAD_BOOT_MODE0 = 138, + MX25_PAD_BOOT_MODE1 = 139, +}; + +/* Pad names for the pinmux subsystem */ +static const struct pinctrl_pin_desc imx25_pinctrl_pads[] = { + IMX_PINCTRL_PIN(MX25_PAD_RESERVE0), + IMX_PINCTRL_PIN(MX25_PAD_RESERVE1), + IMX_PINCTRL_PIN(MX25_PAD_A10), + IMX_PINCTRL_PIN(MX25_PAD_A13), + IMX_PINCTRL_PIN(MX25_PAD_A14), + IMX_PINCTRL_PIN(MX25_PAD_A15), + IMX_PINCTRL_PIN(MX25_PAD_A16), + IMX_PINCTRL_PIN(MX25_PAD_A17), + IMX_PINCTRL_PIN(MX25_PAD_A18), + IMX_PINCTRL_PIN(MX25_PAD_A19), + IMX_PINCTRL_PIN(MX25_PAD_A20), + IMX_PINCTRL_PIN(MX25_PAD_A21), + IMX_PINCTRL_PIN(MX25_PAD_A22), + IMX_PINCTRL_PIN(MX25_PAD_A23), + IMX_PINCTRL_PIN(MX25_PAD_A24), + IMX_PINCTRL_PIN(MX25_PAD_A25), + IMX_PINCTRL_PIN(MX25_PAD_EB0), + IMX_PINCTRL_PIN(MX25_PAD_EB1), + IMX_PINCTRL_PIN(MX25_PAD_OE), + IMX_PINCTRL_PIN(MX25_PAD_CS0), + IMX_PINCTRL_PIN(MX25_PAD_CS1), + IMX_PINCTRL_PIN(MX25_PAD_CS4), + IMX_PINCTRL_PIN(MX25_PAD_CS5), + IMX_PINCTRL_PIN(MX25_PAD_NF_CE0), + IMX_PINCTRL_PIN(MX25_PAD_ECB), + IMX_PINCTRL_PIN(MX25_PAD_LBA), + IMX_PINCTRL_PIN(MX25_PAD_BCLK), + IMX_PINCTRL_PIN(MX25_PAD_RW), + IMX_PINCTRL_PIN(MX25_PAD_NFWE_B), + IMX_PINCTRL_PIN(MX25_PAD_NFRE_B), + IMX_PINCTRL_PIN(MX25_PAD_NFALE), + IMX_PINCTRL_PIN(MX25_PAD_NFCLE), + IMX_PINCTRL_PIN(MX25_PAD_NFWP_B), + IMX_PINCTRL_PIN(MX25_PAD_NFRB), + IMX_PINCTRL_PIN(MX25_PAD_D15), + IMX_PINCTRL_PIN(MX25_PAD_D14), + IMX_PINCTRL_PIN(MX25_PAD_D13), + IMX_PINCTRL_PIN(MX25_PAD_D12), + IMX_PINCTRL_PIN(MX25_PAD_D11), + IMX_PINCTRL_PIN(MX25_PAD_D10), + IMX_PINCTRL_PIN(MX25_PAD_D9), + IMX_PINCTRL_PIN(MX25_PAD_D8), + IMX_PINCTRL_PIN(MX25_PAD_D7), + IMX_PINCTRL_PIN(MX25_PAD_D6), + IMX_PINCTRL_PIN(MX25_PAD_D5), + IMX_PINCTRL_PIN(MX25_PAD_D4), + IMX_PINCTRL_PIN(MX25_PAD_D3), + IMX_PINCTRL_PIN(MX25_PAD_D2), + IMX_PINCTRL_PIN(MX25_PAD_D1), + IMX_PINCTRL_PIN(MX25_PAD_D0), + IMX_PINCTRL_PIN(MX25_PAD_LD0), + IMX_PINCTRL_PIN(MX25_PAD_LD1), + IMX_PINCTRL_PIN(MX25_PAD_LD2), + IMX_PINCTRL_PIN(MX25_PAD_LD3), + IMX_PINCTRL_PIN(MX25_PAD_LD4), + IMX_PINCTRL_PIN(MX25_PAD_LD5), + IMX_PINCTRL_PIN(MX25_PAD_LD6), + IMX_PINCTRL_PIN(MX25_PAD_LD7), + IMX_PINCTRL_PIN(MX25_PAD_LD8), + IMX_PINCTRL_PIN(MX25_PAD_LD9), + IMX_PINCTRL_PIN(MX25_PAD_LD10), + IMX_PINCTRL_PIN(MX25_PAD_LD11), + IMX_PINCTRL_PIN(MX25_PAD_LD12), + IMX_PINCTRL_PIN(MX25_PAD_LD13), + IMX_PINCTRL_PIN(MX25_PAD_LD14), + IMX_PINCTRL_PIN(MX25_PAD_LD15), + IMX_PINCTRL_PIN(MX25_PAD_HSYNC), + IMX_PINCTRL_PIN(MX25_PAD_VSYNC), + IMX_PINCTRL_PIN(MX25_PAD_LSCLK), + IMX_PINCTRL_PIN(MX25_PAD_OE_ACD), + IMX_PINCTRL_PIN(MX25_PAD_CONTRAST), + IMX_PINCTRL_PIN(MX25_PAD_PWM), + IMX_PINCTRL_PIN(MX25_PAD_CSI_D2), + IMX_PINCTRL_PIN(MX25_PAD_CSI_D3), + IMX_PINCTRL_PIN(MX25_PAD_CSI_D4), + IMX_PINCTRL_PIN(MX25_PAD_CSI_D5), + IMX_PINCTRL_PIN(MX25_PAD_CSI_D6), + IMX_PINCTRL_PIN(MX25_PAD_CSI_D7), + IMX_PINCTRL_PIN(MX25_PAD_CSI_D8), + IMX_PINCTRL_PIN(MX25_PAD_CSI_D9), + IMX_PINCTRL_PIN(MX25_PAD_CSI_MCLK), + IMX_PINCTRL_PIN(MX25_PAD_CSI_VSYNC), + IMX_PINCTRL_PIN(MX25_PAD_CSI_HSYNC), + IMX_PINCTRL_PIN(MX25_PAD_CSI_PIXCLK), + IMX_PINCTRL_PIN(MX25_PAD_I2C1_CLK), + IMX_PINCTRL_PIN(MX25_PAD_I2C1_DAT), + IMX_PINCTRL_PIN(MX25_PAD_CSPI1_MOSI), + IMX_PINCTRL_PIN(MX25_PAD_CSPI1_MISO), + IMX_PINCTRL_PIN(MX25_PAD_CSPI1_SS0), + IMX_PINCTRL_PIN(MX25_PAD_CSPI1_SS1), + IMX_PINCTRL_PIN(MX25_PAD_CSPI1_SCLK), + IMX_PINCTRL_PIN(MX25_PAD_CSPI1_RDY), + IMX_PINCTRL_PIN(MX25_PAD_UART1_RXD), + IMX_PINCTRL_PIN(MX25_PAD_UART1_TXD), + IMX_PINCTRL_PIN(MX25_PAD_UART1_RTS), + IMX_PINCTRL_PIN(MX25_PAD_UART1_CTS), + IMX_PINCTRL_PIN(MX25_PAD_UART2_RXD), + IMX_PINCTRL_PIN(MX25_PAD_UART2_TXD), + IMX_PINCTRL_PIN(MX25_PAD_UART2_RTS), + IMX_PINCTRL_PIN(MX25_PAD_UART2_CTS), + IMX_PINCTRL_PIN(MX25_PAD_SD1_CMD), + IMX_PINCTRL_PIN(MX25_PAD_SD1_CLK), + IMX_PINCTRL_PIN(MX25_PAD_SD1_DATA0), + IMX_PINCTRL_PIN(MX25_PAD_SD1_DATA1), + IMX_PINCTRL_PIN(MX25_PAD_SD1_DATA2), + IMX_PINCTRL_PIN(MX25_PAD_SD1_DATA3), + IMX_PINCTRL_PIN(MX25_PAD_KPP_ROW0), + IMX_PINCTRL_PIN(MX25_PAD_KPP_ROW1), + IMX_PINCTRL_PIN(MX25_PAD_KPP_ROW2), + IMX_PINCTRL_PIN(MX25_PAD_KPP_ROW3), + IMX_PINCTRL_PIN(MX25_PAD_KPP_COL0), + IMX_PINCTRL_PIN(MX25_PAD_KPP_COL1), + IMX_PINCTRL_PIN(MX25_PAD_KPP_COL2), + IMX_PINCTRL_PIN(MX25_PAD_KPP_COL3), + IMX_PINCTRL_PIN(MX25_PAD_FEC_MDC), + IMX_PINCTRL_PIN(MX25_PAD_FEC_MDIO), + IMX_PINCTRL_PIN(MX25_PAD_FEC_TDATA0), + IMX_PINCTRL_PIN(MX25_PAD_FEC_TDATA1), + IMX_PINCTRL_PIN(MX25_PAD_FEC_TX_EN), + IMX_PINCTRL_PIN(MX25_PAD_FEC_RDATA0), + IMX_PINCTRL_PIN(MX25_PAD_FEC_RDATA1), + IMX_PINCTRL_PIN(MX25_PAD_FEC_RX_DV), + IMX_PINCTRL_PIN(MX25_PAD_FEC_TX_CLK), + IMX_PINCTRL_PIN(MX25_PAD_RTCK), + IMX_PINCTRL_PIN(MX25_PAD_DE_B), + IMX_PINCTRL_PIN(MX25_PAD_GPIO_A), + IMX_PINCTRL_PIN(MX25_PAD_GPIO_B), + IMX_PINCTRL_PIN(MX25_PAD_GPIO_C), + IMX_PINCTRL_PIN(MX25_PAD_GPIO_D), + IMX_PINCTRL_PIN(MX25_PAD_GPIO_E), + IMX_PINCTRL_PIN(MX25_PAD_GPIO_F), + IMX_PINCTRL_PIN(MX25_PAD_EXT_ARMCLK), + IMX_PINCTRL_PIN(MX25_PAD_UPLL_BYPCLK), + IMX_PINCTRL_PIN(MX25_PAD_VSTBY_REQ), + IMX_PINCTRL_PIN(MX25_PAD_VSTBY_ACK), + IMX_PINCTRL_PIN(MX25_PAD_POWER_FAIL), + IMX_PINCTRL_PIN(MX25_PAD_CLKO), + IMX_PINCTRL_PIN(MX25_PAD_BOOT_MODE0), + IMX_PINCTRL_PIN(MX25_PAD_BOOT_MODE1), +}; + +static struct imx_pinctrl_soc_info imx25_pinctrl_info = { + .pins = imx25_pinctrl_pads, + .npins = ARRAY_SIZE(imx25_pinctrl_pads), +}; + +static struct of_device_id imx25_pinctrl_of_match[] = { + { .compatible = "fsl,imx25-iomuxc", }, + { /* sentinel */ } +}; + +static int imx25_pinctrl_probe(struct platform_device *pdev) +{ + return imx_pinctrl_probe(pdev, &imx25_pinctrl_info); +} + +static struct platform_driver imx25_pinctrl_driver = { + .driver = { + .name = "imx25-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(imx25_pinctrl_of_match), + }, + .probe = imx25_pinctrl_probe, + .remove = imx_pinctrl_remove, +}; + +static int __init imx25_pinctrl_init(void) +{ + return platform_driver_register(&imx25_pinctrl_driver); +} +arch_initcall(imx25_pinctrl_init); + +static void __exit imx25_pinctrl_exit(void) +{ + platform_driver_unregister(&imx25_pinctrl_driver); +} +module_exit(imx25_pinctrl_exit); +MODULE_AUTHOR("Denis Carikli "); +MODULE_DESCRIPTION("Freescale IMX25 pinctrl driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From c6aeb7de226dd08ad9b343fc6cbaf2ff36f69c84 Mon Sep 17 00:00:00 2001 From: Florian Meier Date: Fri, 22 Nov 2013 16:24:08 +0100 Subject: ASoC: Add support for BCM2835 This driver adds support for digital audio (I2S) for the BCM2835 SoC that is used by the Raspberry Pi. External audio codecs can be connected to the Raspberry Pi via P5 header. It relies on cyclic DMA engine support for BCM2835. Signed-off-by: Florian Meier Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/bcm2835-i2s.txt | 25 + sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/bcm/Kconfig | 10 + sound/soc/bcm/Makefile | 5 + sound/soc/bcm/bcm2835-i2s.c | 886 +++++++++++++++++++++ 6 files changed, 928 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/bcm2835-i2s.txt create mode 100644 sound/soc/bcm/Kconfig create mode 100644 sound/soc/bcm/Makefile create mode 100644 sound/soc/bcm/bcm2835-i2s.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/bcm2835-i2s.txt b/Documentation/devicetree/bindings/sound/bcm2835-i2s.txt new file mode 100644 index 000000000000..65783de0aedf --- /dev/null +++ b/Documentation/devicetree/bindings/sound/bcm2835-i2s.txt @@ -0,0 +1,25 @@ +* Broadcom BCM2835 SoC I2S/PCM module + +Required properties: +- compatible: "brcm,bcm2835-i2s" +- reg: A list of base address and size entries: + * The first entry should cover the PCM registers + * The second entry should cover the PCM clock registers +- dmas: List of DMA controller phandle and DMA request line ordered pairs. +- dma-names: Identifier string for each DMA request line in the dmas property. + These strings correspond 1:1 with the ordered pairs in dmas. + + One of the DMA channels will be responsible for transmission (should be + named "tx") and one for reception (should be named "rx"). + +Example: + +bcm2835_i2s: i2s@7e203000 { + compatible = "brcm,bcm2835-i2s"; + reg = <0x7e203000 0x20>, + <0x7e101098 0x02>; + + dmas = <&dma 2>, + <&dma 3>; + dma-names = "tx", "rx"; +}; diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 5138b8493051..a5e3a70c0d3d 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -33,6 +33,7 @@ config SND_SOC_GENERIC_DMAENGINE_PCM # All the supported SoCs source "sound/soc/atmel/Kconfig" source "sound/soc/au1x/Kconfig" +source "sound/soc/bcm/Kconfig" source "sound/soc/blackfin/Kconfig" source "sound/soc/cirrus/Kconfig" source "sound/soc/davinci/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 8b9e70105dd2..b52d4aad0716 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_SND_SOC) += codecs/ obj-$(CONFIG_SND_SOC) += generic/ obj-$(CONFIG_SND_SOC) += atmel/ obj-$(CONFIG_SND_SOC) += au1x/ +obj-$(CONFIG_SND_SOC) += bcm/ obj-$(CONFIG_SND_SOC) += blackfin/ obj-$(CONFIG_SND_SOC) += cirrus/ obj-$(CONFIG_SND_SOC) += davinci/ diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig new file mode 100644 index 000000000000..3d82a29ce3a8 --- /dev/null +++ b/sound/soc/bcm/Kconfig @@ -0,0 +1,10 @@ +config SND_BCM2835_SOC_I2S + tristate "SoC Audio support for the Broadcom BCM2835 I2S module" + depends on ARCH_BCM2835 || COMPILE_TEST + select SND_SOC_DMAENGINE_PCM + select SND_SOC_GENERIC_DMAENGINE_PCM + select REGMAP_MMIO + help + Say Y or M if you want to add support for codecs attached to + the BCM2835 I2S interface. You will also need + to select the audio interfaces to support below. diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile new file mode 100644 index 000000000000..bc816b71e5a4 --- /dev/null +++ b/sound/soc/bcm/Makefile @@ -0,0 +1,5 @@ +# BCM2835 Platform Support +snd-soc-bcm2835-i2s-objs := bcm2835-i2s.o + +obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd-soc-bcm2835-i2s.o + diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c new file mode 100644 index 000000000000..f49b007c8b43 --- /dev/null +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -0,0 +1,886 @@ +/* + * ALSA SoC I2S Audio Layer for Broadcom BCM2835 SoC + * + * Author: Florian Meier + * Copyright 2013 + * + * Based on + * Raspberry Pi PCM I2S ALSA Driver + * Copyright (c) by Phil Poole 2013 + * + * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor + * Vladimir Barinov, + * Copyright (C) 2007 MontaVista Software, Inc., + * + * OMAP ALSA SoC DAI driver using McBSP port + * Copyright (C) 2008 Nokia Corporation + * Contact: Jarkko Nikula + * Peter Ujfalusi + * + * Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver + * Author: Timur Tabi + * Copyright 2007-2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 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 + +/* Clock registers */ +#define BCM2835_CLK_PCMCTL_REG 0x00 +#define BCM2835_CLK_PCMDIV_REG 0x04 + +/* Clock register settings */ +#define BCM2835_CLK_PASSWD (0x5a000000) +#define BCM2835_CLK_PASSWD_MASK (0xff000000) +#define BCM2835_CLK_MASH(v) ((v) << 9) +#define BCM2835_CLK_FLIP BIT(8) +#define BCM2835_CLK_BUSY BIT(7) +#define BCM2835_CLK_KILL BIT(5) +#define BCM2835_CLK_ENAB BIT(4) +#define BCM2835_CLK_SRC(v) (v) + +#define BCM2835_CLK_SHIFT (12) +#define BCM2835_CLK_DIVI(v) ((v) << BCM2835_CLK_SHIFT) +#define BCM2835_CLK_DIVF(v) (v) +#define BCM2835_CLK_DIVF_MASK (0xFFF) + +enum { + BCM2835_CLK_MASH_0 = 0, + BCM2835_CLK_MASH_1, + BCM2835_CLK_MASH_2, + BCM2835_CLK_MASH_3, +}; + +enum { + BCM2835_CLK_SRC_GND = 0, + BCM2835_CLK_SRC_OSC, + BCM2835_CLK_SRC_DBG0, + BCM2835_CLK_SRC_DBG1, + BCM2835_CLK_SRC_PLLA, + BCM2835_CLK_SRC_PLLC, + BCM2835_CLK_SRC_PLLD, + BCM2835_CLK_SRC_HDMI, +}; + +/* Most clocks are not useable (freq = 0) */ +static const unsigned int bcm2835_clk_freq[BCM2835_CLK_SRC_HDMI+1] = { + [BCM2835_CLK_SRC_GND] = 0, + [BCM2835_CLK_SRC_OSC] = 19200000, + [BCM2835_CLK_SRC_DBG0] = 0, + [BCM2835_CLK_SRC_DBG1] = 0, + [BCM2835_CLK_SRC_PLLA] = 0, + [BCM2835_CLK_SRC_PLLC] = 0, + [BCM2835_CLK_SRC_PLLD] = 500000000, + [BCM2835_CLK_SRC_HDMI] = 0, +}; + +/* I2S registers */ +#define BCM2835_I2S_CS_A_REG 0x00 +#define BCM2835_I2S_FIFO_A_REG 0x04 +#define BCM2835_I2S_MODE_A_REG 0x08 +#define BCM2835_I2S_RXC_A_REG 0x0c +#define BCM2835_I2S_TXC_A_REG 0x10 +#define BCM2835_I2S_DREQ_A_REG 0x14 +#define BCM2835_I2S_INTEN_A_REG 0x18 +#define BCM2835_I2S_INTSTC_A_REG 0x1c +#define BCM2835_I2S_GRAY_REG 0x20 + +/* I2S register settings */ +#define BCM2835_I2S_STBY BIT(25) +#define BCM2835_I2S_SYNC BIT(24) +#define BCM2835_I2S_RXSEX BIT(23) +#define BCM2835_I2S_RXF BIT(22) +#define BCM2835_I2S_TXE BIT(21) +#define BCM2835_I2S_RXD BIT(20) +#define BCM2835_I2S_TXD BIT(19) +#define BCM2835_I2S_RXR BIT(18) +#define BCM2835_I2S_TXW BIT(17) +#define BCM2835_I2S_CS_RXERR BIT(16) +#define BCM2835_I2S_CS_TXERR BIT(15) +#define BCM2835_I2S_RXSYNC BIT(14) +#define BCM2835_I2S_TXSYNC BIT(13) +#define BCM2835_I2S_DMAEN BIT(9) +#define BCM2835_I2S_RXTHR(v) ((v) << 7) +#define BCM2835_I2S_TXTHR(v) ((v) << 5) +#define BCM2835_I2S_RXCLR BIT(4) +#define BCM2835_I2S_TXCLR BIT(3) +#define BCM2835_I2S_TXON BIT(2) +#define BCM2835_I2S_RXON BIT(1) +#define BCM2835_I2S_EN (1) + +#define BCM2835_I2S_CLKDIS BIT(28) +#define BCM2835_I2S_PDMN BIT(27) +#define BCM2835_I2S_PDME BIT(26) +#define BCM2835_I2S_FRXP BIT(25) +#define BCM2835_I2S_FTXP BIT(24) +#define BCM2835_I2S_CLKM BIT(23) +#define BCM2835_I2S_CLKI BIT(22) +#define BCM2835_I2S_FSM BIT(21) +#define BCM2835_I2S_FSI BIT(20) +#define BCM2835_I2S_FLEN(v) ((v) << 10) +#define BCM2835_I2S_FSLEN(v) (v) + +#define BCM2835_I2S_CHWEX BIT(15) +#define BCM2835_I2S_CHEN BIT(14) +#define BCM2835_I2S_CHPOS(v) ((v) << 4) +#define BCM2835_I2S_CHWID(v) (v) +#define BCM2835_I2S_CH1(v) ((v) << 16) +#define BCM2835_I2S_CH2(v) (v) + +#define BCM2835_I2S_TX_PANIC(v) ((v) << 24) +#define BCM2835_I2S_RX_PANIC(v) ((v) << 16) +#define BCM2835_I2S_TX(v) ((v) << 8) +#define BCM2835_I2S_RX(v) (v) + +#define BCM2835_I2S_INT_RXERR BIT(3) +#define BCM2835_I2S_INT_TXERR BIT(2) +#define BCM2835_I2S_INT_RXR BIT(1) +#define BCM2835_I2S_INT_TXW BIT(0) + +/* I2S DMA interface */ +/* FIXME: Needs IOMMU support */ +#define BCM2835_VCMMU_SHIFT (0x7E000000 - 0x20000000) + +/* General device struct */ +struct bcm2835_i2s_dev { + struct device *dev; + struct snd_dmaengine_dai_dma_data dma_data[2]; + unsigned int fmt; + unsigned int bclk_ratio; + + struct regmap *i2s_regmap; + struct regmap *clk_regmap; +}; + +static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev) +{ + /* Start the clock if in master mode */ + unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; + + switch (master) { + case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBS_CFM: + regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, + BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB, + BCM2835_CLK_PASSWD | BCM2835_CLK_ENAB); + break; + default: + break; + } +} + +static void bcm2835_i2s_stop_clock(struct bcm2835_i2s_dev *dev) +{ + uint32_t clkreg; + int timeout = 1000; + + /* Stop clock */ + regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, + BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB, + BCM2835_CLK_PASSWD); + + /* Wait for the BUSY flag going down */ + while (--timeout) { + regmap_read(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, &clkreg); + if (!(clkreg & BCM2835_CLK_BUSY)) + break; + } + + if (!timeout) { + /* KILL the clock */ + dev_err(dev->dev, "I2S clock didn't stop. Kill the clock!\n"); + regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, + BCM2835_CLK_KILL | BCM2835_CLK_PASSWD_MASK, + BCM2835_CLK_KILL | BCM2835_CLK_PASSWD); + } +} + +static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev, + bool tx, bool rx) +{ + int timeout = 1000; + uint32_t syncval; + uint32_t csreg; + uint32_t i2s_active_state; + uint32_t clkreg; + uint32_t clk_active_state; + uint32_t off; + uint32_t clr; + + off = tx ? BCM2835_I2S_TXON : 0; + off |= rx ? BCM2835_I2S_RXON : 0; + + clr = tx ? BCM2835_I2S_TXCLR : 0; + clr |= rx ? BCM2835_I2S_RXCLR : 0; + + /* Backup the current state */ + regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg); + i2s_active_state = csreg & (BCM2835_I2S_RXON | BCM2835_I2S_TXON); + + regmap_read(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, &clkreg); + clk_active_state = clkreg & BCM2835_CLK_ENAB; + + /* Start clock if not running */ + if (!clk_active_state) { + regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, + BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB, + BCM2835_CLK_PASSWD | BCM2835_CLK_ENAB); + } + + /* Stop I2S module */ + regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, off, 0); + + /* + * Clear the FIFOs + * Requires at least 2 PCM clock cycles to take effect + */ + regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, clr, clr); + + /* Wait for 2 PCM clock cycles */ + + /* + * Toggle the SYNC flag. After 2 PCM clock cycles it can be read back + * FIXME: This does not seem to work for slave mode! + */ + regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &syncval); + syncval &= BCM2835_I2S_SYNC; + + regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, + BCM2835_I2S_SYNC, ~syncval); + + /* Wait for the SYNC flag changing it's state */ + while (--timeout) { + regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg); + if ((csreg & BCM2835_I2S_SYNC) != syncval) + break; + } + + if (!timeout) + dev_err(dev->dev, "I2S SYNC error!\n"); + + /* Stop clock if it was not running before */ + if (!clk_active_state) + bcm2835_i2s_stop_clock(dev); + + /* Restore I2S state */ + regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, + BCM2835_I2S_RXON | BCM2835_I2S_TXON, i2s_active_state); +} + +static int bcm2835_i2s_set_dai_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + dev->fmt = fmt; + return 0; +} + +static int bcm2835_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai, + unsigned int ratio) +{ + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + dev->bclk_ratio = ratio; + return 0; +} + +static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + + unsigned int sampling_rate = params_rate(params); + unsigned int data_length, data_delay, bclk_ratio; + unsigned int ch1pos, ch2pos, mode, format; + unsigned int mash = BCM2835_CLK_MASH_1; + unsigned int divi, divf, target_frequency; + int clk_src = -1; + unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; + bool bit_master = (master == SND_SOC_DAIFMT_CBS_CFS + || master == SND_SOC_DAIFMT_CBS_CFM); + + bool frame_master = (master == SND_SOC_DAIFMT_CBS_CFS + || master == SND_SOC_DAIFMT_CBM_CFS); + uint32_t csreg; + + /* + * If a stream is already enabled, + * the registers are already set properly. + */ + regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg); + + if (csreg & (BCM2835_I2S_TXON | BCM2835_I2S_RXON)) + return 0; + + /* + * Adjust the data length according to the format. + * We prefill the half frame length with an integer + * divider of 2400 as explained at the clock settings. + * Maybe it is overwritten there, if the Integer mode + * does not apply. + */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + data_length = 16; + bclk_ratio = 40; + break; + case SNDRV_PCM_FORMAT_S32_LE: + data_length = 32; + bclk_ratio = 80; + break; + default: + return -EINVAL; + } + + /* If bclk_ratio already set, use that one. */ + if (dev->bclk_ratio) + bclk_ratio = dev->bclk_ratio; + + /* + * Clock Settings + * + * The target frequency of the bit clock is + * sampling rate * frame length + * + * Integer mode: + * Sampling rates that are multiples of 8000 kHz + * can be driven by the oscillator of 19.2 MHz + * with an integer divider as long as the frame length + * is an integer divider of 19200000/8000=2400 as set up above. + * This is no longer possible if the sampling rate + * is too high (e.g. 192 kHz), because the oscillator is too slow. + * + * MASH mode: + * For all other sampling rates, it is not possible to + * have an integer divider. Approximate the clock + * with the MASH module that induces a slight frequency + * variance. To minimize that it is best to have the fastest + * clock here. That is PLLD with 500 MHz. + */ + target_frequency = sampling_rate * bclk_ratio; + clk_src = BCM2835_CLK_SRC_OSC; + mash = BCM2835_CLK_MASH_0; + + if (bcm2835_clk_freq[clk_src] % target_frequency == 0 + && bit_master && frame_master) { + divi = bcm2835_clk_freq[clk_src] / target_frequency; + divf = 0; + } else { + uint64_t dividend; + + if (!dev->bclk_ratio) { + /* + * Overwrite bclk_ratio, because the + * above trick is not needed or can + * not be used. + */ + bclk_ratio = 2 * data_length; + } + + target_frequency = sampling_rate * bclk_ratio; + + clk_src = BCM2835_CLK_SRC_PLLD; + mash = BCM2835_CLK_MASH_1; + + dividend = bcm2835_clk_freq[clk_src]; + dividend <<= BCM2835_CLK_SHIFT; + do_div(dividend, target_frequency); + divi = dividend >> BCM2835_CLK_SHIFT; + divf = dividend & BCM2835_CLK_DIVF_MASK; + } + + /* Set clock divider */ + regmap_write(dev->clk_regmap, BCM2835_CLK_PCMDIV_REG, BCM2835_CLK_PASSWD + | BCM2835_CLK_DIVI(divi) + | BCM2835_CLK_DIVF(divf)); + + /* Setup clock, but don't start it yet */ + regmap_write(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, BCM2835_CLK_PASSWD + | BCM2835_CLK_MASH(mash) + | BCM2835_CLK_SRC(clk_src)); + + /* Setup the frame format */ + format = BCM2835_I2S_CHEN; + + if (data_length > 24) + format |= BCM2835_I2S_CHWEX; + + format |= BCM2835_I2S_CHWID((data_length-8)&0xf); + + switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + data_delay = 1; + break; + default: + /* + * TODO + * Others are possible but are not implemented at the moment. + */ + dev_err(dev->dev, "%s:bad format\n", __func__); + return -EINVAL; + } + + ch1pos = data_delay; + ch2pos = bclk_ratio / 2 + data_delay; + + switch (params_channels(params)) { + case 2: + format = BCM2835_I2S_CH1(format) | BCM2835_I2S_CH2(format); + format |= BCM2835_I2S_CH1(BCM2835_I2S_CHPOS(ch1pos)); + format |= BCM2835_I2S_CH2(BCM2835_I2S_CHPOS(ch2pos)); + break; + default: + return -EINVAL; + } + + /* + * Set format for both streams. + * We cannot set another frame length + * (and therefore word length) anyway, + * so the format will be the same. + */ + regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format); + regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format); + + /* Setup the I2S mode */ + mode = 0; + + if (data_length <= 16) { + /* + * Use frame packed mode (2 channels per 32 bit word) + * We cannot set another frame length in the second stream + * (and therefore word length) anyway, + * so the format will be the same. + */ + mode |= BCM2835_I2S_FTXP | BCM2835_I2S_FRXP; + } + + mode |= BCM2835_I2S_FLEN(bclk_ratio - 1); + mode |= BCM2835_I2S_FSLEN(bclk_ratio / 2); + + /* Master or slave? */ + switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* CPU is master */ + break; + case SND_SOC_DAIFMT_CBM_CFS: + /* + * CODEC is bit clock master + * CPU is frame master + */ + mode |= BCM2835_I2S_CLKM; + break; + case SND_SOC_DAIFMT_CBS_CFM: + /* + * CODEC is frame master + * CPU is bit clock master + */ + mode |= BCM2835_I2S_FSM; + break; + case SND_SOC_DAIFMT_CBM_CFM: + /* CODEC is master */ + mode |= BCM2835_I2S_CLKM; + mode |= BCM2835_I2S_FSM; + break; + default: + dev_err(dev->dev, "%s:bad master\n", __func__); + return -EINVAL; + } + + /* + * Invert clocks? + * + * The BCM approach seems to be inverted to the classical I2S approach. + */ + switch (dev->fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + /* None. Therefore, both for BCM */ + mode |= BCM2835_I2S_CLKI; + mode |= BCM2835_I2S_FSI; + break; + case SND_SOC_DAIFMT_IB_IF: + /* Both. Therefore, none for BCM */ + break; + case SND_SOC_DAIFMT_NB_IF: + /* + * Invert only frame sync. Therefore, + * invert only bit clock for BCM + */ + mode |= BCM2835_I2S_CLKI; + break; + case SND_SOC_DAIFMT_IB_NF: + /* + * Invert only bit clock. Therefore, + * invert only frame sync for BCM + */ + mode |= BCM2835_I2S_FSI; + break; + default: + return -EINVAL; + } + + regmap_write(dev->i2s_regmap, BCM2835_I2S_MODE_A_REG, mode); + + /* Setup the DMA parameters */ + regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, + BCM2835_I2S_RXTHR(1) + | BCM2835_I2S_TXTHR(1) + | BCM2835_I2S_DMAEN, 0xffffffff); + + regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_DREQ_A_REG, + BCM2835_I2S_TX_PANIC(0x10) + | BCM2835_I2S_RX_PANIC(0x30) + | BCM2835_I2S_TX(0x30) + | BCM2835_I2S_RX(0x20), 0xffffffff); + + /* Clear FIFOs */ + bcm2835_i2s_clear_fifos(dev, true, true); + + return 0; +} + +static int bcm2835_i2s_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + uint32_t cs_reg; + + bcm2835_i2s_start_clock(dev); + + /* + * Clear both FIFOs if the one that should be started + * is not empty at the moment. This should only happen + * after overrun. Otherwise, hw_params would have cleared + * the FIFO. + */ + regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &cs_reg); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK + && !(cs_reg & BCM2835_I2S_TXE)) + bcm2835_i2s_clear_fifos(dev, true, false); + else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE + && (cs_reg & BCM2835_I2S_RXD)) + bcm2835_i2s_clear_fifos(dev, false, true); + + return 0; +} + +static void bcm2835_i2s_stop(struct bcm2835_i2s_dev *dev, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + uint32_t mask; + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + mask = BCM2835_I2S_RXON; + else + mask = BCM2835_I2S_TXON; + + regmap_update_bits(dev->i2s_regmap, + BCM2835_I2S_CS_A_REG, mask, 0); + + /* Stop also the clock when not SND_SOC_DAIFMT_CONT */ + if (!dai->active && !(dev->fmt & SND_SOC_DAIFMT_CONT)) + bcm2835_i2s_stop_clock(dev); +} + +static int bcm2835_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + uint32_t mask; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + bcm2835_i2s_start_clock(dev); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + mask = BCM2835_I2S_RXON; + else + mask = BCM2835_I2S_TXON; + + regmap_update_bits(dev->i2s_regmap, + BCM2835_I2S_CS_A_REG, mask, mask); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + bcm2835_i2s_stop(dev, substream, dai); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int bcm2835_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + + if (dai->active) + return 0; + + /* Should this still be running stop it */ + bcm2835_i2s_stop_clock(dev); + + /* Enable PCM block */ + regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, + BCM2835_I2S_EN, BCM2835_I2S_EN); + + /* + * Disable STBY. + * Requires at least 4 PCM clock cycles to take effect. + */ + regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, + BCM2835_I2S_STBY, BCM2835_I2S_STBY); + + return 0; +} + +static void bcm2835_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + + bcm2835_i2s_stop(dev, substream, dai); + + /* If both streams are stopped, disable module and clock */ + if (dai->active) + return; + + /* Disable the module */ + regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, + BCM2835_I2S_EN, 0); + + /* + * Stopping clock is necessary, because stop does + * not stop the clock when SND_SOC_DAIFMT_CONT + */ + bcm2835_i2s_stop_clock(dev); +} + +static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = { + .startup = bcm2835_i2s_startup, + .shutdown = bcm2835_i2s_shutdown, + .prepare = bcm2835_i2s_prepare, + .trigger = bcm2835_i2s_trigger, + .hw_params = bcm2835_i2s_hw_params, + .set_fmt = bcm2835_i2s_set_dai_fmt, + .set_bclk_ratio = bcm2835_i2s_set_dai_bclk_ratio +}; + +static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, + &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK], + &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]); + + return 0; +} + +static struct snd_soc_dai_driver bcm2835_i2s_dai = { + .name = "bcm2835-i2s", + .probe = bcm2835_i2s_dai_probe, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE + | SNDRV_PCM_FMTBIT_S32_LE + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE + | SNDRV_PCM_FMTBIT_S32_LE + }, + .ops = &bcm2835_i2s_dai_ops, + .symmetric_rates = 1 +}; + +static bool bcm2835_i2s_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case BCM2835_I2S_CS_A_REG: + case BCM2835_I2S_FIFO_A_REG: + case BCM2835_I2S_INTSTC_A_REG: + case BCM2835_I2S_GRAY_REG: + return true; + default: + return false; + }; +} + +static bool bcm2835_i2s_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case BCM2835_I2S_FIFO_A_REG: + return true; + default: + return false; + }; +} + +static bool bcm2835_clk_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case BCM2835_CLK_PCMCTL_REG: + return true; + default: + return false; + }; +} + +static const struct regmap_config bcm2835_regmap_config[] = { + { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = BCM2835_I2S_GRAY_REG, + .precious_reg = bcm2835_i2s_precious_reg, + .volatile_reg = bcm2835_i2s_volatile_reg, + .cache_type = REGCACHE_RBTREE, + }, + { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = BCM2835_CLK_PCMDIV_REG, + .volatile_reg = bcm2835_clk_volatile_reg, + .cache_type = REGCACHE_RBTREE, + }, +}; + +static const struct snd_soc_component_driver bcm2835_i2s_component = { + .name = "bcm2835-i2s-comp", +}; + +static int bcm2835_i2s_probe(struct platform_device *pdev) +{ + struct bcm2835_i2s_dev *dev; + int i; + int ret; + struct regmap *regmap[2]; + struct resource *mem[2]; + + /* Request both ioareas */ + for (i = 0; i <= 1; i++) { + void __iomem *base; + + mem[i] = platform_get_resource(pdev, IORESOURCE_MEM, i); + base = devm_ioremap_resource(&pdev->dev, mem[i]); + if (IS_ERR(base)) + return PTR_ERR(base); + + regmap[i] = devm_regmap_init_mmio(&pdev->dev, base, + &bcm2835_regmap_config[i]); + if (IS_ERR(regmap[i])) + return PTR_ERR(regmap[i]); + } + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), + GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->i2s_regmap = regmap[0]; + dev->clk_regmap = regmap[1]; + + /* Set the DMA address */ + dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = + (dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG + + BCM2835_VCMMU_SHIFT; + + dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = + (dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG + + BCM2835_VCMMU_SHIFT; + + /* Set the bus width */ + dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; + dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; + + /* Set burst */ + dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].maxburst = 2; + dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].maxburst = 2; + + /* BCLK ratio - use default */ + dev->bclk_ratio = 0; + + /* Store the pdev */ + dev->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, dev); + + ret = devm_snd_soc_register_component(&pdev->dev, + &bcm2835_i2s_component, &bcm2835_i2s_dai, 1); + if (ret) { + dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); + return ret; + } + + ret = snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) { + dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct of_device_id bcm2835_i2s_of_match[] = { + { .compatible = "brcm,bcm2835-i2s", }, + {}, +}; + +static int bcm2835_i2s_remove(struct platform_device *pdev) +{ + snd_dmaengine_pcm_unregister(&pdev->dev); + return 0; +} + +static struct platform_driver bcm2835_i2s_driver = { + .probe = bcm2835_i2s_probe, + .remove = bcm2835_i2s_remove, + .driver = { + .name = "bcm2835-i2s", + .owner = THIS_MODULE, + .of_match_table = bcm2835_i2s_of_match, + }, +}; + +module_platform_driver(bcm2835_i2s_driver); + +MODULE_ALIAS("platform:bcm2835-i2s"); +MODULE_DESCRIPTION("BCM2835 I2S interface"); +MODULE_AUTHOR("Florian Meier "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 8fe02e167efa8ed4a4503a5eedc0f49fcb7e3eb9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 21 Oct 2013 19:22:25 +0200 Subject: cfg80211: consolidate passive-scan and no-ibss flags These two flags are used for the same purpose, just combine them into a no-ir flag to annotate no initiating radiation is allowed. Old userspace sending either flag will have it treated as the no-ir flag. To be considerate to older userspace we also send both the no-ir flag and the old no-ibss flags. Newer userspace will have to be aware of older kernels. Update all places in the tree using these flags with the following semantic patch: @@ @@ -NL80211_RRF_PASSIVE_SCAN +NL80211_RRF_NO_IR @@ @@ -NL80211_RRF_NO_IBSS +NL80211_RRF_NO_IR @@ @@ -IEEE80211_CHAN_PASSIVE_SCAN +IEEE80211_CHAN_NO_IR @@ @@ -IEEE80211_CHAN_NO_IBSS +IEEE80211_CHAN_NO_IR @@ @@ -NL80211_RRF_NO_IR | NL80211_RRF_NO_IR +NL80211_RRF_NO_IR @@ @@ -IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_IR +IEEE80211_CHAN_NO_IR @@ @@ -(NL80211_RRF_NO_IR) +NL80211_RRF_NO_IR @@ @@ -(IEEE80211_CHAN_NO_IR) +IEEE80211_CHAN_NO_IR Along with some hand-optimisations in documentation, to remove duplicates and to fix some indentation. Signed-off-by: Luis R. Rodriguez [do all the driver updates in one go] Signed-off-by: Johannes Berg --- Documentation/networking/regulatory.txt | 4 +- drivers/net/wireless/ath/ath10k/mac.c | 4 +- drivers/net/wireless/ath/regd.c | 47 +++++++-------- drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 2 +- .../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 10 ++-- drivers/net/wireless/brcm80211/brcmsmac/channel.c | 31 ++++------ .../net/wireless/brcm80211/brcmsmac/mac80211_if.c | 66 +++++++++++----------- drivers/net/wireless/cw1200/scan.c | 10 ++-- drivers/net/wireless/ipw2x00/ipw2100.c | 4 +- drivers/net/wireless/ipw2x00/ipw2200.c | 8 +-- drivers/net/wireless/iwlegacy/3945-mac.c | 2 +- drivers/net/wireless/iwlegacy/4965-mac.c | 2 +- drivers/net/wireless/iwlegacy/common.c | 4 +- drivers/net/wireless/iwlegacy/debug.c | 8 +-- drivers/net/wireless/iwlwifi/dvm/debugfs.c | 8 +-- drivers/net/wireless/iwlwifi/dvm/scan.c | 2 +- drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c | 4 +- drivers/net/wireless/iwlwifi/iwl-nvm-parse.c | 4 +- drivers/net/wireless/iwlwifi/mvm/scan.c | 4 +- drivers/net/wireless/mac80211_hwsim.c | 4 +- drivers/net/wireless/mwifiex/cfg80211.c | 14 ++--- drivers/net/wireless/mwifiex/scan.c | 4 +- drivers/net/wireless/rtlwifi/regd.c | 48 +++++++--------- drivers/net/wireless/ti/wl12xx/scan.c | 2 +- drivers/net/wireless/ti/wlcore/cmd.c | 2 +- drivers/net/wireless/ti/wlcore/main.c | 3 +- drivers/net/wireless/ti/wlcore/scan.c | 12 ++-- include/net/cfg80211.h | 9 ++- include/uapi/linux/nl80211.h | 30 ++++++---- net/mac80211/scan.c | 10 ++-- net/mac80211/tx.c | 3 +- net/wireless/chan.c | 3 +- net/wireless/genregdb.awk | 7 ++- net/wireless/ibss.c | 4 +- net/wireless/mesh.c | 3 +- net/wireless/nl80211.c | 12 ++-- net/wireless/reg.c | 33 ++++------- 37 files changed, 197 insertions(+), 230 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/regulatory.txt b/Documentation/networking/regulatory.txt index 9551622d0a7b..356f791af574 100644 --- a/Documentation/networking/regulatory.txt +++ b/Documentation/networking/regulatory.txt @@ -159,10 +159,10 @@ struct ieee80211_regdomain mydriver_jp_regdom = { REG_RULE(2412-20, 2484+20, 40, 6, 20, 0), /* IEEE 802.11a, channels 34..48 */ REG_RULE(5170-20, 5240+20, 40, 6, 20, - NL80211_RRF_PASSIVE_SCAN), + NL80211_RRF_NO_IR), /* IEEE 802.11a, channels 52..64 */ REG_RULE(5260-20, 5320+20, 40, 6, 20, - NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_IR| NL80211_RRF_DFS), } }; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 0b1cc516e778..f23d61fda243 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1351,12 +1351,12 @@ static int ath10k_update_channel_list(struct ath10k *ar) ch->allow_vht = true; ch->allow_ibss = - !(channel->flags & IEEE80211_CHAN_NO_IBSS); + !(channel->flags & IEEE80211_CHAN_NO_IR); ch->ht40plus = !(channel->flags & IEEE80211_CHAN_NO_HT40PLUS); - passive = channel->flags & IEEE80211_CHAN_PASSIVE_SCAN; + passive = channel->flags & IEEE80211_CHAN_NO_IR; ch->passive = passive; ch->freq = channel->center_freq; diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index c00687e05688..e93e517a699f 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -37,17 +37,18 @@ static int __ath_regd_init(struct ath_regulatory *reg); /* We enable active scan on these a case by case basis by regulatory domain */ #define ATH9K_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\ - NL80211_RRF_PASSIVE_SCAN) + NL80211_RRF_NO_IR) #define ATH9K_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\ - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM) + NL80211_RRF_NO_IR | \ + NL80211_RRF_NO_OFDM) /* We allow IBSS on these on a case by case basis by regulatory domain */ #define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\ - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\ - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define ATH9K_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 80, 0, 30,\ - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define ATH9K_2GHZ_ALL ATH9K_2GHZ_CH01_11, \ ATH9K_2GHZ_CH12_13, \ @@ -223,18 +224,11 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy, * default during init, prior to calling our * regulatory_hint(). */ - if (!(reg_rule->flags & - NL80211_RRF_NO_IBSS)) - ch->flags &= - ~IEEE80211_CHAN_NO_IBSS; - if (!(reg_rule->flags & - NL80211_RRF_PASSIVE_SCAN)) - ch->flags &= - ~IEEE80211_CHAN_PASSIVE_SCAN; + if (!(reg_rule->flags & NL80211_RRF_NO_IR)) + ch->flags &= ~IEEE80211_CHAN_NO_IR; } else { if (ch->beacon_found) - ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN); + ch->flags &= ~IEEE80211_CHAN_NO_IR; } } } @@ -260,11 +254,11 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy, */ if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { ch = &sband->channels[11]; /* CH 12 */ - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; ch = &sband->channels[12]; /* CH 13 */ - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; return; } @@ -278,17 +272,17 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy, ch = &sband->channels[11]; /* CH 12 */ reg_rule = freq_reg_info(wiphy, ch->center_freq); if (!IS_ERR(reg_rule)) { - if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (!(reg_rule->flags & NL80211_RRF_NO_IR)) + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; } ch = &sband->channels[12]; /* CH 13 */ reg_rule = freq_reg_info(wiphy, ch->center_freq); if (!IS_ERR(reg_rule)) { - if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (!(reg_rule->flags & NL80211_RRF_NO_IR)) + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; } } @@ -320,8 +314,7 @@ static void ath_reg_apply_radar_flags(struct wiphy *wiphy) */ if (!(ch->flags & IEEE80211_CHAN_DISABLED)) ch->flags |= IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR; } } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index d7a974532909..fd0a4971244a 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -812,7 +812,7 @@ static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg, struct ieee80211_channel *chan = request->channels[i]; if (chan->flags & (IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_PASSIVE_SCAN)) + IEEE80211_CHAN_NO_IR)) continue; chanspecs[i] = channel_to_chanspec(&p2p->cfg->d11inf, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 571f013cebbb..b6a09f97f9a3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -202,9 +202,9 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = { /* This is to override regulatory domains defined in cfg80211 module (reg.c) * By default world regulatory domain defined in reg.c puts the flags - * NL80211_RRF_PASSIVE_SCAN and NL80211_RRF_NO_IBSS for 5GHz channels (for - * 36..48 and 149..165). With respect to these flags, wpa_supplicant doesn't - * start p2p operations on 5GHz channels. All the changes in world regulatory + * NL80211_RRF_NO_IR for 5GHz channels (for * 36..48 and 149..165). + * With respect to these flags, wpa_supplicant doesn't * start p2p + * operations on 5GHz channels. All the changes in world regulatory * domain are to be done here. */ static const struct ieee80211_regdomain brcmf_regdom = { @@ -5197,10 +5197,10 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap) if (channel & WL_CHAN_RADAR) band_chan_arr[index].flags |= (IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_NO_IBSS); + IEEE80211_CHAN_NO_IR); if (channel & WL_CHAN_PASSIVE) band_chan_arr[index].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR; } } if (!update) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index cc87926f5055..7d8f3fd69a87 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -59,23 +59,18 @@ #define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 19, 0) #define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, \ - NL80211_RRF_PASSIVE_SCAN | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, \ - NL80211_RRF_PASSIVE_SCAN | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, \ - NL80211_RRF_PASSIVE_SCAN | \ NL80211_RRF_DFS | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, \ - NL80211_RRF_PASSIVE_SCAN | \ NL80211_RRF_DFS | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, \ - NL80211_RRF_PASSIVE_SCAN | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) static const struct ieee80211_regdomain brcms_regdom_x2 = { .n_reg_rules = 6, @@ -395,7 +390,7 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec, brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false); brcms_b_set_chanspec(wlc->hw, chanspec, - !!(ch->flags & IEEE80211_CHAN_PASSIVE_SCAN), + !!(ch->flags & IEEE80211_CHAN_NO_IR), &txpwr); } @@ -657,8 +652,8 @@ static void brcms_reg_apply_radar_flags(struct wiphy *wiphy) */ if (!(ch->flags & IEEE80211_CHAN_DISABLED)) ch->flags |= IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR | + IEEE80211_CHAN_NO_IR; } } @@ -688,14 +683,10 @@ brcms_reg_apply_beaconing_flags(struct wiphy *wiphy, if (IS_ERR(rule)) continue; - if (!(rule->flags & NL80211_RRF_NO_IBSS)) - ch->flags &= ~IEEE80211_CHAN_NO_IBSS; - if (!(rule->flags & NL80211_RRF_PASSIVE_SCAN)) - ch->flags &= - ~IEEE80211_CHAN_PASSIVE_SCAN; + if (!(rule->flags & NL80211_RRF_NO_IR)) + ch->flags &= ~IEEE80211_CHAN_NO_IR; } else if (ch->beacon_found) { - ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN); + ch->flags &= ~IEEE80211_CHAN_NO_IR; } } } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index edc5d105ff98..e71ce8c842a2 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -125,13 +125,13 @@ static struct ieee80211_channel brcms_2ghz_chantable[] = { CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS), CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS), CHAN2GHZ(12, 2467, - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN2GHZ(13, 2472, - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN2GHZ(14, 2484, - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS | IEEE80211_CHAN_NO_OFDM) }; @@ -144,51 +144,51 @@ static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = { CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS), /* UNII-2 */ CHAN5GHZ(52, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS), CHAN5GHZ(56, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN5GHZ(60, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS), CHAN5GHZ(64, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), /* MID */ CHAN5GHZ(100, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS), CHAN5GHZ(104, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN5GHZ(108, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS), CHAN5GHZ(112, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN5GHZ(116, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS), CHAN5GHZ(120, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN5GHZ(124, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS), CHAN5GHZ(128, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN5GHZ(132, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40MINUS), CHAN5GHZ(136, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS), CHAN5GHZ(140, - IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS | + IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS), /* UNII-3 */ CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS), diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c index ee3c19037aac..8c017bfd2ffc 100644 --- a/drivers/net/wireless/cw1200/scan.c +++ b/drivers/net/wireless/cw1200/scan.c @@ -197,9 +197,9 @@ void cw1200_scan_work(struct work_struct *work) if ((*it)->band != first->band) break; if (((*it)->flags ^ first->flags) & - IEEE80211_CHAN_PASSIVE_SCAN) + IEEE80211_CHAN_NO_IR) break; - if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) && + if (!(first->flags & IEEE80211_CHAN_NO_IR) && (*it)->max_power != first->max_power) break; } @@ -210,7 +210,7 @@ void cw1200_scan_work(struct work_struct *work) else scan.max_tx_rate = WSM_TRANSMIT_RATE_1; scan.num_probes = - (first->flags & IEEE80211_CHAN_PASSIVE_SCAN) ? 0 : 2; + (first->flags & IEEE80211_CHAN_NO_IR) ? 0 : 2; scan.num_ssids = priv->scan.n_ssids; scan.ssids = &priv->scan.ssids[0]; scan.num_channels = it - priv->scan.curr; @@ -233,7 +233,7 @@ void cw1200_scan_work(struct work_struct *work) } for (i = 0; i < scan.num_channels; ++i) { scan.ch[i].number = priv->scan.curr[i]->hw_value; - if (priv->scan.curr[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) { + if (priv->scan.curr[i]->flags & IEEE80211_CHAN_NO_IR) { scan.ch[i].min_chan_time = 50; scan.ch[i].max_chan_time = 100; } else { @@ -241,7 +241,7 @@ void cw1200_scan_work(struct work_struct *work) scan.ch[i].max_chan_time = 25; } } - if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) && + if (!(first->flags & IEEE80211_CHAN_NO_IR) && priv->scan.output_power != first->max_power) { priv->scan.output_power = first->max_power; wsm_set_output_power(priv, diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index f8ab193009cd..813c9af0ebd6 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -1930,10 +1930,10 @@ static int ipw2100_wdev_init(struct net_device *dev) bg_band->channels[i].max_power = geo->bg[i].max_power; if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY) bg_band->channels[i].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR; if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS) bg_band->channels[i].flags |= - IEEE80211_CHAN_NO_IBSS; + IEEE80211_CHAN_NO_IR; if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT) bg_band->channels[i].flags |= IEEE80211_CHAN_RADAR; diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index f394af777cf5..4eca9e20adea 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -11472,10 +11472,10 @@ static int ipw_wdev_init(struct net_device *dev) bg_band->channels[i].max_power = geo->bg[i].max_power; if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY) bg_band->channels[i].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR; if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS) bg_band->channels[i].flags |= - IEEE80211_CHAN_NO_IBSS; + IEEE80211_CHAN_NO_IR; if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT) bg_band->channels[i].flags |= IEEE80211_CHAN_RADAR; @@ -11511,10 +11511,10 @@ static int ipw_wdev_init(struct net_device *dev) a_band->channels[i].max_power = geo->a[i].max_power; if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY) a_band->channels[i].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR; if (geo->a[i].flags & LIBIPW_CH_NO_IBSS) a_band->channels[i].flags |= - IEEE80211_CHAN_NO_IBSS; + IEEE80211_CHAN_NO_IR; if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT) a_band->channels[i].flags |= IEEE80211_CHAN_RADAR; diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index dea3b50d68b9..5a66595b0faf 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -1595,7 +1595,7 @@ il3945_get_channels_for_scan(struct il_priv *il, enum ieee80211_band band, * and use long active_dwell time. */ if (!is_active || il_is_channel_passive(ch_info) || - (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) { + (chan->flags & IEEE80211_CHAN_NO_IR)) { scan_ch->type = 0; /* passive */ if (IL_UCODE_API(il->ucode_ver) == 1) scan_ch->active_dwell = diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index 3982ab76f375..1c5f8cdbd3a5 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -805,7 +805,7 @@ il4965_get_channels_for_scan(struct il_priv *il, struct ieee80211_vif *vif, } if (!is_active || il_is_channel_passive(ch_info) || - (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) + (chan->flags & IEEE80211_CHAN_NO_IR)) scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; else scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index b03e22ef5462..a27b14cfeaec 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -3445,10 +3445,10 @@ il_init_geos(struct il_priv *il) if (il_is_channel_valid(ch)) { if (!(ch->flags & EEPROM_CHANNEL_IBSS)) - geo_ch->flags |= IEEE80211_CHAN_NO_IBSS; + geo_ch->flags |= IEEE80211_CHAN_NO_IR; if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) - geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN; + geo_ch->flags |= IEEE80211_CHAN_NO_IR; if (ch->flags & EEPROM_CHANNEL_RADAR) geo_ch->flags |= IEEE80211_CHAN_RADAR; diff --git a/drivers/net/wireless/iwlegacy/debug.c b/drivers/net/wireless/iwlegacy/debug.c index eff26501d60a..3a487a3bb5de 100644 --- a/drivers/net/wireless/iwlegacy/debug.c +++ b/drivers/net/wireless/iwlegacy/debug.c @@ -567,12 +567,12 @@ il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count, flags & IEEE80211_CHAN_RADAR ? " (IEEE 802.11h required)" : "", ((channels[i]. - flags & IEEE80211_CHAN_NO_IBSS) || + flags & IEEE80211_CHAN_NO_IR) || (channels[i]. flags & IEEE80211_CHAN_RADAR)) ? "" : ", IBSS", channels[i]. - flags & IEEE80211_CHAN_PASSIVE_SCAN ? + flags & IEEE80211_CHAN_NO_IR ? "passive only" : "active/passive"); } supp_band = il_get_hw_mode(il, IEEE80211_BAND_5GHZ); @@ -594,12 +594,12 @@ il_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count, flags & IEEE80211_CHAN_RADAR ? " (IEEE 802.11h required)" : "", ((channels[i]. - flags & IEEE80211_CHAN_NO_IBSS) || + flags & IEEE80211_CHAN_NO_IR) || (channels[i]. flags & IEEE80211_CHAN_RADAR)) ? "" : ", IBSS", channels[i]. - flags & IEEE80211_CHAN_PASSIVE_SCAN ? + flags & IEEE80211_CHAN_NO_IR ? "passive only" : "active/passive"); } ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index d94f8ab15004..f69301e505ee 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -352,12 +352,12 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, channels[i].max_power, channels[i].flags & IEEE80211_CHAN_RADAR ? " (IEEE 802.11h required)" : "", - ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) + ((channels[i].flags & IEEE80211_CHAN_NO_IR) || (channels[i].flags & IEEE80211_CHAN_RADAR)) ? "" : ", IBSS", channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? + IEEE80211_CHAN_NO_IR ? "passive only" : "active/passive"); } supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); @@ -375,12 +375,12 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, channels[i].max_power, channels[i].flags & IEEE80211_CHAN_RADAR ? " (IEEE 802.11h required)" : "", - ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) + ((channels[i].flags & IEEE80211_CHAN_NO_IR) || (channels[i].flags & IEEE80211_CHAN_RADAR)) ? "" : ", IBSS", channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? + IEEE80211_CHAN_NO_IR ? "passive only" : "active/passive"); } ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c index 35e0ee8b4e5b..928f8640a0a7 100644 --- a/drivers/net/wireless/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/iwlwifi/dvm/scan.c @@ -544,7 +544,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, channel = chan->hw_value; scan_ch->channel = cpu_to_le16(channel); - if (!is_active || (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) + if (!is_active || (chan->flags & IEEE80211_CHAN_NO_IR)) scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; else scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index 4c887f365908..f4a6d317a023 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c @@ -614,10 +614,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, channel->flags = IEEE80211_CHAN_NO_HT40; if (!(eeprom_ch->flags & EEPROM_CHANNEL_IBSS)) - channel->flags |= IEEE80211_CHAN_NO_IBSS; + channel->flags |= IEEE80211_CHAN_NO_IR; if (!(eeprom_ch->flags & EEPROM_CHANNEL_ACTIVE)) - channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN; + channel->flags |= IEEE80211_CHAN_NO_IR; if (eeprom_ch->flags & EEPROM_CHANNEL_RADAR) channel->flags |= IEEE80211_CHAN_RADAR; diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index b76a9a8fc0b3..2fab203d3027 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -223,10 +223,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, channel->flags |= IEEE80211_CHAN_NO_160MHZ; if (!(ch_flags & NVM_CHANNEL_IBSS)) - channel->flags |= IEEE80211_CHAN_NO_IBSS; + channel->flags |= IEEE80211_CHAN_NO_IR; if (!(ch_flags & NVM_CHANNEL_ACTIVE)) - channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN; + channel->flags |= IEEE80211_CHAN_NO_IR; if (ch_flags & NVM_CHANNEL_RADAR) channel->flags |= IEEE80211_CHAN_RADAR; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index dff7592e1ff8..e0cd100b40cd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -192,7 +192,7 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd, for (i = 0; i < cmd->channel_count; i++) { chan->channel = cpu_to_le16(req->channels[i]->hw_value); chan->type = cpu_to_le32(type); - if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) + if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR) chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE); chan->active_dwell = cpu_to_le16(active_dwell); chan->passive_dwell = cpu_to_le16(passive_dwell); @@ -642,7 +642,7 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm, channels->iter_count[index] = cpu_to_le16(1); channels->iter_interval[index] = 0; - if (!(s_band->channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) + if (!(s_band->channels[i].flags & IEEE80211_CHAN_NO_IR)) channels->type[index] |= cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index de0df86704e7..33d4b31995da 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -159,7 +159,7 @@ static const struct ieee80211_regdomain hwsim_world_regdom_custom_02 = { .reg_rules = { REG_RULE(2412-10, 2462+10, 40, 0, 20, 0), REG_RULE(5725-10, 5850+10, 40, 0, 30, - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), + NL80211_RRF_NO_IR), } }; @@ -1485,7 +1485,7 @@ static void hw_scan_work(struct work_struct *work) req->channels[hwsim->scan_chan_idx]->center_freq); hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx]; - if (hwsim->tmp_chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || + if (hwsim->tmp_chan->flags & IEEE80211_CHAN_NO_IR || !req->n_ssids) { dwell = 120; } else { diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index fbad00a5abc8..7f68943f02c2 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -50,24 +50,24 @@ static const struct ieee80211_regdomain mwifiex_world_regdom_custom = { REG_RULE(2412-10, 2462+10, 40, 3, 20, 0), /* Channel 12 - 13 */ REG_RULE(2467-10, 2472+10, 20, 3, 20, - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), + NL80211_RRF_NO_IR), /* Channel 14 */ REG_RULE(2484-10, 2484+10, 20, 3, 20, - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_IR | NL80211_RRF_NO_OFDM), /* Channel 36 - 48 */ REG_RULE(5180-10, 5240+10, 40, 3, 20, - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), + NL80211_RRF_NO_IR), /* Channel 149 - 165 */ REG_RULE(5745-10, 5825+10, 40, 3, 20, - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), + NL80211_RRF_NO_IR), /* Channel 52 - 64 */ REG_RULE(5260-10, 5320+10, 40, 3, 30, - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_IR | NL80211_RRF_DFS), /* Channel 100 - 140 */ REG_RULE(5500-10, 5700+10, 40, 3, 30, - NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_IR | NL80211_RRF_DFS), } }; @@ -1968,7 +1968,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, user_scan_cfg->chan_list[i].chan_number = chan->hw_value; user_scan_cfg->chan_list[i].radio_type = chan->band; - if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) + if (chan->flags & IEEE80211_CHAN_NO_IR) user_scan_cfg->chan_list[i].scan_type = MWIFIEX_SCAN_TYPE_PASSIVE; else diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 8cf7d50a7603..0ed06646f19a 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -515,14 +515,14 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, scan_chan_list[chan_idx].max_scan_time = cpu_to_le16((u16) user_scan_in-> chan_list[0].scan_time); - else if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + else if (ch->flags & IEEE80211_CHAN_NO_IR) scan_chan_list[chan_idx].max_scan_time = cpu_to_le16(adapter->passive_scan_time); else scan_chan_list[chan_idx].max_scan_time = cpu_to_le16(adapter->active_scan_time); - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) + if (ch->flags & IEEE80211_CHAN_NO_IR) scan_chan_list[chan_idx].chan_scan_mode_bitmap |= MWIFIEX_PASSIVE_SCAN; else diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c index d7d0d4948b01..8453c53143f5 100644 --- a/drivers/net/wireless/rtlwifi/regd.c +++ b/drivers/net/wireless/rtlwifi/regd.c @@ -59,30 +59,26 @@ static struct country_code_to_enum_rd allCountries[] = { */ #define RTL819x_2GHZ_CH12_13 \ REG_RULE(2467-10, 2472+10, 40, 0, 20,\ - NL80211_RRF_PASSIVE_SCAN) + NL80211_RRF_NO_IR) #define RTL819x_2GHZ_CH14 \ REG_RULE(2484-10, 2484+10, 40, 0, 20, \ - NL80211_RRF_PASSIVE_SCAN | \ - NL80211_RRF_NO_OFDM) + NL80211_RRF_NO_IR | NL80211_RRF_NO_OFDM) /* 5G chan 36 - chan 64*/ #define RTL819x_5GHZ_5150_5350 \ REG_RULE(5150-10, 5350+10, 40, 0, 30, \ - NL80211_RRF_PASSIVE_SCAN | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) /* 5G chan 100 - chan 165*/ #define RTL819x_5GHZ_5470_5850 \ REG_RULE(5470-10, 5850+10, 40, 0, 30, \ - NL80211_RRF_PASSIVE_SCAN | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) /* 5G chan 149 - chan 165*/ #define RTL819x_5GHZ_5725_5850 \ REG_RULE(5725-10, 5850+10, 40, 0, 30, \ - NL80211_RRF_PASSIVE_SCAN | \ - NL80211_RRF_NO_IBSS) + NL80211_RRF_NO_IR) #define RTL819x_5GHZ_ALL \ (RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850) @@ -185,16 +181,11 @@ static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy, *regulatory_hint(). */ - if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) - ch->flags &= ~IEEE80211_CHAN_NO_IBSS; - if (!(reg_rule-> - flags & NL80211_RRF_PASSIVE_SCAN)) - ch->flags &= - ~IEEE80211_CHAN_PASSIVE_SCAN; + if (!(reg_rule->flags & NL80211_RRF_NO_IR)) + ch->flags &= ~IEEE80211_CHAN_NO_IR; } else { if (ch->beacon_found) - ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN); + ch->flags &= ~IEEE80211_CHAN_NO_IR; } } } @@ -219,11 +210,11 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, */ if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) { ch = &sband->channels[11]; /* CH 12 */ - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; ch = &sband->channels[12]; /* CH 13 */ - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; return; } @@ -237,17 +228,17 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, ch = &sband->channels[11]; /* CH 12 */ reg_rule = freq_reg_info(wiphy, ch->center_freq); if (!IS_ERR(reg_rule)) { - if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (!(reg_rule->flags & NL80211_RRF_NO_IR)) + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; } ch = &sband->channels[12]; /* CH 13 */ reg_rule = freq_reg_info(wiphy, ch->center_freq); if (!IS_ERR(reg_rule)) { - if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) - if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) - ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + if (!(reg_rule->flags & NL80211_RRF_NO_IR)) + if (ch->flags & IEEE80211_CHAN_NO_IR) + ch->flags &= ~IEEE80211_CHAN_NO_IR; } } @@ -284,8 +275,7 @@ static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy) */ if (!(ch->flags & IEEE80211_CHAN_DISABLED)) ch->flags |= IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN; + IEEE80211_CHAN_NO_IR; } } diff --git a/drivers/net/wireless/ti/wl12xx/scan.c b/drivers/net/wireless/ti/wl12xx/scan.c index 4a0bbb13806b..7541bd1a4a4b 100644 --- a/drivers/net/wireless/ti/wl12xx/scan.c +++ b/drivers/net/wireless/ti/wl12xx/scan.c @@ -47,7 +47,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, * In active scans, we only scan channels not * marked as passive. */ - (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) { + (passive || !(flags & IEEE80211_CHAN_NO_IR))) { wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", req->channels[i]->band, req->channels[i]->center_freq); diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 34d9dfff2ad3..9b2ecf52449f 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -1688,7 +1688,7 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl) if (channel->flags & (IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_PASSIVE_SCAN)) + IEEE80211_CHAN_NO_IR)) continue; ch_bit_idx = wlcore_get_reg_conf_ch_idx(b, ch); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 0368b9cbfb89..e9da47cead58 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -91,8 +91,7 @@ static void wl1271_reg_notify(struct wiphy *wiphy, continue; if (ch->flags & IEEE80211_CHAN_RADAR) - ch->flags |= IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN; + ch->flags |= IEEE80211_CHAN_NO_IR; } diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c index 7ed86203304b..1e3d51cd673a 100644 --- a/drivers/net/wireless/ti/wlcore/scan.c +++ b/drivers/net/wireless/ti/wlcore/scan.c @@ -188,16 +188,14 @@ wlcore_scan_get_channels(struct wl1271 *wl, flags = req_channels[i]->flags; if (force_passive) - flags |= IEEE80211_CHAN_PASSIVE_SCAN; + flags |= IEEE80211_CHAN_NO_IR; if ((req_channels[i]->band == band) && !(flags & IEEE80211_CHAN_DISABLED) && (!!(flags & IEEE80211_CHAN_RADAR) == radar) && /* if radar is set, we ignore the passive flag */ (radar || - !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) { - - + !!(flags & IEEE80211_CHAN_NO_IR) == passive)) { if (flags & IEEE80211_CHAN_RADAR) { channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS; @@ -220,7 +218,7 @@ wlcore_scan_get_channels(struct wl1271 *wl, (band == IEEE80211_BAND_2GHZ) && (channels[j].channel >= 12) && (channels[j].channel <= 14) && - (flags & IEEE80211_CHAN_PASSIVE_SCAN) && + (flags & IEEE80211_CHAN_NO_IR) && !force_passive) { /* pactive channels treated as DFS */ channels[j].flags = SCAN_CHANNEL_FLAGS_DFS; @@ -243,8 +241,8 @@ wlcore_scan_get_channels(struct wl1271 *wl, max_dwell_time_active, flags & IEEE80211_CHAN_RADAR ? ", DFS" : "", - flags & IEEE80211_CHAN_PASSIVE_SCAN ? - ", PASSIVE" : ""); + flags & IEEE80211_CHAN_NO_IR ? + ", NO-IR" : ""); j++; } } diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 3eae46cb1acf..c1b887413234 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -91,9 +91,8 @@ enum ieee80211_band { * Channel flags set by the regulatory control code. * * @IEEE80211_CHAN_DISABLED: This channel is disabled. - * @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted - * on this channel. - * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel. + * @IEEE80211_CHAN_NO_IR: do not initiate radiation, this includes + * sending probe requests or beaconing. * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel. * @IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel * is not permitted. @@ -113,8 +112,8 @@ enum ieee80211_band { */ enum ieee80211_channel_flags { IEEE80211_CHAN_DISABLED = 1<<0, - IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, - IEEE80211_CHAN_NO_IBSS = 1<<2, + IEEE80211_CHAN_NO_IR = 1<<1, + /* hole at 1<<2 */ IEEE80211_CHAN_RADAR = 1<<3, IEEE80211_CHAN_NO_HT40PLUS = 1<<4, IEEE80211_CHAN_NO_HT40MINUS = 1<<5, diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 3d8325bb50cd..7e25164adfe9 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2231,10 +2231,9 @@ enum nl80211_band_attr { * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current * regulatory domain. - * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is - * permitted on this channel in current regulatory domain. - * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted - * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_NO_IR: no mechanisms that initiate radiation + * are permitted on this channel, this includes sending probe + * requests, or modes of operation that require beaconing. * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory * on this channel in current regulatory domain. * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm @@ -2261,8 +2260,8 @@ enum nl80211_frequency_attr { __NL80211_FREQUENCY_ATTR_INVALID, NL80211_FREQUENCY_ATTR_FREQ, NL80211_FREQUENCY_ATTR_DISABLED, - NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, - NL80211_FREQUENCY_ATTR_NO_IBSS, + NL80211_FREQUENCY_ATTR_NO_IR, + __NL80211_FREQUENCY_ATTR_NO_IBSS, NL80211_FREQUENCY_ATTR_RADAR, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, NL80211_FREQUENCY_ATTR_DFS_STATE, @@ -2278,6 +2277,9 @@ enum nl80211_frequency_attr { }; #define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER +#define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN NL80211_FREQUENCY_ATTR_NO_IR +#define NL80211_FREQUENCY_ATTR_NO_IBSS NL80211_FREQUENCY_ATTR_NO_IR +#define NL80211_FREQUENCY_ATTR_NO_IR NL80211_FREQUENCY_ATTR_NO_IR /** * enum nl80211_bitrate_attr - bitrate attributes @@ -2420,8 +2422,9 @@ enum nl80211_sched_scan_match_attr { * @NL80211_RRF_DFS: DFS support is required to be used * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links - * @NL80211_RRF_PASSIVE_SCAN: passive scan is required - * @NL80211_RRF_NO_IBSS: no IBSS is allowed + * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed, + * this includes probe requests or modes of operation that require + * beaconing. */ enum nl80211_reg_rule_flags { NL80211_RRF_NO_OFDM = 1<<0, @@ -2431,10 +2434,17 @@ enum nl80211_reg_rule_flags { NL80211_RRF_DFS = 1<<4, NL80211_RRF_PTP_ONLY = 1<<5, NL80211_RRF_PTMP_ONLY = 1<<6, - NL80211_RRF_PASSIVE_SCAN = 1<<7, - NL80211_RRF_NO_IBSS = 1<<8, + NL80211_RRF_NO_IR = 1<<7, + __NL80211_RRF_NO_IBSS = 1<<8, }; +#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR +#define NL80211_RRF_NO_IBSS NL80211_RRF_NO_IR +#define NL80211_RRF_NO_IR NL80211_RRF_NO_IR + +/* For backport compatibility with older userspace */ +#define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS) + /** * enum nl80211_dfs_regions - regulatory DFS regions * diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 5ad66a83ef7f..c22cbb57b49d 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -526,7 +526,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, ieee80211_hw_config(local, 0); if ((req->channels[0]->flags & - IEEE80211_CHAN_PASSIVE_SCAN) || + IEEE80211_CHAN_NO_IR) || !local->scan_req->n_ssids) { next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; } else { @@ -572,7 +572,7 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan) * TODO: channel switching also consumes quite some time, * add that delay as well to get a better estimation */ - if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) + if (chan->flags & IEEE80211_CHAN_NO_IR) return IEEE80211_PASSIVE_CHANNEL_TIME; return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME; } @@ -696,7 +696,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, * * In any case, it is not necessary for a passive scan. */ - if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN || + if (chan->flags & IEEE80211_CHAN_NO_IR || !local->scan_req->n_ssids) { *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; local->next_scan_state = SCAN_DECISION; @@ -881,7 +881,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, struct ieee80211_channel *tmp_ch = &local->hw.wiphy->bands[band]->channels[i]; - if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS | + if (tmp_ch->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_DISABLED)) continue; @@ -895,7 +895,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, local->int_scan_req->n_channels = n_ch; } else { - if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS | + if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_DISABLED))) goto unlock; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c558b246ef00..5ad2e8b1f92c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1724,8 +1724,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, * radar detection by itself. We can do that later by adding a * monitor flag interfaces used for AP support. */ - if ((chan->flags & (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_RADAR | - IEEE80211_CHAN_PASSIVE_SCAN))) + if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))) goto fail_rcu; ieee80211_xmit(sdata, skb, chan->band); diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 9b8cc877eb19..344966496b70 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -467,8 +467,7 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy, res = cfg80211_chandef_usable(wiphy, chandef, IEEE80211_CHAN_DISABLED | - IEEE80211_CHAN_PASSIVE_SCAN | - IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR); trace_cfg80211_return_bool(res); diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index 42ed274e81f4..c808619ac9c6 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk @@ -107,10 +107,13 @@ active && /^[ \t]*\(/ { } else if (flagarray[arg] == "PTMP-ONLY") { flags = flags "\n\t\t\tNL80211_RRF_PTMP_ONLY | " } else if (flagarray[arg] == "PASSIVE-SCAN") { - flags = flags "\n\t\t\tNL80211_RRF_PASSIVE_SCAN | " + flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " } else if (flagarray[arg] == "NO-IBSS") { - flags = flags "\n\t\t\tNL80211_RRF_NO_IBSS | " + flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " + } else if (flagarray[arg] == "NO-IR") { + flags = flags "\n\t\t\tNL80211_RRF_NO_IR | " } + } flags = flags "0" printf "\t\tREG_RULE(%d, %d, %d, %d, %d, %s),\n", start, end, bw, gain, power, flags diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 9d797df56649..f79105712949 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -274,7 +274,7 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, for (i = 0; i < sband->n_channels; i++) { chan = &sband->channels[i]; - if (chan->flags & IEEE80211_CHAN_NO_IBSS) + if (chan->flags & IEEE80211_CHAN_NO_IR) continue; if (chan->flags & IEEE80211_CHAN_DISABLED) continue; @@ -345,7 +345,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev, chan = ieee80211_get_channel(wdev->wiphy, freq); if (!chan) return -EINVAL; - if (chan->flags & IEEE80211_CHAN_NO_IBSS || + if (chan->flags & IEEE80211_CHAN_NO_IR || chan->flags & IEEE80211_CHAN_DISABLED) return -EINVAL; } diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index 0553fd4d85ae..b0e1869de7de 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -141,8 +141,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, for (i = 0; i < sband->n_channels; i++) { chan = &sband->channels[i]; - if (chan->flags & (IEEE80211_CHAN_NO_IBSS | - IEEE80211_CHAN_PASSIVE_SCAN | + if (chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_RADAR)) continue; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a7f4e7902104..41af3a0e9961 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -545,12 +545,12 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, if ((chan->flags & IEEE80211_CHAN_DISABLED) && nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED)) goto nla_put_failure; - if ((chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) && - nla_put_flag(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN)) - goto nla_put_failure; - if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && - nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) - goto nla_put_failure; + if (chan->flags & IEEE80211_CHAN_NO_IR) { + if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR)) + goto nla_put_failure; + if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS)) + goto nla_put_failure; + } if (chan->flags & IEEE80211_CHAN_RADAR) { if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) goto nla_put_failure; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 7da67fd0b418..e4e3337ba296 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -163,35 +163,29 @@ static const struct ieee80211_regdomain world_regdom = { REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), /* IEEE 802.11b/g, channels 12..13. */ REG_RULE(2467-10, 2472+10, 40, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS), + NL80211_RRF_NO_IR), /* IEEE 802.11 channel 14 - Only JP enables * this and for 802.11b only */ REG_RULE(2484-10, 2484+10, 20, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_IR | NL80211_RRF_NO_OFDM), /* IEEE 802.11a, channel 36..48 */ REG_RULE(5180-10, 5240+10, 160, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS), + NL80211_RRF_NO_IR), /* IEEE 802.11a, channel 52..64 - DFS required */ REG_RULE(5260-10, 5320+10, 160, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_IR | NL80211_RRF_DFS), /* IEEE 802.11a, channel 100..144 - DFS required */ REG_RULE(5500-10, 5720+10, 160, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS | + NL80211_RRF_NO_IR | NL80211_RRF_DFS), /* IEEE 802.11a, channel 149..165 */ REG_RULE(5745-10, 5825+10, 80, 6, 20, - NL80211_RRF_PASSIVE_SCAN | - NL80211_RRF_NO_IBSS), + NL80211_RRF_NO_IR), /* IEEE 802.11ad (60gHz), channels 1..3 */ REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0), @@ -698,10 +692,8 @@ regdom_intersect(const struct ieee80211_regdomain *rd1, static u32 map_regdom_flags(u32 rd_flags) { u32 channel_flags = 0; - if (rd_flags & NL80211_RRF_PASSIVE_SCAN) - channel_flags |= IEEE80211_CHAN_PASSIVE_SCAN; - if (rd_flags & NL80211_RRF_NO_IBSS) - channel_flags |= IEEE80211_CHAN_NO_IBSS; + if (rd_flags & NL80211_RRF_NO_IR_ALL) + channel_flags |= IEEE80211_CHAN_NO_IR; if (rd_flags & NL80211_RRF_DFS) channel_flags |= IEEE80211_CHAN_RADAR; if (rd_flags & NL80211_RRF_NO_OFDM) @@ -1066,13 +1058,8 @@ static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx, chan_before.center_freq = chan->center_freq; chan_before.flags = chan->flags; - if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) { - chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; - channel_changed = true; - } - - if (chan->flags & IEEE80211_CHAN_NO_IBSS) { - chan->flags &= ~IEEE80211_CHAN_NO_IBSS; + if (chan->flags & IEEE80211_CHAN_NO_IR) { + chan->flags &= ~IEEE80211_CHAN_NO_IR; channel_changed = true; } -- cgit v1.2.3 From 07f9e5cf8e4154ad17b92ad288be0f04fa0cb94f Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Tue, 19 Nov 2013 11:56:04 -0800 Subject: Input: tsc2007 - add device tree support. Signed-off-by: Denis Carikli Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/tsc2007.txt | 41 +++++ arch/arm/mach-imx/mach-cpuimx35.c | 2 +- arch/arm/mach-imx/mach-cpuimx51sd.c | 2 +- arch/sh/boards/mach-ecovec24/setup.c | 2 +- drivers/input/touchscreen/tsc2007.c | 173 ++++++++++++++++----- include/linux/i2c/tsc2007.h | 6 +- 6 files changed, 180 insertions(+), 46 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt b/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt new file mode 100644 index 000000000000..ec365e172236 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt @@ -0,0 +1,41 @@ +* Texas Instruments tsc2007 touchscreen controller + +Required properties: +- compatible: must be "ti,tsc2007". +- reg: I2C address of the chip. +- ti,x-plate-ohms: X-plate resistance in ohms. + +Optional properties: +- gpios: the interrupt gpio the chip is connected to (trough the penirq pin). + The penirq pin goes to low when the panel is touched. + (see GPIO binding[1] for more details). +- interrupt-parent: the phandle for the gpio controller + (see interrupt binding[0]). +- interrupts: (gpio) interrupt to which the chip is connected + (see interrupt binding[0]). +- ti,max-rt: maximum pressure. +- ti,fuzzx: specifies the absolute input fuzz x value. + If set, it will permit noise in the data up to +- the value given to the fuzz + parameter, that is used to filter noise from the event stream. +- ti,fuzzy: specifies the absolute input fuzz y value. +- ti,fuzzz: specifies the absolute input fuzz z value. +- ti,poll-period: how much time to wait (in milliseconds) before reading again the + values from the tsc2007. + +[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +[1]: Documentation/devicetree/bindings/gpio/gpio.txt + +Example: + &i2c1 { + /* ... */ + tsc2007@49 { + compatible = "ti,tsc2007"; + reg = <0x49>; + interrupt-parent = <&gpio4>; + interrupts = <0x0 0x8>; + gpios = <&gpio4 0 0>; + ti,x-plate-ohms = <180>; + }; + + /* ... */ + }; diff --git a/arch/arm/mach-imx/mach-cpuimx35.c b/arch/arm/mach-imx/mach-cpuimx35.c index 771362d1fbee..65e4c53e1554 100644 --- a/arch/arm/mach-imx/mach-cpuimx35.c +++ b/arch/arm/mach-imx/mach-cpuimx35.c @@ -53,7 +53,7 @@ static const struct imxi2c_platform_data }; #define TSC2007_IRQGPIO IMX_GPIO_NR(3, 2) -static int tsc2007_get_pendown_state(void) +static int tsc2007_get_pendown_state(struct device *dev) { return !gpio_get_value(TSC2007_IRQGPIO); } diff --git a/arch/arm/mach-imx/mach-cpuimx51sd.c b/arch/arm/mach-imx/mach-cpuimx51sd.c index 9b5ddf5bbd33..1fba2b8e983f 100644 --- a/arch/arm/mach-imx/mach-cpuimx51sd.c +++ b/arch/arm/mach-imx/mach-cpuimx51sd.c @@ -121,7 +121,7 @@ static const struct imxuart_platform_data uart_pdata __initconst = { .flags = IMXUART_HAVE_RTSCTS, }; -static int tsc2007_get_pendown_state(void) +static int tsc2007_get_pendown_state(struct device *dev) { if (mx51_revision() < IMX_CHIP_REVISION_3_0) return !gpio_get_value(TSC2007_IRQGPIO_REV2); diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 1fa8be409771..23d7e45f9d14 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -501,7 +501,7 @@ static struct platform_device keysc_device = { /* TouchScreen */ #define IRQ0 evt2irq(0x600) -static int ts_get_pendown_state(void) +static int ts_get_pendown_state(struct device *dev) { int val = 0; gpio_free(GPIO_FN_INTC_IRQ0); diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 0b67ba476b4c..88b150a0b8ee 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #define TSC2007_MEASURE_TEMP0 (0x0 << 4) #define TSC2007_MEASURE_AUX (0x2 << 4) @@ -74,13 +77,17 @@ struct tsc2007 { u16 max_rt; unsigned long poll_delay; unsigned long poll_period; + int fuzzx; + int fuzzy; + int fuzzz; + unsigned gpio; int irq; wait_queue_head_t wait; bool stopped; - int (*get_pendown_state)(void); + int (*get_pendown_state)(struct device *); void (*clear_penirq)(void); }; @@ -161,7 +168,7 @@ static bool tsc2007_is_pen_down(struct tsc2007 *ts) if (!ts->get_pendown_state) return true; - return ts->get_pendown_state(); + return ts->get_pendown_state(&ts->client->dev); } static irqreturn_t tsc2007_soft_irq(int irq, void *handle) @@ -178,7 +185,7 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle) rt = tsc2007_calculate_pressure(ts, &tc); - if (rt == 0 && !ts->get_pendown_state) { + if (!rt && !ts->get_pendown_state) { /* * If pressure reported is 0 and we don't have * callback to check pendown state, we have to @@ -228,7 +235,7 @@ static irqreturn_t tsc2007_hard_irq(int irq, void *handle) { struct tsc2007 *ts = handle; - if (!ts->get_pendown_state || likely(ts->get_pendown_state())) + if (tsc2007_is_pen_down(ts)) return IRQ_WAKE_THREAD; if (ts->clear_penirq) @@ -273,35 +280,74 @@ static void tsc2007_close(struct input_dev *input_dev) tsc2007_stop(ts); } -static int tsc2007_probe(struct i2c_client *client, - const struct i2c_device_id *id) +#ifdef CONFIG_OF +static int tsc2007_get_pendown_state_gpio(struct device *dev) { - struct tsc2007 *ts; - struct tsc2007_platform_data *pdata = client->dev.platform_data; - struct input_dev *input_dev; - int err; + struct i2c_client *client = to_i2c_client(dev); + struct tsc2007 *ts = i2c_get_clientdata(client); + + return !gpio_get_value(ts->gpio); +} + +static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) +{ + struct device_node *np = client->dev.of_node; + u32 val32; + u64 val64; - if (!pdata) { - dev_err(&client->dev, "platform data is required!\n"); + if (!np) { + dev_err(&client->dev, "missing device tree data\n"); return -EINVAL; } - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_WORD_DATA)) - return -EIO; + if (!of_property_read_u32(np, "ti,max-rt", &val32)) + ts->max_rt = val32; + else + ts->max_rt = MAX_12BIT; - ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!ts || !input_dev) { - err = -ENOMEM; - goto err_free_mem; + if (!of_property_read_u32(np, "ti,fuzzx", &val32)) + ts->fuzzx = val32; + + if (!of_property_read_u32(np, "ti,fuzzy", &val32)) + ts->fuzzy = val32; + + if (!of_property_read_u32(np, "ti,fuzzz", &val32)) + ts->fuzzz = val32; + + if (!of_property_read_u64(np, "ti,poll-period", &val64)) + ts->poll_period = val64; + else + ts->poll_period = 1; + + if (!of_property_read_u32(np, "ti,x-plate-ohms", &val32)) { + ts->x_plate_ohms = val32; + } else { + dev_err(&client->dev, "missing ti,x-plate-ohms devicetree property."); + return -EINVAL; } - ts->client = client; - ts->irq = client->irq; - ts->input = input_dev; - init_waitqueue_head(&ts->wait); + ts->gpio = of_get_gpio(np, 0); + if (gpio_is_valid(ts->gpio)) + ts->get_pendown_state = tsc2007_get_pendown_state_gpio; + else + dev_warn(&client->dev, + "GPIO not specified in DT (of_get_gpio returned %d)\n", + ts->gpio); + return 0; +} +#else +static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) +{ + dev_err(&client->dev, "platform data is required!\n"); + return -EINVAL; +} +#endif + +static int tsc2007_probe_pdev(struct i2c_client *client, struct tsc2007 *ts, + const struct tsc2007_platform_data *pdata, + const struct i2c_device_id *id) +{ ts->model = pdata->model; ts->x_plate_ohms = pdata->x_plate_ohms; ts->max_rt = pdata->max_rt ? : MAX_12BIT; @@ -309,13 +355,54 @@ static int tsc2007_probe(struct i2c_client *client, ts->poll_period = pdata->poll_period ? : 1; ts->get_pendown_state = pdata->get_pendown_state; ts->clear_penirq = pdata->clear_penirq; + ts->fuzzx = pdata->fuzzx; + ts->fuzzy = pdata->fuzzy; + ts->fuzzz = pdata->fuzzz; if (pdata->x_plate_ohms == 0) { dev_err(&client->dev, "x_plate_ohms is not set up in platform data"); - err = -EINVAL; - goto err_free_mem; + return -EINVAL; } + return 0; +} + +static int tsc2007_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct tsc2007_platform_data *pdata = dev_get_platdata(&client->dev); + struct tsc2007 *ts; + struct input_dev *input_dev; + int err; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_WORD_DATA)) + return -EIO; + + ts = devm_kzalloc(&client->dev, sizeof(struct tsc2007), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + if (pdata) + err = tsc2007_probe_pdev(client, ts, pdata, id); + else + err = tsc2007_probe_dt(client, ts); + if (err) + return err; + + input_dev = input_allocate_device(); + if (!input_dev) { + err = -ENOMEM; + goto err_free_input; + }; + + i2c_set_clientdata(client, ts); + + ts->client = client; + ts->irq = client->irq; + ts->input = input_dev; + init_waitqueue_head(&ts->wait); + snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&client->dev)); @@ -331,19 +418,19 @@ static int tsc2007_probe(struct i2c_client *client, input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, pdata->fuzzx, 0); - input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, pdata->fuzzy, 0); + input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0); + input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, - pdata->fuzzz, 0); + ts->fuzzz, 0); - if (pdata->init_platform_hw) + if (pdata && pdata->init_platform_hw) pdata->init_platform_hw(); err = request_threaded_irq(ts->irq, tsc2007_hard_irq, tsc2007_soft_irq, IRQF_ONESHOT, client->dev.driver->name, ts); if (err < 0) { dev_err(&client->dev, "irq %d busy?\n", ts->irq); - goto err_free_mem; + goto err_free_input; } tsc2007_stop(ts); @@ -352,28 +439,25 @@ static int tsc2007_probe(struct i2c_client *client, if (err) goto err_free_irq; - i2c_set_clientdata(client, ts); - return 0; err_free_irq: free_irq(ts->irq, ts); - if (pdata->exit_platform_hw) + if (pdata && pdata->exit_platform_hw) pdata->exit_platform_hw(); - err_free_mem: + err_free_input: input_free_device(input_dev); - kfree(ts); return err; } static int tsc2007_remove(struct i2c_client *client) { - struct tsc2007 *ts = i2c_get_clientdata(client); - struct tsc2007_platform_data *pdata = client->dev.platform_data; + const struct tsc2007_platform_data *pdata = dev_get_platdata(&client->dev); + struct tsc2007 *ts = i2c_get_clientdata(client); free_irq(ts->irq, ts); - if (pdata->exit_platform_hw) + if (pdata && pdata->exit_platform_hw) pdata->exit_platform_hw(); input_unregister_device(ts->input); @@ -389,10 +473,19 @@ static const struct i2c_device_id tsc2007_idtable[] = { MODULE_DEVICE_TABLE(i2c, tsc2007_idtable); +#ifdef CONFIG_OF +static const struct of_device_id tsc2007_of_match[] = { + { .compatible = "ti,tsc2007" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, tsc2007_of_match); +#endif + static struct i2c_driver tsc2007_driver = { .driver = { .owner = THIS_MODULE, - .name = "tsc2007" + .name = "tsc2007", + .of_match_table = of_match_ptr(tsc2007_of_match), }, .id_table = tsc2007_idtable, .probe = tsc2007_probe, diff --git a/include/linux/i2c/tsc2007.h b/include/linux/i2c/tsc2007.h index 506a9f7af51e..041c8e823664 100644 --- a/include/linux/i2c/tsc2007.h +++ b/include/linux/i2c/tsc2007.h @@ -14,9 +14,9 @@ struct tsc2007_platform_data { int fuzzy; int fuzzz; - int (*get_pendown_state)(void); - void (*clear_penirq)(void); /* If needed, clear 2nd level - interrupt source */ + int (*get_pendown_state)(struct device *); + /* If needed, clear 2nd level interrupt source */ + void (*clear_penirq)(void); int (*init_platform_hw)(void); void (*exit_platform_hw)(void); }; -- cgit v1.2.3 From c81e592696bbe1224506087eae8b4e02cd7186c3 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Tue, 19 Nov 2013 13:55:12 -0800 Subject: Input: twl4030-pwrbutton - add device tree support Add device tree support for twl4030 power button driver. Adding device tree support involved converting the driver to module_platform_driver(). Signed-off-by: Sebastian Reichel Acked-by: Kumar Gala Tested-by: Florian Vaussard Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/twl4030-pwrbutton.txt | 21 +++++++++++++++++++++ drivers/input/misc/twl4030-pwrbutton.c | 16 ++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/twl4030-pwrbutton.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/twl4030-pwrbutton.txt b/Documentation/devicetree/bindings/input/twl4030-pwrbutton.txt new file mode 100644 index 000000000000..c864a46cddcf --- /dev/null +++ b/Documentation/devicetree/bindings/input/twl4030-pwrbutton.txt @@ -0,0 +1,21 @@ +Texas Instruments TWL family (twl4030) pwrbutton module + +This module is part of the TWL4030. For more details about the whole +chip see Documentation/devicetree/bindings/mfd/twl-familly.txt. + +This module provides a simple power button event via an Interrupt. + +Required properties: +- compatible: should be one of the following + - "ti,twl4030-pwrbutton": For controllers compatible with twl4030 +- interrupts: should be one of the following + - <8>: For controllers compatible with twl4030 + +Example: + +&twl { + twl_pwrbutton: pwrbutton { + compatible = "ti,twl4030-pwrbutton"; + interrupts = <8>; + }; +}; diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c index b9a05fda03e4..412ef0ecb439 100644 --- a/drivers/input/misc/twl4030-pwrbutton.c +++ b/drivers/input/misc/twl4030-pwrbutton.c @@ -52,7 +52,7 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr) return IRQ_HANDLED; } -static int __init twl4030_pwrbutton_probe(struct platform_device *pdev) +static int twl4030_pwrbutton_probe(struct platform_device *pdev) { struct input_dev *pwr; int irq = platform_get_irq(pdev, 0); @@ -106,16 +106,24 @@ static int __exit twl4030_pwrbutton_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id twl4030_pwrbutton_dt_match_table[] = { + { .compatible = "ti,twl4030-pwrbutton" }, + {}, +}; +MODULE_DEVICE_TABLE(of, twl4030_pwrbutton_dt_match_table); +#endif + static struct platform_driver twl4030_pwrbutton_driver = { + .probe = twl4030_pwrbutton_probe, .remove = __exit_p(twl4030_pwrbutton_remove), .driver = { .name = "twl4030_pwrbutton", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(twl4030_pwrbutton_dt_match_table), }, }; - -module_platform_driver_probe(twl4030_pwrbutton_driver, - twl4030_pwrbutton_probe); +module_platform_driver(twl4030_pwrbutton_driver); MODULE_ALIAS("platform:twl4030_pwrbutton"); MODULE_DESCRIPTION("Triton2 Power Button"); -- cgit v1.2.3 From 76da314df603a08ebc463853030752251b260ab8 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Mon, 9 Sep 2013 13:23:56 +0300 Subject: clk: tegra124: Add support for Tegra124 clocks Implement clock support for Tegra124. Signed-off-by: Peter De Schrijver --- .../bindings/clock/nvidia,tegra124-car.txt | 59 + drivers/clk/tegra/Makefile | 1 + drivers/clk/tegra/clk-tegra124.c | 1370 ++++++++++++++++++++ include/dt-bindings/clock/tegra124-car.h | 341 +++++ 4 files changed, 1771 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt create mode 100644 drivers/clk/tegra/clk-tegra124.c create mode 100644 include/dt-bindings/clock/tegra124-car.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt new file mode 100644 index 000000000000..1a91ec60dee5 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt @@ -0,0 +1,59 @@ +NVIDIA Tegra124 Clock And Reset Controller + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +The CAR (Clock And Reset) Controller on Tegra is the HW module responsible +for muxing and gating Tegra's clocks, and setting their rates. + +Required properties : +- compatible : Should be "nvidia,tegra124-car" +- reg : Should contain CAR registers location and length +- clocks : Should contain phandle and clock specifiers for two clocks: + the 32 KHz "32k_in", and the board-specific oscillator "osc". +- #clock-cells : Should be 1. + In clock consumers, this cell represents the clock ID exposed by the + CAR. The assignments may be found in header file + . + +Example SoC include file: + +/ { + tegra_car: clock { + compatible = "nvidia,tegra124-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + }; + + usb@c5004000 { + clocks = <&tegra_car TEGRA124_CLK_USB2>; + }; +}; + +Example board file: + +/ { + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + osc: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <112400000>; + }; + + clk_32k: clock@1 { + compatible = "fixed-clock"; + reg = <1>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + &tegra_car { + clocks = <&clk_32k> <&osc>; + }; +}; diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index 2d837411dfed..f7dfb72884a4 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -14,3 +14,4 @@ obj-y += clk-tegra-super-gen4.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o +obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124.o diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c new file mode 100644 index 000000000000..f69367a14777 --- /dev/null +++ b/drivers/clk/tegra/clk-tegra124.c @@ -0,0 +1,1370 @@ +/* + * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" +#include "clk-id.h" + +#define CLK_SOURCE_EMC 0x19c +#define CLK_SOURCE_XUSB_SS_SRC 0x610 + +#define PLLC_BASE 0x80 +#define PLLC_OUT 0x84 +#define PLLC_MISC2 0x88 +#define PLLC_MISC 0x8c +#define PLLC2_BASE 0x4e8 +#define PLLC2_MISC 0x4ec +#define PLLC3_BASE 0x4fc +#define PLLC3_MISC 0x500 +#define PLLM_BASE 0x90 +#define PLLM_OUT 0x94 +#define PLLM_MISC 0x9c +#define PLLP_BASE 0xa0 +#define PLLP_MISC 0xac +#define PLLA_BASE 0xb0 +#define PLLA_MISC 0xbc +#define PLLD_BASE 0xd0 +#define PLLD_MISC 0xdc +#define PLLU_BASE 0xc0 +#define PLLU_MISC 0xcc +#define PLLX_BASE 0xe0 +#define PLLX_MISC 0xe4 +#define PLLX_MISC2 0x514 +#define PLLX_MISC3 0x518 +#define PLLE_BASE 0xe8 +#define PLLE_MISC 0xec +#define PLLD2_BASE 0x4b8 +#define PLLD2_MISC 0x4bc +#define PLLE_AUX 0x48c +#define PLLRE_BASE 0x4c4 +#define PLLRE_MISC 0x4c8 +#define PLLDP_BASE 0x590 +#define PLLDP_MISC 0x594 +#define PLLC4_BASE 0x5a4 +#define PLLC4_MISC 0x5a8 + +#define PLLC_IDDQ_BIT 26 +#define PLLRE_IDDQ_BIT 16 +#define PLLSS_IDDQ_BIT 19 + +#define PLL_BASE_LOCK BIT(27) +#define PLLE_MISC_LOCK BIT(11) +#define PLLRE_MISC_LOCK BIT(24) + +#define PLL_MISC_LOCK_ENABLE 18 +#define PLLC_MISC_LOCK_ENABLE 24 +#define PLLDU_MISC_LOCK_ENABLE 22 +#define PLLE_MISC_LOCK_ENABLE 9 +#define PLLRE_MISC_LOCK_ENABLE 30 +#define PLLSS_MISC_LOCK_ENABLE 30 + +#define PLLXC_SW_MAX_P 6 + +#define PMC_PLLM_WB0_OVERRIDE 0x1dc +#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0 + +#define UTMIP_PLL_CFG2 0x488 +#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6) +#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4) + +#define UTMIP_PLL_CFG1 0x484 +#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6) +#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0) +#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP BIT(17) +#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16) +#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP BIT(15) +#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14) +#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12) + +#define UTMIPLL_HW_PWRDN_CFG0 0x52c +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE BIT(25) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE BIT(24) +#define UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET BIT(6) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_RESET_INPUT_VALUE BIT(5) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_IN_SWCTL BIT(4) +#define UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL BIT(2) +#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE BIT(1) +#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL BIT(0) + +static void __iomem *clk_base; +static void __iomem *pmc_base; + +static unsigned long osc_freq; +static unsigned long pll_ref_freq; + +static DEFINE_SPINLOCK(pll_d_lock); +static DEFINE_SPINLOCK(pll_d2_lock); +static DEFINE_SPINLOCK(pll_e_lock); +static DEFINE_SPINLOCK(pll_re_lock); +static DEFINE_SPINLOCK(pll_u_lock); + +/* possible OSC frequencies in Hz */ +static unsigned long tegra124_input_freq[] = { + [0] = 13000000, + [1] = 16800000, + [4] = 19200000, + [5] = 38400000, + [8] = 12000000, + [9] = 48000000, + [12] = 260000000, +}; + +static const char *mux_plld_out0_plld2_out0[] = { + "pll_d_out0", "pll_d2_out0", +}; +#define mux_plld_out0_plld2_out0_idx NULL + +static const char *mux_pllmcp_clkm[] = { + "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_c2", "pll_c3", +}; +#define mux_pllmcp_clkm_idx NULL + +static struct div_nmp pllxc_nmp = { + .divm_shift = 0, + .divm_width = 8, + .divn_shift = 8, + .divn_width = 8, + .divp_shift = 20, + .divp_width = 4, +}; + +static struct pdiv_map pllxc_p[] = { + { .pdiv = 1, .hw_val = 0 }, + { .pdiv = 2, .hw_val = 1 }, + { .pdiv = 3, .hw_val = 2 }, + { .pdiv = 4, .hw_val = 3 }, + { .pdiv = 5, .hw_val = 4 }, + { .pdiv = 6, .hw_val = 5 }, + { .pdiv = 8, .hw_val = 6 }, + { .pdiv = 10, .hw_val = 7 }, + { .pdiv = 12, .hw_val = 8 }, + { .pdiv = 16, .hw_val = 9 }, + { .pdiv = 12, .hw_val = 10 }, + { .pdiv = 16, .hw_val = 11 }, + { .pdiv = 20, .hw_val = 12 }, + { .pdiv = 24, .hw_val = 13 }, + { .pdiv = 32, .hw_val = 14 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_x_freq_table[] = { + /* 1 GHz */ + {12000000, 1000000000, 83, 0, 1}, /* actual: 996.0 MHz */ + {13000000, 1000000000, 76, 0, 1}, /* actual: 988.0 MHz */ + {16800000, 1000000000, 59, 0, 1}, /* actual: 991.2 MHz */ + {19200000, 1000000000, 52, 0, 1}, /* actual: 998.4 MHz */ + {26000000, 1000000000, 76, 1, 1}, /* actual: 988.0 MHz */ + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_x_params = { + .input_min = 12000000, + .input_max = 800000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */ + .vco_min = 700000000, + .vco_max = 3000000000UL, + .base_reg = PLLX_BASE, + .misc_reg = PLLX_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLX_MISC3, + .iddq_bit_idx = 3, + .max_p = 6, + .dyn_ramp_reg = PLLX_MISC2, + .stepa_shift = 16, + .stepb_shift = 24, + .pdiv_tohw = pllxc_p, + .div_nmp = &pllxc_nmp, + .freq_table = pll_x_freq_table, + .flags = TEGRA_PLL_USE_LOCK, +}; + +static struct tegra_clk_pll_freq_table pll_c_freq_table[] = { + { 12000000, 624000000, 104, 1, 2}, + { 12000000, 600000000, 100, 1, 2}, + { 13000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */ + { 16800000, 600000000, 71, 1, 2}, /* actual: 596.4 MHz */ + { 19200000, 600000000, 62, 1, 2}, /* actual: 595.2 MHz */ + { 26000000, 600000000, 92, 2, 2}, /* actual: 598.0 MHz */ + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_params pll_c_params = { + .input_min = 12000000, + .input_max = 800000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */ + .vco_min = 600000000, + .vco_max = 1400000000, + .base_reg = PLLC_BASE, + .misc_reg = PLLC_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLC_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLC_MISC, + .iddq_bit_idx = PLLC_IDDQ_BIT, + .max_p = PLLXC_SW_MAX_P, + .dyn_ramp_reg = PLLC_MISC2, + .stepa_shift = 17, + .stepb_shift = 9, + .pdiv_tohw = pllxc_p, + .div_nmp = &pllxc_nmp, + .freq_table = pll_c_freq_table, + .flags = TEGRA_PLL_USE_LOCK, +}; + +static struct div_nmp pllcx_nmp = { + .divm_shift = 0, + .divm_width = 2, + .divn_shift = 8, + .divn_width = 8, + .divp_shift = 20, + .divp_width = 3, +}; + +static struct pdiv_map pllc_p[] = { + { .pdiv = 1, .hw_val = 0 }, + { .pdiv = 2, .hw_val = 1 }, + { .pdiv = 3, .hw_val = 2 }, + { .pdiv = 4, .hw_val = 3 }, + { .pdiv = 6, .hw_val = 4 }, + { .pdiv = 8, .hw_val = 5 }, + { .pdiv = 12, .hw_val = 6 }, + { .pdiv = 16, .hw_val = 7 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_cx_freq_table[] = { + {12000000, 600000000, 100, 1, 2}, + {13000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */ + {16800000, 600000000, 71, 1, 2}, /* actual: 596.4 MHz */ + {19200000, 600000000, 62, 1, 2}, /* actual: 595.2 MHz */ + {26000000, 600000000, 92, 2, 2}, /* actual: 598.0 MHz */ + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_c2_params = { + .input_min = 12000000, + .input_max = 48000000, + .cf_min = 12000000, + .cf_max = 19200000, + .vco_min = 600000000, + .vco_max = 1200000000, + .base_reg = PLLC2_BASE, + .misc_reg = PLLC2_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .pdiv_tohw = pllc_p, + .div_nmp = &pllcx_nmp, + .max_p = 7, + .ext_misc_reg[0] = 0x4f0, + .ext_misc_reg[1] = 0x4f4, + .ext_misc_reg[2] = 0x4f8, + .freq_table = pll_cx_freq_table, + .flags = TEGRA_PLL_USE_LOCK, +}; + +static struct tegra_clk_pll_params pll_c3_params = { + .input_min = 12000000, + .input_max = 48000000, + .cf_min = 12000000, + .cf_max = 19200000, + .vco_min = 600000000, + .vco_max = 1200000000, + .base_reg = PLLC3_BASE, + .misc_reg = PLLC3_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .pdiv_tohw = pllc_p, + .div_nmp = &pllcx_nmp, + .max_p = 7, + .ext_misc_reg[0] = 0x504, + .ext_misc_reg[1] = 0x508, + .ext_misc_reg[2] = 0x50c, + .freq_table = pll_cx_freq_table, + .flags = TEGRA_PLL_USE_LOCK, +}; + +static struct div_nmp pllss_nmp = { + .divm_shift = 0, + .divm_width = 8, + .divn_shift = 8, + .divn_width = 8, + .divp_shift = 20, + .divp_width = 4, +}; + +static struct pdiv_map pll12g_ssd_esd_p[] = { + { .pdiv = 1, .hw_val = 0 }, + { .pdiv = 2, .hw_val = 1 }, + { .pdiv = 3, .hw_val = 2 }, + { .pdiv = 4, .hw_val = 3 }, + { .pdiv = 5, .hw_val = 4 }, + { .pdiv = 6, .hw_val = 5 }, + { .pdiv = 8, .hw_val = 6 }, + { .pdiv = 10, .hw_val = 7 }, + { .pdiv = 12, .hw_val = 8 }, + { .pdiv = 16, .hw_val = 9 }, + { .pdiv = 12, .hw_val = 10 }, + { .pdiv = 16, .hw_val = 11 }, + { .pdiv = 20, .hw_val = 12 }, + { .pdiv = 24, .hw_val = 13 }, + { .pdiv = 32, .hw_val = 14 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_c4_freq_table[] = { + { 12000000, 600000000, 100, 1, 1}, + { 13000000, 600000000, 92, 1, 1}, /* actual: 598.0 MHz */ + { 16800000, 600000000, 71, 1, 1}, /* actual: 596.4 MHz */ + { 19200000, 600000000, 62, 1, 1}, /* actual: 595.2 MHz */ + { 26000000, 600000000, 92, 2, 1}, /* actual: 598.0 MHz */ + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_params pll_c4_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 38 MHz */ + .vco_min = 600000000, + .vco_max = 1200000000, + .base_reg = PLLC4_BASE, + .misc_reg = PLLC4_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLC4_BASE, + .iddq_bit_idx = PLLSS_IDDQ_BIT, + .pdiv_tohw = pll12g_ssd_esd_p, + .div_nmp = &pllss_nmp, + .ext_misc_reg[0] = 0x5ac, + .ext_misc_reg[1] = 0x5b0, + .ext_misc_reg[2] = 0x5b4, + .freq_table = pll_c4_freq_table, +}; + +static struct pdiv_map pllm_p[] = { + { .pdiv = 1, .hw_val = 0 }, + { .pdiv = 2, .hw_val = 1 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_m_freq_table[] = { + {12000000, 800000000, 66, 1, 1}, /* actual: 792.0 MHz */ + {13000000, 800000000, 61, 1, 1}, /* actual: 793.0 MHz */ + {16800000, 800000000, 47, 1, 1}, /* actual: 789.6 MHz */ + {19200000, 800000000, 41, 1, 1}, /* actual: 787.2 MHz */ + {26000000, 800000000, 61, 2, 1}, /* actual: 793.0 MHz */ + {0, 0, 0, 0, 0, 0}, +}; + +static struct div_nmp pllm_nmp = { + .divm_shift = 0, + .divm_width = 8, + .override_divm_shift = 0, + .divn_shift = 8, + .divn_width = 8, + .override_divn_shift = 8, + .divp_shift = 20, + .divp_width = 1, + .override_divp_shift = 27, +}; + +static struct tegra_clk_pll_params pll_m_params = { + .input_min = 12000000, + .input_max = 500000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */ + .vco_min = 400000000, + .vco_max = 1066000000, + .base_reg = PLLM_BASE, + .misc_reg = PLLM_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .max_p = 2, + .pdiv_tohw = pllm_p, + .div_nmp = &pllm_nmp, + .pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE, + .pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2, + .freq_table = pll_m_freq_table, + .flags = TEGRA_PLL_USE_LOCK, +}; + +static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { + /* PLLE special case: use cpcon field to store cml divider value */ + {336000000, 100000000, 100, 21, 16, 11}, + {312000000, 100000000, 200, 26, 24, 13}, + {13000000, 100000000, 200, 1, 26, 13}, + {12000000, 100000000, 200, 1, 24, 13}, + {0, 0, 0, 0, 0, 0}, +}; + +static struct div_nmp plle_nmp = { + .divm_shift = 0, + .divm_width = 8, + .divn_shift = 8, + .divn_width = 8, + .divp_shift = 24, + .divp_width = 4, +}; + +static struct tegra_clk_pll_params pll_e_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 75000000, + .vco_min = 1600000000, + .vco_max = 2400000000U, + .base_reg = PLLE_BASE, + .misc_reg = PLLE_MISC, + .aux_reg = PLLE_AUX, + .lock_mask = PLLE_MISC_LOCK, + .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, + .lock_delay = 300, + .div_nmp = &plle_nmp, + .freq_table = pll_e_freq_table, + .flags = TEGRA_PLL_FIXED, + .fixed_rate = 100000000, +}; + +static const struct clk_div_table pll_re_div_table[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 3 }, + { .val = 3, .div = 4 }, + { .val = 4, .div = 5 }, + { .val = 5, .div = 6 }, + { .val = 0, .div = 0 }, +}; + +static struct div_nmp pllre_nmp = { + .divm_shift = 0, + .divm_width = 8, + .divn_shift = 8, + .divn_width = 8, + .divp_shift = 16, + .divp_width = 4, +}; + +static struct tegra_clk_pll_params pll_re_vco_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 38 MHz */ + .vco_min = 300000000, + .vco_max = 600000000, + .base_reg = PLLRE_BASE, + .misc_reg = PLLRE_MISC, + .lock_mask = PLLRE_MISC_LOCK, + .lock_enable_bit_idx = PLLRE_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLRE_MISC, + .iddq_bit_idx = PLLRE_IDDQ_BIT, + .div_nmp = &pllre_nmp, + .flags = TEGRA_PLL_USE_LOCK, +}; + +static struct div_nmp pllp_nmp = { + .divm_shift = 0, + .divm_width = 5, + .divn_shift = 8, + .divn_width = 10, + .divp_shift = 20, + .divp_width = 3, +}; + +static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { + {12000000, 216000000, 432, 12, 1, 8}, + {13000000, 216000000, 432, 13, 1, 8}, + {16800000, 216000000, 360, 14, 1, 8}, + {19200000, 216000000, 360, 16, 1, 8}, + {26000000, 216000000, 432, 26, 1, 8}, + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_p_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 200000000, + .vco_max = 700000000, + .base_reg = PLLP_BASE, + .misc_reg = PLLP_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .div_nmp = &pllp_nmp, + .freq_table = pll_p_freq_table, + .fixed_rate = 408000000, + .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK, +}; + +static struct tegra_clk_pll_freq_table pll_a_freq_table[] = { + {9600000, 282240000, 147, 5, 0, 4}, + {9600000, 368640000, 192, 5, 0, 4}, + {9600000, 240000000, 200, 8, 0, 8}, + + {28800000, 282240000, 245, 25, 0, 8}, + {28800000, 368640000, 320, 25, 0, 8}, + {28800000, 240000000, 200, 24, 0, 8}, + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_a_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 200000000, + .vco_max = 700000000, + .base_reg = PLLA_BASE, + .misc_reg = PLLA_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .div_nmp = &pllp_nmp, + .freq_table = pll_a_freq_table, + .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK, +}; + +static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { + {12000000, 216000000, 864, 12, 4, 12}, + {13000000, 216000000, 864, 13, 4, 12}, + {16800000, 216000000, 720, 14, 4, 12}, + {19200000, 216000000, 720, 16, 4, 12}, + {26000000, 216000000, 864, 26, 4, 12}, + + {12000000, 594000000, 594, 12, 1, 12}, + {13000000, 594000000, 594, 13, 1, 12}, + {16800000, 594000000, 495, 14, 1, 12}, + {19200000, 594000000, 495, 16, 1, 12}, + {26000000, 594000000, 594, 26, 1, 12}, + + {12000000, 1000000000, 1000, 12, 1, 12}, + {13000000, 1000000000, 1000, 13, 1, 12}, + {19200000, 1000000000, 625, 12, 1, 12}, + {26000000, 1000000000, 1000, 26, 1, 12}, + + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_d_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 500000000, + .vco_max = 1000000000, + .base_reg = PLLD_BASE, + .misc_reg = PLLD_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, + .div_nmp = &pllp_nmp, + .freq_table = pll_d_freq_table, + .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | + TEGRA_PLL_USE_LOCK, +}; + +static struct tegra_clk_pll_freq_table tegra124_pll_d2_freq_table[] = { + { 12000000, 148500000, 99, 1, 8}, + { 12000000, 594000000, 99, 1, 1}, + { 13000000, 594000000, 91, 1, 1}, /* actual: 591.5 MHz */ + { 16800000, 594000000, 71, 1, 1}, /* actual: 596.4 MHz */ + { 19200000, 594000000, 62, 1, 1}, /* actual: 595.2 MHz */ + { 26000000, 594000000, 91, 2, 1}, /* actual: 591.5 MHz */ + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_params tegra124_pll_d2_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 38 MHz */ + .vco_min = 600000000, + .vco_max = 1200000000, + .base_reg = PLLD2_BASE, + .misc_reg = PLLD2_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLD2_BASE, + .iddq_bit_idx = PLLSS_IDDQ_BIT, + .pdiv_tohw = pll12g_ssd_esd_p, + .div_nmp = &pllss_nmp, + .ext_misc_reg[0] = 0x570, + .ext_misc_reg[1] = 0x574, + .ext_misc_reg[2] = 0x578, + .max_p = 15, + .freq_table = tegra124_pll_d2_freq_table, +}; + +static struct tegra_clk_pll_freq_table pll_dp_freq_table[] = { + { 12000000, 600000000, 100, 1, 1}, + { 13000000, 600000000, 92, 1, 1}, /* actual: 598.0 MHz */ + { 16800000, 600000000, 71, 1, 1}, /* actual: 596.4 MHz */ + { 19200000, 600000000, 62, 1, 1}, /* actual: 595.2 MHz */ + { 26000000, 600000000, 92, 2, 1}, /* actual: 598.0 MHz */ + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_params pll_dp_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 38 MHz */ + .vco_min = 600000000, + .vco_max = 1200000000, + .base_reg = PLLDP_BASE, + .misc_reg = PLLDP_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLDP_BASE, + .iddq_bit_idx = PLLSS_IDDQ_BIT, + .pdiv_tohw = pll12g_ssd_esd_p, + .div_nmp = &pllss_nmp, + .ext_misc_reg[0] = 0x598, + .ext_misc_reg[1] = 0x59c, + .ext_misc_reg[2] = 0x5a0, + .max_p = 5, + .freq_table = pll_dp_freq_table, +}; + +static struct pdiv_map pllu_p[] = { + { .pdiv = 1, .hw_val = 1 }, + { .pdiv = 2, .hw_val = 0 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct div_nmp pllu_nmp = { + .divm_shift = 0, + .divm_width = 5, + .divn_shift = 8, + .divn_width = 10, + .divp_shift = 20, + .divp_width = 1, +}; + +static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { + {12000000, 480000000, 960, 12, 2, 12}, + {13000000, 480000000, 960, 13, 2, 12}, + {16800000, 480000000, 400, 7, 2, 5}, + {19200000, 480000000, 200, 4, 2, 3}, + {26000000, 480000000, 960, 26, 2, 12}, + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_u_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 480000000, + .vco_max = 960000000, + .base_reg = PLLU_BASE, + .misc_reg = PLLU_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, + .pdiv_tohw = pllu_p, + .div_nmp = &pllu_nmp, + .freq_table = pll_u_freq_table, + .flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | + TEGRA_PLL_USE_LOCK, +}; + +struct utmi_clk_param { + /* Oscillator Frequency in KHz */ + u32 osc_frequency; + /* UTMIP PLL Enable Delay Count */ + u8 enable_delay_count; + /* UTMIP PLL Stable count */ + u8 stable_count; + /* UTMIP PLL Active delay count */ + u8 active_delay_count; + /* UTMIP PLL Xtal frequency count */ + u8 xtal_freq_count; +}; + +static const struct utmi_clk_param utmi_parameters[] = { + {.osc_frequency = 13000000, .enable_delay_count = 0x02, + .stable_count = 0x33, .active_delay_count = 0x05, + .xtal_freq_count = 0x7F}, + {.osc_frequency = 19200000, .enable_delay_count = 0x03, + .stable_count = 0x4B, .active_delay_count = 0x06, + .xtal_freq_count = 0xBB}, + {.osc_frequency = 12000000, .enable_delay_count = 0x02, + .stable_count = 0x2F, .active_delay_count = 0x04, + .xtal_freq_count = 0x76}, + {.osc_frequency = 26000000, .enable_delay_count = 0x04, + .stable_count = 0x66, .active_delay_count = 0x09, + .xtal_freq_count = 0xFE}, + {.osc_frequency = 16800000, .enable_delay_count = 0x03, + .stable_count = 0x41, .active_delay_count = 0x0A, + .xtal_freq_count = 0xA4}, +}; + +static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = { + [tegra_clk_ispb] = { .dt_id = TEGRA124_CLK_ISPB, .present = true }, + [tegra_clk_rtc] = { .dt_id = TEGRA124_CLK_RTC, .present = true }, + [tegra_clk_timer] = { .dt_id = TEGRA124_CLK_TIMER, .present = true }, + [tegra_clk_uarta] = { .dt_id = TEGRA124_CLK_UARTA, .present = true }, + [tegra_clk_sdmmc2] = { .dt_id = TEGRA124_CLK_SDMMC2, .present = true }, + [tegra_clk_i2s1] = { .dt_id = TEGRA124_CLK_I2S1, .present = true }, + [tegra_clk_i2c1] = { .dt_id = TEGRA124_CLK_I2C1, .present = true }, + [tegra_clk_ndflash] = { .dt_id = TEGRA124_CLK_NDFLASH, .present = true }, + [tegra_clk_sdmmc1] = { .dt_id = TEGRA124_CLK_SDMMC1, .present = true }, + [tegra_clk_sdmmc4] = { .dt_id = TEGRA124_CLK_SDMMC4, .present = true }, + [tegra_clk_pwm] = { .dt_id = TEGRA124_CLK_PWM, .present = true }, + [tegra_clk_i2s2] = { .dt_id = TEGRA124_CLK_I2S2, .present = true }, + [tegra_clk_gr2d] = { .dt_id = TEGRA124_CLK_GR_2D, .present = true }, + [tegra_clk_usbd] = { .dt_id = TEGRA124_CLK_USBD, .present = true }, + [tegra_clk_isp_8] = { .dt_id = TEGRA124_CLK_ISP, .present = true }, + [tegra_clk_gr3d] = { .dt_id = TEGRA124_CLK_GR_3D, .present = true }, + [tegra_clk_disp2] = { .dt_id = TEGRA124_CLK_DISP2, .present = true }, + [tegra_clk_disp1] = { .dt_id = TEGRA124_CLK_DISP1, .present = true }, + [tegra_clk_host1x] = { .dt_id = TEGRA124_CLK_HOST1X, .present = true }, + [tegra_clk_vcp] = { .dt_id = TEGRA124_CLK_VCP, .present = true }, + [tegra_clk_i2s0] = { .dt_id = TEGRA124_CLK_I2S0, .present = true }, + [tegra_clk_apbdma] = { .dt_id = TEGRA124_CLK_APBDMA, .present = true }, + [tegra_clk_kbc] = { .dt_id = TEGRA124_CLK_KBC, .present = true }, + [tegra_clk_kfuse] = { .dt_id = TEGRA124_CLK_KFUSE, .present = true }, + [tegra_clk_sbc1] = { .dt_id = TEGRA124_CLK_SBC1, .present = true }, + [tegra_clk_nor] = { .dt_id = TEGRA124_CLK_NOR, .present = true }, + [tegra_clk_sbc2] = { .dt_id = TEGRA124_CLK_SBC2, .present = true }, + [tegra_clk_sbc3] = { .dt_id = TEGRA124_CLK_SBC3, .present = true }, + [tegra_clk_i2c5] = { .dt_id = TEGRA124_CLK_I2C5, .present = true }, + [tegra_clk_dsia] = { .dt_id = TEGRA124_CLK_DSIA, .present = true }, + [tegra_clk_mipi] = { .dt_id = TEGRA124_CLK_MIPI, .present = true }, + [tegra_clk_hdmi] = { .dt_id = TEGRA124_CLK_HDMI, .present = true }, + [tegra_clk_csi] = { .dt_id = TEGRA124_CLK_CSI, .present = true }, + [tegra_clk_i2c2] = { .dt_id = TEGRA124_CLK_I2C2, .present = true }, + [tegra_clk_uartc] = { .dt_id = TEGRA124_CLK_UARTC, .present = true }, + [tegra_clk_mipi_cal] = { .dt_id = TEGRA124_CLK_MIPI_CAL, .present = true }, + [tegra_clk_emc] = { .dt_id = TEGRA124_CLK_EMC, .present = true }, + [tegra_clk_usb2] = { .dt_id = TEGRA124_CLK_USB2, .present = true }, + [tegra_clk_usb3] = { .dt_id = TEGRA124_CLK_USB3, .present = true }, + [tegra_clk_vde_8] = { .dt_id = TEGRA124_CLK_VDE, .present = true }, + [tegra_clk_bsea] = { .dt_id = TEGRA124_CLK_BSEA, .present = true }, + [tegra_clk_bsev] = { .dt_id = TEGRA124_CLK_BSEV, .present = true }, + [tegra_clk_uartd] = { .dt_id = TEGRA124_CLK_UARTD, .present = true }, + [tegra_clk_i2c3] = { .dt_id = TEGRA124_CLK_I2C3, .present = true }, + [tegra_clk_sbc4] = { .dt_id = TEGRA124_CLK_SBC4, .present = true }, + [tegra_clk_sdmmc3] = { .dt_id = TEGRA124_CLK_SDMMC3, .present = true }, + [tegra_clk_pcie] = { .dt_id = TEGRA124_CLK_PCIE, .present = true }, + [tegra_clk_owr] = { .dt_id = TEGRA124_CLK_OWR, .present = true }, + [tegra_clk_afi] = { .dt_id = TEGRA124_CLK_AFI, .present = true }, + [tegra_clk_csite] = { .dt_id = TEGRA124_CLK_CSITE, .present = true }, + [tegra_clk_la] = { .dt_id = TEGRA124_CLK_LA, .present = true }, + [tegra_clk_trace] = { .dt_id = TEGRA124_CLK_TRACE, .present = true }, + [tegra_clk_soc_therm] = { .dt_id = TEGRA124_CLK_SOC_THERM, .present = true }, + [tegra_clk_dtv] = { .dt_id = TEGRA124_CLK_DTV, .present = true }, + [tegra_clk_ndspeed] = { .dt_id = TEGRA124_CLK_NDSPEED, .present = true }, + [tegra_clk_i2cslow] = { .dt_id = TEGRA124_CLK_I2CSLOW, .present = true }, + [tegra_clk_dsib] = { .dt_id = TEGRA124_CLK_DSIB, .present = true }, + [tegra_clk_tsec] = { .dt_id = TEGRA124_CLK_TSEC, .present = true }, + [tegra_clk_xusb_host] = { .dt_id = TEGRA124_CLK_XUSB_HOST, .present = true }, + [tegra_clk_msenc] = { .dt_id = TEGRA124_CLK_MSENC, .present = true }, + [tegra_clk_csus] = { .dt_id = TEGRA124_CLK_CSUS, .present = true }, + [tegra_clk_mselect] = { .dt_id = TEGRA124_CLK_MSELECT, .present = true }, + [tegra_clk_tsensor] = { .dt_id = TEGRA124_CLK_TSENSOR, .present = true }, + [tegra_clk_i2s3] = { .dt_id = TEGRA124_CLK_I2S3, .present = true }, + [tegra_clk_i2s4] = { .dt_id = TEGRA124_CLK_I2S4, .present = true }, + [tegra_clk_i2c4] = { .dt_id = TEGRA124_CLK_I2C4, .present = true }, + [tegra_clk_sbc5] = { .dt_id = TEGRA124_CLK_SBC5, .present = true }, + [tegra_clk_sbc6] = { .dt_id = TEGRA124_CLK_SBC6, .present = true }, + [tegra_clk_d_audio] = { .dt_id = TEGRA124_CLK_D_AUDIO, .present = true }, + [tegra_clk_apbif] = { .dt_id = TEGRA124_CLK_APBIF, .present = true }, + [tegra_clk_dam0] = { .dt_id = TEGRA124_CLK_DAM0, .present = true }, + [tegra_clk_dam1] = { .dt_id = TEGRA124_CLK_DAM1, .present = true }, + [tegra_clk_dam2] = { .dt_id = TEGRA124_CLK_DAM2, .present = true }, + [tegra_clk_hda2codec_2x] = { .dt_id = TEGRA124_CLK_HDA2CODEC_2X, .present = true }, + [tegra_clk_audio0_2x] = { .dt_id = TEGRA124_CLK_AUDIO0_2X, .present = true }, + [tegra_clk_audio1_2x] = { .dt_id = TEGRA124_CLK_AUDIO1_2X, .present = true }, + [tegra_clk_audio2_2x] = { .dt_id = TEGRA124_CLK_AUDIO2_2X, .present = true }, + [tegra_clk_audio3_2x] = { .dt_id = TEGRA124_CLK_AUDIO3_2X, .present = true }, + [tegra_clk_audio4_2x] = { .dt_id = TEGRA124_CLK_AUDIO4_2X, .present = true }, + [tegra_clk_spdif_2x] = { .dt_id = TEGRA124_CLK_SPDIF_2X, .present = true }, + [tegra_clk_actmon] = { .dt_id = TEGRA124_CLK_ACTMON, .present = true }, + [tegra_clk_extern1] = { .dt_id = TEGRA124_CLK_EXTERN1, .present = true }, + [tegra_clk_extern2] = { .dt_id = TEGRA124_CLK_EXTERN2, .present = true }, + [tegra_clk_extern3] = { .dt_id = TEGRA124_CLK_EXTERN3, .present = true }, + [tegra_clk_sata_oob] = { .dt_id = TEGRA124_CLK_SATA_OOB, .present = true }, + [tegra_clk_sata] = { .dt_id = TEGRA124_CLK_SATA, .present = true }, + [tegra_clk_hda] = { .dt_id = TEGRA124_CLK_HDA, .present = true }, + [tegra_clk_se] = { .dt_id = TEGRA124_CLK_SE, .present = true }, + [tegra_clk_hda2hdmi] = { .dt_id = TEGRA124_CLK_HDA2HDMI, .present = true }, + [tegra_clk_sata_cold] = { .dt_id = TEGRA124_CLK_SATA_COLD, .present = true }, + [tegra_clk_cilab] = { .dt_id = TEGRA124_CLK_CILAB, .present = true }, + [tegra_clk_cilcd] = { .dt_id = TEGRA124_CLK_CILCD, .present = true }, + [tegra_clk_cile] = { .dt_id = TEGRA124_CLK_CILE, .present = true }, + [tegra_clk_dsialp] = { .dt_id = TEGRA124_CLK_DSIALP, .present = true }, + [tegra_clk_dsiblp] = { .dt_id = TEGRA124_CLK_DSIBLP, .present = true }, + [tegra_clk_entropy] = { .dt_id = TEGRA124_CLK_ENTROPY, .present = true }, + [tegra_clk_dds] = { .dt_id = TEGRA124_CLK_DDS, .present = true }, + [tegra_clk_dp2] = { .dt_id = TEGRA124_CLK_DP2, .present = true }, + [tegra_clk_amx] = { .dt_id = TEGRA124_CLK_AMX, .present = true }, + [tegra_clk_adx] = { .dt_id = TEGRA124_CLK_ADX, .present = true }, + [tegra_clk_xusb_ss] = { .dt_id = TEGRA124_CLK_XUSB_SS, .present = true }, + [tegra_clk_i2c6] = { .dt_id = TEGRA124_CLK_I2C6, .present = true }, + [tegra_clk_vim2_clk] = { .dt_id = TEGRA124_CLK_VIM2_CLK, .present = true }, + [tegra_clk_hdmi_audio] = { .dt_id = TEGRA124_CLK_HDMI_AUDIO, .present = true }, + [tegra_clk_clk72Mhz] = { .dt_id = TEGRA124_CLK_CLK72MHZ, .present = true }, + [tegra_clk_vic03] = { .dt_id = TEGRA124_CLK_VIC03, .present = true }, + [tegra_clk_adx1] = { .dt_id = TEGRA124_CLK_ADX1, .present = true }, + [tegra_clk_dpaux] = { .dt_id = TEGRA124_CLK_DPAUX, .present = true }, + [tegra_clk_sor0] = { .dt_id = TEGRA124_CLK_SOR0, .present = true }, + [tegra_clk_sor0_lvds] = { .dt_id = TEGRA124_CLK_SOR0_LVDS, .present = true }, + [tegra_clk_gpu] = { .dt_id = TEGRA124_CLK_GPU, .present = true }, + [tegra_clk_amx1] = { .dt_id = TEGRA124_CLK_AMX1, .present = true }, + [tegra_clk_uartb] = { .dt_id = TEGRA124_CLK_UARTB, .present = true }, + [tegra_clk_vfir] = { .dt_id = TEGRA124_CLK_VFIR, .present = true }, + [tegra_clk_spdif_in] = { .dt_id = TEGRA124_CLK_SPDIF_IN, .present = true }, + [tegra_clk_spdif_out] = { .dt_id = TEGRA124_CLK_SPDIF_OUT, .present = true }, + [tegra_clk_vi_9] = { .dt_id = TEGRA124_CLK_VI, .present = true }, + [tegra_clk_vi_sensor] = { .dt_id = TEGRA124_CLK_VI_SENSOR, .present = true }, + [tegra_clk_fuse] = { .dt_id = TEGRA124_CLK_FUSE, .present = true }, + [tegra_clk_fuse_burn] = { .dt_id = TEGRA124_CLK_FUSE_BURN, .present = true }, + [tegra_clk_clk_32k] = { .dt_id = TEGRA124_CLK_CLK_32K, .present = true }, + [tegra_clk_clk_m] = { .dt_id = TEGRA124_CLK_CLK_M, .present = true }, + [tegra_clk_clk_m_div2] = { .dt_id = TEGRA124_CLK_CLK_M_DIV2, .present = true }, + [tegra_clk_clk_m_div4] = { .dt_id = TEGRA124_CLK_CLK_M_DIV4, .present = true }, + [tegra_clk_pll_ref] = { .dt_id = TEGRA124_CLK_PLL_REF, .present = true }, + [tegra_clk_pll_c] = { .dt_id = TEGRA124_CLK_PLL_C, .present = true }, + [tegra_clk_pll_c_out1] = { .dt_id = TEGRA124_CLK_PLL_C_OUT1, .present = true }, + [tegra_clk_pll_c2] = { .dt_id = TEGRA124_CLK_PLL_C2, .present = true }, + [tegra_clk_pll_c3] = { .dt_id = TEGRA124_CLK_PLL_C3, .present = true }, + [tegra_clk_pll_m] = { .dt_id = TEGRA124_CLK_PLL_M, .present = true }, + [tegra_clk_pll_m_out1] = { .dt_id = TEGRA124_CLK_PLL_M_OUT1, .present = true }, + [tegra_clk_pll_p] = { .dt_id = TEGRA124_CLK_PLL_P, .present = true }, + [tegra_clk_pll_p_out1] = { .dt_id = TEGRA124_CLK_PLL_P_OUT1, .present = true }, + [tegra_clk_pll_p_out2] = { .dt_id = TEGRA124_CLK_PLL_P_OUT2, .present = true }, + [tegra_clk_pll_p_out3] = { .dt_id = TEGRA124_CLK_PLL_P_OUT3, .present = true }, + [tegra_clk_pll_p_out4] = { .dt_id = TEGRA124_CLK_PLL_P_OUT4, .present = true }, + [tegra_clk_pll_a] = { .dt_id = TEGRA124_CLK_PLL_A, .present = true }, + [tegra_clk_pll_a_out0] = { .dt_id = TEGRA124_CLK_PLL_A_OUT0, .present = true }, + [tegra_clk_pll_d] = { .dt_id = TEGRA124_CLK_PLL_D, .present = true }, + [tegra_clk_pll_d_out0] = { .dt_id = TEGRA124_CLK_PLL_D_OUT0, .present = true }, + [tegra_clk_pll_d2] = { .dt_id = TEGRA124_CLK_PLL_D2, .present = true }, + [tegra_clk_pll_d2_out0] = { .dt_id = TEGRA124_CLK_PLL_D2_OUT0, .present = true }, + [tegra_clk_pll_u] = { .dt_id = TEGRA124_CLK_PLL_U, .present = true }, + [tegra_clk_pll_u_480m] = { .dt_id = TEGRA124_CLK_PLL_U_480M, .present = true }, + [tegra_clk_pll_u_60m] = { .dt_id = TEGRA124_CLK_PLL_U_60M, .present = true }, + [tegra_clk_pll_u_48m] = { .dt_id = TEGRA124_CLK_PLL_U_48M, .present = true }, + [tegra_clk_pll_u_12m] = { .dt_id = TEGRA124_CLK_PLL_U_12M, .present = true }, + [tegra_clk_pll_x] = { .dt_id = TEGRA124_CLK_PLL_X, .present = true }, + [tegra_clk_pll_x_out0] = { .dt_id = TEGRA124_CLK_PLL_X_OUT0, .present = true }, + [tegra_clk_pll_re_vco] = { .dt_id = TEGRA124_CLK_PLL_RE_VCO, .present = true }, + [tegra_clk_pll_re_out] = { .dt_id = TEGRA124_CLK_PLL_RE_OUT, .present = true }, + [tegra_clk_spdif_in_sync] = { .dt_id = TEGRA124_CLK_SPDIF_IN_SYNC, .present = true }, + [tegra_clk_i2s0_sync] = { .dt_id = TEGRA124_CLK_I2S0_SYNC, .present = true }, + [tegra_clk_i2s1_sync] = { .dt_id = TEGRA124_CLK_I2S1_SYNC, .present = true }, + [tegra_clk_i2s2_sync] = { .dt_id = TEGRA124_CLK_I2S2_SYNC, .present = true }, + [tegra_clk_i2s3_sync] = { .dt_id = TEGRA124_CLK_I2S3_SYNC, .present = true }, + [tegra_clk_i2s4_sync] = { .dt_id = TEGRA124_CLK_I2S4_SYNC, .present = true }, + [tegra_clk_vimclk_sync] = { .dt_id = TEGRA124_CLK_VIMCLK_SYNC, .present = true }, + [tegra_clk_audio0] = { .dt_id = TEGRA124_CLK_AUDIO0, .present = true }, + [tegra_clk_audio1] = { .dt_id = TEGRA124_CLK_AUDIO1, .present = true }, + [tegra_clk_audio2] = { .dt_id = TEGRA124_CLK_AUDIO2, .present = true }, + [tegra_clk_audio3] = { .dt_id = TEGRA124_CLK_AUDIO3, .present = true }, + [tegra_clk_audio4] = { .dt_id = TEGRA124_CLK_AUDIO4, .present = true }, + [tegra_clk_spdif] = { .dt_id = TEGRA124_CLK_SPDIF, .present = true }, + [tegra_clk_clk_out_1] = { .dt_id = TEGRA124_CLK_CLK_OUT_1, .present = true }, + [tegra_clk_clk_out_2] = { .dt_id = TEGRA124_CLK_CLK_OUT_2, .present = true }, + [tegra_clk_clk_out_3] = { .dt_id = TEGRA124_CLK_CLK_OUT_3, .present = true }, + [tegra_clk_blink] = { .dt_id = TEGRA124_CLK_BLINK, .present = true }, + [tegra_clk_xusb_host_src] = { .dt_id = TEGRA124_CLK_XUSB_HOST_SRC, .present = true }, + [tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA124_CLK_XUSB_FALCON_SRC, .present = true }, + [tegra_clk_xusb_fs_src] = { .dt_id = TEGRA124_CLK_XUSB_FS_SRC, .present = true }, + [tegra_clk_xusb_ss_src] = { .dt_id = TEGRA124_CLK_XUSB_SS_SRC, .present = true }, + [tegra_clk_xusb_dev_src] = { .dt_id = TEGRA124_CLK_XUSB_DEV_SRC, .present = true }, + [tegra_clk_xusb_dev] = { .dt_id = TEGRA124_CLK_XUSB_DEV, .present = true }, + [tegra_clk_xusb_hs_src] = { .dt_id = TEGRA124_CLK_XUSB_HS_SRC, .present = true }, + [tegra_clk_sclk] = { .dt_id = TEGRA124_CLK_SCLK, .present = true }, + [tegra_clk_hclk] = { .dt_id = TEGRA124_CLK_HCLK, .present = true }, + [tegra_clk_pclk] = { .dt_id = TEGRA124_CLK_PCLK, .present = true }, + [tegra_clk_cclk_g] = { .dt_id = TEGRA124_CLK_CCLK_G, .present = true }, + [tegra_clk_cclk_lp] = { .dt_id = TEGRA124_CLK_CCLK_LP, .present = true }, + [tegra_clk_dfll_ref] = { .dt_id = TEGRA124_CLK_DFLL_REF, .present = true }, + [tegra_clk_dfll_soc] = { .dt_id = TEGRA124_CLK_DFLL_SOC, .present = true }, + [tegra_clk_vi_sensor2] = { .dt_id = TEGRA124_CLK_VI_SENSOR2, .present = true }, + [tegra_clk_pll_p_out5] = { .dt_id = TEGRA124_CLK_PLL_P_OUT5, .present = true }, + [tegra_clk_pll_c4] = { .dt_id = TEGRA124_CLK_PLL_C4, .present = true }, + [tegra_clk_pll_dp] = { .dt_id = TEGRA124_CLK_PLL_DP, .present = true }, + [tegra_clk_audio0_mux] = { .dt_id = TEGRA124_CLK_AUDIO0_MUX, .present = true }, + [tegra_clk_audio1_mux] = { .dt_id = TEGRA124_CLK_AUDIO1_MUX, .present = true }, + [tegra_clk_audio2_mux] = { .dt_id = TEGRA124_CLK_AUDIO2_MUX, .present = true }, + [tegra_clk_audio3_mux] = { .dt_id = TEGRA124_CLK_AUDIO3_MUX, .present = true }, + [tegra_clk_audio4_mux] = { .dt_id = TEGRA124_CLK_AUDIO4_MUX, .present = true }, + [tegra_clk_spdif_mux] = { .dt_id = TEGRA124_CLK_SPDIF_MUX, .present = true }, + [tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_1_MUX, .present = true }, + [tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_2_MUX, .present = true }, + [tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_3_MUX, .present = true }, + [tegra_clk_dsia_mux] = { .dt_id = TEGRA124_CLK_DSIA_MUX, .present = true }, + [tegra_clk_dsib_mux] = { .dt_id = TEGRA124_CLK_DSIB_MUX, .present = true }, + [tegra_clk_uarte] = { .dt_id = TEGRA124_CLK_UARTE, .present = true }, +}; + +static struct tegra_devclk devclks[] __initdata = { + { .con_id = "clk_m", .dt_id = TEGRA124_CLK_CLK_M }, + { .con_id = "pll_ref", .dt_id = TEGRA124_CLK_PLL_REF }, + { .con_id = "clk_32k", .dt_id = TEGRA124_CLK_CLK_32K }, + { .con_id = "clk_m_div2", .dt_id = TEGRA124_CLK_CLK_M_DIV2 }, + { .con_id = "clk_m_div4", .dt_id = TEGRA124_CLK_CLK_M_DIV4 }, + { .con_id = "pll_c", .dt_id = TEGRA124_CLK_PLL_C }, + { .con_id = "pll_c_out1", .dt_id = TEGRA124_CLK_PLL_C_OUT1 }, + { .con_id = "pll_c2", .dt_id = TEGRA124_CLK_PLL_C2 }, + { .con_id = "pll_c3", .dt_id = TEGRA124_CLK_PLL_C3 }, + { .con_id = "pll_p", .dt_id = TEGRA124_CLK_PLL_P }, + { .con_id = "pll_p_out1", .dt_id = TEGRA124_CLK_PLL_P_OUT1 }, + { .con_id = "pll_p_out2", .dt_id = TEGRA124_CLK_PLL_P_OUT2 }, + { .con_id = "pll_p_out3", .dt_id = TEGRA124_CLK_PLL_P_OUT3 }, + { .con_id = "pll_p_out4", .dt_id = TEGRA124_CLK_PLL_P_OUT4 }, + { .con_id = "pll_m", .dt_id = TEGRA124_CLK_PLL_M }, + { .con_id = "pll_m_out1", .dt_id = TEGRA124_CLK_PLL_M_OUT1 }, + { .con_id = "pll_x", .dt_id = TEGRA124_CLK_PLL_X }, + { .con_id = "pll_x_out0", .dt_id = TEGRA124_CLK_PLL_X_OUT0 }, + { .con_id = "pll_u", .dt_id = TEGRA124_CLK_PLL_U }, + { .con_id = "pll_u_480M", .dt_id = TEGRA124_CLK_PLL_U_480M }, + { .con_id = "pll_u_60M", .dt_id = TEGRA124_CLK_PLL_U_60M }, + { .con_id = "pll_u_48M", .dt_id = TEGRA124_CLK_PLL_U_48M }, + { .con_id = "pll_u_12M", .dt_id = TEGRA124_CLK_PLL_U_12M }, + { .con_id = "pll_d", .dt_id = TEGRA124_CLK_PLL_D }, + { .con_id = "pll_d_out0", .dt_id = TEGRA124_CLK_PLL_D_OUT0 }, + { .con_id = "pll_d2", .dt_id = TEGRA124_CLK_PLL_D2 }, + { .con_id = "pll_d2_out0", .dt_id = TEGRA124_CLK_PLL_D2_OUT0 }, + { .con_id = "pll_a", .dt_id = TEGRA124_CLK_PLL_A }, + { .con_id = "pll_a_out0", .dt_id = TEGRA124_CLK_PLL_A_OUT0 }, + { .con_id = "pll_re_vco", .dt_id = TEGRA124_CLK_PLL_RE_VCO }, + { .con_id = "pll_re_out", .dt_id = TEGRA124_CLK_PLL_RE_OUT }, + { .con_id = "spdif_in_sync", .dt_id = TEGRA124_CLK_SPDIF_IN_SYNC }, + { .con_id = "i2s0_sync", .dt_id = TEGRA124_CLK_I2S0_SYNC }, + { .con_id = "i2s1_sync", .dt_id = TEGRA124_CLK_I2S1_SYNC }, + { .con_id = "i2s2_sync", .dt_id = TEGRA124_CLK_I2S2_SYNC }, + { .con_id = "i2s3_sync", .dt_id = TEGRA124_CLK_I2S3_SYNC }, + { .con_id = "i2s4_sync", .dt_id = TEGRA124_CLK_I2S4_SYNC }, + { .con_id = "vimclk_sync", .dt_id = TEGRA124_CLK_VIMCLK_SYNC }, + { .con_id = "audio0", .dt_id = TEGRA124_CLK_AUDIO0 }, + { .con_id = "audio1", .dt_id = TEGRA124_CLK_AUDIO1 }, + { .con_id = "audio2", .dt_id = TEGRA124_CLK_AUDIO2 }, + { .con_id = "audio3", .dt_id = TEGRA124_CLK_AUDIO3 }, + { .con_id = "audio4", .dt_id = TEGRA124_CLK_AUDIO4 }, + { .con_id = "spdif", .dt_id = TEGRA124_CLK_SPDIF }, + { .con_id = "audio0_2x", .dt_id = TEGRA124_CLK_AUDIO0_2X }, + { .con_id = "audio1_2x", .dt_id = TEGRA124_CLK_AUDIO1_2X }, + { .con_id = "audio2_2x", .dt_id = TEGRA124_CLK_AUDIO2_2X }, + { .con_id = "audio3_2x", .dt_id = TEGRA124_CLK_AUDIO3_2X }, + { .con_id = "audio4_2x", .dt_id = TEGRA124_CLK_AUDIO4_2X }, + { .con_id = "spdif_2x", .dt_id = TEGRA124_CLK_SPDIF_2X }, + { .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA124_CLK_EXTERN1 }, + { .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA124_CLK_EXTERN2 }, + { .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA124_CLK_EXTERN3 }, + { .con_id = "blink", .dt_id = TEGRA124_CLK_BLINK }, + { .con_id = "cclk_g", .dt_id = TEGRA124_CLK_CCLK_G }, + { .con_id = "cclk_lp", .dt_id = TEGRA124_CLK_CCLK_LP }, + { .con_id = "sclk", .dt_id = TEGRA124_CLK_SCLK }, + { .con_id = "hclk", .dt_id = TEGRA124_CLK_HCLK }, + { .con_id = "pclk", .dt_id = TEGRA124_CLK_PCLK }, + { .dev_id = "rtc-tegra", .dt_id = TEGRA124_CLK_RTC }, + { .dev_id = "timer", .dt_id = TEGRA124_CLK_TIMER }, +}; + +static struct clk **clks; + +static void tegra124_utmi_param_configure(void __iomem *clk_base) +{ + u32 reg; + int i; + + for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) { + if (osc_freq == utmi_parameters[i].osc_frequency) + break; + } + + if (i >= ARRAY_SIZE(utmi_parameters)) { + pr_err("%s: Unexpected oscillator freq %lu\n", __func__, + osc_freq); + return; + } + + reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2); + + /* Program UTMIP PLL stable and active counts */ + /* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */ + reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0); + reg |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count); + + reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0); + + reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(utmi_parameters[i]. + active_delay_count); + + /* Remove power downs from UTMIP PLL control bits */ + reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN; + reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN; + reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN; + + writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2); + + /* Program UTMIP PLL delay and oscillator frequency counts */ + reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1); + reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0); + + reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(utmi_parameters[i]. + enable_delay_count); + + reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0); + reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(utmi_parameters[i]. + xtal_freq_count); + + /* Remove power downs from UTMIP PLL control bits */ + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN; + writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1); + + /* Setup HW control of UTMIPLL */ + reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0); + reg |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET; + reg &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL; + reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE; + writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0); + + reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1); + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; + writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1); + + udelay(1); + + /* Setup SW override of UTMIPLL assuming USB2.0 + ports are assigned to USB2 */ + reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0); + reg |= UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL; + reg &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE; + writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0); + + udelay(1); + + /* Enable HW control UTMIPLL */ + reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0); + reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE; + writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0); +} + +static __init void tegra124_periph_clk_init(void __iomem *clk_base, + void __iomem *pmc_base) +{ + struct clk *clk; + u32 val; + + /* xusb_hs_src */ + val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC); + val |= BIT(25); /* always select PLLU_60M */ + writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC); + + clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0, + 1, 1); + clks[TEGRA124_CLK_XUSB_HS_SRC] = clk; + + /* dsia mux */ + clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0, + ARRAY_SIZE(mux_plld_out0_plld2_out0), 0, + clk_base + PLLD_BASE, 25, 1, 0, &pll_d_lock); + clks[TEGRA124_CLK_DSIA_MUX] = clk; + + /* dsib mux */ + clk = clk_register_mux(NULL, "dsib_mux", mux_plld_out0_plld2_out0, + ARRAY_SIZE(mux_plld_out0_plld2_out0), 0, + clk_base + PLLD2_BASE, 25, 1, 0, &pll_d2_lock); + clks[TEGRA124_CLK_DSIB_MUX] = clk; + + /* emc mux */ + clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, + ARRAY_SIZE(mux_pllmcp_clkm), 0, + clk_base + CLK_SOURCE_EMC, + 29, 3, 0, NULL); + + /* cml0 */ + clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX, + 0, 0, &pll_e_lock); + clk_register_clkdev(clk, "cml0", NULL); + clks[TEGRA124_CLK_CML0] = clk; + + /* cml1 */ + clk = clk_register_gate(NULL, "cml1", "pll_e", 0, clk_base + PLLE_AUX, + 1, 0, &pll_e_lock); + clk_register_clkdev(clk, "cml1", NULL); + clks[TEGRA124_CLK_CML1] = clk; + + tegra_periph_clk_init(clk_base, pmc_base, tegra124_clks, &pll_p_params); +} + +static void __init tegra124_pll_init(void __iomem *clk_base, + void __iomem *pmc) +{ + u32 val; + struct clk *clk; + + /* PLLC */ + clk = tegra_clk_register_pllxc("pll_c", "pll_ref", clk_base, + pmc, 0, &pll_c_params, NULL); + clk_register_clkdev(clk, "pll_c", NULL); + clks[TEGRA124_CLK_PLL_C] = clk; + + /* PLLC_OUT1 */ + clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c", + clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div", + clk_base + PLLC_OUT, 1, 0, + CLK_SET_RATE_PARENT, 0, NULL); + clk_register_clkdev(clk, "pll_c_out1", NULL); + clks[TEGRA124_CLK_PLL_C_OUT1] = clk; + + /* PLLC2 */ + clk = tegra_clk_register_pllc("pll_c2", "pll_ref", clk_base, pmc, 0, + &pll_c2_params, NULL); + clk_register_clkdev(clk, "pll_c2", NULL); + clks[TEGRA124_CLK_PLL_C2] = clk; + + /* PLLC3 */ + clk = tegra_clk_register_pllc("pll_c3", "pll_ref", clk_base, pmc, 0, + &pll_c3_params, NULL); + clk_register_clkdev(clk, "pll_c3", NULL); + clks[TEGRA124_CLK_PLL_C3] = clk; + + /* PLLM */ + clk = tegra_clk_register_pllm("pll_m", "pll_ref", clk_base, pmc, + CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, + &pll_m_params, NULL); + clk_register_clkdev(clk, "pll_m", NULL); + clks[TEGRA124_CLK_PLL_M] = clk; + + /* PLLM_OUT1 */ + clk = tegra_clk_register_divider("pll_m_out1_div", "pll_m", + clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", + clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + CLK_SET_RATE_PARENT, 0, NULL); + clk_register_clkdev(clk, "pll_m_out1", NULL); + clks[TEGRA124_CLK_PLL_M_OUT1] = clk; + + /* PLLM_UD */ + clk = clk_register_fixed_factor(NULL, "pll_m_ud", "pll_m", + CLK_SET_RATE_PARENT, 1, 1); + + /* PLLU */ + val = readl(clk_base + pll_u_params.base_reg); + val &= ~BIT(24); /* disable PLLU_OVERRIDE */ + writel(val, clk_base + pll_u_params.base_reg); + + clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, pmc, 0, + &pll_u_params, &pll_u_lock); + clk_register_clkdev(clk, "pll_u", NULL); + clks[TEGRA124_CLK_PLL_U] = clk; + + tegra124_utmi_param_configure(clk_base); + + /* PLLU_480M */ + clk = clk_register_gate(NULL, "pll_u_480M", "pll_u", + CLK_SET_RATE_PARENT, clk_base + PLLU_BASE, + 22, 0, &pll_u_lock); + clk_register_clkdev(clk, "pll_u_480M", NULL); + clks[TEGRA124_CLK_PLL_U_480M] = clk; + + /* PLLU_60M */ + clk = clk_register_fixed_factor(NULL, "pll_u_60M", "pll_u", + CLK_SET_RATE_PARENT, 1, 8); + clk_register_clkdev(clk, "pll_u_60M", NULL); + clks[TEGRA124_CLK_PLL_U_60M] = clk; + + /* PLLU_48M */ + clk = clk_register_fixed_factor(NULL, "pll_u_48M", "pll_u", + CLK_SET_RATE_PARENT, 1, 10); + clk_register_clkdev(clk, "pll_u_48M", NULL); + clks[TEGRA124_CLK_PLL_U_48M] = clk; + + /* PLLU_12M */ + clk = clk_register_fixed_factor(NULL, "pll_u_12M", "pll_u", + CLK_SET_RATE_PARENT, 1, 40); + clk_register_clkdev(clk, "pll_u_12M", NULL); + clks[TEGRA124_CLK_PLL_U_12M] = clk; + + /* PLLD */ + clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc, 0, + &pll_d_params, &pll_d_lock); + clk_register_clkdev(clk, "pll_d", NULL); + clks[TEGRA124_CLK_PLL_D] = clk; + + /* PLLD_OUT0 */ + clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll_d_out0", NULL); + clks[TEGRA124_CLK_PLL_D_OUT0] = clk; + + /* PLLRE */ + clk = tegra_clk_register_pllre("pll_re_vco", "pll_ref", clk_base, pmc, + 0, &pll_re_vco_params, &pll_re_lock, pll_ref_freq); + clk_register_clkdev(clk, "pll_re_vco", NULL); + clks[TEGRA124_CLK_PLL_RE_VCO] = clk; + + clk = clk_register_divider_table(NULL, "pll_re_out", "pll_re_vco", 0, + clk_base + PLLRE_BASE, 16, 4, 0, + pll_re_div_table, &pll_re_lock); + clk_register_clkdev(clk, "pll_re_out", NULL); + clks[TEGRA124_CLK_PLL_RE_OUT] = clk; + + /* PLLE */ + clk = tegra_clk_register_plle_tegra114("pll_e", "pll_ref", + clk_base, 0, &pll_e_params, NULL); + clk_register_clkdev(clk, "pll_e", NULL); + clks[TEGRA124_CLK_PLL_E] = clk; + + /* PLLC4 */ + clk = tegra_clk_register_pllss("pll_c4", "pll_ref", clk_base, 0, + &pll_c4_params, NULL); + clk_register_clkdev(clk, "pll_c4", NULL); + clks[TEGRA124_CLK_PLL_C4] = clk; + + /* PLLDP */ + clk = tegra_clk_register_pllss("pll_dp", "pll_ref", clk_base, 0, + &pll_dp_params, NULL); + clk_register_clkdev(clk, "pll_dp", NULL); + clks[TEGRA124_CLK_PLL_DP] = clk; + + /* PLLD2 */ + clk = tegra_clk_register_pllss("pll_d2", "pll_ref", clk_base, 0, + &tegra124_pll_d2_params, NULL); + clk_register_clkdev(clk, "pll_d2", NULL); + clks[TEGRA124_CLK_PLL_D2] = clk; + + /* PLLD2_OUT0 ?? */ + clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll_d2_out0", NULL); + clks[TEGRA124_CLK_PLL_D2_OUT0] = clk; + +} + +static const struct of_device_id pmc_match[] __initconst = { + { .compatible = "nvidia,tegra124-pmc" }, + {}, +}; + +static struct tegra_clk_init_table init_table[] __initdata = { + {TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 408000000, 0}, + {TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 408000000, 0}, + {TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 408000000, 0}, + {TEGRA124_CLK_UARTD, TEGRA124_CLK_PLL_P, 408000000, 0}, + {TEGRA124_CLK_PLL_A, TEGRA124_CLK_CLK_MAX, 564480000, 1}, + {TEGRA124_CLK_PLL_A_OUT0, TEGRA124_CLK_CLK_MAX, 11289600, 1}, + {TEGRA124_CLK_EXTERN1, TEGRA124_CLK_PLL_A_OUT0, 0, 1}, + {TEGRA124_CLK_CLK_OUT_1_MUX, TEGRA124_CLK_EXTERN1, 0, 1}, + {TEGRA124_CLK_CLK_OUT_1, TEGRA124_CLK_CLK_MAX, 0, 1}, + {TEGRA124_CLK_I2S0, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA124_CLK_I2S1, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA124_CLK_I2S3, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_P, 0, 0}, + {TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1}, + {TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 1}, + {TEGRA124_CLK_DFLL_SOC, TEGRA124_CLK_PLL_P, 51000000, 1}, + {TEGRA124_CLK_DFLL_REF, TEGRA124_CLK_PLL_P, 51000000, 1}, + {TEGRA124_CLK_PLL_C, TEGRA124_CLK_CLK_MAX, 768000000, 0}, + {TEGRA124_CLK_PLL_C_OUT1, TEGRA124_CLK_CLK_MAX, 100000000, 0}, + {TEGRA124_CLK_SBC4, TEGRA124_CLK_PLL_P, 12000000, 1}, + {TEGRA124_CLK_TSEC, TEGRA124_CLK_PLL_C3, 0, 0}, + {TEGRA124_CLK_MSENC, TEGRA124_CLK_PLL_C3, 0, 0}, + /* This MUST be the last entry. */ + {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0}, +}; + +static void __init tegra124_clock_apply_init_table(void) +{ + tegra_init_from_table(init_table, clks, TEGRA124_CLK_CLK_MAX); +} + +static void __init tegra124_clock_init(struct device_node *np) +{ + struct device_node *node; + + clk_base = of_iomap(np, 0); + if (!clk_base) { + pr_err("ioremap tegra124 CAR failed\n"); + return; + } + + node = of_find_matching_node(NULL, pmc_match); + if (!node) { + pr_err("Failed to find pmc node\n"); + WARN_ON(1); + return; + } + + pmc_base = of_iomap(node, 0); + if (!pmc_base) { + pr_err("Can't map pmc registers\n"); + WARN_ON(1); + return; + } + + clks = tegra_clk_init(TEGRA124_CLK_CLK_MAX, 6); + if (!clks) + return; + + if (tegra_osc_clk_init(clk_base, tegra124_clks, tegra124_input_freq, + ARRAY_SIZE(tegra124_input_freq), &osc_freq, &pll_ref_freq) < 0) + return; + + tegra_fixed_clk_init(tegra124_clks); + tegra124_pll_init(clk_base, pmc_base); + tegra124_periph_clk_init(clk_base, pmc_base); + tegra_audio_clk_init(clk_base, pmc_base, tegra124_clks, &pll_a_params); + tegra_pmc_clk_init(pmc_base, tegra124_clks); + + tegra_super_clk_gen4_init(clk_base, pmc_base, tegra124_clks, + &pll_x_params); + tegra_add_of_provider(np); + tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); + + tegra_clk_apply_init_table = tegra124_clock_apply_init_table; +} +CLK_OF_DECLARE(tegra124, "nvidia,tegra124-car", tegra124_clock_init); diff --git a/include/dt-bindings/clock/tegra124-car.h b/include/dt-bindings/clock/tegra124-car.h new file mode 100644 index 000000000000..a1116a3b54ef --- /dev/null +++ b/include/dt-bindings/clock/tegra124-car.h @@ -0,0 +1,341 @@ +/* + * This header provides constants for binding nvidia,tegra124-car. + * + * The first 192 clocks are numbered to match the bits in the CAR's CLK_OUT_ENB + * registers. These IDs often match those in the CAR's RST_DEVICES registers, + * but not in all cases. Some bits in CLK_OUT_ENB affect multiple clocks. In + * this case, those clocks are assigned IDs above 185 in order to highlight + * this issue. Implementations that interpret these clock IDs as bit values + * within the CLK_OUT_ENB or RST_DEVICES registers should be careful to + * explicitly handle these special cases. + * + * The balance of the clocks controlled by the CAR are assigned IDs of 185 and + * above. + */ + +#ifndef _DT_BINDINGS_CLOCK_TEGRA124_CAR_H +#define _DT_BINDINGS_CLOCK_TEGRA124_CAR_H + +/* 0 */ +/* 1 */ +/* 2 */ +#define TEGRA124_CLK_ISPB 3 +#define TEGRA124_CLK_RTC 4 +#define TEGRA124_CLK_TIMER 5 +#define TEGRA124_CLK_UARTA 6 +/* 7 (register bit affects uartb and vfir) */ +/* 8 */ +#define TEGRA124_CLK_SDMMC2 9 +/* 10 (register bit affects spdif_in and spdif_out) */ +#define TEGRA124_CLK_I2S1 11 +#define TEGRA124_CLK_I2C1 12 +#define TEGRA124_CLK_NDFLASH 13 +#define TEGRA124_CLK_SDMMC1 14 +#define TEGRA124_CLK_SDMMC4 15 +/* 16 */ +#define TEGRA124_CLK_PWM 17 +#define TEGRA124_CLK_I2S2 18 +/* 20 (register bit affects vi and vi_sensor) */ +#define TEGRA124_CLK_GR_2D 21 +#define TEGRA124_CLK_USBD 22 +#define TEGRA124_CLK_ISP 23 +#define TEGRA124_CLK_GR_3D 24 +/* 25 */ +#define TEGRA124_CLK_DISP2 26 +#define TEGRA124_CLK_DISP1 27 +#define TEGRA124_CLK_HOST1X 28 +#define TEGRA124_CLK_VCP 29 +#define TEGRA124_CLK_I2S0 30 +/* 31 */ + +/* 32 */ +/* 33 */ +#define TEGRA124_CLK_APBDMA 34 +/* 35 */ +#define TEGRA124_CLK_KBC 36 +/* 37 */ +/* 38 */ +/* 39 (register bit affects fuse and fuse_burn) */ +#define TEGRA124_CLK_KFUSE 40 +#define TEGRA124_CLK_SBC1 41 +#define TEGRA124_CLK_NOR 42 +/* 43 */ +#define TEGRA124_CLK_SBC2 44 +/* 45 */ +#define TEGRA124_CLK_SBC3 46 +#define TEGRA124_CLK_I2C5 47 +#define TEGRA124_CLK_DSIA 48 +/* 49 */ +#define TEGRA124_CLK_MIPI 50 +#define TEGRA124_CLK_HDMI 51 +#define TEGRA124_CLK_CSI 52 +/* 53 */ +#define TEGRA124_CLK_I2C2 54 +#define TEGRA124_CLK_UARTC 55 +#define TEGRA124_CLK_MIPI_CAL 56 +#define TEGRA124_CLK_EMC 57 +#define TEGRA124_CLK_USB2 58 +#define TEGRA124_CLK_USB3 59 +/* 60 */ +#define TEGRA124_CLK_VDE 61 +#define TEGRA124_CLK_BSEA 62 +#define TEGRA124_CLK_BSEV 63 + +/* 64 */ +#define TEGRA124_CLK_UARTD 65 +#define TEGRA124_CLK_UARTE 66 +#define TEGRA124_CLK_I2C3 67 +#define TEGRA124_CLK_SBC4 68 +#define TEGRA124_CLK_SDMMC3 69 +#define TEGRA124_CLK_PCIE 70 +#define TEGRA124_CLK_OWR 71 +#define TEGRA124_CLK_AFI 72 +#define TEGRA124_CLK_CSITE 73 +/* 74 */ +/* 75 */ +#define TEGRA124_CLK_LA 76 +#define TEGRA124_CLK_TRACE 77 +#define TEGRA124_CLK_SOC_THERM 78 +#define TEGRA124_CLK_DTV 79 +#define TEGRA124_CLK_NDSPEED 80 +#define TEGRA124_CLK_I2CSLOW 81 +#define TEGRA124_CLK_DSIB 82 +#define TEGRA124_CLK_TSEC 83 +/* 84 */ +/* 85 */ +/* 86 */ +/* 87 */ +/* 88 */ +#define TEGRA124_CLK_XUSB_HOST 89 +/* 90 */ +#define TEGRA124_CLK_MSENC 91 +#define TEGRA124_CLK_CSUS 92 +/* 93 */ +/* 94 */ +/* 95 (bit affects xusb_dev and xusb_dev_src) */ + +/* 96 */ +/* 97 */ +/* 98 */ +#define TEGRA124_CLK_MSELECT 99 +#define TEGRA124_CLK_TSENSOR 100 +#define TEGRA124_CLK_I2S3 101 +#define TEGRA124_CLK_I2S4 102 +#define TEGRA124_CLK_I2C4 103 +#define TEGRA124_CLK_SBC5 104 +#define TEGRA124_CLK_SBC6 105 +#define TEGRA124_CLK_D_AUDIO 106 +#define TEGRA124_CLK_APBIF 107 +#define TEGRA124_CLK_DAM0 108 +#define TEGRA124_CLK_DAM1 109 +#define TEGRA124_CLK_DAM2 110 +#define TEGRA124_CLK_HDA2CODEC_2X 111 +/* 112 */ +#define TEGRA124_CLK_AUDIO0_2X 113 +#define TEGRA124_CLK_AUDIO1_2X 114 +#define TEGRA124_CLK_AUDIO2_2X 115 +#define TEGRA124_CLK_AUDIO3_2X 116 +#define TEGRA124_CLK_AUDIO4_2X 117 +#define TEGRA124_CLK_SPDIF_2X 118 +#define TEGRA124_CLK_ACTMON 119 +#define TEGRA124_CLK_EXTERN1 120 +#define TEGRA124_CLK_EXTERN2 121 +#define TEGRA124_CLK_EXTERN3 122 +#define TEGRA124_CLK_SATA_OOB 123 +#define TEGRA124_CLK_SATA 124 +#define TEGRA124_CLK_HDA 125 +/* 126 */ +#define TEGRA124_CLK_SE 127 + +#define TEGRA124_CLK_HDA2HDMI 128 +#define TEGRA124_CLK_SATA_COLD 129 +/* 130 */ +/* 131 */ +/* 132 */ +/* 133 */ +/* 134 */ +/* 135 */ +/* 136 */ +/* 137 */ +/* 138 */ +/* 139 */ +/* 140 */ +/* 141 */ +/* 142 */ +/* 143 (bit affects xusb_falcon_src, xusb_fs_src, */ +/* xusb_host_src and xusb_ss_src) */ +#define TEGRA124_CLK_CILAB 144 +#define TEGRA124_CLK_CILCD 145 +#define TEGRA124_CLK_CILE 146 +#define TEGRA124_CLK_DSIALP 147 +#define TEGRA124_CLK_DSIBLP 148 +#define TEGRA124_CLK_ENTROPY 149 +#define TEGRA124_CLK_DDS 150 +/* 151 */ +#define TEGRA124_CLK_DP2 152 +#define TEGRA124_CLK_AMX 153 +#define TEGRA124_CLK_ADX 154 +/* 155 (bit affects dfll_ref and dfll_soc) */ +#define TEGRA124_CLK_XUSB_SS 156 +/* 157 */ +/* 158 */ +/* 159 */ + +/* 160 */ +/* 161 */ +/* 162 */ +/* 163 */ +/* 164 */ +/* 165 */ +#define TEGRA124_CLK_I2C6 166 +/* 167 */ +/* 168 */ +/* 169 */ +/* 170 */ +#define TEGRA124_CLK_VIM2_CLK 171 +/* 172 */ +/* 173 */ +/* 174 */ +/* 175 */ +#define TEGRA124_CLK_HDMI_AUDIO 176 +#define TEGRA124_CLK_CLK72MHZ 177 +#define TEGRA124_CLK_VIC03 178 +/* 179 */ +#define TEGRA124_CLK_ADX1 180 +#define TEGRA124_CLK_DPAUX 181 +#define TEGRA124_CLK_SOR0 182 +/* 183 */ +#define TEGRA124_CLK_GPU 184 +#define TEGRA124_CLK_AMX1 185 +/* 186 */ +/* 187 */ +/* 188 */ +/* 189 */ +/* 190 */ +/* 191 */ +#define TEGRA124_CLK_UARTB 192 +#define TEGRA124_CLK_VFIR 193 +#define TEGRA124_CLK_SPDIF_IN 194 +#define TEGRA124_CLK_SPDIF_OUT 195 +#define TEGRA124_CLK_VI 196 +#define TEGRA124_CLK_VI_SENSOR 197 +#define TEGRA124_CLK_FUSE 198 +#define TEGRA124_CLK_FUSE_BURN 199 +#define TEGRA124_CLK_CLK_32K 200 +#define TEGRA124_CLK_CLK_M 201 +#define TEGRA124_CLK_CLK_M_DIV2 202 +#define TEGRA124_CLK_CLK_M_DIV4 203 +#define TEGRA124_CLK_PLL_REF 204 +#define TEGRA124_CLK_PLL_C 205 +#define TEGRA124_CLK_PLL_C_OUT1 206 +#define TEGRA124_CLK_PLL_C2 207 +#define TEGRA124_CLK_PLL_C3 208 +#define TEGRA124_CLK_PLL_M 209 +#define TEGRA124_CLK_PLL_M_OUT1 210 +#define TEGRA124_CLK_PLL_P 211 +#define TEGRA124_CLK_PLL_P_OUT1 212 +#define TEGRA124_CLK_PLL_P_OUT2 213 +#define TEGRA124_CLK_PLL_P_OUT3 214 +#define TEGRA124_CLK_PLL_P_OUT4 215 +#define TEGRA124_CLK_PLL_A 216 +#define TEGRA124_CLK_PLL_A_OUT0 217 +#define TEGRA124_CLK_PLL_D 218 +#define TEGRA124_CLK_PLL_D_OUT0 219 +#define TEGRA124_CLK_PLL_D2 220 +#define TEGRA124_CLK_PLL_D2_OUT0 221 +#define TEGRA124_CLK_PLL_U 222 +#define TEGRA124_CLK_PLL_U_480M 223 + +#define TEGRA124_CLK_PLL_U_60M 224 +#define TEGRA124_CLK_PLL_U_48M 225 +#define TEGRA124_CLK_PLL_U_12M 226 +#define TEGRA124_CLK_PLL_X 227 +#define TEGRA124_CLK_PLL_X_OUT0 228 +#define TEGRA124_CLK_PLL_RE_VCO 229 +#define TEGRA124_CLK_PLL_RE_OUT 230 +#define TEGRA124_CLK_PLL_E 231 +#define TEGRA124_CLK_SPDIF_IN_SYNC 232 +#define TEGRA124_CLK_I2S0_SYNC 233 +#define TEGRA124_CLK_I2S1_SYNC 234 +#define TEGRA124_CLK_I2S2_SYNC 235 +#define TEGRA124_CLK_I2S3_SYNC 236 +#define TEGRA124_CLK_I2S4_SYNC 237 +#define TEGRA124_CLK_VIMCLK_SYNC 238 +#define TEGRA124_CLK_AUDIO0 239 +#define TEGRA124_CLK_AUDIO1 240 +#define TEGRA124_CLK_AUDIO2 241 +#define TEGRA124_CLK_AUDIO3 242 +#define TEGRA124_CLK_AUDIO4 243 +#define TEGRA124_CLK_SPDIF 244 +#define TEGRA124_CLK_CLK_OUT_1 245 +#define TEGRA124_CLK_CLK_OUT_2 246 +#define TEGRA124_CLK_CLK_OUT_3 247 +#define TEGRA124_CLK_BLINK 248 +/* 249 */ +/* 250 */ +/* 251 */ +#define TEGRA124_CLK_XUSB_HOST_SRC 252 +#define TEGRA124_CLK_XUSB_FALCON_SRC 253 +#define TEGRA124_CLK_XUSB_FS_SRC 254 +#define TEGRA124_CLK_XUSB_SS_SRC 255 + +#define TEGRA124_CLK_XUSB_DEV_SRC 256 +#define TEGRA124_CLK_XUSB_DEV 257 +#define TEGRA124_CLK_XUSB_HS_SRC 258 +#define TEGRA124_CLK_SCLK 259 +#define TEGRA124_CLK_HCLK 260 +#define TEGRA124_CLK_PCLK 261 +#define TEGRA124_CLK_CCLK_G 262 +#define TEGRA124_CLK_CCLK_LP 263 +#define TEGRA124_CLK_DFLL_REF 264 +#define TEGRA124_CLK_DFLL_SOC 265 +#define TEGRA124_CLK_VI_SENSOR2 266 +#define TEGRA124_CLK_PLL_P_OUT5 267 +#define TEGRA124_CLK_CML0 268 +#define TEGRA124_CLK_CML1 269 +#define TEGRA124_CLK_PLL_C4 270 +#define TEGRA124_CLK_PLL_DP 271 +#define TEGRA124_CLK_PLL_E_MUX 272 +/* 273 */ +/* 274 */ +/* 275 */ +/* 276 */ +/* 277 */ +/* 278 */ +/* 279 */ +/* 280 */ +/* 281 */ +/* 282 */ +/* 283 */ +/* 284 */ +/* 285 */ +/* 286 */ +/* 287 */ + +/* 288 */ +/* 289 */ +/* 290 */ +/* 291 */ +/* 292 */ +/* 293 */ +/* 294 */ +/* 295 */ +/* 296 */ +/* 297 */ +/* 298 */ +/* 299 */ +#define TEGRA124_CLK_AUDIO0_MUX 300 +#define TEGRA124_CLK_AUDIO1_MUX 301 +#define TEGRA124_CLK_AUDIO2_MUX 302 +#define TEGRA124_CLK_AUDIO3_MUX 303 +#define TEGRA124_CLK_AUDIO4_MUX 304 +#define TEGRA124_CLK_SPDIF_MUX 305 +#define TEGRA124_CLK_CLK_OUT_1_MUX 306 +#define TEGRA124_CLK_CLK_OUT_2_MUX 307 +#define TEGRA124_CLK_CLK_OUT_3_MUX 308 +#define TEGRA124_CLK_DSIA_MUX 309 +#define TEGRA124_CLK_DSIB_MUX 310 +#define TEGRA124_CLK_SOR0_LVDS 311 +#define TEGRA124_CLK_CLK_MAX 312 + +#endif /* _DT_BINDINGS_CLOCK_TEGRA124_CAR_H */ -- cgit v1.2.3 From c0501f47c68997ea2933460b9908e6a049c59f21 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 7 Nov 2013 08:41:27 +0100 Subject: usb: gadget: f_loopback: add configfs support Add support for using the loopback USB function in gadgets composed with configfs. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- .../ABI/testing/configfs-usb-gadget-loopback | 8 ++ drivers/usb/gadget/Kconfig | 12 ++ drivers/usb/gadget/f_loopback.c | 132 +++++++++++++++++++++ drivers/usb/gadget/g_zero.h | 12 ++ drivers/usb/gadget/zero.c | 4 +- 5 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-loopback (limited to 'Documentation') diff --git a/Documentation/ABI/testing/configfs-usb-gadget-loopback b/Documentation/ABI/testing/configfs-usb-gadget-loopback new file mode 100644 index 000000000000..852b2365a5b5 --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-loopback @@ -0,0 +1,8 @@ +What: /config/usb-gadget/gadget/functions/Loopback.name +Date: Nov 2013 +KenelVersion: 3.13 +Description: + The attributes: + + qlen - depth of loopback queue + bulk_buflen - buffer length diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index a91e6422f930..26fe8769be45 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -689,6 +689,18 @@ config USB_CONFIGFS_MASS_STORAGE device (in much the same way as the "loop" device driver), specified as a module parameter or sysfs option. +config USB_CONFIGFS_F_LB + boolean "Loopback function (for testing)" + depends on USB_CONFIGFS + select USB_F_SS_LB + help + It loops back a configurable number of transfers. + It also implements control requests, for "chapter 9" conformance. + Make this be the first driver you try using on top of any new + USB peripheral controller driver. Then you can use host-side + test software, like the "usbtest" driver, to put your hardware + and its driver through a basic set of functional tests. + config USB_ZERO tristate "Gadget Zero (DEVELOPMENT)" select USB_LIBCOMPOSITE diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index b79065376a16..c35bb40cabf2 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c @@ -231,6 +231,14 @@ autoconf_fail: static void lb_free_func(struct usb_function *f) { + struct f_lb_opts *opts; + + opts = container_of(f->fi, struct f_lb_opts, func_inst); + + mutex_lock(&opts->lock); + opts->refcnt--; + mutex_unlock(&opts->lock); + usb_free_all_descriptors(f); kfree(func_to_loop(f)); } @@ -386,6 +394,11 @@ static struct usb_function *loopback_alloc(struct usb_function_instance *fi) return ERR_PTR(-ENOMEM); lb_opts = container_of(fi, struct f_lb_opts, func_inst); + + mutex_lock(&lb_opts->lock); + lb_opts->refcnt++; + mutex_unlock(&lb_opts->lock); + buflen = lb_opts->bulk_buflen; qlen = lb_opts->qlen; if (!qlen) @@ -402,6 +415,118 @@ static struct usb_function *loopback_alloc(struct usb_function_instance *fi) return &loop->function; } +static inline struct f_lb_opts *to_f_lb_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_lb_opts, + func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(f_lb_opts); +CONFIGFS_ATTR_OPS(f_lb_opts); + +static void lb_attr_release(struct config_item *item) +{ + struct f_lb_opts *lb_opts = to_f_lb_opts(item); + + usb_put_function_instance(&lb_opts->func_inst); +} + +static struct configfs_item_operations lb_item_ops = { + .release = lb_attr_release, + .show_attribute = f_lb_opts_attr_show, + .store_attribute = f_lb_opts_attr_store, +}; + +static ssize_t f_lb_opts_qlen_show(struct f_lb_opts *opts, char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = sprintf(page, "%d", opts->qlen); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_lb_opts_qlen_store(struct f_lb_opts *opts, + const char *page, size_t len) +{ + int ret; + u32 num; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + + ret = kstrtou32(page, 0, &num); + if (ret) + goto end; + + opts->qlen = num; + ret = len; +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct f_lb_opts_attribute f_lb_opts_qlen = + __CONFIGFS_ATTR(qlen, S_IRUGO | S_IWUSR, + f_lb_opts_qlen_show, + f_lb_opts_qlen_store); + +static ssize_t f_lb_opts_bulk_buflen_show(struct f_lb_opts *opts, char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = sprintf(page, "%d", opts->bulk_buflen); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_lb_opts_bulk_buflen_store(struct f_lb_opts *opts, + const char *page, size_t len) +{ + int ret; + u32 num; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + + ret = kstrtou32(page, 0, &num); + if (ret) + goto end; + + opts->bulk_buflen = num; + ret = len; +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct f_lb_opts_attribute f_lb_opts_bulk_buflen = + __CONFIGFS_ATTR(buflen, S_IRUGO | S_IWUSR, + f_lb_opts_bulk_buflen_show, + f_lb_opts_bulk_buflen_store); + +static struct configfs_attribute *lb_attrs[] = { + &f_lb_opts_qlen.attr, + &f_lb_opts_bulk_buflen.attr, + NULL, +}; + +static struct config_item_type lb_func_type = { + .ct_item_ops = &lb_item_ops, + .ct_attrs = lb_attrs, + .ct_owner = THIS_MODULE, +}; + static void lb_free_instance(struct usb_function_instance *fi) { struct f_lb_opts *lb_opts; @@ -417,7 +542,14 @@ static struct usb_function_instance *loopback_alloc_instance(void) lb_opts = kzalloc(sizeof(*lb_opts), GFP_KERNEL); if (!lb_opts) return ERR_PTR(-ENOMEM); + mutex_init(&lb_opts->lock); lb_opts->func_inst.free_func_inst = lb_free_instance; + lb_opts->bulk_buflen = GZERO_BULK_BUFLEN; + lb_opts->qlen = GZERO_QLEN; + + config_group_init_type_name(&lb_opts->func_inst.group, "", + &lb_func_type); + return &lb_opts->func_inst; } DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc); diff --git a/drivers/usb/gadget/g_zero.h b/drivers/usb/gadget/g_zero.h index a1c1a978b5e9..19ec50a42a74 100644 --- a/drivers/usb/gadget/g_zero.h +++ b/drivers/usb/gadget/g_zero.h @@ -6,6 +6,9 @@ #ifndef __G_ZERO_H #define __G_ZERO_H +#define GZERO_BULK_BUFLEN 4096 +#define GZERO_QLEN 32 + struct usb_zero_options { unsigned pattern; unsigned isoc_interval; @@ -30,6 +33,15 @@ struct f_lb_opts { struct usb_function_instance func_inst; unsigned bulk_buflen; unsigned qlen; + + /* + * Read/write access to configfs attributes is handled by configfs. + * + * This is to protect the data from concurrent access by read/write + * and create symlink/remove symlink. + */ + struct mutex lock; + int refcnt; }; void lb_modexit(void); diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 0dd07ae1555d..d954bba7b405 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -66,8 +66,8 @@ module_param(loopdefault, bool, S_IRUGO|S_IWUSR); static struct usb_zero_options gzero_options = { .isoc_interval = 4, .isoc_maxpacket = 1024, - .bulk_buflen = 4096, - .qlen = 32, + .bulk_buflen = GZERO_BULK_BUFLEN, + .qlen = GZERO_QLEN, }; /*-------------------------------------------------------------------------*/ -- cgit v1.2.3 From 25d8015177ae7baedb8bdc76dffc0884b0d785a3 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Thu, 7 Nov 2013 08:41:28 +0100 Subject: usb: gadget: f_sourcesink: add configfs support Add support for using the sourcesink function in gadgets composed with configfs. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- .../ABI/testing/configfs-usb-gadget-sourcesink | 12 + drivers/usb/gadget/Kconfig | 7 +- drivers/usb/gadget/f_sourcesink.c | 318 +++++++++++++++++++++ drivers/usb/gadget/g_zero.h | 11 + drivers/usb/gadget/zero.c | 4 +- 5 files changed, 347 insertions(+), 5 deletions(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-sourcesink (limited to 'Documentation') diff --git a/Documentation/ABI/testing/configfs-usb-gadget-sourcesink b/Documentation/ABI/testing/configfs-usb-gadget-sourcesink new file mode 100644 index 000000000000..a30f3093ef6c --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-sourcesink @@ -0,0 +1,12 @@ +What: /config/usb-gadget/gadget/functions/SourceSink.name +Date: Nov 2013 +KenelVersion: 3.13 +Description: + The attributes: + + pattern - 0 (all zeros), 1 (mod63), 2 (none) + isoc_interval - 1..16 + isoc_maxpacket - 0 - 1023 (fs), 0 - 1024 (hs/ss) + isoc_mult - 0..2 (hs/ss only) + isoc_maxburst - 0..15 (ss only) + qlen - buffer length diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 26fe8769be45..5f1d4443aa0c 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -689,12 +689,13 @@ config USB_CONFIGFS_MASS_STORAGE device (in much the same way as the "loop" device driver), specified as a module parameter or sysfs option. -config USB_CONFIGFS_F_LB - boolean "Loopback function (for testing)" +config USB_CONFIGFS_F_LB_SS + boolean "Loopback and sourcesink function (for testing)" depends on USB_CONFIGFS select USB_F_SS_LB help - It loops back a configurable number of transfers. + Loopback function loops back a configurable number of transfers. + Sourcesink function either sinks and sources bulk data. It also implements control requests, for "chapter 9" conformance. Make this be the first driver you try using on top of any new USB peripheral controller driver. Then you can use host-side diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index c5ad4a1fa3c7..5d4251e7a377 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -477,6 +477,14 @@ no_iso: static void sourcesink_free_func(struct usb_function *f) { + struct f_ss_opts *opts; + + opts = container_of(f->fi, struct f_ss_opts, func_inst); + + mutex_lock(&opts->lock); + opts->refcnt--; + mutex_unlock(&opts->lock); + usb_free_all_descriptors(f); kfree(func_to_ss(f)); } @@ -865,6 +873,11 @@ static struct usb_function *source_sink_alloc_func( return NULL; ss_opts = container_of(fi, struct f_ss_opts, func_inst); + + mutex_lock(&ss_opts->lock); + ss_opts->refcnt++; + mutex_unlock(&ss_opts->lock); + pattern = ss_opts->pattern; isoc_interval = ss_opts->isoc_interval; isoc_maxpacket = ss_opts->isoc_maxpacket; @@ -885,6 +898,303 @@ static struct usb_function *source_sink_alloc_func( return &ss->function; } +static inline struct f_ss_opts *to_f_ss_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_ss_opts, + func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(f_ss_opts); +CONFIGFS_ATTR_OPS(f_ss_opts); + +static void ss_attr_release(struct config_item *item) +{ + struct f_ss_opts *ss_opts = to_f_ss_opts(item); + + usb_put_function_instance(&ss_opts->func_inst); +} + +static struct configfs_item_operations ss_item_ops = { + .release = ss_attr_release, + .show_attribute = f_ss_opts_attr_show, + .store_attribute = f_ss_opts_attr_store, +}; + +static ssize_t f_ss_opts_pattern_show(struct f_ss_opts *opts, char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = sprintf(page, "%d", opts->pattern); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_ss_opts_pattern_store(struct f_ss_opts *opts, + const char *page, size_t len) +{ + int ret; + u8 num; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + + ret = kstrtou8(page, 0, &num); + if (ret) + goto end; + + if (num != 0 && num != 1 && num != 2) { + ret = -EINVAL; + goto end; + } + + opts->pattern = num; + ret = len; +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_pattern = + __CONFIGFS_ATTR(pattern, S_IRUGO | S_IWUSR, + f_ss_opts_pattern_show, + f_ss_opts_pattern_store); + +static ssize_t f_ss_opts_isoc_interval_show(struct f_ss_opts *opts, char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = sprintf(page, "%d", opts->isoc_interval); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_ss_opts_isoc_interval_store(struct f_ss_opts *opts, + const char *page, size_t len) +{ + int ret; + u8 num; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + + ret = kstrtou8(page, 0, &num); + if (ret) + goto end; + + if (num > 16) { + ret = -EINVAL; + goto end; + } + + opts->isoc_interval = num; + ret = len; +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_isoc_interval = + __CONFIGFS_ATTR(isoc_interval, S_IRUGO | S_IWUSR, + f_ss_opts_isoc_interval_show, + f_ss_opts_isoc_interval_store); + +static ssize_t f_ss_opts_isoc_maxpacket_show(struct f_ss_opts *opts, char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = sprintf(page, "%d", opts->isoc_maxpacket); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_ss_opts_isoc_maxpacket_store(struct f_ss_opts *opts, + const char *page, size_t len) +{ + int ret; + u16 num; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + + ret = kstrtou16(page, 0, &num); + if (ret) + goto end; + + if (num > 1024) { + ret = -EINVAL; + goto end; + } + + opts->isoc_maxpacket = num; + ret = len; +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_isoc_maxpacket = + __CONFIGFS_ATTR(isoc_maxpacket, S_IRUGO | S_IWUSR, + f_ss_opts_isoc_maxpacket_show, + f_ss_opts_isoc_maxpacket_store); + +static ssize_t f_ss_opts_isoc_mult_show(struct f_ss_opts *opts, char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = sprintf(page, "%d", opts->isoc_mult); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_ss_opts_isoc_mult_store(struct f_ss_opts *opts, + const char *page, size_t len) +{ + int ret; + u8 num; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + + ret = kstrtou8(page, 0, &num); + if (ret) + goto end; + + if (num > 2) { + ret = -EINVAL; + goto end; + } + + opts->isoc_mult = num; + ret = len; +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_isoc_mult = + __CONFIGFS_ATTR(isoc_mult, S_IRUGO | S_IWUSR, + f_ss_opts_isoc_mult_show, + f_ss_opts_isoc_mult_store); + +static ssize_t f_ss_opts_isoc_maxburst_show(struct f_ss_opts *opts, char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = sprintf(page, "%d", opts->isoc_maxburst); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_ss_opts_isoc_maxburst_store(struct f_ss_opts *opts, + const char *page, size_t len) +{ + int ret; + u8 num; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + + ret = kstrtou8(page, 0, &num); + if (ret) + goto end; + + if (num > 15) { + ret = -EINVAL; + goto end; + } + + opts->isoc_maxburst = num; + ret = len; +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_isoc_maxburst = + __CONFIGFS_ATTR(isoc_maxburst, S_IRUGO | S_IWUSR, + f_ss_opts_isoc_maxburst_show, + f_ss_opts_isoc_maxburst_store); + +static ssize_t f_ss_opts_bulk_buflen_show(struct f_ss_opts *opts, char *page) +{ + int result; + + mutex_lock(&opts->lock); + result = sprintf(page, "%d", opts->bulk_buflen); + mutex_unlock(&opts->lock); + + return result; +} + +static ssize_t f_ss_opts_bulk_buflen_store(struct f_ss_opts *opts, + const char *page, size_t len) +{ + int ret; + u32 num; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto end; + } + + ret = kstrtou32(page, 0, &num); + if (ret) + goto end; + + opts->bulk_buflen = num; + ret = len; +end: + mutex_unlock(&opts->lock); + return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_bulk_buflen = + __CONFIGFS_ATTR(buflen, S_IRUGO | S_IWUSR, + f_ss_opts_bulk_buflen_show, + f_ss_opts_bulk_buflen_store); + +static struct configfs_attribute *ss_attrs[] = { + &f_ss_opts_pattern.attr, + &f_ss_opts_isoc_interval.attr, + &f_ss_opts_isoc_maxpacket.attr, + &f_ss_opts_isoc_mult.attr, + &f_ss_opts_isoc_maxburst.attr, + &f_ss_opts_bulk_buflen.attr, + NULL, +}; + +static struct config_item_type ss_func_type = { + .ct_item_ops = &ss_item_ops, + .ct_attrs = ss_attrs, + .ct_owner = THIS_MODULE, +}; + static void source_sink_free_instance(struct usb_function_instance *fi) { struct f_ss_opts *ss_opts; @@ -900,7 +1210,15 @@ static struct usb_function_instance *source_sink_alloc_inst(void) ss_opts = kzalloc(sizeof(*ss_opts), GFP_KERNEL); if (!ss_opts) return ERR_PTR(-ENOMEM); + mutex_init(&ss_opts->lock); ss_opts->func_inst.free_func_inst = source_sink_free_instance; + ss_opts->isoc_interval = GZERO_ISOC_INTERVAL; + ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET; + ss_opts->bulk_buflen = GZERO_BULK_BUFLEN; + + config_group_init_type_name(&ss_opts->func_inst.group, "", + &ss_func_type); + return &ss_opts->func_inst; } DECLARE_USB_FUNCTION(SourceSink, source_sink_alloc_inst, diff --git a/drivers/usb/gadget/g_zero.h b/drivers/usb/gadget/g_zero.h index 19ec50a42a74..15f180904f8a 100644 --- a/drivers/usb/gadget/g_zero.h +++ b/drivers/usb/gadget/g_zero.h @@ -8,6 +8,8 @@ #define GZERO_BULK_BUFLEN 4096 #define GZERO_QLEN 32 +#define GZERO_ISOC_INTERVAL 4 +#define GZERO_ISOC_MAXPACKET 1024 struct usb_zero_options { unsigned pattern; @@ -27,6 +29,15 @@ struct f_ss_opts { unsigned isoc_mult; unsigned isoc_maxburst; unsigned bulk_buflen; + + /* + * Read/write access to configfs attributes is handled by configfs. + * + * This is to protect the data from concurrent access by read/write + * and create symlink/remove symlink. + */ + struct mutex lock; + int refcnt; }; struct f_lb_opts { diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index d954bba7b405..00b401906a32 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -64,8 +64,8 @@ static bool loopdefault = 0; module_param(loopdefault, bool, S_IRUGO|S_IWUSR); static struct usb_zero_options gzero_options = { - .isoc_interval = 4, - .isoc_maxpacket = 1024, + .isoc_interval = GZERO_ISOC_INTERVAL, + .isoc_maxpacket = GZERO_ISOC_MAXPACKET, .bulk_buflen = GZERO_BULK_BUFLEN, .qlen = GZERO_QLEN, }; -- cgit v1.2.3 From 0a05ef0ec1cb1b76b362096b48190fd8a1af487d Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 19 Nov 2013 11:07:40 +0000 Subject: dma: ste_dma40: Expand DT binding to accept 'high-priority channel' flag This is used for MSP (audio) devices which is about to be fully DT:ed. Cc: devicetree@vger.kernel.org Acked-by: Vinod Koul Signed-off-by: Lee Jones Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/dma/ste-dma40.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/dma/ste-dma40.txt b/Documentation/devicetree/bindings/dma/ste-dma40.txt index a8c21c256baa..1f5729f10621 100644 --- a/Documentation/devicetree/bindings/dma/ste-dma40.txt +++ b/Documentation/devicetree/bindings/dma/ste-dma40.txt @@ -50,6 +50,9 @@ Each dmas request consists of 4 cells: 0x00000008: Use fixed channel: Use automatic channel selection when unset Use DMA request line number when set + 0x00000010: Set channel as high priority: + Normal priority when unset + High priority when set Example: -- cgit v1.2.3 From 976358e2343566207fed2101ce62ff6fbad7f830 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Mon, 25 Nov 2013 19:17:09 -0800 Subject: Input: add a new driver for GPIO beeper This patch adds a new driver for the beeper controlled via GPIO pin. The driver does not depend on the architecture and is positioned as a replacement for the specific drivers that are used for this function. Signed-off-by: Alexander Shiyan Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/gpio-beeper.txt | 13 +++ drivers/input/misc/Kconfig | 9 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/gpio-beeper.c | 127 +++++++++++++++++++++ 4 files changed, 150 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/gpio-beeper.txt create mode 100644 drivers/input/misc/gpio-beeper.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/gpio-beeper.txt b/Documentation/devicetree/bindings/input/gpio-beeper.txt new file mode 100644 index 000000000000..a5086e37fce6 --- /dev/null +++ b/Documentation/devicetree/bindings/input/gpio-beeper.txt @@ -0,0 +1,13 @@ +* GPIO beeper device tree bindings + +Register a beeper connected to GPIO pin. + +Required properties: +- compatible: Should be "gpio-beeper". +- gpios: From common gpio binding; gpio connection to beeper enable pin. + +Example: + beeper: beeper { + compatible = "gpio-beeper"; + gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>; + }; diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 5f4967d01bc3..4ffc39732513 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -222,6 +222,15 @@ config INPUT_GP2A To compile this driver as a module, choose M here: the module will be called gp2ap002a00f. +config INPUT_GPIO_BEEPER + tristate "Generic GPIO Beeper support" + depends on OF_GPIO + help + Say Y here if you have a beeper connected to a GPIO pin. + + To compile this driver as a module, choose M here: the + module will be called gpio-beeper. + config INPUT_GPIO_TILT_POLLED tristate "Polled GPIO tilt switch" depends on GPIOLIB diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 0ebfb6dbf0f7..cda71fc52fb3 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o +obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o diff --git a/drivers/input/misc/gpio-beeper.c b/drivers/input/misc/gpio-beeper.c new file mode 100644 index 000000000000..b757435e2b3d --- /dev/null +++ b/drivers/input/misc/gpio-beeper.c @@ -0,0 +1,127 @@ +/* + * Generic GPIO beeper driver + * + * Copyright (C) 2013 Alexander Shiyan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#define BEEPER_MODNAME "gpio-beeper" + +struct gpio_beeper { + struct work_struct work; + int gpio; + bool active_low; + bool beeping; +}; + +static void gpio_beeper_toggle(struct gpio_beeper *beep, bool on) +{ + gpio_set_value_cansleep(beep->gpio, on ^ beep->active_low); +} + +static void gpio_beeper_work(struct work_struct *work) +{ + struct gpio_beeper *beep = container_of(work, struct gpio_beeper, work); + + gpio_beeper_toggle(beep, beep->beeping); +} + +static int gpio_beeper_event(struct input_dev *dev, unsigned int type, + unsigned int code, int value) +{ + struct gpio_beeper *beep = input_get_drvdata(dev); + + if (type != EV_SND || code != SND_BELL) + return -ENOTSUPP; + + if (value < 0) + return -EINVAL; + + beep->beeping = value; + /* Schedule work to actually turn the beeper on or off */ + schedule_work(&beep->work); + + return 0; +} + +static void gpio_beeper_close(struct input_dev *input) +{ + struct gpio_beeper *beep = input_get_drvdata(input); + + cancel_work_sync(&beep->work); + gpio_beeper_toggle(beep, false); +} + +static int gpio_beeper_probe(struct platform_device *pdev) +{ + struct gpio_beeper *beep; + enum of_gpio_flags flags; + struct input_dev *input; + unsigned long gflags; + int err; + + beep = devm_kzalloc(&pdev->dev, sizeof(*beep), GFP_KERNEL); + if (!beep) + return -ENOMEM; + + beep->gpio = of_get_gpio_flags(pdev->dev.of_node, 0, &flags); + if (!gpio_is_valid(beep->gpio)) + return beep->gpio; + + input = devm_input_allocate_device(&pdev->dev); + if (!input) + return -ENOMEM; + + INIT_WORK(&beep->work, gpio_beeper_work); + + input->name = pdev->name; + input->id.bustype = BUS_HOST; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0100; + input->close = gpio_beeper_close; + input->event = gpio_beeper_event; + + input_set_capability(input, EV_SND, SND_BELL); + + beep->active_low = flags & OF_GPIO_ACTIVE_LOW; + gflags = beep->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + + err = devm_gpio_request_one(&pdev->dev, beep->gpio, gflags, pdev->name); + if (err) + return err; + + input_set_drvdata(input, beep); + + return input_register_device(input); +} + +static struct of_device_id gpio_beeper_of_match[] = { + { .compatible = BEEPER_MODNAME, }, + { } +}; +MODULE_DEVICE_TABLE(of, gpio_beeper_of_match); + +static struct platform_driver gpio_beeper_platform_driver = { + .driver = { + .name = BEEPER_MODNAME, + .owner = THIS_MODULE, + .of_match_table = gpio_beeper_of_match, + }, + .probe = gpio_beeper_probe, +}; +module_platform_driver(gpio_beeper_platform_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alexander Shiyan "); +MODULE_DESCRIPTION("Generic GPIO beeper driver"); -- cgit v1.2.3 From f881591dd4d522b44722eb6b78c6a01a9c1bbd7c Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 25 Sep 2013 16:10:18 -0300 Subject: clk: fixed-factor: Fix device-tree binding typo The required properties are not named "div" and "mult", but rather "clock-div" and "clock-mult". Signed-off-by: Ezequiel Garcia Signed-off-by: Mike Turquette --- Documentation/devicetree/bindings/clock/fixed-factor-clock.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/fixed-factor-clock.txt b/Documentation/devicetree/bindings/clock/fixed-factor-clock.txt index 5757f9abfc26..1bae8527eb9b 100644 --- a/Documentation/devicetree/bindings/clock/fixed-factor-clock.txt +++ b/Documentation/devicetree/bindings/clock/fixed-factor-clock.txt @@ -19,6 +19,6 @@ Example: compatible = "fixed-factor-clock"; clocks = <&parentclk>; #clock-cells = <0>; - div = <2>; - mult = <1>; + clock-div = <2>; + clock-mult = <1>; }; -- cgit v1.2.3 From 3a85ca9d8a06c873b7a5fb24319572926fa20e10 Mon Sep 17 00:00:00 2001 From: Brian Austin Date: Fri, 15 Nov 2013 09:35:34 -0600 Subject: ASoC: dt: binding: sound cs42l52 driver Signed-off-by: Brian Austin Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/cs42l52.txt | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/cs42l52.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/cs42l52.txt b/Documentation/devicetree/bindings/sound/cs42l52.txt new file mode 100644 index 000000000000..bc03c9312a19 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs42l52.txt @@ -0,0 +1,46 @@ +CS42L52 audio CODEC + +Required properties: + + - compatible : "cirrus,cs42l52" + + - reg : the I2C address of the device for I2C + +Optional properties: + + - cirrus,reset-gpio : GPIO controller's phandle and the number + of the GPIO used to reset the codec. + + - cirrus,chgfreq-divisor : Values used to set the Charge Pump Frequency. + Allowable values of 0x00 through 0x0F. These are raw values written to the + register, not the actual frequency. The frequency is determined by the following. + Frequency = (64xFs)/(N+2) + N = chgfreq_val + Fs = Sample Rate (variable) + + - cirrus,mica-differential-cfg : boolean, If present, then the MICA input is configured + as a differential input. If not present then the MICA input is configured as + Single-ended input. Single-ended mode allows for MIC1 or MIC2 muxing for input. + + - cirrus,micb-differential-cfg : boolean, If present, then the MICB input is configured + as a differential input. If not present then the MICB input is configured as + Single-ended input. Single-ended mode allows for MIC1 or MIC2 muxing for input. + + - cirrus,micbias-lvl: Set the output voltage level on the MICBIAS Pin + 0 = 0.5 x VA + 1 = 0.6 x VA + 2 = 0.7 x VA + 3 = 0.8 x VA + 4 = 0.83 x VA + 5 = 0.91 x VA + +Example: + +codec: codec@4a { + compatible = "cirrus,cs42l52"; + reg = <0x4a>; + reset-gpio = <&gpio 10 0>; + cirrus,chgfreq-divisor = <0x05>; + cirrus.mica-differential-cfg; + cirrus,micbias-lvl = <5>; +}; -- cgit v1.2.3 From ea3aba8482be6f3e4815f4014fa7302fc77c9c3f Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 21 May 2013 05:11:35 -0300 Subject: [media] videobuf2: Add support for file access mode flags for DMABUF exporting Currently it is not possible for userspace to map a DMABUF exported buffer with write permissions. This patch allows to also pass O_RDONLY/O_RDWR when exporting the buffer, so that userspace may map it with write permissions. Signed-off-by: Philipp Zabel Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/vidioc-expbuf.xml | 8 +++++--- drivers/media/v4l2-core/videobuf2-core.c | 8 ++++---- drivers/media/v4l2-core/videobuf2-dma-contig.c | 4 ++-- include/media/videobuf2-core.h | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/vidioc-expbuf.xml b/Documentation/DocBook/media/v4l/vidioc-expbuf.xml index e287c8fc803b..4165e7bfa4ff 100644 --- a/Documentation/DocBook/media/v4l/vidioc-expbuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-expbuf.xml @@ -73,7 +73,8 @@ range from zero to the maximal number of valid planes for the currently active format. For the single-planar API, applications must set plane to zero. Additional flags may be posted in the flags field. Refer to a manual for open() for details. -Currently only O_CLOEXEC is supported. All other fields must be set to zero. +Currently only O_CLOEXEC, O_RDONLY, O_WRONLY, and O_RDWR are supported. All +other fields must be set to zero. In the case of multi-planar API, every plane is exported separately using multiple VIDIOC_EXPBUF calls. @@ -170,8 +171,9 @@ multi-planar API. Otherwise this value must be set to zero. __u32 flags Flags for the newly created file, currently only -O_CLOEXEC is supported, refer to the manual of open() for more -details. +O_CLOEXEC , O_RDONLY, O_WRONLY +, and O_RDWR are supported, refer to the manual +of open() for more details. __s32 diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index b19b306c8f7f..57ba131f08ad 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1824,8 +1824,8 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) return -EINVAL; } - if (eb->flags & ~O_CLOEXEC) { - dprintk(1, "Queue does support only O_CLOEXEC flag\n"); + if (eb->flags & ~(O_CLOEXEC | O_ACCMODE)) { + dprintk(1, "Queue does support only O_CLOEXEC and access mode flags\n"); return -EINVAL; } @@ -1848,14 +1848,14 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) vb_plane = &vb->planes[eb->plane]; - dbuf = call_memop(q, get_dmabuf, vb_plane->mem_priv); + dbuf = call_memop(q, get_dmabuf, vb_plane->mem_priv, eb->flags & O_ACCMODE); if (IS_ERR_OR_NULL(dbuf)) { dprintk(1, "Failed to export buffer %d, plane %d\n", eb->index, eb->plane); return -EINVAL; } - ret = dma_buf_fd(dbuf, eb->flags); + ret = dma_buf_fd(dbuf, eb->flags & ~O_ACCMODE); if (ret < 0) { dprintk(3, "buffer %d, plane %d failed to export (%d)\n", eb->index, eb->plane, ret); diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 646f08f4f504..33d3871d1e13 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -393,7 +393,7 @@ static struct sg_table *vb2_dc_get_base_sgt(struct vb2_dc_buf *buf) return sgt; } -static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv) +static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, unsigned long flags) { struct vb2_dc_buf *buf = buf_priv; struct dma_buf *dbuf; @@ -404,7 +404,7 @@ static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv) if (WARN_ON(!buf->sgt_base)) return NULL; - dbuf = dma_buf_export(buf, &vb2_dc_dmabuf_ops, buf->size, 0); + dbuf = dma_buf_export(buf, &vb2_dc_dmabuf_ops, buf->size, flags); if (IS_ERR(dbuf)) return NULL; diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index bd8218b15009..941055e9d125 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -83,7 +83,7 @@ struct vb2_fileio_data; struct vb2_mem_ops { void *(*alloc)(void *alloc_ctx, unsigned long size, gfp_t gfp_flags); void (*put)(void *buf_priv); - struct dma_buf *(*get_dmabuf)(void *buf_priv); + struct dma_buf *(*get_dmabuf)(void *buf_priv, unsigned long flags); void *(*get_userptr)(void *alloc_ctx, unsigned long vaddr, unsigned long size, int write); -- cgit v1.2.3 From fa558c2801fc173758c742d836f3cc4621851557 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 20 Nov 2013 15:25:02 +0900 Subject: ASoC: simple-card: add Device Tree support Support for loading the simple-card module via DeviceTree. It requests CPU/CODEC information. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/simple-card.txt | 68 +++++++++ sound/soc/generic/simple-card.c | 156 ++++++++++++++++++++- 2 files changed, 218 insertions(+), 6 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/simple-card.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt new file mode 100644 index 000000000000..769a346f890c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/simple-card.txt @@ -0,0 +1,68 @@ +Simple-Card: + +Simple-Card specifies audio DAI connection of SoC <-> codec. + +Required properties: + +- compatible : "simple-audio-card" + +Optional properties: + +- simple-audio-card,format : CPU/CODEC common audio format. + "i2s", "right_j", "left_j" , "dsp_a" + "dsp_b", "ac97", "pdm", "msb", "lsb" +Required subnodes: + +- simple-audio-card,cpu : CPU sub-node +- simple-audio-card,codec : CODEC sub-node + +Required CPU/CODEC subnodes properties: + +- sound-dai : phandle and port of CPU/CODEC + +Optional CPU/CODEC subnodes properties: + +- format : CPU/CODEC specific audio format if needed. + see simple-audio-card,format +- frame-master : bool property. add this if subnode is frame master +- bitclock-master : bool property. add this if subnode is bitclock master +- bitclock-inversion : bool property. add this if subnode has clock inversion +- frame-inversion : bool property. add this if subnode has frame inversion +- clocks / system-clock-frequency : specify subnode's clock if needed. + it can be specified via "clocks" if system has + clock node (= common clock), or "system-clock-frequency" + (if system doens't support common clock) + +Example: + +sound { + compatible = "simple-audio-card"; + simple-audio-card,format = "left_j"; + + simple-audio-card,cpu { + sound-dai = <&sh_fsi2 0>; + }; + + simple-audio-card,codec { + sound-dai = <&ak4648>; + bitclock-master; + frame-master; + clocks = <&osc>; + }; +}; + +&i2c0 { + ak4648: ak4648@12 { + #sound-dai-cells = <0>; + compatible = "asahi-kasei,ak4648"; + reg = <0x12>; + }; +}; + +sh_fsi2: sh_fsi2@ec230000 { + #sound-dai-cells = <1>; + compatible = "renesas,sh_fsi2"; + reg = <0xec230000 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 146 0x4>; +}; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index b2fbb7075a6c..7a9b6b4898c0 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -8,7 +8,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#include +#include #include #include #include @@ -57,11 +58,144 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static int +asoc_simple_card_sub_parse_of(struct device_node *np, + struct asoc_simple_dai *dai, + struct device_node **node) +{ + struct clk *clk; + int ret; + + /* + * get node via "sound-dai = <&phandle port>" + * it will be used as xxx_of_node on soc_bind_dai_link() + */ + *node = of_parse_phandle(np, "sound-dai", 0); + if (!*node) + return -ENODEV; + + /* get dai->name */ + ret = snd_soc_of_get_dai_name(np, &dai->name); + if (ret < 0) + goto parse_error; + + /* + * bitclock-inversion, frame-inversion + * bitclock-master, frame-master + * and specific "format" if it has + */ + dai->fmt = snd_soc_of_parse_daifmt(np, NULL); + + /* + * dai->sysclk come from + * "clocks = <&xxx>" (if system has common clock) + * or "system-clock-frequency = " + */ + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) + of_property_read_u32(np, + "system-clock-frequency", + &dai->sysclk); + else + dai->sysclk = clk_get_rate(clk); + + ret = 0; + +parse_error: + of_node_put(*node); + + return ret; +} + +static int asoc_simple_card_parse_of(struct device_node *node, + struct asoc_simple_card_info *info, + struct device *dev, + struct device_node **of_cpu, + struct device_node **of_codec, + struct device_node **of_platform) +{ + struct device_node *np; + char *name; + int ret = 0; + + /* get CPU/CODEC common format via simple-audio-card,format */ + info->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") & + (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK); + + /* CPU sub-node */ + ret = -EINVAL; + np = of_get_child_by_name(node, "simple-audio-card,cpu"); + if (np) + ret = asoc_simple_card_sub_parse_of(np, + &info->cpu_dai, + of_cpu); + if (ret < 0) + return ret; + + /* CODEC sub-node */ + ret = -EINVAL; + np = of_get_child_by_name(node, "simple-audio-card,codec"); + if (np) + ret = asoc_simple_card_sub_parse_of(np, + &info->codec_dai, + of_codec); + if (ret < 0) + return ret; + + /* card name is created from CPU/CODEC dai name */ + name = devm_kzalloc(dev, + strlen(info->cpu_dai.name) + + strlen(info->codec_dai.name) + 2, + GFP_KERNEL); + sprintf(name, "%s-%s", info->cpu_dai.name, info->codec_dai.name); + info->name = info->card = name; + + /* simple-card assumes platform == cpu */ + *of_platform = *of_cpu; + + dev_dbg(dev, "card-name : %s\n", info->card); + dev_dbg(dev, "platform : %04x\n", info->daifmt); + dev_dbg(dev, "cpu : %s / %04x / %d\n", + info->cpu_dai.name, + info->cpu_dai.fmt, + info->cpu_dai.sysclk); + dev_dbg(dev, "codec : %s / %04x / %d\n", + info->codec_dai.name, + info->codec_dai.fmt, + info->codec_dai.sysclk); + + return 0; +} + static int asoc_simple_card_probe(struct platform_device *pdev) { - struct asoc_simple_card_info *cinfo = pdev->dev.platform_data; + struct asoc_simple_card_info *cinfo; + struct device_node *np = pdev->dev.of_node; + struct device_node *of_cpu, *of_codec, *of_platform; struct device *dev = &pdev->dev; + cinfo = NULL; + of_cpu = NULL; + of_codec = NULL; + of_platform = NULL; + if (np && of_device_is_available(np)) { + cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL); + if (cinfo) { + int ret; + ret = asoc_simple_card_parse_of(np, cinfo, dev, + &of_cpu, + &of_codec, + &of_platform); + if (ret < 0) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "parse error %d\n", ret); + return ret; + } + } + } else { + cinfo = pdev->dev.platform_data; + } + if (!cinfo) { dev_err(dev, "no info for asoc-simple-card\n"); return -EINVAL; @@ -69,10 +203,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (!cinfo->name || !cinfo->card || - !cinfo->codec || - !cinfo->platform || - !cinfo->cpu_dai.name || - !cinfo->codec_dai.name) { + !cinfo->codec_dai.name || + !(cinfo->codec || of_codec) || + !(cinfo->platform || of_platform) || + !(cinfo->cpu_dai.name || of_cpu)) { dev_err(dev, "insufficient asoc_simple_card_info settings\n"); return -EINVAL; } @@ -86,6 +220,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) cinfo->snd_link.platform_name = cinfo->platform; cinfo->snd_link.codec_name = cinfo->codec; cinfo->snd_link.codec_dai_name = cinfo->codec_dai.name; + cinfo->snd_link.cpu_of_node = of_cpu; + cinfo->snd_link.codec_of_node = of_codec; + cinfo->snd_link.platform_of_node = of_platform; cinfo->snd_link.init = asoc_simple_card_dai_init; /* @@ -107,10 +244,17 @@ static int asoc_simple_card_remove(struct platform_device *pdev) return snd_soc_unregister_card(&cinfo->snd_card); } +static const struct of_device_id asoc_simple_of_match[] = { + { .compatible = "simple-audio-card", }, + {}, +}; +MODULE_DEVICE_TABLE(of, asoc_simple_of_match); + static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card", .owner = THIS_MODULE, + .of_match_table = asoc_simple_of_match, }, .probe = asoc_simple_card_probe, .remove = asoc_simple_card_remove, -- cgit v1.2.3 From 066602943521d64f8ac5e6824fdd91580024b44d Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 6 Nov 2013 13:18:25 -0800 Subject: DocBook: include !Emm/util.c in kernel-api to include, kzfree and more Add the exported symbols from mm/util.c to the kernel-api memory management section, to pick up obvious routines like kzfree and krealloc. Signed-off-by: Robert P. J. Day Acked-by: Rob Landley Signed-off-by: Jiri Kosina --- Documentation/DocBook/kernel-api.tmpl | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index f75ab4c1b281..ecfd0ea40661 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -109,6 +109,7 @@ X!Ilib/string.c The Slab Cache !Iinclude/linux/slab.h !Emm/slab.c +!Emm/util.c User Space Memory Access !Iarch/x86/include/asm/uaccess_32.h -- cgit v1.2.3 From c79a8d85d7f540e9dbe3e3111c41d14395a0c9e2 Mon Sep 17 00:00:00 2001 From: Xishi Qiu Date: Wed, 6 Nov 2013 13:18:21 -0800 Subject: doc: fix some typos in documentations Fix some typos in five documentations, no functional change. Signed-off-by: Xishi Qiu Acked-by: Rob Landley Signed-off-by: Jiri Kosina --- Documentation/md.txt | 2 +- Documentation/rfkill.txt | 2 +- Documentation/rt-mutex-design.txt | 2 +- Documentation/static-keys.txt | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/md.txt b/Documentation/md.txt index fbb2fcbf16b6..f925666e4342 100644 --- a/Documentation/md.txt +++ b/Documentation/md.txt @@ -533,7 +533,7 @@ also have found. The count in 'mismatch_cnt' is the number of sectors that were re-written, or (for 'check') would have been re-written. As most raid levels work in units of pages rather - than sectors, this my be larger than the number of actual errors + than sectors, this may be larger than the number of actual errors by a factor of the number of sectors in a page. bitmap_set_bits diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index 03c9d9299c6b..f430004df73c 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt @@ -71,7 +71,7 @@ To create an rfkill driver, driver's Kconfig needs to have depends on RFKILL || !RFKILL to ensure the driver cannot be built-in when rfkill is modular. The !RFKILL -case allows the driver to be built when rfkill is not configured, which which +case allows the driver to be built when rfkill is not configured, which case all rfkill API can still be used but will be provided by static inlines which compile to almost nothing. diff --git a/Documentation/rt-mutex-design.txt b/Documentation/rt-mutex-design.txt index a5bcd7f5c33f..8666070d3189 100644 --- a/Documentation/rt-mutex-design.txt +++ b/Documentation/rt-mutex-design.txt @@ -30,7 +30,7 @@ is something called unbounded priority inversion. That is when the high priority process is prevented from running by a lower priority process for an undetermined amount of time. -The classic example of unbounded priority inversion is were you have three +The classic example of unbounded priority inversion is where you have three processes, let's call them processes A, B, and C, where A is the highest priority process, C is the lowest, and B is in between. A tries to grab a lock that C owns and must wait and lets C run to release the lock. But in the diff --git a/Documentation/static-keys.txt b/Documentation/static-keys.txt index 9f5263d3152c..c4407a41b0fc 100644 --- a/Documentation/static-keys.txt +++ b/Documentation/static-keys.txt @@ -116,7 +116,7 @@ The branch(es) can then be switched via: static_key_slow_dec(&key); Thus, 'static_key_slow_inc()' means 'make the branch true', and -'static_key_slow_dec()' means 'make the the branch false' with appropriate +'static_key_slow_dec()' means 'make the branch false' with appropriate reference counting. For example, if the key is initialized true, a static_key_slow_dec(), will switch the branch to false. And a subsequent static_key_slow_inc(), will change the branch back to true. Likewise, if the @@ -236,7 +236,7 @@ label case adds: If we then include the padding bytes, the jump label code saves, 16 total bytes of instruction memory for this small function. In this case the non-jump label -function is 80 bytes long. Thus, we have have saved 20% of the instruction +function is 80 bytes long. Thus, we have saved 20% of the instruction footprint. We can in fact improve this even further, since the 5-byte no-op really can be a 2-byte no-op since we can reach the branch with a 2-byte jmp. However, we have not yet implemented optimal no-op sizes (they are currently -- cgit v1.2.3 From c4d79a4799719f2b0cd354ee498aad605730c97e Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 6 Nov 2013 13:18:27 -0800 Subject: work around xmlto bug in htmldocs Trying to generate xhtml causes all functions to show up with a prefix of "fsfunc" in the output, so just back off to html until someone fixes the toolchain. Note that this is not a problem with kernel-doc, it's an issue with however "xmlto" renders xhtml output. Signed-off-by: Robert P. J. Day Acked-by: Rob Landley Signed-off-by: Jiri Kosina --- Documentation/DocBook/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index bc3d9f8c0a90..5cf621b78c5e 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -145,7 +145,7 @@ build_main_index = rm -rf $(main_idx); \ cat $(HTML) >> $(main_idx) quiet_cmd_db2html = HTML $@ - cmd_db2html = xmlto xhtml $(XMLTOFLAGS) -o $(patsubst %.html,%,$@) $< && \ + cmd_db2html = xmlto html $(XMLTOFLAGS) -o $(patsubst %.html,%,$@) $< && \ echo ' \ $(patsubst %.html,%,$(notdir $@))

' > $@ -- cgit v1.2.3 From 832919bfcf0cfd75767c68b0c61f7cf48be860a8 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 6 Nov 2013 13:18:30 -0800 Subject: DocBook: Make mandocs parallel-safe Two concurrent calls to cmd_db2man may attempt to compress manual pages generated by each other. gzip can then fail due to an input file having already been compressed and removed. Move the gzip command to the top-level mandocs target. Signed-off-by: Ben Hutchings Cc: Bastian Blank Acked-by: Rob Landley Signed-off-by: Jiri Kosina --- Documentation/DocBook/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 5cf621b78c5e..0f9c6ff41aac 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -54,6 +54,7 @@ htmldocs: $(HTML) MAN := $(patsubst %.xml, %.9, $(BOOKS)) mandocs: $(MAN) + $(if $(wildcard $(obj)/man/*.9),gzip -f $(obj)/man/*.9) installmandocs: mandocs mkdir -p /usr/local/man/man9/ @@ -159,7 +160,7 @@ quiet_cmd_db2html = HTML $@ cp $(PNG-$(basename $(notdir $@))) $(patsubst %.html,%,$@); fi quiet_cmd_db2man = MAN $@ - cmd_db2man = if grep -q refentry $<; then xmlto man $(XMLTOFLAGS) -o $(obj)/man $< ; gzip -f $(obj)/man/*.9; fi + cmd_db2man = if grep -q refentry $<; then xmlto man $(XMLTOFLAGS) -o $(obj)/man $< ; fi %.9 : %.xml @(which xmlto > /dev/null 2>&1) || \ (echo "*** You need to install xmlto ***"; \ -- cgit v1.2.3 From 0899d6ac4677efc6839a4532adcaeb772021f38d Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Wed, 6 Nov 2013 13:18:28 -0800 Subject: documentation: Add links to TRACE_EVENT documentation documentation: Add links to TRACE_EVENT documentation Existing tracepoint documentation doesn't mention the popular TRACE_EVENT macro. Since an excellent series of articles on proper usage already exists, respective links are added to the existing documentation. Signed-off-by: Stefan Raspl Acked-by: Rob Landley Signed-off-by: Jiri Kosina --- Documentation/trace/tracepoints.txt | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Documentation') diff --git a/Documentation/trace/tracepoints.txt b/Documentation/trace/tracepoints.txt index ac4170dd0f24..6b018b53177a 100644 --- a/Documentation/trace/tracepoints.txt +++ b/Documentation/trace/tracepoints.txt @@ -114,3 +114,8 @@ core kernel image or in modules. If the tracepoint has to be used in kernel modules, an EXPORT_TRACEPOINT_SYMBOL_GPL() or EXPORT_TRACEPOINT_SYMBOL() can be used to export the defined tracepoints. + +Note: The convenience macro TRACE_EVENT provides an alternative way to + define tracepoints. Check http://lwn.net/Articles/379903, + http://lwn.net/Articles/381064 and http://lwn.net/Articles/383362 + for a series of articles with more details. -- cgit v1.2.3 From ff18dd8f1c7579d8b013705877c9bf4260770822 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 6 Nov 2013 13:18:22 -0800 Subject: Documentation: Update x86_64/boot-options.txt Removed obsolte parameters from boot-options.txt. Verified by grepping around in arch/x86/. Signed-off-by: Richard Weinberger Acked-by: Rob Landley Signed-off-by: Jiri Kosina --- Documentation/x86/x86_64/boot-options.txt | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'Documentation') diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt index 1228b22e142b..5223479291a2 100644 --- a/Documentation/x86/x86_64/boot-options.txt +++ b/Documentation/x86/x86_64/boot-options.txt @@ -78,14 +78,6 @@ APICs no_timer_check Don't check the IO-APIC timer. This can work around problems with incorrect timer initialization on some boards. - - apicmaintimer Run time keeping from the local APIC timer instead - of using the PIT/HPET interrupt for this. This is useful - when the PIT/HPET interrupts are unreliable. - - noapicmaintimer Don't do time keeping using the APIC timer. - Useful when this option was auto selected, but doesn't work. - apicpmtimer Do APIC timer calibration using the pmtimer. Implies apicmaintimer. Useful when your PIT timer is totally @@ -144,11 +136,6 @@ Non Executable Mappings on Enable(default) off Disable -SMP - - additional_cpus=NUM Allow NUM more CPUs for hotplug - (defaults are specified by the BIOS, see Documentation/x86/x86_64/cpu-hotplug-spec) - NUMA numa=off Only set up a single NUMA node spanning all memory. @@ -289,16 +276,6 @@ Debugging kstack=N Print N words from the kernel stack in oops dumps. - pagefaulttrace Dump all page faults. Only useful for extreme debugging - and will create a lot of output. - - call_trace=[old|both|newfallback|new] - old: use old inexact backtracer - new: use new exact dwarf2 unwinder - both: print entries from both - newfallback: use new unwinder but fall back to old if it gets - stuck (default) - Miscellaneous nogbpages -- cgit v1.2.3 From d9a6ed1fa43859a5eb94725b6c9565f8cbd113ab Mon Sep 17 00:00:00 2001 From: Xishi Qiu Date: Wed, 6 Nov 2013 13:18:19 -0800 Subject: doc: fix some typos Fix some typos in three documentations. Signed-off-by: Xishi Qiu Acked-by: Rob Landley Signed-off-by: Jiri Kosina --- Documentation/IRQ-domain.txt | 2 +- Documentation/email-clients.txt | 2 +- Documentation/io-mapping.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/IRQ-domain.txt b/Documentation/IRQ-domain.txt index 9bc95942ec22..03df71aeb38c 100644 --- a/Documentation/IRQ-domain.txt +++ b/Documentation/IRQ-domain.txt @@ -141,7 +141,7 @@ will use a legacy domain only if an IRQ range is supplied by the system and will otherwise use a linear domain mapping. The semantics of this call are such that if an IRQ range is specified then descriptors will be allocated on-the-fly for it, and if no range is -specified it will fall through to irq_domain_add_linear() which meand +specified it will fall through to irq_domain_add_linear() which means *no* irq descriptors will be allocated. A typical use case for simple domains is where an irqchip provider diff --git a/Documentation/email-clients.txt b/Documentation/email-clients.txt index 860c29a472ad..e9f5daccbd02 100644 --- a/Documentation/email-clients.txt +++ b/Documentation/email-clients.txt @@ -104,7 +104,7 @@ Then from the "Message" menu item, select insert file and choose your patch. As an added bonus you can customise the message creation toolbar menu and put the "insert file" icon there. -Make the the composer window wide enough so that no lines wrap. As of +Make the composer window wide enough so that no lines wrap. As of KMail 1.13.5 (KDE 4.5.4), KMail will apply word wrapping when sending the email if the lines wrap in the composer window. Having word wrapping disabled in the Options menu isn't enough. Thus, if your patch has very diff --git a/Documentation/io-mapping.txt b/Documentation/io-mapping.txt index 473e43b2d588..5ca78426f54c 100644 --- a/Documentation/io-mapping.txt +++ b/Documentation/io-mapping.txt @@ -38,7 +38,7 @@ maps are more efficient: void io_mapping_unmap_atomic(void *vaddr) - 'vaddr' must be the the value returned by the last + 'vaddr' must be the value returned by the last io_mapping_map_atomic_wc call. This unmaps the specified page and allows the task to sleep once again. -- cgit v1.2.3 From ac6d662a95a6989d83b259ccf8ec01dd7903af73 Mon Sep 17 00:00:00 2001 From: ZHAO Gang Date: Wed, 6 Nov 2013 13:18:15 -0800 Subject: doc: Add "*.svg" to DocBook/.gitignore Mauro add "*.png" and "*.gif" in DocBook/.gitignore in commit 6d172492, but forgot to add "*.svg", this made git unnecessary to track directory DocBook/media_api generated by `make htmldocs`: $ git status # On branch master # Untracked files: # (use "git add ..." to include in what will be committed) # # Documentation/DocBook/media_api/ nothing added to commit but untracked files present (use "git add" to track) Add "*.svg" to DocBook/.gitignore so git will not track directory DocBook/media_api, since there is no file in that directory it interest in. Signed-off-by: ZHAO Gang Acked-by: Rob Landley Signed-off-by: Jiri Kosina --- Documentation/DocBook/.gitignore | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/.gitignore b/Documentation/DocBook/.gitignore index 720f245ceb1f..7ebd5465d927 100644 --- a/Documentation/DocBook/.gitignore +++ b/Documentation/DocBook/.gitignore @@ -10,5 +10,6 @@ *.out *.png *.gif +*.svg media-indices.tmpl media-entities.tmpl -- cgit v1.2.3 From ca0bdbb5fd0ed9ac024c74f563bed7571eae304c Mon Sep 17 00:00:00 2001 From: Qiang Huang Date: Wed, 6 Nov 2013 13:18:09 -0800 Subject: cgroup, doc: make cgroup_disable doc more accurate In doc, it said that 'Currently supported controllers - "memory"', but actually we can use cgroup_disable=cpu,cpuset and all other controllers, so this is confusing for cgroup users without much cgroup knowledge. We need to make it clear. [some comments copied from Paul Menage's original patch 8bab8dded] Signed-off-by: Qiang Huang Acked-by: Rob Landley Signed-off-by: Jiri Kosina --- Documentation/kernel-parameters.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 479eeaf44024..5589f4dbc12f 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -511,7 +511,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted. cgroup_disable= [KNL] Disable a particular controller Format: {name of the controller(s) to disable} - {Currently supported controllers - "memory"} + The effects of cgroup_disable=foo are: + - foo isn't auto-mounted if you mount all cgroups in + a single hierarchy + - foo isn't visible as an individually mountable + subsystem + {Currently only "memory" controller deal with this and + cut the overhead, others just disable the usage. So + only cgroup_disable=memory is actually worthy} checkreqprot [SELINUX] Set initial checkreqprot flag value. Format: { "0" | "1" } -- cgit v1.2.3 From 32f955c6da20af07ffb059c060ea2e8f15a2bbb9 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Fri, 11 Oct 2013 13:38:52 +0200 Subject: dt: binding: add at91 clks dt bindings documentation This patch adds new at91 clks dt bindings documentation. Signed-off-by: Boris BREZILLON Acked-by: Mike Turquette Signed-off-by: Nicolas Ferre --- .../devicetree/bindings/clock/at91-clock.txt | 339 +++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/at91-clock.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt new file mode 100644 index 000000000000..cd5e23912888 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/at91-clock.txt @@ -0,0 +1,339 @@ +Device Tree Clock bindings for arch-at91 + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of the following: + "atmel,at91rm9200-pmc" or + "atmel,at91sam9g45-pmc" or + "atmel,at91sam9n12-pmc" or + "atmel,at91sam9x5-pmc" or + "atmel,sama5d3-pmc": + at91 PMC (Power Management Controller) + All at91 specific clocks (clocks defined below) must be child + node of the PMC node. + + "atmel,at91rm9200-clk-main": + at91 main oscillator + + "atmel,at91rm9200-clk-master" or + "atmel,at91sam9x5-clk-master": + at91 master clock + + "atmel,at91sam9x5-clk-peripheral" or + "atmel,at91rm9200-clk-peripheral": + at91 peripheral clocks + + "atmel,at91rm9200-clk-pll" or + "atmel,at91sam9g45-clk-pll" or + "atmel,at91sam9g20-clk-pllb" or + "atmel,sama5d3-clk-pll": + at91 pll clocks + + "atmel,at91sam9x5-clk-plldiv": + at91 plla divisor + + "atmel,at91rm9200-clk-programmable" or + "atmel,at91sam9g45-clk-programmable" or + "atmel,at91sam9x5-clk-programmable": + at91 programmable clocks + + "atmel,at91sam9x5-clk-smd": + at91 SMD (Soft Modem) clock + + "atmel,at91rm9200-clk-system": + at91 system clocks + + "atmel,at91rm9200-clk-usb" or + "atmel,at91sam9x5-clk-usb" or + "atmel,at91sam9n12-clk-usb": + at91 usb clock + + "atmel,at91sam9x5-clk-utmi": + at91 utmi clock + +Required properties for PMC node: +- reg : defines the IO memory reserved for the PMC. +- #size-cells : shall be 0 (reg is used to encode clk id). +- #address-cells : shall be 1 (reg is used to encode clk id). +- interrupts : shall be set to PMC interrupt line. +- interrupt-controller : tell that the PMC is an interrupt controller. +- #interrupt-cells : must be set to 1. The first cell encodes the interrupt id, + and reflect the bit position in the PMC_ER/DR/SR registers. + You can use the dt macros defined in dt-bindings/clk/at91.h. + 0 (AT91_PMC_MOSCS) -> main oscillator ready + 1 (AT91_PMC_LOCKA) -> PLL A ready + 2 (AT91_PMC_LOCKB) -> PLL B ready + 3 (AT91_PMC_MCKRDY) -> master clock ready + 6 (AT91_PMC_LOCKU) -> UTMI PLL clock ready + 8 .. 15 (AT91_PMC_PCKRDY(id)) -> programmable clock ready + 16 (AT91_PMC_MOSCSELS) -> main oscillator selected + 17 (AT91_PMC_MOSCRCS) -> RC main oscillator stabilized + 18 (AT91_PMC_CFDEV) -> clock failure detected + +For example: + pmc: pmc@fffffc00 { + compatible = "atmel,sama5d3-pmc"; + interrupts = <1 4 7>; + interrupt-controller; + #interrupt-cells = <2>; + #size-cells = <0>; + #address-cells = <1>; + + /* put at91 clocks here */ + }; + +Required properties for main clock: +- interrupt-parent : must reference the PMC node. +- interrupts : shall be set to "<0>". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks (optional if clock-frequency is provided) : shall be the slow clock + phandle. This clock is used to calculate the main clock rate if + "clock-frequency" is not provided. +- clock-frequency : the main oscillator frequency.Prefer the use of + "clock-frequency" over automatic clock rate calculation. + +For example: + main: mainck { + compatible = "atmel,at91rm9200-clk-main"; + interrupt-parent = <&pmc>; + interrupts = <0>; + #clock-cells = <0>; + clocks = <&ck32k>; + clock-frequency = <18432000>; + }; + +Required properties for master clock: +- interrupt-parent : must reference the PMC node. +- interrupts : shall be set to "<3>". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the master clock sources (see atmel datasheet) phandles. + e.g. "<&ck32k>, <&main>, <&plla>, <&pllb>". +- atmel,clk-output-range : minimum and maximum clock frequency (two u32 + fields). + e.g. output = <0 133000000>; <=> 0 to 133MHz. +- atmel,clk-divisors : master clock divisors table (four u32 fields). + 0 <=> reserved value. + e.g. divisors = <1 2 4 6>; +- atmel,master-clk-have-div3-pres : some SoC use the reserved value 7 in the + PRES field as CLOCK_DIV3 (e.g sam9x5). + +For example: + mck: mck { + compatible = "atmel,at91rm9200-clk-master"; + interrupt-parent = <&pmc>; + interrupts = <3>; + #clock-cells = <0>; + atmel,clk-output-range = <0 133000000>; + atmel,clk-divisors = <1 2 4 0>; + }; + +Required properties for peripheral clocks: +- #size-cells : shall be 0 (reg is used to encode clk id). +- #address-cells : shall be 1 (reg is used to encode clk id). +- clocks : shall be the master clock phandle. + e.g. clocks = <&mck>; +- name: device tree node describing a specific system clock. + * #clock-cells : from common clock binding; shall be set to 0. + * reg: peripheral id. See Atmel's datasheets to get a full + list of peripheral ids. + * atmel,clk-output-range : minimum and maximum clock frequency + (two u32 fields). Only valid on at91sam9x5-clk-peripheral + compatible IPs. + +For example: + periph: periphck { + compatible = "atmel,at91sam9x5-clk-peripheral"; + #size-cells = <0>; + #address-cells = <1>; + clocks = <&mck>; + + ssc0_clk { + #clock-cells = <0>; + reg = <2>; + atmel,clk-output-range = <0 133000000>; + }; + + usart0_clk { + #clock-cells = <0>; + reg = <3>; + atmel,clk-output-range = <0 66000000>; + }; + }; + + +Required properties for pll clocks: +- interrupt-parent : must reference the PMC node. +- interrupts : shall be set to "<1>". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the main clock phandle. +- reg : pll id. + 0 -> PLL A + 1 -> PLL B +- atmel,clk-input-range : minimum and maximum source clock frequency (two u32 + fields). + e.g. input = <1 32000000>; <=> 1 to 32MHz. +- #atmel,pll-clk-output-range-cells : number of cells reserved for pll output + range description. Sould be set to 2, 3 + or 4. + * 1st and 2nd cells represent the frequency range (min-max). + * 3rd cell is optional and represents the OUT field value for the given + range. + * 4th cell is optional and represents the ICPLL field (PLLICPR + register) +- atmel,pll-clk-output-ranges : pll output frequency ranges + optional parameter + depending on #atmel,pll-output-range-cells + property value. + +For example: + plla: pllack { + compatible = "atmel,at91sam9g45-clk-pll"; + interrupt-parent = <&pmc>; + interrupts = <1>; + #clock-cells = <0>; + clocks = <&main>; + reg = <0>; + atmel,clk-input-range = <2000000 32000000>; + #atmel,pll-clk-output-range-cells = <4>; + atmel,pll-clk-output-ranges = <74500000 800000000 0 0 + 69500000 750000000 1 0 + 64500000 700000000 2 0 + 59500000 650000000 3 0 + 54500000 600000000 0 1 + 49500000 550000000 1 1 + 44500000 500000000 2 1 + 40000000 450000000 3 1>; + }; + +Required properties for plldiv clocks (plldiv = pll / 2): +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the plla clock phandle. + +The pll divisor is equal to 2 and cannot be changed. + +For example: + plladiv: plladivck { + compatible = "atmel,at91sam9x5-clk-plldiv"; + #clock-cells = <0>; + clocks = <&plla>; + }; + +Required properties for programmable clocks: +- interrupt-parent : must reference the PMC node. +- #size-cells : shall be 0 (reg is used to encode clk id). +- #address-cells : shall be 1 (reg is used to encode clk id). +- clocks : shall be the programmable clock source phandles. + e.g. clocks = <&clk32k>, <&main>, <&plla>, <&pllb>; +- name: device tree node describing a specific prog clock. + * #clock-cells : from common clock binding; shall be set to 0. + * reg : programmable clock id (register offset from PCKx + register). + * interrupts : shall be set to "<(8 + id)>". + +For example: + prog: progck { + compatible = "atmel,at91sam9g45-clk-programmable"; + #size-cells = <0>; + #address-cells = <1>; + interrupt-parent = <&pmc>; + clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>; + + prog0 { + #clock-cells = <0>; + reg = <0>; + interrupts = <8>; + }; + + prog1 { + #clock-cells = <0>; + reg = <1>; + interrupts = <9>; + }; + }; + + +Required properties for smd clock: +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the smd clock source phandles. + e.g. clocks = <&plladiv>, <&utmi>; + +For example: + smd: smdck { + compatible = "atmel,at91sam9x5-clk-smd"; + #clock-cells = <0>; + clocks = <&plladiv>, <&utmi>; + }; + +Required properties for system clocks: +- #size-cells : shall be 0 (reg is used to encode clk id). +- #address-cells : shall be 1 (reg is used to encode clk id). +- name: device tree node describing a specific system clock. + * #clock-cells : from common clock binding; shall be set to 0. + * reg: system clock id (bit position in SCER/SCDR/SCSR registers). + See Atmel's datasheet to get a full list of system clock ids. + +For example: + system: systemck { + compatible = "atmel,at91rm9200-clk-system"; + #address-cells = <1>; + #size-cells = <0>; + + ddrck { + #clock-cells = <0>; + reg = <2>; + clocks = <&mck>; + }; + + uhpck { + #clock-cells = <0>; + reg = <6>; + clocks = <&usb>; + }; + + udpck { + #clock-cells = <0>; + reg = <7>; + clocks = <&usb>; + }; + }; + + +Required properties for usb clock: +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the smd clock source phandles. + e.g. clocks = <&pllb>; +- atmel,clk-divisors (only available for "atmel,at91rm9200-clk-usb"): + usb clock divisor table. + e.g. divisors = <1 2 4 0>; + +For example: + usb: usbck { + compatible = "atmel,at91sam9x5-clk-usb"; + #clock-cells = <0>; + clocks = <&plladiv>, <&utmi>; + }; + + usb: usbck { + compatible = "atmel,at91rm9200-clk-usb"; + #clock-cells = <0>; + clocks = <&pllb>; + atmel,clk-divisors = <1 2 4 0>; + }; + + +Required properties for utmi clock: +- interrupt-parent : must reference the PMC node. +- interrupts : shall be set to "". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the main clock source phandle. + +For example: + utmi: utmick { + compatible = "atmel,at91sam9x5-clk-utmi"; + interrupt-parent = <&pmc>; + interrupts = ; + #clock-cells = <0>; + clocks = <&main>; + }; -- cgit v1.2.3 From 80361fa02e59cbc4ddfd4ceae18441092797149f Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Fri, 8 Nov 2013 16:09:30 +0400 Subject: libata, dt: Document sata_rcar bindings These bindings can be used to register SATA devices found on R-Car SoC. Signed-off-by: Valentine Barshak Signed-off-by: Tejun Heo --- Documentation/devicetree/bindings/ata/sata_rcar.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Documentation/devicetree/bindings/ata/sata_rcar.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/ata/sata_rcar.txt b/Documentation/devicetree/bindings/ata/sata_rcar.txt new file mode 100644 index 000000000000..1e6111333fa8 --- /dev/null +++ b/Documentation/devicetree/bindings/ata/sata_rcar.txt @@ -0,0 +1,18 @@ +* Renesas R-Car SATA + +Required properties: +- compatible : should contain one of the following: + - "renesas,sata-r8a7779" for R-Car H1 + - "renesas,sata-r8a7790" for R-Car H2 + - "renesas,sata-r8a7791" for R-Car M2 +- reg : address and length of the SATA registers; +- interrupts : must consist of one interrupt specifier. + +Example: + +sata: sata@fc600000 { + compatible = "renesas,sata-r8a7779"; + reg = <0xfc600000 0x2000>; + interrupt-parent = <&gic>; + interrupts = <0 100 IRQ_TYPE_LEVEL_HIGH>; +}; -- cgit v1.2.3 From 612575255635f67f09f6261114f58965f2062584 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 29 Nov 2013 21:14:57 +0100 Subject: gpio: rcar: Add r8a7791 support to the DT bindings The r8a7791 (R-Car M2) has a GPIO controller with additional features compared to the generic renesas,gpio-rcar compatible devices. Add a model-specific string to let the driver enable these features. Signed-off-by: Laurent Pinchart Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt index 8655df9440d5..f61cef74a212 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt +++ b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt @@ -2,10 +2,11 @@ Required Properties: - - compatible: should be one of the following. + - compatible: should contain one of the following. - "renesas,gpio-r8a7778": for R8A7778 (R-Mobile M1) compatible GPIO controller. - "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller. - "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller. + - "renesas,gpio-r8a7791": for R8A7791 (R-Car M2) compatible GPIO controller. - "renesas,gpio-rcar": for generic R-Car GPIO controller. - reg: Base address and length of each memory resource used by the GPIO -- cgit v1.2.3 From 0299b77b44531ae0963fe86d8b9cb9b5ddb584b7 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Fri, 29 Nov 2013 12:11:34 +0100 Subject: gpio: Add MOXA ART GPIO driver Add GPIO driver for MOXA ART SoCs. Signed-off-by: Jonas Jensen Acked-by: Arnd Bergmann Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/moxa,moxart-gpio.txt | 19 +++ drivers/gpio/Kconfig | 7 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-moxart.c | 162 +++++++++++++++++++++ 4 files changed, 189 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/moxa,moxart-gpio.txt create mode 100644 drivers/gpio/gpio-moxart.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpio/moxa,moxart-gpio.txt b/Documentation/devicetree/bindings/gpio/moxa,moxart-gpio.txt new file mode 100644 index 000000000000..f8e8f185a3db --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/moxa,moxart-gpio.txt @@ -0,0 +1,19 @@ +MOXA ART GPIO Controller + +Required properties: + +- #gpio-cells : Should be 2, The first cell is the pin number, + the second cell is used to specify polarity: + 0 = active high + 1 = active low +- compatible : Must be "moxa,moxart-gpio" +- reg : Should contain registers location and length + +Example: + + gpio: gpio@98700000 { + gpio-controller; + #gpio-cells = <2>; + compatible = "moxa,moxart-gpio"; + reg = <0x98700000 0xC>; + }; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 58d98dd9e4b9..ae3682d25a3c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -156,6 +156,13 @@ config GPIO_F7188X To compile this driver as a module, choose M here: the module will be called f7188x-gpio. +config GPIO_MOXART + bool "MOXART GPIO support" + depends on ARCH_MOXART + help + Select this option to enable GPIO driver for + MOXA ART SoC devices. + config GPIO_MPC5200 def_bool y depends on PPC_MPC52xx diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 7971e36b8b12..ee95154cb1d2 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o +obj-$(CONFIG_GPIO_MOXART) += gpio-moxart.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c new file mode 100644 index 000000000000..d662cdededac --- /dev/null +++ b/drivers/gpio/gpio-moxart.c @@ -0,0 +1,162 @@ +/* + * MOXA ART SoCs GPIO driver. + * + * Copyright (C) 2013 Jonas Jensen + * + * Jonas Jensen + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPIO_DATA_OUT 0x00 +#define GPIO_DATA_IN 0x04 +#define GPIO_PIN_DIRECTION 0x08 + +struct moxart_gpio_chip { + struct gpio_chip gpio; + void __iomem *moxart_gpio_base; +}; + +static inline struct moxart_gpio_chip *to_moxart_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct moxart_gpio_chip, gpio); +} + +static int moxart_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + return pinctrl_request_gpio(offset); +} + +static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + pinctrl_free_gpio(offset); +} + +static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + void __iomem *ioaddr = gc->moxart_gpio_base + GPIO_PIN_DIRECTION; + + writel(readl(ioaddr) & ~BIT(offset), ioaddr); + return 0; +} + +static int moxart_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + void __iomem *ioaddr = gc->moxart_gpio_base + GPIO_PIN_DIRECTION; + + writel(readl(ioaddr) | BIT(offset), ioaddr); + return 0; +} + +static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + void __iomem *ioaddr = gc->moxart_gpio_base + GPIO_DATA_OUT; + u32 reg = readl(ioaddr); + + if (value) + reg = reg | BIT(offset); + else + reg = reg & ~BIT(offset); + + + writel(reg, ioaddr); +} + +static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + u32 ret = readl(gc->moxart_gpio_base + GPIO_PIN_DIRECTION); + + if (ret & BIT(offset)) + return !!(readl(gc->moxart_gpio_base + GPIO_DATA_OUT) & + BIT(offset)); + else + return !!(readl(gc->moxart_gpio_base + GPIO_DATA_IN) & + BIT(offset)); +} + +static struct gpio_chip moxart_template_chip = { + .label = "moxart-gpio", + .request = moxart_gpio_request, + .free = moxart_gpio_free, + .direction_input = moxart_gpio_direction_input, + .direction_output = moxart_gpio_direction_output, + .set = moxart_gpio_set, + .get = moxart_gpio_get, + .base = 0, + .ngpio = 32, + .can_sleep = 0, +}; + +static int moxart_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct moxart_gpio_chip *mgc; + int ret; + + mgc = devm_kzalloc(dev, sizeof(*mgc), GFP_KERNEL); + if (!mgc) { + dev_err(dev, "can't allocate GPIO chip container\n"); + return -ENOMEM; + } + mgc->gpio = moxart_template_chip; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mgc->moxart_gpio_base = devm_ioremap_resource(dev, res); + if (IS_ERR(mgc->moxart_gpio_base)) { + dev_err(dev, "%s: devm_ioremap_resource res_gpio failed\n", + dev->of_node->full_name); + return PTR_ERR(mgc->moxart_gpio_base); + } + + mgc->gpio.dev = dev; + + ret = gpiochip_add(&mgc->gpio); + if (ret) { + dev_err(dev, "%s: gpiochip_add failed\n", + dev->of_node->full_name); + return ret; + } + + return 0; +} + +static const struct of_device_id moxart_gpio_match[] = { + { .compatible = "moxa,moxart-gpio" }, + { } +}; + +static struct platform_driver moxart_gpio_driver = { + .driver = { + .name = "moxart-gpio", + .owner = THIS_MODULE, + .of_match_table = moxart_gpio_match, + }, + .probe = moxart_gpio_probe, +}; +module_platform_driver(moxart_gpio_driver); + +MODULE_DESCRIPTION("MOXART GPIO chip driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jonas Jensen "); -- cgit v1.2.3 From 831eae69a855983099072e0c0e490bca6f02d54e Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 26 Nov 2013 18:58:01 -0700 Subject: staging: dwc2: set up all module params The DWC2 USB controller in the BCM2835 (Raspberry Pi) needs some non- default parameters. Select these based on the compatible value from the DT node. For all other HW, fall back to the default parameters currently in use. The values in params_bcm2835[] were posted to the mailing list by Paul quite some time ago. I made a couple of minor modifications since then; to set ahbcfg instead of ahb_single, and to set uframe_sched. Signed-off-by: Stephen Warren Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/staging/dwc2.txt | 4 +- drivers/staging/dwc2/platform.c | 58 ++++++++++++++++++---- 2 files changed, 51 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/staging/dwc2.txt b/Documentation/devicetree/bindings/staging/dwc2.txt index 1a1b7cfa4845..8b60e90efe33 100644 --- a/Documentation/devicetree/bindings/staging/dwc2.txt +++ b/Documentation/devicetree/bindings/staging/dwc2.txt @@ -2,7 +2,9 @@ Platform DesignWare HS OTG USB 2.0 controller ----------------------------------------------------- Required properties: -- compatible : "snps,dwc2" +- compatible : One of: + - brcm,bcm2835-usb: The DWC2 USB controller instance in the BCM2835 SoC. + - snps,dwc2: A generic DWC2 USB controller with default parameters. - reg : Should contain 1 register range (address and length) - interrupts : Should contain 1 interrupt diff --git a/drivers/staging/dwc2/platform.c b/drivers/staging/dwc2/platform.c index 4d9fac017044..28a78fe48453 100644 --- a/drivers/staging/dwc2/platform.c +++ b/drivers/staging/dwc2/platform.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include "core.h" @@ -46,6 +47,34 @@ static const char dwc2_driver_name[] = "dwc2"; +static const struct dwc2_core_params params_bcm2835 = { + .otg_cap = 0, /* HNP/SRP capable */ + .otg_ver = 0, /* 1.3 */ + .dma_enable = 1, + .dma_desc_enable = 0, + .speed = 0, /* High Speed */ + .enable_dynamic_fifo = 1, + .en_multiple_tx_fifo = 1, + .host_rx_fifo_size = 774, /* 774 DWORDs */ + .host_nperio_tx_fifo_size = 256, /* 256 DWORDs */ + .host_perio_tx_fifo_size = 512, /* 512 DWORDs */ + .max_transfer_size = 65535, + .max_packet_count = 511, + .host_channels = 8, + .phy_type = 1, /* UTMI */ + .phy_utmi_width = 8, /* 8 bits */ + .phy_ulpi_ddr = 0, /* Single */ + .phy_ulpi_ext_vbus = 0, + .i2c_enable = 0, + .ulpi_fs_ls = 0, + .host_support_fs_ls_low_power = 0, + .host_ls_low_power_phy_clk = 0, /* 48 MHz */ + .ts_dline = 0, + .reload_ctl = 0, + .ahbcfg = 0x10, + .uframe_sched = 1, +}; + /** * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the * DWC_otg driver @@ -66,6 +95,13 @@ static int dwc2_driver_remove(struct platform_device *dev) return 0; } +static const struct of_device_id dwc2_of_match_table[] = { + { .compatible = "brcm,bcm2835-usb", .data = ¶ms_bcm2835 }, + { .compatible = "snps,dwc2", .data = NULL }, + {}, +}; +MODULE_DEVICE_TABLE(of, dwc2_of_match_table); + /** * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg * driver @@ -80,14 +116,22 @@ static int dwc2_driver_remove(struct platform_device *dev) */ static int dwc2_driver_probe(struct platform_device *dev) { + const struct of_device_id *match; + const struct dwc2_core_params *params; + struct dwc2_core_params defparams; struct dwc2_hsotg *hsotg; struct resource *res; int retval; int irq; - struct dwc2_core_params params; - /* Default all params to autodetect */ - dwc2_set_all_params(¶ms, -1); + match = of_match_device(dwc2_of_match_table, &dev->dev); + if (match && match->data) { + params = match->data; + } else { + /* Default all params to autodetect */ + dwc2_set_all_params(&defparams, -1); + params = &defparams; + } hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL); if (!hsotg) @@ -118,7 +162,7 @@ static int dwc2_driver_probe(struct platform_device *dev) dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n", (unsigned long)res->start, hsotg->regs); - retval = dwc2_hcd_init(hsotg, irq, ¶ms); + retval = dwc2_hcd_init(hsotg, irq, params); if (retval) return retval; @@ -127,12 +171,6 @@ static int dwc2_driver_probe(struct platform_device *dev) return retval; } -static const struct of_device_id dwc2_of_match_table[] = { - { .compatible = "snps,dwc2" }, - {}, -}; -MODULE_DEVICE_TABLE(of, dwc2_of_match_table); - static struct platform_driver dwc2_platform_driver = { .driver = { .name = dwc2_driver_name, -- cgit v1.2.3 From 978f47d64365fa1659178e54c5106154c315b595 Mon Sep 17 00:00:00 2001 From: Martyn Welch Date: Fri, 8 Nov 2013 11:58:34 +0000 Subject: VME: Provide access to VME bus enumeration and fix vme_user match function The match function for vme_user is completely wrong. It will blindly bind against the first VME slot on each bus (at this point that would be just the first bus as the driver can only handle one bus). The original intention (before some major subsystem changes) was that the driver bind against the slot to which the bridge was attached in the VME system and to the bus(es) provided via the "bus" module parameter. To do this cleanly (i.e. without poking arround in the subsystems internal stuctures) a functionality has been added to provide access to the bus enumeration. Signed-off-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- Documentation/vme_api.txt | 10 ++++++++++ drivers/staging/vme/devices/vme_user.c | 13 ++++++++++--- drivers/vme/vme.c | 13 +++++++++++++ include/linux/vme.h | 1 + 4 files changed, 34 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/vme_api.txt b/Documentation/vme_api.txt index 856efa35f6e3..126a1f1d5151 100644 --- a/Documentation/vme_api.txt +++ b/Documentation/vme_api.txt @@ -394,3 +394,13 @@ Slot Detection This function returns the slot ID of the provided bridge. int vme_slot_get(struct vme_dev *dev); + + +Bus Detection +============= + +This function returns the bus ID of the provided bridge. + + int vme_bus_num(struct vme_dev *dev); + + diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index daec15565a43..caee906f9b38 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -663,9 +663,16 @@ err_nocard: static int vme_user_match(struct vme_dev *vdev) { - if (vdev->num >= VME_USER_BUS_MAX) - return 0; - return 1; + int i; + + int cur_bus = vme_bus_num(vdev); + int cur_slot = vme_slot_get(vdev); + + for (i = 0; i < bus_num; i++) + if ((cur_bus == bus[i]) && (cur_slot == vdev->num)) + return 1; + + return 0; } /* diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c index f6856b427496..8df5e4efc1ca 100644 --- a/drivers/vme/vme.c +++ b/drivers/vme/vme.c @@ -1293,6 +1293,19 @@ int vme_slot_get(struct vme_dev *vdev) } EXPORT_SYMBOL(vme_slot_get); +int vme_bus_num(struct vme_dev *vdev) +{ + struct vme_bridge *bridge; + + bridge = vdev->bridge; + if (bridge == NULL) { + pr_err("Can't find VME bus\n"); + return -EINVAL; + } + + return bridge->num; +} +EXPORT_SYMBOL(vme_bus_num); /* - Bridge Registration --------------------------------------------------- */ diff --git a/include/linux/vme.h b/include/linux/vme.h index c9d65bf14cec..4eb42c8f097d 100644 --- a/include/linux/vme.h +++ b/include/linux/vme.h @@ -165,6 +165,7 @@ int vme_lm_detach(struct vme_resource *, int); void vme_lm_free(struct vme_resource *); int vme_slot_get(struct vme_dev *); +int vme_bus_num(struct vme_dev *); int vme_register_driver(struct vme_driver *, unsigned int); void vme_unregister_driver(struct vme_driver *); -- cgit v1.2.3 From d7729f0fc40296f91b483dfb929e71b27cf75345 Mon Sep 17 00:00:00 2001 From: Martyn Welch Date: Fri, 8 Nov 2013 11:58:35 +0000 Subject: VME: Rename vme_slot_get to avoid confusion with reference counting Traditionally the "get" functions increment the reference count of the object that is returned, which does not happen with vme_slot_get. The function vme_slot_get returns the physical VME slot associated with a particular struct vme_dev. Rename vme_slot_num to avoid any confusion. Signed-off-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- Documentation/vme_api.txt | 2 +- drivers/staging/vme/devices/vme_user.c | 2 +- drivers/vme/vme.c | 6 +++--- include/linux/vme.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/vme_api.txt b/Documentation/vme_api.txt index 126a1f1d5151..ffe6e22a2ccd 100644 --- a/Documentation/vme_api.txt +++ b/Documentation/vme_api.txt @@ -393,7 +393,7 @@ Slot Detection This function returns the slot ID of the provided bridge. - int vme_slot_get(struct vme_dev *dev); + int vme_slot_num(struct vme_dev *dev); Bus Detection diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index caee906f9b38..bc4f8623c8cc 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -666,7 +666,7 @@ static int vme_user_match(struct vme_dev *vdev) int i; int cur_bus = vme_bus_num(vdev); - int cur_slot = vme_slot_get(vdev); + int cur_slot = vme_slot_num(vdev); for (i = 0; i < bus_num; i++) if ((cur_bus == bus[i]) && (cur_slot == vdev->num)) diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c index 8df5e4efc1ca..96562c9a8b1b 100644 --- a/drivers/vme/vme.c +++ b/drivers/vme/vme.c @@ -1274,7 +1274,7 @@ void vme_lm_free(struct vme_resource *resource) } EXPORT_SYMBOL(vme_lm_free); -int vme_slot_get(struct vme_dev *vdev) +int vme_slot_num(struct vme_dev *vdev) { struct vme_bridge *bridge; @@ -1285,13 +1285,13 @@ int vme_slot_get(struct vme_dev *vdev) } if (bridge->slot_get == NULL) { - printk(KERN_WARNING "vme_slot_get not supported\n"); + printk(KERN_WARNING "vme_slot_num not supported\n"); return -EINVAL; } return bridge->slot_get(bridge); } -EXPORT_SYMBOL(vme_slot_get); +EXPORT_SYMBOL(vme_slot_num); int vme_bus_num(struct vme_dev *vdev) { diff --git a/include/linux/vme.h b/include/linux/vme.h index 4eb42c8f097d..8cd6f19ca518 100644 --- a/include/linux/vme.h +++ b/include/linux/vme.h @@ -164,7 +164,7 @@ int vme_lm_attach(struct vme_resource *, int, void (*callback)(int)); int vme_lm_detach(struct vme_resource *, int); void vme_lm_free(struct vme_resource *); -int vme_slot_get(struct vme_dev *); +int vme_slot_num(struct vme_dev *); int vme_bus_num(struct vme_dev *); int vme_register_driver(struct vme_driver *, unsigned int); -- cgit v1.2.3 From 59f0ad8076816d13f7cba80d2b178ff5ab787e2e Mon Sep 17 00:00:00 2001 From: Sergio Aguirre Date: Mon, 24 Jan 2011 15:48:19 -0300 Subject: [media] v4l: omap4iss: Add support for OMAP4 camera interface - Core This adds a very simplistic driver to utilize the CSI2A interface inside the ISS subsystem in OMAP4, and dump the data to memory. Check Documentation/video4linux/omap4_camera.txt for details. This commit adds the driver core, registers definitions and documentation. Signed-off-by: Sergio Aguirre Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/omap4_camera.txt | 60 ++ drivers/staging/media/omap4iss/iss.c | 1477 ++++++++++++++++++++++++++++ drivers/staging/media/omap4iss/iss.h | 153 +++ drivers/staging/media/omap4iss/iss_regs.h | 883 +++++++++++++++++ include/media/omap4iss.h | 65 ++ 5 files changed, 2638 insertions(+) create mode 100644 Documentation/video4linux/omap4_camera.txt create mode 100644 drivers/staging/media/omap4iss/iss.c create mode 100644 drivers/staging/media/omap4iss/iss.h create mode 100644 drivers/staging/media/omap4iss/iss_regs.h create mode 100644 include/media/omap4iss.h (limited to 'Documentation') diff --git a/Documentation/video4linux/omap4_camera.txt b/Documentation/video4linux/omap4_camera.txt new file mode 100644 index 000000000000..25d9b40a4651 --- /dev/null +++ b/Documentation/video4linux/omap4_camera.txt @@ -0,0 +1,60 @@ + OMAP4 ISS Driver + ================ + +Introduction +------------ + +The OMAP44XX family of chips contains the Imaging SubSystem (a.k.a. ISS), +Which contains several components that can be categorized in 3 big groups: + +- Interfaces (2 Interfaces: CSI2-A & CSI2-B/CCP2) +- ISP (Image Signal Processor) +- SIMCOP (Still Image Coprocessor) + +For more information, please look in [1] for latest version of: + "OMAP4430 Multimedia Device Silicon Revision 2.x" + +As of Revision AB, the ISS is described in detail in section 8. + +This driver is supporting _only_ the CSI2-A/B interfaces for now. + +It makes use of the Media Controller framework [2], and inherited most of the +code from OMAP3 ISP driver (found under drivers/media/platform/omap3isp/*), +except that it doesn't need an IOMMU now for ISS buffers memory mapping. + +Supports usage of MMAP buffers only (for now). + +Tested platforms +---------------- + +- OMAP4430SDP, w/ ES2.1 GP & SEVM4430-CAM-V1-0 (Contains IMX060 & OV5640, in + which only the last one is supported, outputting YUV422 frames). + +- TI Blaze MDP, w/ OMAP4430 ES2.2 EMU (Contains 1 IMX060 & 2 OV5650 sensors, in + which only the OV5650 are supported, outputting RAW10 frames). + +- PandaBoard, Rev. A2, w/ OMAP4430 ES2.1 GP & OV adapter board, tested with + following sensors: + * OV5640 + * OV5650 + +- Tested on mainline kernel: + + http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=summary + + Tag: v3.3 (commit c16fa4f2ad19908a47c63d8fa436a1178438c7e7) + +File list +--------- +drivers/staging/media/omap4iss/ +include/media/omap4iss.h + +References +---------- + +[1] http://focus.ti.com/general/docs/wtbu/wtbudocumentcenter.tsp?navigationId=12037&templateId=6123#62 +[2] http://lwn.net/Articles/420485/ +[3] http://www.spinics.net/lists/linux-media/msg44370.html +-- +Author: Sergio Aguirre +Copyright (C) 2012, Texas Instruments diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c new file mode 100644 index 000000000000..d054d9b6eb0f --- /dev/null +++ b/drivers/staging/media/omap4iss/iss.c @@ -0,0 +1,1477 @@ +/* + * TI OMAP4 ISS V4L2 Driver + * + * Copyright (C) 2012, Texas Instruments + * + * Author: Sergio Aguirre + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "iss.h" +#include "iss_regs.h" + +#define ISS_PRINT_REGISTER(iss, name)\ + dev_dbg(iss->dev, "###ISS " #name "=0x%08x\n", \ + readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_##name)) + +static void iss_print_status(struct iss_device *iss) +{ + dev_dbg(iss->dev, "-------------ISS HL Register dump-------------\n"); + + ISS_PRINT_REGISTER(iss, HL_REVISION); + ISS_PRINT_REGISTER(iss, HL_SYSCONFIG); + ISS_PRINT_REGISTER(iss, HL_IRQSTATUS_5); + ISS_PRINT_REGISTER(iss, HL_IRQENABLE_5_SET); + ISS_PRINT_REGISTER(iss, HL_IRQENABLE_5_CLR); + ISS_PRINT_REGISTER(iss, CTRL); + ISS_PRINT_REGISTER(iss, CLKCTRL); + ISS_PRINT_REGISTER(iss, CLKSTAT); + + dev_dbg(iss->dev, "-----------------------------------------------\n"); +} + +/* + * omap4iss_flush - Post pending L3 bus writes by doing a register readback + * @iss: OMAP4 ISS device + * + * In order to force posting of pending writes, we need to write and + * readback the same register, in this case the revision register. + * + * See this link for reference: + * http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html + */ +void omap4iss_flush(struct iss_device *iss) +{ + writel(0, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_REVISION); + readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_REVISION); +} + +/* + * iss_enable_interrupts - Enable ISS interrupts. + * @iss: OMAP4 ISS device + */ +static void iss_enable_interrupts(struct iss_device *iss) +{ + static const u32 hl_irq = ISS_HL_IRQ_CSIA | ISS_HL_IRQ_CSIB | ISS_HL_IRQ_ISP(0); + + /* Enable HL interrupts */ + writel(hl_irq, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQSTATUS_5); + writel(hl_irq, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQENABLE_5_SET); + +} + +/* + * iss_disable_interrupts - Disable ISS interrupts. + * @iss: OMAP4 ISS device + */ +static void iss_disable_interrupts(struct iss_device *iss) +{ + writel(-1, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQENABLE_5_CLR); +} + +/* + * iss_isp_enable_interrupts - Enable ISS ISP interrupts. + * @iss: OMAP4 ISS device + */ +void omap4iss_isp_enable_interrupts(struct iss_device *iss) +{ + static const u32 isp_irq = ISP5_IRQ_OCP_ERR | + ISP5_IRQ_RSZ_FIFO_IN_BLK | + ISP5_IRQ_RSZ_FIFO_OVF | + ISP5_IRQ_RSZ_INT_DMA | + ISP5_IRQ_ISIF0; + + /* Enable ISP interrupts */ + writel(isp_irq, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_IRQSTATUS(0)); + writel(isp_irq, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_IRQENABLE_SET(0)); +} + +/* + * iss_isp_disable_interrupts - Disable ISS interrupts. + * @iss: OMAP4 ISS device + */ +void omap4iss_isp_disable_interrupts(struct iss_device *iss) +{ + writel(-1, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_IRQENABLE_CLR(0)); +} + +int omap4iss_get_external_info(struct iss_pipeline *pipe, + struct media_link *link) +{ + struct iss_device *iss = + container_of(pipe, struct iss_video, pipe)->iss; + struct v4l2_subdev_format fmt; + struct v4l2_ext_controls ctrls; + struct v4l2_ext_control ctrl; + int ret; + + if (!pipe->external) + return 0; + + if (pipe->external_rate) + return 0; + + memset(&fmt, 0, sizeof(fmt)); + + fmt.pad = link->source->index; + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(media_entity_to_v4l2_subdev(link->sink->entity), + pad, get_fmt, NULL, &fmt); + if (ret < 0) + return -EPIPE; + + pipe->external_bpp = omap4iss_video_format_info(fmt.format.code)->bpp; + + memset(&ctrls, 0, sizeof(ctrls)); + memset(&ctrl, 0, sizeof(ctrl)); + + ctrl.id = V4L2_CID_PIXEL_RATE; + + ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(ctrl.id); + ctrls.count = 1; + ctrls.controls = &ctrl; + + ret = v4l2_g_ext_ctrls(pipe->external->ctrl_handler, &ctrls); + if (ret < 0) { + dev_warn(iss->dev, "no pixel rate control in subdev %s\n", + pipe->external->name); + return ret; + } + + pipe->external_rate = ctrl.value64; + + return 0; +} + +/* + * Configure the bridge. Valid inputs are + * + * IPIPEIF_INPUT_CSI2A: CSI2a receiver + * IPIPEIF_INPUT_CSI2B: CSI2b receiver + * + * The bridge and lane shifter are configured according to the selected input + * and the ISP platform data. + */ +void omap4iss_configure_bridge(struct iss_device *iss, + enum ipipeif_input_entity input) +{ + u32 issctrl_val; + u32 isp5ctrl_val; + + issctrl_val = readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CTRL); + issctrl_val &= ~ISS_CTRL_INPUT_SEL_MASK; + issctrl_val &= ~ISS_CTRL_CLK_DIV_MASK; + + isp5ctrl_val = readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL); + + switch (input) { + case IPIPEIF_INPUT_CSI2A: + issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2A; + isp5ctrl_val |= ISP5_CTRL_VD_PULSE_EXT; + break; + + case IPIPEIF_INPUT_CSI2B: + issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2B; + isp5ctrl_val |= ISP5_CTRL_VD_PULSE_EXT; + break; + + default: + return; + } + + issctrl_val |= ISS_CTRL_SYNC_DETECT_VS_RAISING; + + isp5ctrl_val |= ISP5_CTRL_PSYNC_CLK_SEL | ISP5_CTRL_SYNC_ENABLE; + + writel(issctrl_val, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CTRL); + writel(isp5ctrl_val, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL); +} + +static inline void iss_isr_dbg(struct iss_device *iss, u32 irqstatus) +{ + static const char *name[] = { + "ISP_IRQ0", + "ISP_IRQ1", + "ISP_IRQ2", + "ISP_IRQ3", + "CSIA_IRQ", + "CSIB_IRQ", + "CCP2_IRQ0", + "CCP2_IRQ1", + "CCP2_IRQ2", + "CCP2_IRQ3", + "CBUFF_IRQ", + "BTE_IRQ", + "SIMCOP_IRQ0", + "SIMCOP_IRQ1", + "SIMCOP_IRQ2", + "SIMCOP_IRQ3", + "CCP2_IRQ8", + "HS_VS_IRQ", + "res18", + "res19", + "res20", + "res21", + "res22", + "res23", + "res24", + "res25", + "res26", + "res27", + "res28", + "res29", + "res30", + "res31", + }; + int i; + + dev_dbg(iss->dev, "ISS IRQ: "); + + for (i = 0; i < ARRAY_SIZE(name); i++) { + if ((1 << i) & irqstatus) + pr_cont("%s ", name[i]); + } + pr_cont("\n"); +} + +/* + * iss_isr - Interrupt Service Routine for ISS module. + * @irq: Not used currently. + * @_iss: Pointer to the OMAP4 ISS device + * + * Handles the corresponding callback if plugged in. + * + * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the + * IRQ wasn't handled. + */ +static irqreturn_t iss_isr(int irq, void *_iss) +{ + static const u32 ipipeif_events = ISP5_IRQ_IPIPEIF | + ISP5_IRQ_ISIF0; + static const u32 resizer_events = ISP5_IRQ_RSZ_FIFO_IN_BLK | + ISP5_IRQ_RSZ_FIFO_OVF | + ISP5_IRQ_RSZ_INT_DMA; + struct iss_device *iss = _iss; + u32 irqstatus; + + irqstatus = readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQSTATUS_5); + writel(irqstatus, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQSTATUS_5); + + if (irqstatus & ISS_HL_IRQ_CSIA) + omap4iss_csi2_isr(&iss->csi2a); + + if (irqstatus & ISS_HL_IRQ_CSIB) + omap4iss_csi2_isr(&iss->csi2b); + + if (irqstatus & ISS_HL_IRQ_ISP(0)) { + u32 isp_irqstatus = readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + + ISP5_IRQSTATUS(0)); + writel(isp_irqstatus, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + + ISP5_IRQSTATUS(0)); + + if (isp_irqstatus & ISP5_IRQ_OCP_ERR) + dev_dbg(iss->dev, "ISP5 OCP Error!\n"); + + if (isp_irqstatus & ipipeif_events) { + omap4iss_ipipeif_isr(&iss->ipipeif, + isp_irqstatus & ipipeif_events); + } + + if (isp_irqstatus & resizer_events) + omap4iss_resizer_isr(&iss->resizer, + isp_irqstatus & resizer_events); + } + + omap4iss_flush(iss); + +#if defined(DEBUG) && defined(ISS_ISR_DEBUG) + iss_isr_dbg(iss, irqstatus); +#endif + + return IRQ_HANDLED; +} + +/* ----------------------------------------------------------------------------- + * Pipeline power management + * + * Entities must be powered up when part of a pipeline that contains at least + * one open video device node. + * + * To achieve this use the entity use_count field to track the number of users. + * For entities corresponding to video device nodes the use_count field stores + * the users count of the node. For entities corresponding to subdevs the + * use_count field stores the total number of users of all video device nodes + * in the pipeline. + * + * The omap4iss_pipeline_pm_use() function must be called in the open() and + * close() handlers of video device nodes. It increments or decrements the use + * count of all subdev entities in the pipeline. + * + * To react to link management on powered pipelines, the link setup notification + * callback updates the use count of all entities in the source and sink sides + * of the link. + */ + +/* + * iss_pipeline_pm_use_count - Count the number of users of a pipeline + * @entity: The entity + * + * Return the total number of users of all video device nodes in the pipeline. + */ +static int iss_pipeline_pm_use_count(struct media_entity *entity) +{ + struct media_entity_graph graph; + int use = 0; + + media_entity_graph_walk_start(&graph, entity); + + while ((entity = media_entity_graph_walk_next(&graph))) { + if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE) + use += entity->use_count; + } + + return use; +} + +/* + * iss_pipeline_pm_power_one - Apply power change to an entity + * @entity: The entity + * @change: Use count change + * + * Change the entity use count by @change. If the entity is a subdev update its + * power state by calling the core::s_power operation when the use count goes + * from 0 to != 0 or from != 0 to 0. + * + * Return 0 on success or a negative error code on failure. + */ +static int iss_pipeline_pm_power_one(struct media_entity *entity, int change) +{ + struct v4l2_subdev *subdev; + + subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV + ? media_entity_to_v4l2_subdev(entity) : NULL; + + if (entity->use_count == 0 && change > 0 && subdev != NULL) { + int ret; + + ret = v4l2_subdev_call(subdev, core, s_power, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) + return ret; + } + + entity->use_count += change; + WARN_ON(entity->use_count < 0); + + if (entity->use_count == 0 && change < 0 && subdev != NULL) + v4l2_subdev_call(subdev, core, s_power, 0); + + return 0; +} + +/* + * iss_pipeline_pm_power - Apply power change to all entities in a pipeline + * @entity: The entity + * @change: Use count change + * + * Walk the pipeline to update the use count and the power state of all non-node + * entities. + * + * Return 0 on success or a negative error code on failure. + */ +static int iss_pipeline_pm_power(struct media_entity *entity, int change) +{ + struct media_entity_graph graph; + struct media_entity *first = entity; + int ret = 0; + + if (!change) + return 0; + + media_entity_graph_walk_start(&graph, entity); + + while (!ret && (entity = media_entity_graph_walk_next(&graph))) + if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE) + ret = iss_pipeline_pm_power_one(entity, change); + + if (!ret) + return 0; + + media_entity_graph_walk_start(&graph, first); + + while ((first = media_entity_graph_walk_next(&graph)) + && first != entity) + if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE) + iss_pipeline_pm_power_one(first, -change); + + return ret; +} + +/* + * omap4iss_pipeline_pm_use - Update the use count of an entity + * @entity: The entity + * @use: Use (1) or stop using (0) the entity + * + * Update the use count of all entities in the pipeline and power entities on or + * off accordingly. + * + * Return 0 on success or a negative error code on failure. Powering entities + * off is assumed to never fail. No failure can occur when the use parameter is + * set to 0. + */ +int omap4iss_pipeline_pm_use(struct media_entity *entity, int use) +{ + int change = use ? 1 : -1; + int ret; + + mutex_lock(&entity->parent->graph_mutex); + + /* Apply use count to node. */ + entity->use_count += change; + WARN_ON(entity->use_count < 0); + + /* Apply power change to connected non-nodes. */ + ret = iss_pipeline_pm_power(entity, change); + if (ret < 0) + entity->use_count -= change; + + mutex_unlock(&entity->parent->graph_mutex); + + return ret; +} + +/* + * iss_pipeline_link_notify - Link management notification callback + * @link: The link + * @flags: New link flags that will be applied + * + * React to link management on powered pipelines by updating the use count of + * all entities in the source and sink sides of the link. Entities are powered + * on or off accordingly. + * + * Return 0 on success or a negative error code on failure. Powering entities + * off is assumed to never fail. This function will not fail for disconnection + * events. + */ +static int iss_pipeline_link_notify(struct media_link *link, u32 flags, + unsigned int notification) +{ + struct media_entity *source = link->source->entity; + struct media_entity *sink = link->sink->entity; + int source_use = iss_pipeline_pm_use_count(source); + int sink_use = iss_pipeline_pm_use_count(sink); + int ret; + + if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH && + !(link->flags & MEDIA_LNK_FL_ENABLED)) { + /* Powering off entities is assumed to never fail. */ + iss_pipeline_pm_power(source, -sink_use); + iss_pipeline_pm_power(sink, -source_use); + return 0; + } + + if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH && + (flags & MEDIA_LNK_FL_ENABLED)) { + ret = iss_pipeline_pm_power(source, sink_use); + if (ret < 0) + return ret; + + ret = iss_pipeline_pm_power(sink, source_use); + if (ret < 0) + iss_pipeline_pm_power(source, -sink_use); + + return ret; + } + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Pipeline stream management + */ + +/* + * iss_pipeline_enable - Enable streaming on a pipeline + * @pipe: ISS pipeline + * @mode: Stream mode (single shot or continuous) + * + * Walk the entities chain starting at the pipeline output video node and start + * all modules in the chain in the given mode. + * + * Return 0 if successful, or the return value of the failed video::s_stream + * operation otherwise. + */ +static int iss_pipeline_enable(struct iss_pipeline *pipe, + enum iss_pipeline_stream_state mode) +{ + struct media_entity *entity; + struct media_pad *pad; + struct v4l2_subdev *subdev; + unsigned long flags; + int ret; + + spin_lock_irqsave(&pipe->lock, flags); + pipe->state &= ~(ISS_PIPELINE_IDLE_INPUT | ISS_PIPELINE_IDLE_OUTPUT); + spin_unlock_irqrestore(&pipe->lock, flags); + + pipe->do_propagation = false; + + entity = &pipe->output->video.entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_pad(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + entity = pad->entity; + subdev = media_entity_to_v4l2_subdev(entity); + + ret = v4l2_subdev_call(subdev, video, s_stream, mode); + if (ret < 0 && ret != -ENOIOCTLCMD) + return ret; + } + iss_print_status(pipe->output->iss); + return 0; +} + +/* + * iss_pipeline_disable - Disable streaming on a pipeline + * @pipe: ISS pipeline + * + * Walk the entities chain starting at the pipeline output video node and stop + * all modules in the chain. Wait synchronously for the modules to be stopped if + * necessary. + */ +static int iss_pipeline_disable(struct iss_pipeline *pipe) +{ + struct media_entity *entity; + struct media_pad *pad; + struct v4l2_subdev *subdev; + int failure = 0; + + entity = &pipe->output->video.entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_pad(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + entity = pad->entity; + subdev = media_entity_to_v4l2_subdev(entity); + + v4l2_subdev_call(subdev, video, s_stream, 0); + } + + return failure; +} + +/* + * omap4iss_pipeline_set_stream - Enable/disable streaming on a pipeline + * @pipe: ISS pipeline + * @state: Stream state (stopped, single shot or continuous) + * + * Set the pipeline to the given stream state. Pipelines can be started in + * single-shot or continuous mode. + * + * Return 0 if successful, or the return value of the failed video::s_stream + * operation otherwise. The pipeline state is not updated when the operation + * fails, except when stopping the pipeline. + */ +int omap4iss_pipeline_set_stream(struct iss_pipeline *pipe, + enum iss_pipeline_stream_state state) +{ + int ret; + + if (state == ISS_PIPELINE_STREAM_STOPPED) + ret = iss_pipeline_disable(pipe); + else + ret = iss_pipeline_enable(pipe, state); + + if (ret == 0 || state == ISS_PIPELINE_STREAM_STOPPED) + pipe->stream_state = state; + + return ret; +} + +/* + * iss_pipeline_is_last - Verify if entity has an enabled link to the output + * video node + * @me: ISS module's media entity + * + * Returns 1 if the entity has an enabled link to the output video node or 0 + * otherwise. It's true only while pipeline can have no more than one output + * node. + */ +static int iss_pipeline_is_last(struct media_entity *me) +{ + struct iss_pipeline *pipe; + struct media_pad *pad; + + if (!me->pipe) + return 0; + pipe = to_iss_pipeline(me); + if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED) + return 0; + pad = media_entity_remote_pad(&pipe->output->pad); + return pad->entity == me; +} + +static int iss_reset(struct iss_device *iss) +{ + unsigned long timeout = 0; + + writel(readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_SYSCONFIG) | + ISS_HL_SYSCONFIG_SOFTRESET, + iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_SYSCONFIG); + + while (readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_SYSCONFIG) & + ISS_HL_SYSCONFIG_SOFTRESET) { + if (timeout++ > 10000) { + dev_alert(iss->dev, "cannot reset ISS\n"); + return -ETIMEDOUT; + } + udelay(1); + } + + return 0; +} + +static int iss_isp_reset(struct iss_device *iss) +{ + unsigned long timeout = 0; + + /* Fist, ensure that the ISP is IDLE (no transactions happening) */ + writel((readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG) & + ~ISP5_SYSCONFIG_STANDBYMODE_MASK) | + ISP5_SYSCONFIG_STANDBYMODE_SMART, + iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG); + + writel(readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL) | + ISP5_CTRL_MSTANDBY, + iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL); + + for (;;) { + if (readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL) & + ISP5_CTRL_MSTANDBY_WAIT) + break; + if (timeout++ > 1000) { + dev_alert(iss->dev, "cannot set ISP5 to standby\n"); + return -ETIMEDOUT; + } + msleep(1); + } + + /* Now finally, do the reset */ + writel(readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG) | + ISP5_SYSCONFIG_SOFTRESET, + iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG); + + timeout = 0; + while (readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG) & + ISP5_SYSCONFIG_SOFTRESET) { + if (timeout++ > 1000) { + dev_alert(iss->dev, "cannot reset ISP5\n"); + return -ETIMEDOUT; + } + msleep(1); + } + + return 0; +} + +/* + * iss_module_sync_idle - Helper to sync module with its idle state + * @me: ISS submodule's media entity + * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization + * @stopping: flag which tells module wants to stop + * + * This function checks if ISS submodule needs to wait for next interrupt. If + * yes, makes the caller to sleep while waiting for such event. + */ +int omap4iss_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait, + atomic_t *stopping) +{ + struct iss_pipeline *pipe = to_iss_pipeline(me); + struct iss_video *video = pipe->output; + unsigned long flags; + + if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED || + (pipe->stream_state == ISS_PIPELINE_STREAM_SINGLESHOT && + !iss_pipeline_ready(pipe))) + return 0; + + /* + * atomic_set() doesn't include memory barrier on ARM platform for SMP + * scenario. We'll call it here to avoid race conditions. + */ + atomic_set(stopping, 1); + smp_wmb(); + + /* + * If module is the last one, it's writing to memory. In this case, + * it's necessary to check if the module is already paused due to + * DMA queue underrun or if it has to wait for next interrupt to be + * idle. + * If it isn't the last one, the function won't sleep but *stopping + * will still be set to warn next submodule caller's interrupt the + * module wants to be idle. + */ + if (!iss_pipeline_is_last(me)) + return 0; + + spin_lock_irqsave(&video->qlock, flags); + if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) { + spin_unlock_irqrestore(&video->qlock, flags); + atomic_set(stopping, 0); + smp_wmb(); + return 0; + } + spin_unlock_irqrestore(&video->qlock, flags); + if (!wait_event_timeout(*wait, !atomic_read(stopping), + msecs_to_jiffies(1000))) { + atomic_set(stopping, 0); + smp_wmb(); + return -ETIMEDOUT; + } + + return 0; +} + +/* + * omap4iss_module_sync_is_stopped - Helper to verify if module was stopping + * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization + * @stopping: flag which tells module wants to stop + * + * This function checks if ISS submodule was stopping. In case of yes, it + * notices the caller by setting stopping to 0 and waking up the wait queue. + * Returns 1 if it was stopping or 0 otherwise. + */ +int omap4iss_module_sync_is_stopping(wait_queue_head_t *wait, + atomic_t *stopping) +{ + if (atomic_cmpxchg(stopping, 1, 0)) { + wake_up(wait); + return 1; + } + + return 0; +} + +/* -------------------------------------------------------------------------- + * Clock management + */ + +#define ISS_CLKCTRL_MASK (ISS_CLKCTRL_CSI2_A |\ + ISS_CLKCTRL_CSI2_B |\ + ISS_CLKCTRL_ISP) + +static int __iss_subclk_update(struct iss_device *iss) +{ + u32 clk = 0; + int ret = 0, timeout = 1000; + + if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_A) + clk |= ISS_CLKCTRL_CSI2_A; + + if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_B) + clk |= ISS_CLKCTRL_CSI2_B; + + if (iss->subclk_resources & OMAP4_ISS_SUBCLK_ISP) + clk |= ISS_CLKCTRL_ISP; + + writel((readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CLKCTRL) & + ~ISS_CLKCTRL_MASK) | clk, + iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CLKCTRL); + + /* Wait for HW assertion */ + while (--timeout > 0) { + udelay(1); + if ((readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CLKSTAT) & + ISS_CLKCTRL_MASK) == clk) + break; + } + + if (!timeout) + ret = -EBUSY; + + return ret; +} + +int omap4iss_subclk_enable(struct iss_device *iss, + enum iss_subclk_resource res) +{ + iss->subclk_resources |= res; + + return __iss_subclk_update(iss); +} + +int omap4iss_subclk_disable(struct iss_device *iss, + enum iss_subclk_resource res) +{ + iss->subclk_resources &= ~res; + + return __iss_subclk_update(iss); +} + +#define ISS_ISP5_CLKCTRL_MASK (ISP5_CTRL_BL_CLK_ENABLE |\ + ISP5_CTRL_ISIF_CLK_ENABLE |\ + ISP5_CTRL_H3A_CLK_ENABLE |\ + ISP5_CTRL_RSZ_CLK_ENABLE |\ + ISP5_CTRL_IPIPE_CLK_ENABLE |\ + ISP5_CTRL_IPIPEIF_CLK_ENABLE) + +static int __iss_isp_subclk_update(struct iss_device *iss) +{ + u32 clk = 0; + + if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_ISIF) + clk |= ISP5_CTRL_ISIF_CLK_ENABLE; + + if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_H3A) + clk |= ISP5_CTRL_H3A_CLK_ENABLE; + + if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_RSZ) + clk |= ISP5_CTRL_RSZ_CLK_ENABLE; + + if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPE) + clk |= ISP5_CTRL_IPIPE_CLK_ENABLE; + + if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPEIF) + clk |= ISP5_CTRL_IPIPEIF_CLK_ENABLE; + + if (clk) + clk |= ISP5_CTRL_BL_CLK_ENABLE; + + writel((readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL) & + ~ISS_ISP5_CLKCTRL_MASK) | clk, + iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL); + + return 0; +} + +int omap4iss_isp_subclk_enable(struct iss_device *iss, + enum iss_isp_subclk_resource res) +{ + iss->isp_subclk_resources |= res; + + return __iss_isp_subclk_update(iss); +} + +int omap4iss_isp_subclk_disable(struct iss_device *iss, + enum iss_isp_subclk_resource res) +{ + iss->isp_subclk_resources &= ~res; + + return __iss_isp_subclk_update(iss); +} + +/* + * iss_enable_clocks - Enable ISS clocks + * @iss: OMAP4 ISS device + * + * Return 0 if successful, or clk_enable return value if any of tthem fails. + */ +static int iss_enable_clocks(struct iss_device *iss) +{ + int r; + + r = clk_enable(iss->iss_fck); + if (r) { + dev_err(iss->dev, "clk_enable iss_fck failed\n"); + return r; + } + + r = clk_enable(iss->iss_ctrlclk); + if (r) { + dev_err(iss->dev, "clk_enable iss_ctrlclk failed\n"); + goto out_clk_enable_ctrlclk; + } + return 0; + +out_clk_enable_ctrlclk: + clk_disable(iss->iss_fck); + return r; +} + +/* + * iss_disable_clocks - Disable ISS clocks + * @iss: OMAP4 ISS device + */ +static void iss_disable_clocks(struct iss_device *iss) +{ + clk_disable(iss->iss_ctrlclk); + clk_disable(iss->iss_fck); +} + +static void iss_put_clocks(struct iss_device *iss) +{ + if (iss->iss_fck) { + clk_put(iss->iss_fck); + iss->iss_fck = NULL; + } + + if (iss->iss_ctrlclk) { + clk_put(iss->iss_ctrlclk); + iss->iss_ctrlclk = NULL; + } +} + +static int iss_get_clocks(struct iss_device *iss) +{ + iss->iss_fck = clk_get(iss->dev, "iss_fck"); + if (IS_ERR(iss->iss_fck)) { + dev_err(iss->dev, "Unable to get iss_fck clock info\n"); + iss_put_clocks(iss); + return PTR_ERR(iss->iss_fck); + } + + iss->iss_ctrlclk = clk_get(iss->dev, "iss_ctrlclk"); + if (IS_ERR(iss->iss_ctrlclk)) { + dev_err(iss->dev, "Unable to get iss_ctrlclk clock info\n"); + iss_put_clocks(iss); + return PTR_ERR(iss->iss_fck); + } + + return 0; +} + +/* + * omap4iss_get - Acquire the ISS resource. + * + * Initializes the clocks for the first acquire. + * + * Increment the reference count on the ISS. If the first reference is taken, + * enable clocks and power-up all submodules. + * + * Return a pointer to the ISS device structure, or NULL if an error occurred. + */ +struct iss_device *omap4iss_get(struct iss_device *iss) +{ + struct iss_device *__iss = iss; + + if (iss == NULL) + return NULL; + + mutex_lock(&iss->iss_mutex); + if (iss->ref_count > 0) + goto out; + + if (iss_enable_clocks(iss) < 0) { + __iss = NULL; + goto out; + } + + iss_enable_interrupts(iss); + +out: + if (__iss != NULL) + iss->ref_count++; + mutex_unlock(&iss->iss_mutex); + + return __iss; +} + +/* + * omap4iss_put - Release the ISS + * + * Decrement the reference count on the ISS. If the last reference is released, + * power-down all submodules, disable clocks and free temporary buffers. + */ +void omap4iss_put(struct iss_device *iss) +{ + if (iss == NULL) + return; + + mutex_lock(&iss->iss_mutex); + BUG_ON(iss->ref_count == 0); + if (--iss->ref_count == 0) { + iss_disable_interrupts(iss); + iss_disable_clocks(iss); + } + mutex_unlock(&iss->iss_mutex); +} + +static int iss_map_mem_resource(struct platform_device *pdev, + struct iss_device *iss, + enum iss_mem_resources res) +{ + struct resource *mem; + + /* request the mem region for the camera registers */ + + mem = platform_get_resource(pdev, IORESOURCE_MEM, res); + if (!mem) { + dev_err(iss->dev, "no mem resource?\n"); + return -ENODEV; + } + + if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) { + dev_err(iss->dev, + "cannot reserve camera register I/O region\n"); + return -ENODEV; + } + iss->res[res] = mem; + + /* map the region */ + iss->regs[res] = ioremap_nocache(mem->start, resource_size(mem)); + if (!iss->regs[res]) { + dev_err(iss->dev, "cannot map camera register I/O region\n"); + return -ENODEV; + } + + return 0; +} + +static void iss_unregister_entities(struct iss_device *iss) +{ + omap4iss_resizer_unregister_entities(&iss->resizer); + omap4iss_ipipe_unregister_entities(&iss->ipipe); + omap4iss_ipipeif_unregister_entities(&iss->ipipeif); + omap4iss_csi2_unregister_entities(&iss->csi2a); + omap4iss_csi2_unregister_entities(&iss->csi2b); + + v4l2_device_unregister(&iss->v4l2_dev); + media_device_unregister(&iss->media_dev); +} + +/* + * iss_register_subdev_group - Register a group of subdevices + * @iss: OMAP4 ISS device + * @board_info: I2C subdevs board information array + * + * Register all I2C subdevices in the board_info array. The array must be + * terminated by a NULL entry, and the first entry must be the sensor. + * + * Return a pointer to the sensor media entity if it has been successfully + * registered, or NULL otherwise. + */ +static struct v4l2_subdev * +iss_register_subdev_group(struct iss_device *iss, + struct iss_subdev_i2c_board_info *board_info) +{ + struct v4l2_subdev *sensor = NULL; + unsigned int first; + + if (board_info->board_info == NULL) + return NULL; + + for (first = 1; board_info->board_info; ++board_info, first = 0) { + struct v4l2_subdev *subdev; + struct i2c_adapter *adapter; + + adapter = i2c_get_adapter(board_info->i2c_adapter_id); + if (adapter == NULL) { + dev_err(iss->dev, "%s: Unable to get I2C adapter %d for " + "device %s\n", __func__, + board_info->i2c_adapter_id, + board_info->board_info->type); + continue; + } + + subdev = v4l2_i2c_new_subdev_board(&iss->v4l2_dev, adapter, + board_info->board_info, NULL); + if (subdev == NULL) { + dev_err(iss->dev, "%s: Unable to register subdev %s\n", + __func__, board_info->board_info->type); + continue; + } + + if (first) + sensor = subdev; + } + + return sensor; +} + +static int iss_register_entities(struct iss_device *iss) +{ + struct iss_platform_data *pdata = iss->pdata; + struct iss_v4l2_subdevs_group *subdevs; + int ret; + + iss->media_dev.dev = iss->dev; + strlcpy(iss->media_dev.model, "TI OMAP4 ISS", + sizeof(iss->media_dev.model)); + iss->media_dev.hw_revision = iss->revision; + iss->media_dev.link_notify = iss_pipeline_link_notify; + ret = media_device_register(&iss->media_dev); + if (ret < 0) { + printk(KERN_ERR "%s: Media device registration failed (%d)\n", + __func__, ret); + return ret; + } + + iss->v4l2_dev.mdev = &iss->media_dev; + ret = v4l2_device_register(iss->dev, &iss->v4l2_dev); + if (ret < 0) { + printk(KERN_ERR "%s: V4L2 device registration failed (%d)\n", + __func__, ret); + goto done; + } + + /* Register internal entities */ + ret = omap4iss_csi2_register_entities(&iss->csi2a, &iss->v4l2_dev); + if (ret < 0) + goto done; + + ret = omap4iss_csi2_register_entities(&iss->csi2b, &iss->v4l2_dev); + if (ret < 0) + goto done; + + ret = omap4iss_ipipeif_register_entities(&iss->ipipeif, &iss->v4l2_dev); + if (ret < 0) + goto done; + + ret = omap4iss_ipipe_register_entities(&iss->ipipe, &iss->v4l2_dev); + if (ret < 0) + goto done; + + ret = omap4iss_resizer_register_entities(&iss->resizer, &iss->v4l2_dev); + if (ret < 0) + goto done; + + /* Register external entities */ + for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) { + struct v4l2_subdev *sensor; + struct media_entity *input; + unsigned int flags; + unsigned int pad; + + sensor = iss_register_subdev_group(iss, subdevs->subdevs); + if (sensor == NULL) + continue; + + sensor->host_priv = subdevs; + + /* Connect the sensor to the correct interface module. + * CSI2a receiver through CSIPHY1, or + * CSI2b receiver through CSIPHY2 + */ + switch (subdevs->interface) { + case ISS_INTERFACE_CSI2A_PHY1: + input = &iss->csi2a.subdev.entity; + pad = CSI2_PAD_SINK; + flags = MEDIA_LNK_FL_IMMUTABLE + | MEDIA_LNK_FL_ENABLED; + break; + + case ISS_INTERFACE_CSI2B_PHY2: + input = &iss->csi2b.subdev.entity; + pad = CSI2_PAD_SINK; + flags = MEDIA_LNK_FL_IMMUTABLE + | MEDIA_LNK_FL_ENABLED; + break; + + default: + printk(KERN_ERR "%s: invalid interface type %u\n", + __func__, subdevs->interface); + ret = -EINVAL; + goto done; + } + + ret = media_entity_create_link(&sensor->entity, 0, input, pad, + flags); + if (ret < 0) + goto done; + } + + ret = v4l2_device_register_subdev_nodes(&iss->v4l2_dev); + +done: + if (ret < 0) + iss_unregister_entities(iss); + + return ret; +} + +static void iss_cleanup_modules(struct iss_device *iss) +{ + omap4iss_csi2_cleanup(iss); + omap4iss_ipipeif_cleanup(iss); + omap4iss_ipipe_cleanup(iss); + omap4iss_resizer_cleanup(iss); +} + +static int iss_initialize_modules(struct iss_device *iss) +{ + int ret; + + ret = omap4iss_csiphy_init(iss); + if (ret < 0) { + dev_err(iss->dev, "CSI PHY initialization failed\n"); + goto error_csiphy; + } + + ret = omap4iss_csi2_init(iss); + if (ret < 0) { + dev_err(iss->dev, "CSI2 initialization failed\n"); + goto error_csi2; + } + + ret = omap4iss_ipipeif_init(iss); + if (ret < 0) { + dev_err(iss->dev, "ISP IPIPEIF initialization failed\n"); + goto error_ipipeif; + } + + ret = omap4iss_ipipe_init(iss); + if (ret < 0) { + dev_err(iss->dev, "ISP IPIPE initialization failed\n"); + goto error_ipipe; + } + + ret = omap4iss_resizer_init(iss); + if (ret < 0) { + dev_err(iss->dev, "ISP RESIZER initialization failed\n"); + goto error_resizer; + } + + /* Connect the submodules. */ + ret = media_entity_create_link( + &iss->csi2a.subdev.entity, CSI2_PAD_SOURCE, + &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0); + if (ret < 0) + goto error_link; + + ret = media_entity_create_link( + &iss->csi2b.subdev.entity, CSI2_PAD_SOURCE, + &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0); + if (ret < 0) + goto error_link; + + ret = media_entity_create_link( + &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP, + &iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0); + if (ret < 0) + goto error_link; + + ret = media_entity_create_link( + &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP, + &iss->ipipe.subdev.entity, IPIPE_PAD_SINK, 0); + if (ret < 0) + goto error_link; + + ret = media_entity_create_link( + &iss->ipipe.subdev.entity, IPIPE_PAD_SOURCE_VP, + &iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0); + if (ret < 0) + goto error_link; + + return 0; + +error_link: + omap4iss_resizer_cleanup(iss); +error_resizer: + omap4iss_ipipe_cleanup(iss); +error_ipipe: + omap4iss_ipipeif_cleanup(iss); +error_ipipeif: + omap4iss_csi2_cleanup(iss); +error_csi2: +error_csiphy: + return ret; +} + +static int iss_probe(struct platform_device *pdev) +{ + struct iss_platform_data *pdata = pdev->dev.platform_data; + struct iss_device *iss; + int i, ret; + + if (pdata == NULL) + return -EINVAL; + + iss = kzalloc(sizeof(*iss), GFP_KERNEL); + if (!iss) { + dev_err(&pdev->dev, "Could not allocate memory\n"); + return -ENOMEM; + } + + mutex_init(&iss->iss_mutex); + + iss->dev = &pdev->dev; + iss->pdata = pdata; + iss->ref_count = 0; + + iss->raw_dmamask = DMA_BIT_MASK(32); + iss->dev->dma_mask = &iss->raw_dmamask; + iss->dev->coherent_dma_mask = DMA_BIT_MASK(32); + + platform_set_drvdata(pdev, iss); + + /* Clocks */ + ret = iss_map_mem_resource(pdev, iss, OMAP4_ISS_MEM_TOP); + if (ret < 0) + goto error; + + ret = iss_get_clocks(iss); + if (ret < 0) + goto error; + + if (omap4iss_get(iss) == NULL) + goto error; + + ret = iss_reset(iss); + if (ret < 0) + goto error_iss; + + iss->revision = readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_REVISION); + dev_info(iss->dev, "Revision %08x found\n", iss->revision); + + for (i = 1; i < OMAP4_ISS_MEM_LAST; i++) { + ret = iss_map_mem_resource(pdev, iss, i); + if (ret) + goto error_iss; + } + + /* Configure BTE BW_LIMITER field to max recommended value (1 GB) */ + writel((readl(iss->regs[OMAP4_ISS_MEM_BTE] + BTE_CTRL) & ~BTE_CTRL_BW_LIMITER_MASK) | + (18 << BTE_CTRL_BW_LIMITER_SHIFT), + iss->regs[OMAP4_ISS_MEM_BTE] + BTE_CTRL); + + /* Perform ISP reset */ + ret = omap4iss_subclk_enable(iss, OMAP4_ISS_SUBCLK_ISP); + if (ret < 0) + goto error_iss; + + ret = iss_isp_reset(iss); + if (ret < 0) + goto error_iss; + + dev_info(iss->dev, "ISP Revision %08x found\n", + readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_REVISION)); + + /* Interrupt */ + iss->irq_num = platform_get_irq(pdev, 0); + if (iss->irq_num <= 0) { + dev_err(iss->dev, "No IRQ resource\n"); + ret = -ENODEV; + goto error_iss; + } + + if (request_irq(iss->irq_num, iss_isr, IRQF_SHARED, "OMAP4 ISS", iss)) { + dev_err(iss->dev, "Unable to request IRQ\n"); + ret = -EINVAL; + goto error_iss; + } + + /* Entities */ + ret = iss_initialize_modules(iss); + if (ret < 0) + goto error_irq; + + ret = iss_register_entities(iss); + if (ret < 0) + goto error_modules; + + omap4iss_put(iss); + + return 0; + +error_modules: + iss_cleanup_modules(iss); +error_irq: + free_irq(iss->irq_num, iss); +error_iss: + omap4iss_put(iss); +error: + iss_put_clocks(iss); + + for (i = 0; i < OMAP4_ISS_MEM_LAST; i++) { + if (iss->regs[i]) { + iounmap(iss->regs[i]); + iss->regs[i] = NULL; + } + + if (iss->res[i]) { + release_mem_region(iss->res[i]->start, + resource_size(iss->res[i])); + iss->res[i] = NULL; + } + } + platform_set_drvdata(pdev, NULL); + + mutex_destroy(&iss->iss_mutex); + kfree(iss); + + return ret; +} + +static int iss_remove(struct platform_device *pdev) +{ + struct iss_device *iss = platform_get_drvdata(pdev); + int i; + + iss_unregister_entities(iss); + iss_cleanup_modules(iss); + + free_irq(iss->irq_num, iss); + iss_put_clocks(iss); + + for (i = 0; i < OMAP4_ISS_MEM_LAST; i++) { + if (iss->regs[i]) { + iounmap(iss->regs[i]); + iss->regs[i] = NULL; + } + + if (iss->res[i]) { + release_mem_region(iss->res[i]->start, + resource_size(iss->res[i])); + iss->res[i] = NULL; + } + } + + kfree(iss); + + return 0; +} + +static struct platform_device_id omap4iss_id_table[] = { + { "omap4iss", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(platform, omap4iss_id_table); + +static struct platform_driver iss_driver = { + .probe = iss_probe, + .remove = iss_remove, + .id_table = omap4iss_id_table, + .driver = { + .owner = THIS_MODULE, + .name = "omap4iss", + }, +}; + +module_platform_driver(iss_driver); + +MODULE_DESCRIPTION("TI OMAP4 ISS driver"); +MODULE_AUTHOR("Sergio Aguirre "); +MODULE_LICENSE("GPL"); +MODULE_VERSION(ISS_VIDEO_DRIVER_VERSION); diff --git a/drivers/staging/media/omap4iss/iss.h b/drivers/staging/media/omap4iss/iss.h new file mode 100644 index 000000000000..cc24f1ae17c6 --- /dev/null +++ b/drivers/staging/media/omap4iss/iss.h @@ -0,0 +1,153 @@ +/* + * TI OMAP4 ISS V4L2 Driver + * + * Copyright (C) 2012 Texas Instruments. + * + * Author: Sergio Aguirre + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _OMAP4_ISS_H_ +#define _OMAP4_ISS_H_ + +#include +#include +#include +#include +#include + +#include + +#include "iss_regs.h" +#include "iss_csiphy.h" +#include "iss_csi2.h" +#include "iss_ipipeif.h" +#include "iss_ipipe.h" +#include "iss_resizer.h" + +#define to_iss_device(ptr_module) \ + container_of(ptr_module, struct iss_device, ptr_module) +#define to_device(ptr_module) \ + (to_iss_device(ptr_module)->dev) + +enum iss_mem_resources { + OMAP4_ISS_MEM_TOP, + OMAP4_ISS_MEM_CSI2_A_REGS1, + OMAP4_ISS_MEM_CAMERARX_CORE1, + OMAP4_ISS_MEM_CSI2_B_REGS1, + OMAP4_ISS_MEM_CAMERARX_CORE2, + OMAP4_ISS_MEM_BTE, + OMAP4_ISS_MEM_ISP_SYS1, + OMAP4_ISS_MEM_ISP_RESIZER, + OMAP4_ISS_MEM_ISP_IPIPE, + OMAP4_ISS_MEM_ISP_ISIF, + OMAP4_ISS_MEM_ISP_IPIPEIF, + OMAP4_ISS_MEM_LAST, +}; + +enum iss_subclk_resource { + OMAP4_ISS_SUBCLK_SIMCOP = (1 << 0), + OMAP4_ISS_SUBCLK_ISP = (1 << 1), + OMAP4_ISS_SUBCLK_CSI2_A = (1 << 2), + OMAP4_ISS_SUBCLK_CSI2_B = (1 << 3), + OMAP4_ISS_SUBCLK_CCP2 = (1 << 4), +}; + +enum iss_isp_subclk_resource { + OMAP4_ISS_ISP_SUBCLK_BL = (1 << 0), + OMAP4_ISS_ISP_SUBCLK_ISIF = (1 << 1), + OMAP4_ISS_ISP_SUBCLK_H3A = (1 << 2), + OMAP4_ISS_ISP_SUBCLK_RSZ = (1 << 3), + OMAP4_ISS_ISP_SUBCLK_IPIPE = (1 << 4), + OMAP4_ISS_ISP_SUBCLK_IPIPEIF = (1 << 5), +}; + +/* + * struct iss_reg - Structure for ISS register values. + * @reg: 32-bit Register address. + * @val: 32-bit Register value. + */ +struct iss_reg { + enum iss_mem_resources mmio_range; + u32 reg; + u32 val; +}; + +struct iss_device { + struct v4l2_device v4l2_dev; + struct media_device media_dev; + struct device *dev; + u32 revision; + + /* platform HW resources */ + struct iss_platform_data *pdata; + unsigned int irq_num; + + struct resource *res[OMAP4_ISS_MEM_LAST]; + void __iomem *regs[OMAP4_ISS_MEM_LAST]; + + u64 raw_dmamask; + + struct mutex iss_mutex; /* For handling ref_count field */ + int has_context; + int ref_count; + + struct clk *iss_fck; + struct clk *iss_ctrlclk; + + /* ISS modules */ + struct iss_csi2_device csi2a; + struct iss_csi2_device csi2b; + struct iss_csiphy csiphy1; + struct iss_csiphy csiphy2; + struct iss_ipipeif_device ipipeif; + struct iss_ipipe_device ipipe; + struct iss_resizer_device resizer; + + unsigned int subclk_resources; + unsigned int isp_subclk_resources; +}; + +#define v4l2_dev_to_iss_device(dev) \ + container_of(dev, struct iss_device, v4l2_dev) + +int omap4iss_get_external_info(struct iss_pipeline *pipe, + struct media_link *link); + +int omap4iss_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait, + atomic_t *stopping); + +int omap4iss_module_sync_is_stopping(wait_queue_head_t *wait, + atomic_t *stopping); + +int omap4iss_pipeline_set_stream(struct iss_pipeline *pipe, + enum iss_pipeline_stream_state state); + +void omap4iss_configure_bridge(struct iss_device *iss, + enum ipipeif_input_entity input); + +struct iss_device *omap4iss_get(struct iss_device *iss); +void omap4iss_put(struct iss_device *iss); +int omap4iss_subclk_enable(struct iss_device *iss, + enum iss_subclk_resource res); +int omap4iss_subclk_disable(struct iss_device *iss, + enum iss_subclk_resource res); +int omap4iss_isp_subclk_enable(struct iss_device *iss, + enum iss_isp_subclk_resource res); +int omap4iss_isp_subclk_disable(struct iss_device *iss, + enum iss_isp_subclk_resource res); + +void omap4iss_isp_enable_interrupts(struct iss_device *iss); +void omap4iss_isp_disable_interrupts(struct iss_device *iss); + +int omap4iss_pipeline_pm_use(struct media_entity *entity, int use); + +int omap4iss_register_entities(struct platform_device *pdev, + struct v4l2_device *v4l2_dev); +void omap4iss_unregister_entities(struct platform_device *pdev); + +#endif /* _OMAP4_ISS_H_ */ diff --git a/drivers/staging/media/omap4iss/iss_regs.h b/drivers/staging/media/omap4iss/iss_regs.h new file mode 100644 index 000000000000..7327d0c1ae37 --- /dev/null +++ b/drivers/staging/media/omap4iss/iss_regs.h @@ -0,0 +1,883 @@ +/* + * TI OMAP4 ISS V4L2 Driver - Register defines + * + * Copyright (C) 2012 Texas Instruments. + * + * Author: Sergio Aguirre + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _OMAP4_ISS_REGS_H_ +#define _OMAP4_ISS_REGS_H_ + +/* ISS */ +#define ISS_HL_REVISION 0x0 + +#define ISS_HL_SYSCONFIG 0x10 +#define ISS_HL_SYSCONFIG_IDLEMODE_SHIFT 2 +#define ISS_HL_SYSCONFIG_IDLEMODE_FORCEIDLE 0x0 +#define ISS_HL_SYSCONFIG_IDLEMODE_NOIDLE 0x1 +#define ISS_HL_SYSCONFIG_IDLEMODE_SMARTIDLE 0x2 +#define ISS_HL_SYSCONFIG_SOFTRESET (1 << 0) + +#define ISS_HL_IRQSTATUS_5 (0x24 + (0x10 * 5)) +#define ISS_HL_IRQENABLE_5_SET (0x28 + (0x10 * 5)) +#define ISS_HL_IRQENABLE_5_CLR (0x2C + (0x10 * 5)) + +#define ISS_HL_IRQ_BTE (1 << 11) +#define ISS_HL_IRQ_CBUFF (1 << 10) +#define ISS_HL_IRQ_CSIB (1 << 5) +#define ISS_HL_IRQ_CSIA (1 << 4) +#define ISS_HL_IRQ_ISP(i) (1 << (i)) + +#define ISS_CTRL 0x80 +#define ISS_CTRL_CLK_DIV_MASK (3 << 4) +#define ISS_CTRL_INPUT_SEL_MASK (3 << 2) +#define ISS_CTRL_INPUT_SEL_CSI2A (0 << 2) +#define ISS_CTRL_INPUT_SEL_CSI2B (1 << 2) +#define ISS_CTRL_SYNC_DETECT_VS_RAISING (3 << 0) + +#define ISS_CLKCTRL 0x84 +#define ISS_CLKCTRL_VPORT2_CLK (1 << 30) +#define ISS_CLKCTRL_VPORT1_CLK (1 << 29) +#define ISS_CLKCTRL_VPORT0_CLK (1 << 28) +#define ISS_CLKCTRL_CCP2 (1 << 4) +#define ISS_CLKCTRL_CSI2_B (1 << 3) +#define ISS_CLKCTRL_CSI2_A (1 << 2) +#define ISS_CLKCTRL_ISP (1 << 1) +#define ISS_CLKCTRL_SIMCOP (1 << 0) + +#define ISS_CLKSTAT 0x88 +#define ISS_CLKSTAT_VPORT2_CLK (1 << 30) +#define ISS_CLKSTAT_VPORT1_CLK (1 << 29) +#define ISS_CLKSTAT_VPORT0_CLK (1 << 28) +#define ISS_CLKSTAT_CCP2 (1 << 4) +#define ISS_CLKSTAT_CSI2_B (1 << 3) +#define ISS_CLKSTAT_CSI2_A (1 << 2) +#define ISS_CLKSTAT_ISP (1 << 1) +#define ISS_CLKSTAT_SIMCOP (1 << 0) + +#define ISS_PM_STATUS 0x8C +#define ISS_PM_STATUS_CBUFF_PM_MASK (3 << 12) +#define ISS_PM_STATUS_BTE_PM_MASK (3 << 10) +#define ISS_PM_STATUS_SIMCOP_PM_MASK (3 << 8) +#define ISS_PM_STATUS_ISP_PM_MASK (3 << 6) +#define ISS_PM_STATUS_CCP2_PM_MASK (3 << 4) +#define ISS_PM_STATUS_CSI2_B_PM_MASK (3 << 2) +#define ISS_PM_STATUS_CSI2_A_PM_MASK (3 << 0) + +#define REGISTER0 0x0 +#define REGISTER0_HSCLOCKCONFIG (1 << 24) +#define REGISTER0_THS_TERM_MASK (0xFF << 8) +#define REGISTER0_THS_TERM_SHIFT 8 +#define REGISTER0_THS_SETTLE_MASK (0xFF << 0) +#define REGISTER0_THS_SETTLE_SHIFT 0 + +#define REGISTER1 0x4 +#define REGISTER1_RESET_DONE_CTRLCLK (1 << 29) +#define REGISTER1_CLOCK_MISS_DETECTOR_STATUS (1 << 25) +#define REGISTER1_TCLK_TERM_MASK (0x3F << 18) +#define REGISTER1_TCLK_TERM_SHIFT 18 +#define REGISTER1_DPHY_HS_SYNC_PATTERN_SHIFT 10 +#define REGISTER1_CTRLCLK_DIV_FACTOR_MASK (0x3 << 8) +#define REGISTER1_CTRLCLK_DIV_FACTOR_SHIFT 8 +#define REGISTER1_TCLK_SETTLE_MASK (0xFF << 0) +#define REGISTER1_TCLK_SETTLE_SHIFT 0 + +#define REGISTER2 0x8 + +#define CSI2_SYSCONFIG 0x10 +#define CSI2_SYSCONFIG_MSTANDBY_MODE_MASK (3 << 12) +#define CSI2_SYSCONFIG_MSTANDBY_MODE_FORCE (0 << 12) +#define CSI2_SYSCONFIG_MSTANDBY_MODE_NO (1 << 12) +#define CSI2_SYSCONFIG_MSTANDBY_MODE_SMART (2 << 12) +#define CSI2_SYSCONFIG_SOFT_RESET (1 << 1) +#define CSI2_SYSCONFIG_AUTO_IDLE (1 << 0) + +#define CSI2_SYSSTATUS 0x14 +#define CSI2_SYSSTATUS_RESET_DONE (1 << 0) + +#define CSI2_IRQSTATUS 0x18 +#define CSI2_IRQENABLE 0x1C + +/* Shared bits across CSI2_IRQENABLE and IRQSTATUS */ + +#define CSI2_IRQ_OCP_ERR (1 << 14) +#define CSI2_IRQ_SHORT_PACKET (1 << 13) +#define CSI2_IRQ_ECC_CORRECTION (1 << 12) +#define CSI2_IRQ_ECC_NO_CORRECTION (1 << 11) +#define CSI2_IRQ_COMPLEXIO_ERR (1 << 9) +#define CSI2_IRQ_FIFO_OVF (1 << 8) +#define CSI2_IRQ_CONTEXT0 (1 << 0) + +#define CSI2_CTRL 0x40 +#define CSI2_CTRL_MFLAG_LEVH_MASK (7 << 20) +#define CSI2_CTRL_MFLAG_LEVH_SHIFT 20 +#define CSI2_CTRL_MFLAG_LEVL_MASK (7 << 17) +#define CSI2_CTRL_MFLAG_LEVL_SHIFT 17 +#define CSI2_CTRL_BURST_SIZE_EXPAND (1 << 16) +#define CSI2_CTRL_VP_CLK_EN (1 << 15) +#define CSI2_CTRL_NON_POSTED_WRITE (1 << 13) +#define CSI2_CTRL_VP_ONLY_EN (1 << 11) +#define CSI2_CTRL_VP_OUT_CTRL_MASK (3 << 8) +#define CSI2_CTRL_VP_OUT_CTRL_SHIFT 8 +#define CSI2_CTRL_DBG_EN (1 << 7) +#define CSI2_CTRL_BURST_SIZE_MASK (3 << 5) +#define CSI2_CTRL_ENDIANNESS (1 << 4) +#define CSI2_CTRL_FRAME (1 << 3) +#define CSI2_CTRL_ECC_EN (1 << 2) +#define CSI2_CTRL_IF_EN (1 << 0) + +#define CSI2_DBG_H 0x44 + +#define CSI2_COMPLEXIO_CFG 0x50 +#define CSI2_COMPLEXIO_CFG_RESET_CTRL (1 << 30) +#define CSI2_COMPLEXIO_CFG_RESET_DONE (1 << 29) +#define CSI2_COMPLEXIO_CFG_PWD_CMD_MASK (3 << 27) +#define CSI2_COMPLEXIO_CFG_PWD_CMD_OFF (0 << 27) +#define CSI2_COMPLEXIO_CFG_PWD_CMD_ON (1 << 27) +#define CSI2_COMPLEXIO_CFG_PWD_CMD_ULP (2 << 27) +#define CSI2_COMPLEXIO_CFG_PWD_STATUS_MASK (3 << 25) +#define CSI2_COMPLEXIO_CFG_PWD_STATUS_OFF (0 << 25) +#define CSI2_COMPLEXIO_CFG_PWD_STATUS_ON (1 << 25) +#define CSI2_COMPLEXIO_CFG_PWD_STATUS_ULP (2 << 25) +#define CSI2_COMPLEXIO_CFG_PWR_AUTO (1 << 24) +#define CSI2_COMPLEXIO_CFG_DATA_POL(i) (1 << (((i) * 4) + 3)) +#define CSI2_COMPLEXIO_CFG_DATA_POSITION_MASK(i) (7 << ((i) * 4)) +#define CSI2_COMPLEXIO_CFG_DATA_POSITION_SHIFT(i) ((i) * 4) +#define CSI2_COMPLEXIO_CFG_CLOCK_POL (1 << 3) +#define CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK (7 << 0) +#define CSI2_COMPLEXIO_CFG_CLOCK_POSITION_SHIFT 0 + +#define CSI2_COMPLEXIO_IRQSTATUS 0x54 + +#define CSI2_SHORT_PACKET 0x5C + +#define CSI2_COMPLEXIO_IRQENABLE 0x60 + +/* Shared bits across CSI2_COMPLEXIO_IRQENABLE and IRQSTATUS */ +#define CSI2_COMPLEXIO_IRQ_STATEALLULPMEXIT (1 << 26) +#define CSI2_COMPLEXIO_IRQ_STATEALLULPMENTER (1 << 25) +#define CSI2_COMPLEXIO_IRQ_STATEULPM5 (1 << 24) +#define CSI2_COMPLEXIO_IRQ_STATEULPM4 (1 << 23) +#define CSI2_COMPLEXIO_IRQ_STATEULPM3 (1 << 22) +#define CSI2_COMPLEXIO_IRQ_STATEULPM2 (1 << 21) +#define CSI2_COMPLEXIO_IRQ_STATEULPM1 (1 << 20) +#define CSI2_COMPLEXIO_IRQ_ERRCONTROL5 (1 << 19) +#define CSI2_COMPLEXIO_IRQ_ERRCONTROL4 (1 << 18) +#define CSI2_COMPLEXIO_IRQ_ERRCONTROL3 (1 << 17) +#define CSI2_COMPLEXIO_IRQ_ERRCONTROL2 (1 << 16) +#define CSI2_COMPLEXIO_IRQ_ERRCONTROL1 (1 << 15) +#define CSI2_COMPLEXIO_IRQ_ERRESC5 (1 << 14) +#define CSI2_COMPLEXIO_IRQ_ERRESC4 (1 << 13) +#define CSI2_COMPLEXIO_IRQ_ERRESC3 (1 << 12) +#define CSI2_COMPLEXIO_IRQ_ERRESC2 (1 << 11) +#define CSI2_COMPLEXIO_IRQ_ERRESC1 (1 << 10) +#define CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS5 (1 << 9) +#define CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS4 (1 << 8) +#define CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS3 (1 << 7) +#define CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS2 (1 << 6) +#define CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS1 (1 << 5) +#define CSI2_COMPLEXIO_IRQ_ERRSOTHS5 (1 << 4) +#define CSI2_COMPLEXIO_IRQ_ERRSOTHS4 (1 << 3) +#define CSI2_COMPLEXIO_IRQ_ERRSOTHS3 (1 << 2) +#define CSI2_COMPLEXIO_IRQ_ERRSOTHS2 (1 << 1) +#define CSI2_COMPLEXIO_IRQ_ERRSOTHS1 (1 << 0) + +#define CSI2_DBG_P 0x68 + +#define CSI2_TIMING 0x6C +#define CSI2_TIMING_FORCE_RX_MODE_IO1 (1 << 15) +#define CSI2_TIMING_STOP_STATE_X16_IO1 (1 << 14) +#define CSI2_TIMING_STOP_STATE_X4_IO1 (1 << 13) +#define CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK (0x1FFF << 0) +#define CSI2_TIMING_STOP_STATE_COUNTER_IO1_SHIFT 0 + +#define CSI2_CTX_CTRL1(i) (0x70 + (0x20 * i)) +#define CSI2_CTX_CTRL1_GENERIC (1 << 30) +#define CSI2_CTX_CTRL1_TRANSCODE (0xF << 24) +#define CSI2_CTX_CTRL1_FEC_NUMBER_MASK (0xFF << 16) +#define CSI2_CTX_CTRL1_COUNT_MASK (0xFF << 8) +#define CSI2_CTX_CTRL1_COUNT_SHIFT 8 +#define CSI2_CTX_CTRL1_EOF_EN (1 << 7) +#define CSI2_CTX_CTRL1_EOL_EN (1 << 6) +#define CSI2_CTX_CTRL1_CS_EN (1 << 5) +#define CSI2_CTX_CTRL1_COUNT_UNLOCK (1 << 4) +#define CSI2_CTX_CTRL1_PING_PONG (1 << 3) +#define CSI2_CTX_CTRL1_CTX_EN (1 << 0) + +#define CSI2_CTX_CTRL2(i) (0x74 + (0x20 * i)) +#define CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT 13 +#define CSI2_CTX_CTRL2_USER_DEF_MAP_MASK \ + (0x3 << CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT) +#define CSI2_CTX_CTRL2_VIRTUAL_ID_MASK (3 << 11) +#define CSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT 11 +#define CSI2_CTX_CTRL2_DPCM_PRED (1 << 10) +#define CSI2_CTX_CTRL2_FORMAT_MASK (0x3FF << 0) +#define CSI2_CTX_CTRL2_FORMAT_SHIFT 0 + +#define CSI2_CTX_DAT_OFST(i) (0x78 + (0x20 * i)) +#define CSI2_CTX_DAT_OFST_MASK (0xFFF << 5) + +#define CSI2_CTX_PING_ADDR(i) (0x7C + (0x20 * i)) +#define CSI2_CTX_PING_ADDR_MASK 0xFFFFFFE0 + +#define CSI2_CTX_PONG_ADDR(i) (0x80 + (0x20 * i)) +#define CSI2_CTX_PONG_ADDR_MASK CSI2_CTX_PING_ADDR_MASK + +#define CSI2_CTX_IRQENABLE(i) (0x84 + (0x20 * i)) +#define CSI2_CTX_IRQSTATUS(i) (0x88 + (0x20 * i)) + +#define CSI2_CTX_CTRL3(i) (0x8C + (0x20 * i)) +#define CSI2_CTX_CTRL3_ALPHA_SHIFT 5 +#define CSI2_CTX_CTRL3_ALPHA_MASK \ + (0x3fff << CSI2_CTX_CTRL3_ALPHA_SHIFT) + +/* Shared bits across CSI2_CTX_IRQENABLE and IRQSTATUS */ +#define CSI2_CTX_IRQ_ECC_CORRECTION (1 << 8) +#define CSI2_CTX_IRQ_LINE_NUMBER (1 << 7) +#define CSI2_CTX_IRQ_FRAME_NUMBER (1 << 6) +#define CSI2_CTX_IRQ_CS (1 << 5) +#define CSI2_CTX_IRQ_LE (1 << 3) +#define CSI2_CTX_IRQ_LS (1 << 2) +#define CSI2_CTX_IRQ_FE (1 << 1) +#define CSI2_CTX_IRQ_FS (1 << 0) + +/* ISS BTE */ +#define BTE_CTRL (0x0030) +#define BTE_CTRL_BW_LIMITER_MASK (0x3FF << 22) +#define BTE_CTRL_BW_LIMITER_SHIFT 22 + +/* ISS ISP_SYS1 */ +#define ISP5_REVISION (0x0000) +#define ISP5_SYSCONFIG (0x0010) +#define ISP5_SYSCONFIG_STANDBYMODE_MASK (3 << 4) +#define ISP5_SYSCONFIG_STANDBYMODE_FORCE (0 << 4) +#define ISP5_SYSCONFIG_STANDBYMODE_NO (1 << 4) +#define ISP5_SYSCONFIG_STANDBYMODE_SMART (2 << 4) +#define ISP5_SYSCONFIG_SOFTRESET (1 << 1) + +#define ISP5_IRQSTATUS(i) (0x0028 + (0x10 * (i))) +#define ISP5_IRQENABLE_SET(i) (0x002C + (0x10 * (i))) +#define ISP5_IRQENABLE_CLR(i) (0x0030 + (0x10 * (i))) + +/* Bits shared for ISP5_IRQ* registers */ +#define ISP5_IRQ_OCP_ERR (1 << 31) +#define ISP5_IRQ_RSZ_INT_EOF0 (1 << 22) +#define ISP5_IRQ_RSZ_FIFO_IN_BLK (1 << 19) +#define ISP5_IRQ_RSZ_FIFO_OVF (1 << 18) +#define ISP5_IRQ_RSZ_INT_CYC_RSZA (1 << 16) +#define ISP5_IRQ_RSZ_INT_DMA (1 << 15) +#define ISP5_IRQ_IPIPEIF (1 << 9) +#define ISP5_IRQ_ISIF3 (1 << 3) +#define ISP5_IRQ_ISIF2 (1 << 2) +#define ISP5_IRQ_ISIF1 (1 << 1) +#define ISP5_IRQ_ISIF0 (1 << 0) + +#define ISP5_CTRL (0x006C) +#define ISP5_CTRL_MSTANDBY (1 << 24) +#define ISP5_CTRL_VD_PULSE_EXT (1 << 23) +#define ISP5_CTRL_MSTANDBY_WAIT (1 << 20) +#define ISP5_CTRL_BL_CLK_ENABLE (1 << 15) +#define ISP5_CTRL_ISIF_CLK_ENABLE (1 << 14) +#define ISP5_CTRL_H3A_CLK_ENABLE (1 << 13) +#define ISP5_CTRL_RSZ_CLK_ENABLE (1 << 12) +#define ISP5_CTRL_IPIPE_CLK_ENABLE (1 << 11) +#define ISP5_CTRL_IPIPEIF_CLK_ENABLE (1 << 10) +#define ISP5_CTRL_SYNC_ENABLE (1 << 9) +#define ISP5_CTRL_PSYNC_CLK_SEL (1 << 8) + +/* ISS ISP ISIF register offsets */ +#define ISIF_SYNCEN (0x0000) +#define ISIF_SYNCEN_DWEN (1 << 1) +#define ISIF_SYNCEN_SYEN (1 << 0) + +#define ISIF_MODESET (0x0004) +#define ISIF_MODESET_INPMOD_MASK (3 << 12) +#define ISIF_MODESET_INPMOD_RAW (0 << 12) +#define ISIF_MODESET_INPMOD_YCBCR16 (1 << 12) +#define ISIF_MODESET_INPMOD_YCBCR8 (2 << 12) +#define ISIF_MODESET_CCDW_MASK (7 << 8) +#define ISIF_MODESET_CCDW_2BIT (2 << 8) +#define ISIF_MODESET_CCDMD (1 << 7) +#define ISIF_MODESET_SWEN (1 << 5) +#define ISIF_MODESET_HDPOL (1 << 3) +#define ISIF_MODESET_VDPOL (1 << 2) + +#define ISIF_SPH (0x0018) +#define ISIF_SPH_MASK (0x7FFF) + +#define ISIF_LNH (0x001C) +#define ISIF_LNH_MASK (0x7FFF) + +#define ISIF_LNV (0x0028) +#define ISIF_LNV_MASK (0x7FFF) + +#define ISIF_HSIZE (0x0034) +#define ISIF_HSIZE_ADCR (1 << 12) +#define ISIF_HSIZE_HSIZE_MASK (0xFFF) + +#define ISIF_CADU (0x003C) +#define ISIF_CADU_MASK (0x7FF) + +#define ISIF_CADL (0x0040) +#define ISIF_CADL_MASK (0xFFFF) + +#define ISIF_CCOLP (0x004C) +#define ISIF_CCOLP_CP0_F0_R (0 << 6) +#define ISIF_CCOLP_CP0_F0_GR (1 << 6) +#define ISIF_CCOLP_CP0_F0_B (3 << 6) +#define ISIF_CCOLP_CP0_F0_GB (2 << 6) +#define ISIF_CCOLP_CP1_F0_R (0 << 4) +#define ISIF_CCOLP_CP1_F0_GR (1 << 4) +#define ISIF_CCOLP_CP1_F0_B (3 << 4) +#define ISIF_CCOLP_CP1_F0_GB (2 << 4) +#define ISIF_CCOLP_CP2_F0_R (0 << 2) +#define ISIF_CCOLP_CP2_F0_GR (1 << 2) +#define ISIF_CCOLP_CP2_F0_B (3 << 2) +#define ISIF_CCOLP_CP2_F0_GB (2 << 2) +#define ISIF_CCOLP_CP3_F0_R (0 << 0) +#define ISIF_CCOLP_CP3_F0_GR (1 << 0) +#define ISIF_CCOLP_CP3_F0_B (3 << 0) +#define ISIF_CCOLP_CP3_F0_GB (2 << 0) + +#define ISIF_VDINT0 (0x0070) +#define ISIF_VDINT0_MASK (0x7FFF) + +#define ISIF_CGAMMAWD (0x0080) +#define ISIF_CGAMMAWD_GWDI_MASK (0xF << 1) +#define ISIF_CGAMMAWD_GWDI_BIT11 (0x4 << 1) + +#define ISIF_CCDCFG (0x0088) +#define ISIF_CCDCFG_Y8POS (1 << 11) + +/* ISS ISP IPIPEIF register offsets */ +#define IPIPEIF_ENABLE (0x0000) + +#define IPIPEIF_CFG1 (0x0004) +#define IPIPEIF_CFG1_INPSRC1_MASK (3 << 14) +#define IPIPEIF_CFG1_INPSRC1_VPORT_RAW (0 << 14) +#define IPIPEIF_CFG1_INPSRC1_SDRAM_RAW (1 << 14) +#define IPIPEIF_CFG1_INPSRC1_ISIF_DARKFM (2 << 14) +#define IPIPEIF_CFG1_INPSRC1_SDRAM_YUV (3 << 14) +#define IPIPEIF_CFG1_INPSRC2_MASK (3 << 2) +#define IPIPEIF_CFG1_INPSRC2_ISIF (0 << 2) +#define IPIPEIF_CFG1_INPSRC2_SDRAM_RAW (1 << 2) +#define IPIPEIF_CFG1_INPSRC2_ISIF_DARKFM (2 << 2) +#define IPIPEIF_CFG1_INPSRC2_SDRAM_YUV (3 << 2) + +#define IPIPEIF_CFG2 (0x0030) +#define IPIPEIF_CFG2_YUV8P (1 << 7) +#define IPIPEIF_CFG2_YUV8 (1 << 6) +#define IPIPEIF_CFG2_YUV16 (1 << 3) +#define IPIPEIF_CFG2_VDPOL (1 << 2) +#define IPIPEIF_CFG2_HDPOL (1 << 1) +#define IPIPEIF_CFG2_INTSW (1 << 0) + +#define IPIPEIF_CLKDIV (0x0040) + +/* ISS ISP IPIPE register offsets */ +#define IPIPE_SRC_EN (0x0000) +#define IPIPE_SRC_EN_EN (1 << 0) + +#define IPIPE_SRC_MODE (0x0004) +#define IPIPE_SRC_MODE_WRT (1 << 1) +#define IPIPE_SRC_MODE_OST (1 << 0) + +#define IPIPE_SRC_FMT (0x0008) +#define IPIPE_SRC_FMT_RAW2YUV (0 << 0) +#define IPIPE_SRC_FMT_RAW2RAW (1 << 0) +#define IPIPE_SRC_FMT_RAW2STATS (2 << 0) +#define IPIPE_SRC_FMT_YUV2YUV (3 << 0) + +#define IPIPE_SRC_COL (0x000C) +#define IPIPE_SRC_COL_OO_R (0 << 6) +#define IPIPE_SRC_COL_OO_GR (1 << 6) +#define IPIPE_SRC_COL_OO_B (3 << 6) +#define IPIPE_SRC_COL_OO_GB (2 << 6) +#define IPIPE_SRC_COL_OE_R (0 << 4) +#define IPIPE_SRC_COL_OE_GR (1 << 4) +#define IPIPE_SRC_COL_OE_B (3 << 4) +#define IPIPE_SRC_COL_OE_GB (2 << 4) +#define IPIPE_SRC_COL_EO_R (0 << 2) +#define IPIPE_SRC_COL_EO_GR (1 << 2) +#define IPIPE_SRC_COL_EO_B (3 << 2) +#define IPIPE_SRC_COL_EO_GB (2 << 2) +#define IPIPE_SRC_COL_EE_R (0 << 0) +#define IPIPE_SRC_COL_EE_GR (1 << 0) +#define IPIPE_SRC_COL_EE_B (3 << 0) +#define IPIPE_SRC_COL_EE_GB (2 << 0) + +#define IPIPE_SRC_VPS (0x0010) +#define IPIPE_SRC_VPS_MASK (0xFFFF) + +#define IPIPE_SRC_VSZ (0x0014) +#define IPIPE_SRC_VSZ_MASK (0x1FFF) + +#define IPIPE_SRC_HPS (0x0018) +#define IPIPE_SRC_HPS_MASK (0xFFFF) + +#define IPIPE_SRC_HSZ (0x001C) +#define IPIPE_SRC_HSZ_MASK (0x1FFE) + +#define IPIPE_SEL_SBU (0x0020) + +#define IPIPE_SRC_STA (0x0024) + +#define IPIPE_GCK_MMR (0x0028) +#define IPIPE_GCK_MMR_REG (1 << 0) + +#define IPIPE_GCK_PIX (0x002C) +#define IPIPE_GCK_PIX_G3 (1 << 3) +#define IPIPE_GCK_PIX_G2 (1 << 2) +#define IPIPE_GCK_PIX_G1 (1 << 1) +#define IPIPE_GCK_PIX_G0 (1 << 0) + +#define IPIPE_DPC_LUT_EN (0x0034) +#define IPIPE_DPC_LUT_SEL (0x0038) +#define IPIPE_DPC_LUT_ADR (0x003C) +#define IPIPE_DPC_LUT_SIZ (0x0040) + +#define IPIPE_DPC_OTF_EN (0x0044) +#define IPIPE_DPC_OTF_TYP (0x0048) +#define IPIPE_DPC_OTF_2_D_THR_R (0x004C) +#define IPIPE_DPC_OTF_2_D_THR_GR (0x0050) +#define IPIPE_DPC_OTF_2_D_THR_GB (0x0054) +#define IPIPE_DPC_OTF_2_D_THR_B (0x0058) +#define IPIPE_DPC_OTF_2_C_THR_R (0x005C) +#define IPIPE_DPC_OTF_2_C_THR_GR (0x0060) +#define IPIPE_DPC_OTF_2_C_THR_GB (0x0064) +#define IPIPE_DPC_OTF_2_C_THR_B (0x0068) +#define IPIPE_DPC_OTF_3_SHF (0x006C) +#define IPIPE_DPC_OTF_3_D_THR (0x0070) +#define IPIPE_DPC_OTF_3_D_SPL (0x0074) +#define IPIPE_DPC_OTF_3_D_MIN (0x0078) +#define IPIPE_DPC_OTF_3_D_MAX (0x007C) +#define IPIPE_DPC_OTF_3_C_THR (0x0080) +#define IPIPE_DPC_OTF_3_C_SLP (0x0084) +#define IPIPE_DPC_OTF_3_C_MIN (0x0088) +#define IPIPE_DPC_OTF_3_C_MAX (0x008C) + +#define IPIPE_LSC_VOFT (0x0090) +#define IPIPE_LSC_VA2 (0x0094) +#define IPIPE_LSC_VA1 (0x0098) +#define IPIPE_LSC_VS (0x009C) +#define IPIPE_LSC_HOFT (0x00A0) +#define IPIPE_LSC_HA2 (0x00A4) +#define IPIPE_LSC_HA1 (0x00A8) +#define IPIPE_LSC_HS (0x00AC) +#define IPIPE_LSC_GAN_R (0x00B0) +#define IPIPE_LSC_GAN_GR (0x00B4) +#define IPIPE_LSC_GAN_GB (0x00B8) +#define IPIPE_LSC_GAN_B (0x00BC) +#define IPIPE_LSC_OFT_R (0x00C0) +#define IPIPE_LSC_OFT_GR (0x00C4) +#define IPIPE_LSC_OFT_GB (0x00C8) +#define IPIPE_LSC_OFT_B (0x00CC) +#define IPIPE_LSC_SHF (0x00D0) +#define IPIPE_LSC_MAX (0x00D4) + +#define IPIPE_D2F_1ST_EN (0x00D8) +#define IPIPE_D2F_1ST_TYP (0x00DC) +#define IPIPE_D2F_1ST_THR_00 (0x00E0) +#define IPIPE_D2F_1ST_THR_01 (0x00E4) +#define IPIPE_D2F_1ST_THR_02 (0x00E8) +#define IPIPE_D2F_1ST_THR_03 (0x00EC) +#define IPIPE_D2F_1ST_THR_04 (0x00F0) +#define IPIPE_D2F_1ST_THR_05 (0x00F4) +#define IPIPE_D2F_1ST_THR_06 (0x00F8) +#define IPIPE_D2F_1ST_THR_07 (0x00FC) +#define IPIPE_D2F_1ST_STR_00 (0x0100) +#define IPIPE_D2F_1ST_STR_01 (0x0104) +#define IPIPE_D2F_1ST_STR_02 (0x0108) +#define IPIPE_D2F_1ST_STR_03 (0x010C) +#define IPIPE_D2F_1ST_STR_04 (0x0110) +#define IPIPE_D2F_1ST_STR_05 (0x0114) +#define IPIPE_D2F_1ST_STR_06 (0x0118) +#define IPIPE_D2F_1ST_STR_07 (0x011C) +#define IPIPE_D2F_1ST_SPR_00 (0x0120) +#define IPIPE_D2F_1ST_SPR_01 (0x0124) +#define IPIPE_D2F_1ST_SPR_02 (0x0128) +#define IPIPE_D2F_1ST_SPR_03 (0x012C) +#define IPIPE_D2F_1ST_SPR_04 (0x0130) +#define IPIPE_D2F_1ST_SPR_05 (0x0134) +#define IPIPE_D2F_1ST_SPR_06 (0x0138) +#define IPIPE_D2F_1ST_SPR_07 (0x013C) +#define IPIPE_D2F_1ST_EDG_MIN (0x0140) +#define IPIPE_D2F_1ST_EDG_MAX (0x0144) +#define IPIPE_D2F_2ND_EN (0x0148) +#define IPIPE_D2F_2ND_TYP (0x014C) +#define IPIPE_D2F_2ND_THR00 (0x0150) +#define IPIPE_D2F_2ND_THR01 (0x0154) +#define IPIPE_D2F_2ND_THR02 (0x0158) +#define IPIPE_D2F_2ND_THR03 (0x015C) +#define IPIPE_D2F_2ND_THR04 (0x0160) +#define IPIPE_D2F_2ND_THR05 (0x0164) +#define IPIPE_D2F_2ND_THR06 (0x0168) +#define IPIPE_D2F_2ND_THR07 (0x016C) +#define IPIPE_D2F_2ND_STR_00 (0x0170) +#define IPIPE_D2F_2ND_STR_01 (0x0174) +#define IPIPE_D2F_2ND_STR_02 (0x0178) +#define IPIPE_D2F_2ND_STR_03 (0x017C) +#define IPIPE_D2F_2ND_STR_04 (0x0180) +#define IPIPE_D2F_2ND_STR_05 (0x0184) +#define IPIPE_D2F_2ND_STR_06 (0x0188) +#define IPIPE_D2F_2ND_STR_07 (0x018C) +#define IPIPE_D2F_2ND_SPR_00 (0x0190) +#define IPIPE_D2F_2ND_SPR_01 (0x0194) +#define IPIPE_D2F_2ND_SPR_02 (0x0198) +#define IPIPE_D2F_2ND_SPR_03 (0x019C) +#define IPIPE_D2F_2ND_SPR_04 (0x01A0) +#define IPIPE_D2F_2ND_SPR_05 (0x01A4) +#define IPIPE_D2F_2ND_SPR_06 (0x01A8) +#define IPIPE_D2F_2ND_SPR_07 (0x01AC) +#define IPIPE_D2F_2ND_EDG_MIN (0x01B0) +#define IPIPE_D2F_2ND_EDG_MAX (0x01B4) + +#define IPIPE_GIC_EN (0x01B8) +#define IPIPE_GIC_TYP (0x01BC) +#define IPIPE_GIC_GAN (0x01C0) +#define IPIPE_GIC_NFGAIN (0x01C4) +#define IPIPE_GIC_THR (0x01C8) +#define IPIPE_GIC_SLP (0x01CC) + +#define IPIPE_WB2_OFT_R (0x01D0) +#define IPIPE_WB2_OFT_GR (0x01D4) +#define IPIPE_WB2_OFT_GB (0x01D8) +#define IPIPE_WB2_OFT_B (0x01DC) + +#define IPIPE_WB2_WGN_R (0x01E0) +#define IPIPE_WB2_WGN_GR (0x01E4) +#define IPIPE_WB2_WGN_GB (0x01E8) +#define IPIPE_WB2_WGN_B (0x01EC) + +#define IPIPE_CFA_MODE (0x01F0) +#define IPIPE_CFA_2DIR_HPF_THR (0x01F4) +#define IPIPE_CFA_2DIR_HPF_SLP (0x01F8) +#define IPIPE_CFA_2DIR_MIX_THR (0x01FC) +#define IPIPE_CFA_2DIR_MIX_SLP (0x0200) +#define IPIPE_CFA_2DIR_DIR_TRH (0x0204) +#define IPIPE_CFA_2DIR_DIR_SLP (0x0208) +#define IPIPE_CFA_2DIR_NDWT (0x020C) +#define IPIPE_CFA_MONO_HUE_FRA (0x0210) +#define IPIPE_CFA_MONO_EDG_THR (0x0214) +#define IPIPE_CFA_MONO_THR_MIN (0x0218) + +#define IPIPE_CFA_MONO_THR_SLP (0x021C) +#define IPIPE_CFA_MONO_SLP_MIN (0x0220) +#define IPIPE_CFA_MONO_SLP_SLP (0x0224) +#define IPIPE_CFA_MONO_LPWT (0x0228) + +#define IPIPE_RGB1_MUL_RR (0x022C) +#define IPIPE_RGB1_MUL_GR (0x0230) +#define IPIPE_RGB1_MUL_BR (0x0234) +#define IPIPE_RGB1_MUL_RG (0x0238) +#define IPIPE_RGB1_MUL_GG (0x023C) +#define IPIPE_RGB1_MUL_BG (0x0240) +#define IPIPE_RGB1_MUL_RB (0x0244) +#define IPIPE_RGB1_MUL_GB (0x0248) +#define IPIPE_RGB1_MUL_BB (0x024C) +#define IPIPE_RGB1_OFT_OR (0x0250) +#define IPIPE_RGB1_OFT_OG (0x0254) +#define IPIPE_RGB1_OFT_OB (0x0258) +#define IPIPE_GMM_CFG (0x025C) +#define IPIPE_RGB2_MUL_RR (0x0260) +#define IPIPE_RGB2_MUL_GR (0x0264) +#define IPIPE_RGB2_MUL_BR (0x0268) +#define IPIPE_RGB2_MUL_RG (0x026C) +#define IPIPE_RGB2_MUL_GG (0x0270) +#define IPIPE_RGB2_MUL_BG (0x0274) +#define IPIPE_RGB2_MUL_RB (0x0278) +#define IPIPE_RGB2_MUL_GB (0x027C) +#define IPIPE_RGB2_MUL_BB (0x0280) +#define IPIPE_RGB2_OFT_OR (0x0284) +#define IPIPE_RGB2_OFT_OG (0x0288) +#define IPIPE_RGB2_OFT_OB (0x028C) + +#define IPIPE_YUV_ADJ (0x0294) +#define IPIPE_YUV_MUL_RY (0x0298) +#define IPIPE_YUV_MUL_GY (0x029C) +#define IPIPE_YUV_MUL_BY (0x02A0) +#define IPIPE_YUV_MUL_RCB (0x02A4) +#define IPIPE_YUV_MUL_GCB (0x02A8) +#define IPIPE_YUV_MUL_BCB (0x02AC) +#define IPIPE_YUV_MUL_RCR (0x02B0) +#define IPIPE_YUV_MUL_GCR (0x02B4) +#define IPIPE_YUV_MUL_BCR (0x02B8) +#define IPIPE_YUV_OFT_Y (0x02BC) +#define IPIPE_YUV_OFT_CB (0x02C0) +#define IPIPE_YUV_OFT_CR (0x02C4) + +#define IPIPE_YUV_PHS (0x02C8) +#define IPIPE_YUV_PHS_LPF (1 << 1) +#define IPIPE_YUV_PHS_POS (1 << 0) + +#define IPIPE_YEE_EN (0x02D4) +#define IPIPE_YEE_TYP (0x02D8) +#define IPIPE_YEE_SHF (0x02DC) +#define IPIPE_YEE_MUL_00 (0x02E0) +#define IPIPE_YEE_MUL_01 (0x02E4) +#define IPIPE_YEE_MUL_02 (0x02E8) +#define IPIPE_YEE_MUL_10 (0x02EC) +#define IPIPE_YEE_MUL_11 (0x02F0) +#define IPIPE_YEE_MUL_12 (0x02F4) +#define IPIPE_YEE_MUL_20 (0x02F8) +#define IPIPE_YEE_MUL_21 (0x02FC) +#define IPIPE_YEE_MUL_22 (0x0300) +#define IPIPE_YEE_THR (0x0304) +#define IPIPE_YEE_E_GAN (0x0308) +#define IPIPE_YEE_E_THR_1 (0x030C) +#define IPIPE_YEE_E_THR_2 (0x0310) +#define IPIPE_YEE_G_GAN (0x0314) +#define IPIPE_YEE_G_OFT (0x0318) + +#define IPIPE_CAR_EN (0x031C) +#define IPIPE_CAR_TYP (0x0320) +#define IPIPE_CAR_SW (0x0324) +#define IPIPE_CAR_HPF_TYP (0x0328) +#define IPIPE_CAR_HPF_SHF (0x032C) +#define IPIPE_CAR_HPF_THR (0x0330) +#define IPIPE_CAR_GN1_GAN (0x0334) +#define IPIPE_CAR_GN1_SHF (0x0338) +#define IPIPE_CAR_GN1_MIN (0x033C) +#define IPIPE_CAR_GN2_GAN (0x0340) +#define IPIPE_CAR_GN2_SHF (0x0344) +#define IPIPE_CAR_GN2_MIN (0x0348) +#define IPIPE_CGS_EN (0x034C) +#define IPIPE_CGS_GN1_L_THR (0x0350) +#define IPIPE_CGS_GN1_L_GAIN (0x0354) +#define IPIPE_CGS_GN1_L_SHF (0x0358) +#define IPIPE_CGS_GN1_L_MIN (0x035C) +#define IPIPE_CGS_GN1_H_THR (0x0360) +#define IPIPE_CGS_GN1_H_GAIN (0x0364) +#define IPIPE_CGS_GN1_H_SHF (0x0368) +#define IPIPE_CGS_GN1_H_MIN (0x036C) +#define IPIPE_CGS_GN2_L_THR (0x0370) +#define IPIPE_CGS_GN2_L_GAIN (0x0374) +#define IPIPE_CGS_GN2_L_SHF (0x0378) +#define IPIPE_CGS_GN2_L_MIN (0x037C) + +#define IPIPE_BOX_EN (0x0380) +#define IPIPE_BOX_MODE (0x0384) +#define IPIPE_BOX_TYP (0x0388) +#define IPIPE_BOX_SHF (0x038C) +#define IPIPE_BOX_SDR_SAD_H (0x0390) +#define IPIPE_BOX_SDR_SAD_L (0x0394) + +#define IPIPE_HST_EN (0x039C) +#define IPIPE_HST_MODE (0x03A0) +#define IPIPE_HST_SEL (0x03A4) +#define IPIPE_HST_PARA (0x03A8) +#define IPIPE_HST_0_VPS (0x03AC) +#define IPIPE_HST_0_VSZ (0x03B0) +#define IPIPE_HST_0_HPS (0x03B4) +#define IPIPE_HST_0_HSZ (0x03B8) +#define IPIPE_HST_1_VPS (0x03BC) +#define IPIPE_HST_1_VSZ (0x03C0) +#define IPIPE_HST_1_HPS (0x03C4) +#define IPIPE_HST_1_HSZ (0x03C8) +#define IPIPE_HST_2_VPS (0x03CC) +#define IPIPE_HST_2_VSZ (0x03D0) +#define IPIPE_HST_2_HPS (0x03D4) +#define IPIPE_HST_2_HSZ (0x03D8) +#define IPIPE_HST_3_VPS (0x03DC) +#define IPIPE_HST_3_VSZ (0x03E0) +#define IPIPE_HST_3_HPS (0x03E4) +#define IPIPE_HST_3_HSZ (0x03E8) +#define IPIPE_HST_TBL (0x03EC) +#define IPIPE_HST_MUL_R (0x03F0) +#define IPIPE_HST_MUL_GR (0x03F4) +#define IPIPE_HST_MUL_GB (0x03F8) +#define IPIPE_HST_MUL_B (0x03FC) + +#define IPIPE_BSC_EN (0x0400) +#define IPIPE_BSC_MODE (0x0404) +#define IPIPE_BSC_TYP (0x0408) +#define IPIPE_BSC_ROW_VCT (0x040C) +#define IPIPE_BSC_ROW_SHF (0x0410) +#define IPIPE_BSC_ROW_VPO (0x0414) +#define IPIPE_BSC_ROW_VNU (0x0418) +#define IPIPE_BSC_ROW_VSKIP (0x041C) +#define IPIPE_BSC_ROW_HPO (0x0420) +#define IPIPE_BSC_ROW_HNU (0x0424) +#define IPIPE_BSC_ROW_HSKIP (0x0428) +#define IPIPE_BSC_COL_VCT (0x042C) +#define IPIPE_BSC_COL_SHF (0x0430) +#define IPIPE_BSC_COL_VPO (0x0434) +#define IPIPE_BSC_COL_VNU (0x0438) +#define IPIPE_BSC_COL_VSKIP (0x043C) +#define IPIPE_BSC_COL_HPO (0x0440) +#define IPIPE_BSC_COL_HNU (0x0444) +#define IPIPE_BSC_COL_HSKIP (0x0448) + +#define IPIPE_BSC_EN (0x0400) + +/* ISS ISP Resizer register offsets */ +#define RSZ_REVISION (0x0000) +#define RSZ_SYSCONFIG (0x0004) +#define RSZ_SYSCONFIG_RSZB_CLK_EN (1 << 9) +#define RSZ_SYSCONFIG_RSZA_CLK_EN (1 << 8) + +#define RSZ_IN_FIFO_CTRL (0x000C) +#define RSZ_IN_FIFO_CTRL_THRLD_LOW_MASK (0x1FF << 16) +#define RSZ_IN_FIFO_CTRL_THRLD_LOW_SHIFT 16 +#define RSZ_IN_FIFO_CTRL_THRLD_HIGH_MASK (0x1FF << 0) +#define RSZ_IN_FIFO_CTRL_THRLD_HIGH_SHIFT 0 + +#define RSZ_FRACDIV (0x0008) +#define RSZ_FRACDIV_MASK (0xFFFF) + +#define RSZ_SRC_EN (0x0020) +#define RSZ_SRC_EN_SRC_EN (1 << 0) + +#define RSZ_SRC_MODE (0x0024) +#define RSZ_SRC_MODE_OST (1 << 0) +#define RSZ_SRC_MODE_WRT (1 << 1) + +#define RSZ_SRC_FMT0 (0x0028) +#define RSZ_SRC_FMT0_BYPASS (1 << 1) +#define RSZ_SRC_FMT0_SEL (1 << 0) + +#define RSZ_SRC_FMT1 (0x002C) +#define RSZ_SRC_FMT1_IN420 (1 << 1) + +#define RSZ_SRC_VPS (0x0030) +#define RSZ_SRC_VSZ (0x0034) +#define RSZ_SRC_HPS (0x0038) +#define RSZ_SRC_HSZ (0x003C) +#define RSZ_DMA_RZA (0x0040) +#define RSZ_DMA_RZB (0x0044) +#define RSZ_DMA_STA (0x0048) +#define RSZ_GCK_MMR (0x004C) +#define RSZ_GCK_MMR_MMR (1 << 0) + +#define RSZ_GCK_SDR (0x0054) +#define RSZ_GCK_SDR_CORE (1 << 0) + +#define RSZ_IRQ_RZA (0x0058) +#define RSZ_IRQ_RZA_MASK (0x1FFF) + +#define RSZ_IRQ_RZB (0x005C) +#define RSZ_IRQ_RZB_MASK (0x1FFF) + +#define RSZ_YUV_Y_MIN (0x0060) +#define RSZ_YUV_Y_MAX (0x0064) +#define RSZ_YUV_C_MIN (0x0068) +#define RSZ_YUV_C_MAX (0x006C) + +#define RSZ_SEQ (0x0074) +#define RSZ_SEQ_HRVB (1 << 2) +#define RSZ_SEQ_HRVA (1 << 0) + +#define RZA_EN (0x0078) +#define RZA_MODE (0x007C) +#define RZA_MODE_ONE_SHOT (1 << 0) + +#define RZA_420 (0x0080) +#define RZA_I_VPS (0x0084) +#define RZA_I_HPS (0x0088) +#define RZA_O_VSZ (0x008C) +#define RZA_O_HSZ (0x0090) +#define RZA_V_PHS_Y (0x0094) +#define RZA_V_PHS_C (0x0098) +#define RZA_V_DIF (0x009C) +#define RZA_V_TYP (0x00A0) +#define RZA_V_LPF (0x00A4) +#define RZA_H_PHS (0x00A8) +#define RZA_H_DIF (0x00B0) +#define RZA_H_TYP (0x00B4) +#define RZA_H_LPF (0x00B8) +#define RZA_DWN_EN (0x00BC) +#define RZA_SDR_Y_BAD_H (0x00D0) +#define RZA_SDR_Y_BAD_L (0x00D4) +#define RZA_SDR_Y_SAD_H (0x00D8) +#define RZA_SDR_Y_SAD_L (0x00DC) +#define RZA_SDR_Y_OFT (0x00E0) +#define RZA_SDR_Y_PTR_S (0x00E4) +#define RZA_SDR_Y_PTR_E (0x00E8) +#define RZA_SDR_C_BAD_H (0x00EC) +#define RZA_SDR_C_BAD_L (0x00F0) +#define RZA_SDR_C_SAD_H (0x00F4) +#define RZA_SDR_C_SAD_L (0x00F8) +#define RZA_SDR_C_OFT (0x00FC) +#define RZA_SDR_C_PTR_S (0x0100) +#define RZA_SDR_C_PTR_E (0x0104) + +#define RZB_EN (0x0108) +#define RZB_MODE (0x010C) +#define RZB_420 (0x0110) +#define RZB_I_VPS (0x0114) +#define RZB_I_HPS (0x0118) +#define RZB_O_VSZ (0x011C) +#define RZB_O_HSZ (0x0120) + +#define RZB_V_DIF (0x012C) +#define RZB_V_TYP (0x0130) +#define RZB_V_LPF (0x0134) + +#define RZB_H_DIF (0x0140) +#define RZB_H_TYP (0x0144) +#define RZB_H_LPF (0x0148) + +#define RZB_SDR_Y_BAD_H (0x0160) +#define RZB_SDR_Y_BAD_L (0x0164) +#define RZB_SDR_Y_SAD_H (0x0168) +#define RZB_SDR_Y_SAD_L (0x016C) +#define RZB_SDR_Y_OFT (0x0170) +#define RZB_SDR_Y_PTR_S (0x0174) +#define RZB_SDR_Y_PTR_E (0x0178) +#define RZB_SDR_C_BAD_H (0x017C) +#define RZB_SDR_C_BAD_L (0x0180) +#define RZB_SDR_C_SAD_H (0x0184) +#define RZB_SDR_C_SAD_L (0x0188) + +#define RZB_SDR_C_PTR_S (0x0190) +#define RZB_SDR_C_PTR_E (0x0194) + +/* Shared Bitmasks between RZA & RZB */ +#define RSZ_EN_EN (1 << 0) + +#define RSZ_420_CEN (1 << 1) +#define RSZ_420_YEN (1 << 0) + +#define RSZ_I_VPS_MASK (0x1FFF) + +#define RSZ_I_HPS_MASK (0x1FFF) + +#define RSZ_O_VSZ_MASK (0x1FFF) + +#define RSZ_O_HSZ_MASK (0x1FFE) + +#define RSZ_V_PHS_Y_MASK (0x3FFF) + +#define RSZ_V_PHS_C_MASK (0x3FFF) + +#define RSZ_V_DIF_MASK (0x3FFF) + +#define RSZ_V_TYP_C (1 << 1) +#define RSZ_V_TYP_Y (1 << 0) + +#define RSZ_V_LPF_C_MASK (0x3F << 6) +#define RSZ_V_LPF_C_SHIFT 6 +#define RSZ_V_LPF_Y_MASK (0x3F << 0) +#define RSZ_V_LPF_Y_SHIFT 0 + +#define RSZ_H_PHS_MASK (0x3FFF) + +#define RSZ_H_DIF_MASK (0x3FFF) + +#define RSZ_H_TYP_C (1 << 1) +#define RSZ_H_TYP_Y (1 << 0) + +#define RSZ_H_LPF_C_MASK (0x3F << 6) +#define RSZ_H_LPF_C_SHIFT 6 +#define RSZ_H_LPF_Y_MASK (0x3F << 0) +#define RSZ_H_LPF_Y_SHIFT 0 + +#define RSZ_DWN_EN_DWN_EN (1 << 0) + +#endif /* _OMAP4_ISS_REGS_H_ */ diff --git a/include/media/omap4iss.h b/include/media/omap4iss.h new file mode 100644 index 000000000000..0d7620db5e32 --- /dev/null +++ b/include/media/omap4iss.h @@ -0,0 +1,65 @@ +#ifndef ARCH_ARM_PLAT_OMAP4_ISS_H +#define ARCH_ARM_PLAT_OMAP4_ISS_H + +#include + +struct iss_device; + +enum iss_interface_type { + ISS_INTERFACE_CSI2A_PHY1, + ISS_INTERFACE_CSI2B_PHY2, +}; + +/** + * struct iss_csiphy_lane: CSI2 lane position and polarity + * @pos: position of the lane + * @pol: polarity of the lane + */ +struct iss_csiphy_lane { + u8 pos; + u8 pol; +}; + +#define ISS_CSIPHY1_NUM_DATA_LANES 4 +#define ISS_CSIPHY2_NUM_DATA_LANES 1 + +/** + * struct iss_csiphy_lanes_cfg - CSI2 lane configuration + * @data: Configuration of one or two data lanes + * @clk: Clock lane configuration + */ +struct iss_csiphy_lanes_cfg { + struct iss_csiphy_lane data[ISS_CSIPHY1_NUM_DATA_LANES]; + struct iss_csiphy_lane clk; +}; + +/** + * struct iss_csi2_platform_data - CSI2 interface platform data + * @crc: Enable the cyclic redundancy check + * @vpclk_div: Video port output clock control + */ +struct iss_csi2_platform_data { + unsigned crc:1; + unsigned vpclk_div:2; + struct iss_csiphy_lanes_cfg lanecfg; +}; + +struct iss_subdev_i2c_board_info { + struct i2c_board_info *board_info; + int i2c_adapter_id; +}; + +struct iss_v4l2_subdevs_group { + struct iss_subdev_i2c_board_info *subdevs; + enum iss_interface_type interface; + union { + struct iss_csi2_platform_data csi2; + } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */ +}; + +struct iss_platform_data { + struct iss_v4l2_subdevs_group *subdevs; + void (*set_constraints)(struct iss_device *iss, bool enable); +}; + +#endif -- cgit v1.2.3 From ac216aa290c48a5e9d7b9f2473abb977a175683a Mon Sep 17 00:00:00 2001 From: Harald Geyer Date: Sun, 1 Dec 2013 15:08:00 +0000 Subject: iio: Add support for humidity sensors There are already humidity sensors in the hwmon subsystem, so we use their unit (milli percent) here as well. Signed-off-by: Harald Geyer Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 13 +++++++++++++ drivers/iio/industrialio-core.c | 1 + include/linux/iio/types.h | 1 + 3 files changed, 15 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index b20e829d350f..6e02c5029152 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -197,6 +197,19 @@ Description: Raw pressure measurement from channel Y. Units after application of scale and offset are kilopascal. +What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_raw +KernelVersion: 3.14 +Contact: linux-iio@vger.kernel.org +Description: + Raw humidity measurement of air. Units after application of + scale and offset are milli percent. + +What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_input +KernelVersion: 3.14 +Contact: linux-iio@vger.kernel.org +Description: + Scaled humidity measurement in milli percent. + What: /sys/bus/iio/devices/iio:deviceX/in_accel_offset What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_offset What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_offset diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 2fe88c189f74..acc911a836ca 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -69,6 +69,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_ALTVOLTAGE] = "altvoltage", [IIO_CCT] = "cct", [IIO_PRESSURE] = "pressure", + [IIO_HUMIDITYRELATIVE] = "humidityrelative", }; static const char * const iio_modifier_names[] = { diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 4ac928ee31c5..084d882fe01b 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -29,6 +29,7 @@ enum iio_chan_type { IIO_ALTVOLTAGE, IIO_CCT, IIO_PRESSURE, + IIO_HUMIDITYRELATIVE, }; enum iio_modifier { -- cgit v1.2.3 From 091a121b04547fab2045951aff6219318ede0560 Mon Sep 17 00:00:00 2001 From: Harald Geyer Date: Sun, 1 Dec 2013 15:04:00 +0000 Subject: iio: Add new driver dht11 This driver handles DHT11 and DHT22 sensors. Signed-off-by: Harald Geyer Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/humidity/dht11.txt | 14 + drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/humidity/Kconfig | 15 ++ drivers/iio/humidity/Makefile | 5 + drivers/iio/humidity/dht11.c | 294 +++++++++++++++++++++ 6 files changed, 330 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/humidity/dht11.txt create mode 100644 drivers/iio/humidity/Kconfig create mode 100644 drivers/iio/humidity/Makefile create mode 100644 drivers/iio/humidity/dht11.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/humidity/dht11.txt b/Documentation/devicetree/bindings/iio/humidity/dht11.txt new file mode 100644 index 000000000000..ecc24c199fd6 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/humidity/dht11.txt @@ -0,0 +1,14 @@ +* DHT11 humidity/temperature sensor (and compatibles like DHT22) + +Required properties: + - compatible: Should be "dht11" + - gpios: Should specify the GPIO connected to the sensor's data + line, see "gpios property" in + Documentation/devicetree/bindings/gpio/gpio.txt. + +Example: + +humidity_sensor { + compatible = "dht11"; + gpios = <&gpio0 6 0>; +} diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 90cf0cda50c4..a5ed88226276 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -65,6 +65,7 @@ source "drivers/iio/common/Kconfig" source "drivers/iio/dac/Kconfig" source "drivers/iio/frequency/Kconfig" source "drivers/iio/gyro/Kconfig" +source "drivers/iio/humidity/Kconfig" source "drivers/iio/imu/Kconfig" source "drivers/iio/light/Kconfig" source "drivers/iio/magnetometer/Kconfig" diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index bcf7e9e3b053..b3b50968b46b 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -18,6 +18,7 @@ obj-y += common/ obj-y += dac/ obj-y += gyro/ obj-y += frequency/ +obj-y += humidity/ obj-y += imu/ obj-y += light/ obj-y += magnetometer/ diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig new file mode 100644 index 000000000000..463c4d9da79e --- /dev/null +++ b/drivers/iio/humidity/Kconfig @@ -0,0 +1,15 @@ +# +# humidity sensor drivers +# +menu "Humidity sensors" + +config DHT11 + tristate "DHT11 (and compatible sensors) driver" + depends on GPIOLIB + help + This driver supports reading data via a single interrupt + generating GPIO line. Currently tested are DHT11 and DHT22. + Other sensors should work as well as long as they speak the + same protocol. + +endmenu diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile new file mode 100644 index 000000000000..d5d36c0c95f9 --- /dev/null +++ b/drivers/iio/humidity/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for IIO humidity sensor drivers +# + +obj-$(CONFIG_DHT11) += dht11.o diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c new file mode 100644 index 000000000000..d8771f546bf2 --- /dev/null +++ b/drivers/iio/humidity/dht11.c @@ -0,0 +1,294 @@ +/* + * DHT11/DHT22 bit banging GPIO driver + * + * Copyright (c) Harald Geyer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRIVER_NAME "dht11" + +#define DHT11_DATA_VALID_TIME 2000000000 /* 2s in ns */ + +#define DHT11_EDGES_PREAMBLE 4 +#define DHT11_BITS_PER_READ 40 +#define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE + 1) + +/* Data transmission timing (nano seconds) */ +#define DHT11_START_TRANSMISSION 18 /* ms */ +#define DHT11_SENSOR_RESPONSE 80000 +#define DHT11_START_BIT 50000 +#define DHT11_DATA_BIT_LOW 27000 +#define DHT11_DATA_BIT_HIGH 70000 + +struct dht11 { + struct device *dev; + + int gpio; + int irq; + + struct completion completion; + + s64 timestamp; + int temperature; + int humidity; + + /* num_edges: -1 means "no transmission in progress" */ + int num_edges; + struct {s64 ts; int value; } edges[DHT11_EDGES_PER_READ]; +}; + +static unsigned char dht11_decode_byte(int *timing, int threshold) +{ + unsigned char ret = 0; + int i; + + for (i = 0; i < 8; ++i) { + ret <<= 1; + if (timing[i] >= threshold) + ++ret; + } + + return ret; +} + +static int dht11_decode(struct dht11 *dht11, int offset) +{ + int i, t, timing[DHT11_BITS_PER_READ], threshold, + timeres = DHT11_SENSOR_RESPONSE; + unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum; + + /* Calculate timestamp resolution */ + for (i = 0; i < dht11->num_edges; ++i) { + t = dht11->edges[i].ts - dht11->edges[i-1].ts; + if (t > 0 && t < timeres) + timeres = t; + } + if (2*timeres > DHT11_DATA_BIT_HIGH) { + pr_err("dht11: timeresolution %d too bad for decoding\n", + timeres); + return -EIO; + } + threshold = DHT11_DATA_BIT_HIGH / timeres; + if (DHT11_DATA_BIT_LOW/timeres + 1 >= threshold) + pr_err("dht11: WARNING: decoding ambiguous\n"); + + /* scale down with timeres and check validity */ + for (i = 0; i < DHT11_BITS_PER_READ; ++i) { + t = dht11->edges[offset + 2*i + 2].ts - + dht11->edges[offset + 2*i + 1].ts; + if (!dht11->edges[offset + 2*i + 1].value) + return -EIO; /* lost synchronisation */ + timing[i] = t / timeres; + } + + hum_int = dht11_decode_byte(timing, threshold); + hum_dec = dht11_decode_byte(&timing[8], threshold); + temp_int = dht11_decode_byte(&timing[16], threshold); + temp_dec = dht11_decode_byte(&timing[24], threshold); + checksum = dht11_decode_byte(&timing[32], threshold); + + if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum) + return -EIO; + + dht11->timestamp = iio_get_time_ns(); + if (hum_int < 20) { /* DHT22 */ + dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) * + ((temp_int & 0x80) ? -100 : 100); + dht11->humidity = ((hum_int << 8) + hum_dec) * 100; + } else if (temp_dec == 0 && hum_dec == 0) { /* DHT11 */ + dht11->temperature = temp_int * 1000; + dht11->humidity = hum_int * 1000; + } else { + dev_err(dht11->dev, + "Don't know how to decode data: %d %d %d %d\n", + hum_int, hum_dec, temp_int, temp_dec); + return -EIO; + } + + return 0; +} + +static int dht11_read_raw(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long m) +{ + struct dht11 *dht11 = iio_priv(iio_dev); + int ret; + + if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) { + reinit_completion(&dht11->completion); + + dht11->num_edges = 0; + ret = gpio_direction_output(dht11->gpio, 0); + if (ret) + goto err; + msleep(DHT11_START_TRANSMISSION); + ret = gpio_direction_input(dht11->gpio); + if (ret) + goto err; + + ret = wait_for_completion_killable_timeout(&dht11->completion, + HZ); + if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) { + dev_err(&iio_dev->dev, + "Only %d signal edges detected\n", + dht11->num_edges); + ret = -ETIMEDOUT; + } + if (ret < 0) + goto err; + + ret = dht11_decode(dht11, + dht11->num_edges == DHT11_EDGES_PER_READ ? + DHT11_EDGES_PREAMBLE : + DHT11_EDGES_PREAMBLE - 2); + if (ret) + goto err; + } + + ret = IIO_VAL_INT; + if (chan->type == IIO_TEMP) + *val = dht11->temperature; + else if (chan->type == IIO_HUMIDITYRELATIVE) + *val = dht11->humidity; + else + ret = -EINVAL; +err: + dht11->num_edges = -1; + return ret; +} + +static const struct iio_info dht11_iio_info = { + .driver_module = THIS_MODULE, + .read_raw = dht11_read_raw, +}; + +/* + * IRQ handler called on GPIO edges +*/ +static irqreturn_t dht11_handle_irq(int irq, void *data) +{ + struct iio_dev *iio = data; + struct dht11 *dht11 = iio_priv(iio); + + /* TODO: Consider making the handler safe for IRQ sharing */ + if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) { + dht11->edges[dht11->num_edges].ts = iio_get_time_ns(); + dht11->edges[dht11->num_edges++].value = + gpio_get_value(dht11->gpio); + + if (dht11->num_edges >= DHT11_EDGES_PER_READ) + complete(&dht11->completion); + } + + return IRQ_HANDLED; +} + +static const struct iio_chan_spec dht11_chan_spec[] = { + { .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), }, + { .type = IIO_HUMIDITYRELATIVE, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), } +}; + +static const struct of_device_id dht11_dt_ids[] = { + { .compatible = "dht11", }, + { } +}; +MODULE_DEVICE_TABLE(of, dht11_dt_ids); + +static int dht11_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct dht11 *dht11; + struct iio_dev *iio; + int ret; + + iio = devm_iio_device_alloc(dev, sizeof(*dht11)); + if (!iio) { + dev_err(dev, "Failed to allocate IIO device\n"); + return -ENOMEM; + } + + dht11 = iio_priv(iio); + dht11->dev = dev; + + dht11->gpio = ret = of_get_gpio(node, 0); + if (ret < 0) + return ret; + ret = devm_gpio_request_one(dev, dht11->gpio, GPIOF_IN, pdev->name); + if (ret) + return ret; + + dht11->irq = gpio_to_irq(dht11->gpio); + if (dht11->irq < 0) { + dev_err(dev, "GPIO %d has no interrupt\n", dht11->gpio); + return -EINVAL; + } + ret = devm_request_irq(dev, dht11->irq, dht11_handle_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + pdev->name, iio); + if (ret) + return ret; + + dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1; + dht11->num_edges = -1; + + platform_set_drvdata(pdev, iio); + + init_completion(&dht11->completion); + iio->name = pdev->name; + iio->dev.parent = &pdev->dev; + iio->info = &dht11_iio_info; + iio->modes = INDIO_DIRECT_MODE; + iio->channels = dht11_chan_spec; + iio->num_channels = ARRAY_SIZE(dht11_chan_spec); + + return devm_iio_device_register(dev, iio); +} + +static struct platform_driver dht11_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = dht11_dt_ids, + }, + .probe = dht11_probe, +}; + +module_platform_driver(dht11_driver); + +MODULE_AUTHOR("Harald Geyer "); +MODULE_DESCRIPTION("DHT11 humidity/temperature sensor driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From b52fa7bc5dc9697fb5983727d276dd565d85a8d0 Mon Sep 17 00:00:00 2001 From: Mike Dunn Date: Sat, 21 Sep 2013 12:19:33 -0700 Subject: pwm: pxa: Add device tree support This patch adds device tree support to the PXA's PWM driver. Nothing needs to be extracted from the device tree node by the PWM device. Client devices need only specify the period; the per-chip index is implicitly zero because one device node must be present for each PWM output in use. This approach is more convenient due to the wide variability in the number of PWM channels present across the various PXA variants, and is made possible by the fact that the register sets for each PWM channel are segregated from each other. An of_xlate() method is added to parse this single-cell node. The existing ID table is reused for the match table data. Tested on a Palm Treo 680 (both platform data and DT cases). Signed-off-by: Mike Dunn Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/pwm/pxa-pwm.txt | 30 +++++++++++++ drivers/pwm/pwm-pxa.c | 53 +++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/pxa-pwm.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pwm/pxa-pwm.txt b/Documentation/devicetree/bindings/pwm/pxa-pwm.txt new file mode 100644 index 000000000000..5ae9f1e3c338 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pxa-pwm.txt @@ -0,0 +1,30 @@ +Marvell PWM controller + +Required properties: +- compatible: should be one or more of: + - "marvell,pxa250-pwm" + - "marvell,pxa270-pwm" + - "marvell,pxa168-pwm" + - "marvell,pxa910-pwm" +- reg: Physical base address and length of the registers used by the PWM channel + Note that one device instance must be created for each PWM that is used, so the + length covers only the register window for one PWM output, not that of the + entire PWM controller. Currently length is 0x10 for all supported devices. +- #pwm-cells: Should be 1. This cell is used to specify the period in + nanoseconds. + +Example PWM device node: + +pwm0: pwm@40b00000 { + compatible = "marvell,pxa250-pwm"; + reg = <0x40b00000 0x10>; + #pwm-cells = <1>; +}; + +Example PWM client node: + +backlight { + compatible = "pwm-backlight"; + pwms = <&pwm0 5000000>; + ... +} diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index a4d2164aaf55..3dc7c10bb7a0 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -124,6 +125,46 @@ static struct pwm_ops pxa_pwm_ops = { .owner = THIS_MODULE, }; +#ifdef CONFIG_OF +/* + * Device tree users must create one device instance for each pwm channel. + * Hence we dispense with the HAS_SECONDARY_PWM and "tell" the original driver + * code that this is a single channel pxa25x-pwm. Currently all devices are + * supported identically. + */ +static struct of_device_id pwm_of_match[] = { + { .compatible = "marvell,pxa250-pwm", .data = &pwm_id_table[0]}, + { .compatible = "marvell,pxa270-pwm", .data = &pwm_id_table[0]}, + { .compatible = "marvell,pxa168-pwm", .data = &pwm_id_table[0]}, + { .compatible = "marvell,pxa910-pwm", .data = &pwm_id_table[0]}, + { } +}; +MODULE_DEVICE_TABLE(of, pwm_of_match); +#else +#define pwm_of_match NULL +#endif + +static const struct platform_device_id *pxa_pwm_get_id_dt(struct device *dev) +{ + const struct of_device_id *id = of_match_device(pwm_of_match, dev); + + return id ? id->data : NULL; +} + +static struct pwm_device * +pxa_pwm_of_xlate(struct pwm_chip *pc, const struct of_phandle_args *args) +{ + struct pwm_device *pwm; + + pwm = pwm_request_from_chip(pc, 0, NULL); + if (IS_ERR(pwm)) + return pwm; + + pwm_set_period(pwm, args->args[0]); + + return pwm; +} + static int pwm_probe(struct platform_device *pdev) { const struct platform_device_id *id = platform_get_device_id(pdev); @@ -131,6 +172,12 @@ static int pwm_probe(struct platform_device *pdev) struct resource *r; int ret = 0; + if (IS_ENABLED(CONFIG_OF) && id == NULL) + id = pxa_pwm_get_id_dt(&pdev->dev); + + if (id == NULL) + return -EINVAL; + pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); if (pwm == NULL) { dev_err(&pdev->dev, "failed to allocate memory\n"); @@ -146,6 +193,11 @@ static int pwm_probe(struct platform_device *pdev) pwm->chip.base = -1; pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1; + if (IS_ENABLED(CONFIG_OF)) { + pwm->chip.of_xlate = pxa_pwm_of_xlate; + pwm->chip.of_pwm_n_cells = 1; + } + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); pwm->mmio_base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(pwm->mmio_base)) @@ -176,6 +228,7 @@ static struct platform_driver pwm_driver = { .driver = { .name = "pxa25x-pwm", .owner = THIS_MODULE, + .of_match_table = pwm_of_match, }, .probe = pwm_probe, .remove = pwm_remove, -- cgit v1.2.3 From 0aa0c95f743a06893dbc494b2a75fbf7093330d4 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 13 Nov 2013 08:51:23 +0800 Subject: clk: hisilicon: add common clock support Enable common clock driver of Hi3620 SoC. clkgate-seperated driver is used to support the clock gate that enable/disable/status registers are seperated. Signed-off-by: Haojian Zhuang --- .../devicetree/bindings/clock/hi3620-clock.txt | 19 ++ drivers/clk/Makefile | 1 + drivers/clk/hisilicon/Makefile | 5 + drivers/clk/hisilicon/clk-hi3620.c | 242 +++++++++++++++++++++ drivers/clk/hisilicon/clk.c | 171 +++++++++++++++ drivers/clk/hisilicon/clk.h | 103 +++++++++ drivers/clk/hisilicon/clkgate-separated.c | 130 +++++++++++ include/dt-bindings/clock/hi3620-clock.h | 152 +++++++++++++ 8 files changed, 823 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/hi3620-clock.txt create mode 100644 drivers/clk/hisilicon/Makefile create mode 100644 drivers/clk/hisilicon/clk-hi3620.c create mode 100644 drivers/clk/hisilicon/clk.c create mode 100644 drivers/clk/hisilicon/clk.h create mode 100644 drivers/clk/hisilicon/clkgate-separated.c create mode 100644 include/dt-bindings/clock/hi3620-clock.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/hi3620-clock.txt b/Documentation/devicetree/bindings/clock/hi3620-clock.txt new file mode 100644 index 000000000000..4b71ab41be53 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/hi3620-clock.txt @@ -0,0 +1,19 @@ +* Hisilicon Hi3620 Clock Controller + +The Hi3620 clock controller generates and supplies clock to various +controllers within the Hi3620 SoC. + +Required Properties: + +- compatible: should be one of the following. + - "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC. + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in . diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 7a10bc9a23e7..cd51428c2aa2 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o +obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o obj-$(CONFIG_ARCH_MXS) += mxs/ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile new file mode 100644 index 000000000000..a049108341fc --- /dev/null +++ b/drivers/clk/hisilicon/Makefile @@ -0,0 +1,5 @@ +# +# Hisilicon Clock specific Makefile +# + +obj-y += clk.o clkgate-separated.o clk-hi3620.o diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c new file mode 100644 index 000000000000..b66b074fbda5 --- /dev/null +++ b/drivers/clk/hisilicon/clk-hi3620.c @@ -0,0 +1,242 @@ +/* + * Hisilicon Hi3620 clock driver + * + * Copyright (c) 2012-2013 Hisilicon Limited. + * Copyright (c) 2012-2013 Linaro Limited. + * + * Author: Haojian Zhuang + * Xin Li + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "clk.h" + +/* clock parent list */ +static const char *timer0_mux_p[] __initdata = { "osc32k", "timerclk01", }; +static const char *timer1_mux_p[] __initdata = { "osc32k", "timerclk01", }; +static const char *timer2_mux_p[] __initdata = { "osc32k", "timerclk23", }; +static const char *timer3_mux_p[] __initdata = { "osc32k", "timerclk23", }; +static const char *timer4_mux_p[] __initdata = { "osc32k", "timerclk45", }; +static const char *timer5_mux_p[] __initdata = { "osc32k", "timerclk45", }; +static const char *timer6_mux_p[] __initdata = { "osc32k", "timerclk67", }; +static const char *timer7_mux_p[] __initdata = { "osc32k", "timerclk67", }; +static const char *timer8_mux_p[] __initdata = { "osc32k", "timerclk89", }; +static const char *timer9_mux_p[] __initdata = { "osc32k", "timerclk89", }; +static const char *uart0_mux_p[] __initdata = { "osc26m", "pclk", }; +static const char *uart1_mux_p[] __initdata = { "osc26m", "pclk", }; +static const char *uart2_mux_p[] __initdata = { "osc26m", "pclk", }; +static const char *uart3_mux_p[] __initdata = { "osc26m", "pclk", }; +static const char *uart4_mux_p[] __initdata = { "osc26m", "pclk", }; +static const char *spi0_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", }; +static const char *spi1_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", }; +static const char *spi2_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", }; +/* share axi parent */ +static const char *saxi_mux_p[] __initdata = { "armpll3", "armpll2", }; +static const char *pwm0_mux_p[] __initdata = { "osc32k", "osc26m", }; +static const char *pwm1_mux_p[] __initdata = { "osc32k", "osc26m", }; +static const char *sd_mux_p[] __initdata = { "armpll3", "armpll2", }; +static const char *mmc1_mux_p[] __initdata = { "armpll3", "armpll2", }; +static const char *mmc1_mux2_p[] __initdata = { "osc26m", "mmc1_div", }; +static const char *g2d_mux_p[] __initdata = { "armpll2", "armpll3", }; +static const char *venc_mux_p[] __initdata = { "armpll2", "armpll3", }; +static const char *vdec_mux_p[] __initdata = { "armpll2", "armpll3", }; +static const char *vpp_mux_p[] __initdata = { "armpll2", "armpll3", }; +static const char *edc0_mux_p[] __initdata = { "armpll2", "armpll3", }; +static const char *ldi0_mux_p[] __initdata = { "armpll2", "armpll4", + "armpll3", "armpll5", }; +static const char *edc1_mux_p[] __initdata = { "armpll2", "armpll3", }; +static const char *ldi1_mux_p[] __initdata = { "armpll2", "armpll4", + "armpll3", "armpll5", }; +static const char *rclk_hsic_p[] __initdata = { "armpll3", "armpll2", }; +static const char *mmc2_mux_p[] __initdata = { "armpll3", "armpll2", }; +static const char *mmc3_mux_p[] __initdata = { "armpll3", "armpll2", }; + + +/* fixed rate clocks */ +static struct hisi_fixed_rate_clock hi3620_fixed_rate_clks[] __initdata = { + { HI3620_OSC32K, "osc32k", NULL, CLK_IS_ROOT, 32768, }, + { HI3620_OSC26M, "osc26m", NULL, CLK_IS_ROOT, 26000000, }, + { HI3620_PCLK, "pclk", NULL, CLK_IS_ROOT, 26000000, }, + { HI3620_PLL_ARM0, "armpll0", NULL, CLK_IS_ROOT, 1600000000, }, + { HI3620_PLL_ARM1, "armpll1", NULL, CLK_IS_ROOT, 1600000000, }, + { HI3620_PLL_PERI, "armpll2", NULL, CLK_IS_ROOT, 1440000000, }, + { HI3620_PLL_USB, "armpll3", NULL, CLK_IS_ROOT, 1440000000, }, + { HI3620_PLL_HDMI, "armpll4", NULL, CLK_IS_ROOT, 1188000000, }, + { HI3620_PLL_GPU, "armpll5", NULL, CLK_IS_ROOT, 1300000000, }, +}; + +/* fixed factor clocks */ +static struct hisi_fixed_factor_clock hi3620_fixed_factor_clks[] __initdata = { + { HI3620_RCLK_TCXO, "rclk_tcxo", "osc26m", 1, 4, 0, }, + { HI3620_RCLK_CFGAXI, "rclk_cfgaxi", "armpll2", 1, 30, 0, }, + { HI3620_RCLK_PICO, "rclk_pico", "hsic_div", 1, 40, 0, }, +}; + +static struct hisi_mux_clock hi3620_mux_clks[] __initdata = { + { HI3620_TIMER0_MUX, "timer0_mux", timer0_mux_p, ARRAY_SIZE(timer0_mux_p), CLK_SET_RATE_PARENT, 0, 15, 2, 0, }, + { HI3620_TIMER1_MUX, "timer1_mux", timer1_mux_p, ARRAY_SIZE(timer1_mux_p), CLK_SET_RATE_PARENT, 0, 17, 2, 0, }, + { HI3620_TIMER2_MUX, "timer2_mux", timer2_mux_p, ARRAY_SIZE(timer2_mux_p), CLK_SET_RATE_PARENT, 0, 19, 2, 0, }, + { HI3620_TIMER3_MUX, "timer3_mux", timer3_mux_p, ARRAY_SIZE(timer3_mux_p), CLK_SET_RATE_PARENT, 0, 21, 2, 0, }, + { HI3620_TIMER4_MUX, "timer4_mux", timer4_mux_p, ARRAY_SIZE(timer4_mux_p), CLK_SET_RATE_PARENT, 0x18, 0, 2, 0, }, + { HI3620_TIMER5_MUX, "timer5_mux", timer5_mux_p, ARRAY_SIZE(timer5_mux_p), CLK_SET_RATE_PARENT, 0x18, 2, 2, 0, }, + { HI3620_TIMER6_MUX, "timer6_mux", timer6_mux_p, ARRAY_SIZE(timer6_mux_p), CLK_SET_RATE_PARENT, 0x18, 4, 2, 0, }, + { HI3620_TIMER7_MUX, "timer7_mux", timer7_mux_p, ARRAY_SIZE(timer7_mux_p), CLK_SET_RATE_PARENT, 0x18, 6, 2, 0, }, + { HI3620_TIMER8_MUX, "timer8_mux", timer8_mux_p, ARRAY_SIZE(timer8_mux_p), CLK_SET_RATE_PARENT, 0x18, 8, 2, 0, }, + { HI3620_TIMER9_MUX, "timer9_mux", timer9_mux_p, ARRAY_SIZE(timer9_mux_p), CLK_SET_RATE_PARENT, 0x18, 10, 2, 0, }, + { HI3620_UART0_MUX, "uart0_mux", uart0_mux_p, ARRAY_SIZE(uart0_mux_p), CLK_SET_RATE_PARENT, 0x100, 7, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_UART1_MUX, "uart1_mux", uart1_mux_p, ARRAY_SIZE(uart1_mux_p), CLK_SET_RATE_PARENT, 0x100, 8, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_UART2_MUX, "uart2_mux", uart2_mux_p, ARRAY_SIZE(uart2_mux_p), CLK_SET_RATE_PARENT, 0x100, 9, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_UART3_MUX, "uart3_mux", uart3_mux_p, ARRAY_SIZE(uart3_mux_p), CLK_SET_RATE_PARENT, 0x100, 10, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_UART4_MUX, "uart4_mux", uart4_mux_p, ARRAY_SIZE(uart4_mux_p), CLK_SET_RATE_PARENT, 0x100, 11, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_SPI0_MUX, "spi0_mux", spi0_mux_p, ARRAY_SIZE(spi0_mux_p), CLK_SET_RATE_PARENT, 0x100, 12, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_SPI1_MUX, "spi1_mux", spi1_mux_p, ARRAY_SIZE(spi1_mux_p), CLK_SET_RATE_PARENT, 0x100, 13, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_SPI2_MUX, "spi2_mux", spi2_mux_p, ARRAY_SIZE(spi2_mux_p), CLK_SET_RATE_PARENT, 0x100, 14, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_SAXI_MUX, "saxi_mux", saxi_mux_p, ARRAY_SIZE(saxi_mux_p), CLK_SET_RATE_PARENT, 0x100, 15, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_PWM0_MUX, "pwm0_mux", pwm0_mux_p, ARRAY_SIZE(pwm0_mux_p), CLK_SET_RATE_PARENT, 0x104, 10, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_PWM1_MUX, "pwm1_mux", pwm1_mux_p, ARRAY_SIZE(pwm1_mux_p), CLK_SET_RATE_PARENT, 0x104, 11, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_SD_MUX, "sd_mux", sd_mux_p, ARRAY_SIZE(sd_mux_p), CLK_SET_RATE_PARENT, 0x108, 4, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_MMC1_MUX, "mmc1_mux", mmc1_mux_p, ARRAY_SIZE(mmc1_mux_p), CLK_SET_RATE_PARENT, 0x108, 9, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_MMC1_MUX2, "mmc1_mux2", mmc1_mux2_p, ARRAY_SIZE(mmc1_mux2_p), CLK_SET_RATE_PARENT, 0x108, 10, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_G2D_MUX, "g2d_mux", g2d_mux_p, ARRAY_SIZE(g2d_mux_p), CLK_SET_RATE_PARENT, 0x10c, 5, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_VENC_MUX, "venc_mux", venc_mux_p, ARRAY_SIZE(venc_mux_p), CLK_SET_RATE_PARENT, 0x10c, 11, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_VDEC_MUX, "vdec_mux", vdec_mux_p, ARRAY_SIZE(vdec_mux_p), CLK_SET_RATE_PARENT, 0x110, 5, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_VPP_MUX, "vpp_mux", vpp_mux_p, ARRAY_SIZE(vpp_mux_p), CLK_SET_RATE_PARENT, 0x110, 11, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_EDC0_MUX, "edc0_mux", edc0_mux_p, ARRAY_SIZE(edc0_mux_p), CLK_SET_RATE_PARENT, 0x114, 6, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_LDI0_MUX, "ldi0_mux", ldi0_mux_p, ARRAY_SIZE(ldi0_mux_p), CLK_SET_RATE_PARENT, 0x114, 13, 2, CLK_MUX_HIWORD_MASK, }, + { HI3620_EDC1_MUX, "edc1_mux", edc1_mux_p, ARRAY_SIZE(edc1_mux_p), CLK_SET_RATE_PARENT, 0x118, 6, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_LDI1_MUX, "ldi1_mux", ldi1_mux_p, ARRAY_SIZE(ldi1_mux_p), CLK_SET_RATE_PARENT, 0x118, 14, 2, CLK_MUX_HIWORD_MASK, }, + { HI3620_RCLK_HSIC, "rclk_hsic", rclk_hsic_p, ARRAY_SIZE(rclk_hsic_p), CLK_SET_RATE_PARENT, 0x130, 2, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_MMC2_MUX, "mmc2_mux", mmc2_mux_p, ARRAY_SIZE(mmc2_mux_p), CLK_SET_RATE_PARENT, 0x140, 4, 1, CLK_MUX_HIWORD_MASK, }, + { HI3620_MMC3_MUX, "mmc3_mux", mmc3_mux_p, ARRAY_SIZE(mmc3_mux_p), CLK_SET_RATE_PARENT, 0x140, 9, 1, CLK_MUX_HIWORD_MASK, }, +}; + +static struct hisi_divider_clock hi3620_div_clks[] __initdata = { + { HI3620_SHAREAXI_DIV, "saxi_div", "saxi_mux", 0, 0x100, 0, 5, CLK_MUX_HIWORD_MASK, NULL, }, + { HI3620_CFGAXI_DIV, "cfgaxi_div", "saxi_div", 0, 0x100, 5, 2, CLK_MUX_HIWORD_MASK, NULL, }, + { HI3620_SD_DIV, "sd_div", "sd_mux", 0, 0x108, 0, 4, CLK_MUX_HIWORD_MASK, NULL, }, + { HI3620_MMC1_DIV, "mmc1_div", "mmc1_mux", 0, 0x108, 5, 4, CLK_MUX_HIWORD_MASK, NULL, }, + { HI3620_HSIC_DIV, "hsic_div", "rclk_hsic", 0, 0x130, 0, 2, CLK_MUX_HIWORD_MASK, NULL, }, + { HI3620_MMC2_DIV, "mmc2_div", "mmc2_mux", 0, 0x140, 0, 4, CLK_MUX_HIWORD_MASK, NULL, }, + { HI3620_MMC3_DIV, "mmc3_div", "mmc3_mux", 0, 0x140, 5, 4, CLK_MUX_HIWORD_MASK, NULL, }, +}; + +static struct hisi_gate_clock hi3620_seperated_gate_clks[] __initdata = { + { HI3620_TIMERCLK01, "timerclk01", "timer_rclk01", 0, 0x20, 0, 0, }, + { HI3620_TIMER_RCLK01, "timer_rclk01", "rclk_tcxo", 0, 0x20, 1, 0, }, + { HI3620_TIMERCLK23, "timerclk23", "timer_rclk23", 0, 0x20, 2, 0, }, + { HI3620_TIMER_RCLK23, "timer_rclk23", "rclk_tcxo", 0, 0x20, 3, 0, }, + { HI3620_RTCCLK, "rtcclk", "pclk", 0, 0x20, 5, 0, }, + { HI3620_KPC_CLK, "kpc_clk", "pclk", 0, 0x20, 6, 0, }, + { HI3620_GPIOCLK0, "gpioclk0", "pclk", 0, 0x20, 8, 0, }, + { HI3620_GPIOCLK1, "gpioclk1", "pclk", 0, 0x20, 9, 0, }, + { HI3620_GPIOCLK2, "gpioclk2", "pclk", 0, 0x20, 10, 0, }, + { HI3620_GPIOCLK3, "gpioclk3", "pclk", 0, 0x20, 11, 0, }, + { HI3620_GPIOCLK4, "gpioclk4", "pclk", 0, 0x20, 12, 0, }, + { HI3620_GPIOCLK5, "gpioclk5", "pclk", 0, 0x20, 13, 0, }, + { HI3620_GPIOCLK6, "gpioclk6", "pclk", 0, 0x20, 14, 0, }, + { HI3620_GPIOCLK7, "gpioclk7", "pclk", 0, 0x20, 15, 0, }, + { HI3620_GPIOCLK8, "gpioclk8", "pclk", 0, 0x20, 16, 0, }, + { HI3620_GPIOCLK9, "gpioclk9", "pclk", 0, 0x20, 17, 0, }, + { HI3620_GPIOCLK10, "gpioclk10", "pclk", 0, 0x20, 18, 0, }, + { HI3620_GPIOCLK11, "gpioclk11", "pclk", 0, 0x20, 19, 0, }, + { HI3620_GPIOCLK12, "gpioclk12", "pclk", 0, 0x20, 20, 0, }, + { HI3620_GPIOCLK13, "gpioclk13", "pclk", 0, 0x20, 21, 0, }, + { HI3620_GPIOCLK14, "gpioclk14", "pclk", 0, 0x20, 22, 0, }, + { HI3620_GPIOCLK15, "gpioclk15", "pclk", 0, 0x20, 23, 0, }, + { HI3620_GPIOCLK16, "gpioclk16", "pclk", 0, 0x20, 24, 0, }, + { HI3620_GPIOCLK17, "gpioclk17", "pclk", 0, 0x20, 25, 0, }, + { HI3620_GPIOCLK18, "gpioclk18", "pclk", 0, 0x20, 26, 0, }, + { HI3620_GPIOCLK19, "gpioclk19", "pclk", 0, 0x20, 27, 0, }, + { HI3620_GPIOCLK20, "gpioclk20", "pclk", 0, 0x20, 28, 0, }, + { HI3620_GPIOCLK21, "gpioclk21", "pclk", 0, 0x20, 29, 0, }, + { HI3620_DPHY0_CLK, "dphy0_clk", "osc26m", 0, 0x30, 15, 0, }, + { HI3620_DPHY1_CLK, "dphy1_clk", "osc26m", 0, 0x30, 16, 0, }, + { HI3620_DPHY2_CLK, "dphy2_clk", "osc26m", 0, 0x30, 17, 0, }, + { HI3620_USBPHY_CLK, "usbphy_clk", "rclk_pico", 0, 0x30, 24, 0, }, + { HI3620_ACP_CLK, "acp_clk", "rclk_cfgaxi", 0, 0x30, 28, 0, }, + { HI3620_TIMERCLK45, "timerclk45", "rclk_tcxo", 0, 0x40, 3, 0, }, + { HI3620_TIMERCLK67, "timerclk67", "rclk_tcxo", 0, 0x40, 4, 0, }, + { HI3620_TIMERCLK89, "timerclk89", "rclk_tcxo", 0, 0x40, 5, 0, }, + { HI3620_PWMCLK0, "pwmclk0", "pwm0_mux", 0, 0x40, 7, 0, }, + { HI3620_PWMCLK1, "pwmclk1", "pwm1_mux", 0, 0x40, 8, 0, }, + { HI3620_UARTCLK0, "uartclk0", "uart0_mux", 0, 0x40, 16, 0, }, + { HI3620_UARTCLK1, "uartclk1", "uart1_mux", 0, 0x40, 17, 0, }, + { HI3620_UARTCLK2, "uartclk2", "uart2_mux", 0, 0x40, 18, 0, }, + { HI3620_UARTCLK3, "uartclk3", "uart3_mux", 0, 0x40, 19, 0, }, + { HI3620_UARTCLK4, "uartclk4", "uart4_mux", 0, 0x40, 20, 0, }, + { HI3620_SPICLK0, "spiclk0", "spi0_mux", 0, 0x40, 21, 0, }, + { HI3620_SPICLK1, "spiclk1", "spi1_mux", 0, 0x40, 22, 0, }, + { HI3620_SPICLK2, "spiclk2", "spi2_mux", 0, 0x40, 23, 0, }, + { HI3620_I2CCLK0, "i2cclk0", "pclk", 0, 0x40, 24, 0, }, + { HI3620_I2CCLK1, "i2cclk1", "pclk", 0, 0x40, 25, 0, }, + { HI3620_SCI_CLK, "sci_clk", "osc26m", 0, 0x40, 26, 0, }, + { HI3620_I2CCLK2, "i2cclk2", "pclk", 0, 0x40, 28, 0, }, + { HI3620_I2CCLK3, "i2cclk3", "pclk", 0, 0x40, 29, 0, }, + { HI3620_DDRC_PER_CLK, "ddrc_per_clk", "rclk_cfgaxi", 0, 0x50, 9, 0, }, + { HI3620_DMAC_CLK, "dmac_clk", "rclk_cfgaxi", 0, 0x50, 10, 0, }, + { HI3620_USB2DVC_CLK, "usb2dvc_clk", "rclk_cfgaxi", 0, 0x50, 17, 0, }, + { HI3620_SD_CLK, "sd_clk", "sd_div", 0, 0x50, 20, 0, }, + { HI3620_MMC_CLK1, "mmc_clk1", "mmc1_mux2", 0, 0x50, 21, 0, }, + { HI3620_MMC_CLK2, "mmc_clk2", "mmc2_div", 0, 0x50, 22, 0, }, + { HI3620_MMC_CLK3, "mmc_clk3", "mmc3_div", 0, 0x50, 23, 0, }, + { HI3620_MCU_CLK, "mcu_clk", "acp_clk", 0, 0x50, 24, 0, }, +}; + +static void __init hi3620_clk_init(struct device_node *np) +{ + void __iomem *base; + + if (np) { + base = of_iomap(np, 0); + if (!base) { + pr_err("failed to map Hi3620 clock registers\n"); + return; + } + } else { + pr_err("failed to find Hi3620 clock node in DTS\n"); + return; + } + + hisi_clk_init(np, HI3620_NR_CLKS); + + hisi_clk_register_fixed_rate(hi3620_fixed_rate_clks, + ARRAY_SIZE(hi3620_fixed_rate_clks), + base); + hisi_clk_register_fixed_factor(hi3620_fixed_factor_clks, + ARRAY_SIZE(hi3620_fixed_factor_clks), + base); + hisi_clk_register_mux(hi3620_mux_clks, ARRAY_SIZE(hi3620_mux_clks), + base); + hisi_clk_register_divider(hi3620_div_clks, ARRAY_SIZE(hi3620_div_clks), + base); + hisi_clk_register_gate_sep(hi3620_seperated_gate_clks, + ARRAY_SIZE(hi3620_seperated_gate_clks), + base); +} +CLK_OF_DECLARE(hi3620_clk, "hisilicon,hi3620-clock", hi3620_clk_init); diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c new file mode 100644 index 000000000000..a3a7152c92d9 --- /dev/null +++ b/drivers/clk/hisilicon/clk.c @@ -0,0 +1,171 @@ +/* + * Hisilicon clock driver + * + * Copyright (c) 2012-2013 Hisilicon Limited. + * Copyright (c) 2012-2013 Linaro Limited. + * + * Author: Haojian Zhuang + * Xin Li + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static DEFINE_SPINLOCK(hisi_clk_lock); +static struct clk **clk_table; +static struct clk_onecell_data clk_data; + +void __init hisi_clk_init(struct device_node *np, int nr_clks) +{ + clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL); + if (!clk_table) { + pr_err("%s: could not allocate clock lookup table\n", __func__); + return; + } + clk_data.clks = clk_table; + clk_data.clk_num = nr_clks; + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); +} + +void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks, + int nums, void __iomem *base) +{ + struct clk *clk; + int i; + + for (i = 0; i < nums; i++) { + clk = clk_register_fixed_rate(NULL, clks[i].name, + clks[i].parent_name, + clks[i].flags, + clks[i].fixed_rate); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + } +} + +void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks, + int nums, void __iomem *base) +{ + struct clk *clk; + int i; + + for (i = 0; i < nums; i++) { + clk = clk_register_fixed_factor(NULL, clks[i].name, + clks[i].parent_name, + clks[i].flags, clks[i].mult, + clks[i].div); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + } +} + +void __init hisi_clk_register_mux(struct hisi_mux_clock *clks, + int nums, void __iomem *base) +{ + struct clk *clk; + int i; + + for (i = 0; i < nums; i++) { + clk = clk_register_mux(NULL, clks[i].name, clks[i].parent_names, + clks[i].num_parents, clks[i].flags, + base + clks[i].offset, clks[i].shift, + clks[i].width, clks[i].mux_flags, + &hisi_clk_lock); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + + if (clks[i].alias) + clk_register_clkdev(clk, clks[i].alias, NULL); + + clk_table[clks[i].id] = clk; + } +} + +void __init hisi_clk_register_divider(struct hisi_divider_clock *clks, + int nums, void __iomem *base) +{ + struct clk *clk; + int i; + + for (i = 0; i < nums; i++) { + clk = clk_register_divider_table(NULL, clks[i].name, + clks[i].parent_name, + clks[i].flags, + base + clks[i].offset, + clks[i].shift, clks[i].width, + clks[i].div_flags, + clks[i].table, + &hisi_clk_lock); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + + if (clks[i].alias) + clk_register_clkdev(clk, clks[i].alias, NULL); + + clk_table[clks[i].id] = clk; + } +} + +void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks, + int nums, void __iomem *base) +{ + struct clk *clk; + int i; + + for (i = 0; i < nums; i++) { + clk = hisi_register_clkgate_sep(NULL, clks[i].name, + clks[i].parent_name, + clks[i].flags, + base + clks[i].offset, + clks[i].bit_idx, + clks[i].gate_flags, + &hisi_clk_lock); + if (IS_ERR(clk)) { + pr_err("%s: failed to register clock %s\n", + __func__, clks[i].name); + continue; + } + + if (clks[i].alias) + clk_register_clkdev(clk, clks[i].alias, NULL); + + clk_table[clks[i].id] = clk; + } +} diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h new file mode 100644 index 000000000000..4a6beebefb7a --- /dev/null +++ b/drivers/clk/hisilicon/clk.h @@ -0,0 +1,103 @@ +/* + * Hisilicon Hi3620 clock gate driver + * + * Copyright (c) 2012-2013 Hisilicon Limited. + * Copyright (c) 2012-2013 Linaro Limited. + * + * Author: Haojian Zhuang + * Xin Li + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef __HISI_CLK_H +#define __HISI_CLK_H + +#include +#include +#include + +struct hisi_fixed_rate_clock { + unsigned int id; + char *name; + const char *parent_name; + unsigned long flags; + unsigned long fixed_rate; +}; + +struct hisi_fixed_factor_clock { + unsigned int id; + char *name; + const char *parent_name; + unsigned long mult; + unsigned long div; + unsigned long flags; +}; + +struct hisi_mux_clock { + unsigned int id; + const char *name; + const char **parent_names; + u8 num_parents; + unsigned long flags; + unsigned long offset; + u8 shift; + u8 width; + u8 mux_flags; + const char *alias; +}; + +struct hisi_divider_clock { + unsigned int id; + const char *name; + const char *parent_name; + unsigned long flags; + unsigned long offset; + u8 shift; + u8 width; + u8 div_flags; + struct clk_div_table *table; + const char *alias; +}; + +struct hisi_gate_clock { + unsigned int id; + const char *name; + const char *parent_name; + unsigned long flags; + unsigned long offset; + u8 bit_idx; + u8 gate_flags; + const char *alias; +}; + +struct clk *hisi_register_clkgate_sep(struct device *, const char *, + const char *, unsigned long, + void __iomem *, u8, + u8, spinlock_t *); + +void __init hisi_clk_init(struct device_node *, int); +void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *, + int, void __iomem *); +void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *, + int, void __iomem *); +void __init hisi_clk_register_mux(struct hisi_mux_clock *, int, + void __iomem *); +void __init hisi_clk_register_divider(struct hisi_divider_clock *, + int, void __iomem *); +void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *, + int, void __iomem *); +#endif /* __HISI_CLK_H */ diff --git a/drivers/clk/hisilicon/clkgate-separated.c b/drivers/clk/hisilicon/clkgate-separated.c new file mode 100644 index 000000000000..b03d5a7246f9 --- /dev/null +++ b/drivers/clk/hisilicon/clkgate-separated.c @@ -0,0 +1,130 @@ +/* + * Hisilicon clock separated gate driver + * + * Copyright (c) 2012-2013 Hisilicon Limited. + * Copyright (c) 2012-2013 Linaro Limited. + * + * Author: Haojian Zhuang + * Xin Li + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +/* clock separated gate register offset */ +#define CLKGATE_SEPERATED_ENABLE 0x0 +#define CLKGATE_SEPERATED_DISABLE 0x4 +#define CLKGATE_SEPERATED_STATUS 0x8 + +struct clkgate_separated { + struct clk_hw hw; + void __iomem *enable; /* enable register */ + u8 bit_idx; /* bits in enable/disable register */ + u8 flags; + spinlock_t *lock; +}; + +static int clkgate_separated_enable(struct clk_hw *hw) +{ + struct clkgate_separated *sclk; + unsigned long flags = 0; + u32 reg; + + sclk = container_of(hw, struct clkgate_separated, hw); + if (sclk->lock) + spin_lock_irqsave(sclk->lock, flags); + reg = BIT(sclk->bit_idx); + writel_relaxed(reg, sclk->enable); + readl_relaxed(sclk->enable + CLKGATE_SEPERATED_STATUS); + if (sclk->lock) + spin_unlock_irqrestore(sclk->lock, flags); + return 0; +} + +static void clkgate_separated_disable(struct clk_hw *hw) +{ + struct clkgate_separated *sclk; + unsigned long flags = 0; + u32 reg; + + sclk = container_of(hw, struct clkgate_separated, hw); + if (sclk->lock) + spin_lock_irqsave(sclk->lock, flags); + reg = BIT(sclk->bit_idx); + writel_relaxed(reg, sclk->enable + CLKGATE_SEPERATED_DISABLE); + readl_relaxed(sclk->enable + CLKGATE_SEPERATED_STATUS); + if (sclk->lock) + spin_unlock_irqrestore(sclk->lock, flags); +} + +static int clkgate_separated_is_enabled(struct clk_hw *hw) +{ + struct clkgate_separated *sclk; + u32 reg; + + sclk = container_of(hw, struct clkgate_separated, hw); + reg = readl_relaxed(sclk->enable + CLKGATE_SEPERATED_STATUS); + reg &= BIT(sclk->bit_idx); + + return reg ? 1 : 0; +} + +static struct clk_ops clkgate_separated_ops = { + .enable = clkgate_separated_enable, + .disable = clkgate_separated_disable, + .is_enabled = clkgate_separated_is_enabled, +}; + +struct clk *hisi_register_clkgate_sep(struct device *dev, const char *name, + const char *parent_name, + unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock) +{ + struct clkgate_separated *sclk; + struct clk *clk; + struct clk_init_data init; + + sclk = kzalloc(sizeof(*sclk), GFP_KERNEL); + if (!sclk) { + pr_err("%s: fail to allocate separated gated clk\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &clkgate_separated_ops; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + sclk->enable = reg + CLKGATE_SEPERATED_ENABLE; + sclk->bit_idx = bit_idx; + sclk->flags = clk_gate_flags; + sclk->hw.init = &init; + + clk = clk_register(dev, &sclk->hw); + if (IS_ERR(clk)) + kfree(sclk); + return clk; +} diff --git a/include/dt-bindings/clock/hi3620-clock.h b/include/dt-bindings/clock/hi3620-clock.h new file mode 100644 index 000000000000..6eaa6a45e110 --- /dev/null +++ b/include/dt-bindings/clock/hi3620-clock.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2012-2013 Hisilicon Limited. + * Copyright (c) 2012-2013 Linaro Limited. + * + * Author: Haojian Zhuang + * Xin Li + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef __DTS_HI3620_CLOCK_H +#define __DTS_HI3620_CLOCK_H + +#define HI3620_NONE_CLOCK 0 + +/* fixed rate & fixed factor clocks */ +#define HI3620_OSC32K 1 +#define HI3620_OSC26M 2 +#define HI3620_PCLK 3 +#define HI3620_PLL_ARM0 4 +#define HI3620_PLL_ARM1 5 +#define HI3620_PLL_PERI 6 +#define HI3620_PLL_USB 7 +#define HI3620_PLL_HDMI 8 +#define HI3620_PLL_GPU 9 +#define HI3620_RCLK_TCXO 10 +#define HI3620_RCLK_CFGAXI 11 +#define HI3620_RCLK_PICO 12 + +/* mux clocks */ +#define HI3620_TIMER0_MUX 32 +#define HI3620_TIMER1_MUX 33 +#define HI3620_TIMER2_MUX 34 +#define HI3620_TIMER3_MUX 35 +#define HI3620_TIMER4_MUX 36 +#define HI3620_TIMER5_MUX 37 +#define HI3620_TIMER6_MUX 38 +#define HI3620_TIMER7_MUX 39 +#define HI3620_TIMER8_MUX 40 +#define HI3620_TIMER9_MUX 41 +#define HI3620_UART0_MUX 42 +#define HI3620_UART1_MUX 43 +#define HI3620_UART2_MUX 44 +#define HI3620_UART3_MUX 45 +#define HI3620_UART4_MUX 46 +#define HI3620_SPI0_MUX 47 +#define HI3620_SPI1_MUX 48 +#define HI3620_SPI2_MUX 49 +#define HI3620_SAXI_MUX 50 +#define HI3620_PWM0_MUX 51 +#define HI3620_PWM1_MUX 52 +#define HI3620_SD_MUX 53 +#define HI3620_MMC1_MUX 54 +#define HI3620_MMC1_MUX2 55 +#define HI3620_G2D_MUX 56 +#define HI3620_VENC_MUX 57 +#define HI3620_VDEC_MUX 58 +#define HI3620_VPP_MUX 59 +#define HI3620_EDC0_MUX 60 +#define HI3620_LDI0_MUX 61 +#define HI3620_EDC1_MUX 62 +#define HI3620_LDI1_MUX 63 +#define HI3620_RCLK_HSIC 64 +#define HI3620_MMC2_MUX 65 +#define HI3620_MMC3_MUX 66 + +/* divider clocks */ +#define HI3620_SHAREAXI_DIV 128 +#define HI3620_CFGAXI_DIV 129 +#define HI3620_SD_DIV 130 +#define HI3620_MMC1_DIV 131 +#define HI3620_HSIC_DIV 132 +#define HI3620_MMC2_DIV 133 +#define HI3620_MMC3_DIV 134 + +/* gate clocks */ +#define HI3620_TIMERCLK01 160 +#define HI3620_TIMER_RCLK01 161 +#define HI3620_TIMERCLK23 162 +#define HI3620_TIMER_RCLK23 163 +#define HI3620_TIMERCLK45 164 +#define HI3620_TIMERCLK67 165 +#define HI3620_TIMERCLK89 166 +#define HI3620_RTCCLK 167 +#define HI3620_KPC_CLK 168 +#define HI3620_GPIOCLK0 169 +#define HI3620_GPIOCLK1 170 +#define HI3620_GPIOCLK2 171 +#define HI3620_GPIOCLK3 172 +#define HI3620_GPIOCLK4 173 +#define HI3620_GPIOCLK5 174 +#define HI3620_GPIOCLK6 175 +#define HI3620_GPIOCLK7 176 +#define HI3620_GPIOCLK8 177 +#define HI3620_GPIOCLK9 178 +#define HI3620_GPIOCLK10 179 +#define HI3620_GPIOCLK11 180 +#define HI3620_GPIOCLK12 181 +#define HI3620_GPIOCLK13 182 +#define HI3620_GPIOCLK14 183 +#define HI3620_GPIOCLK15 184 +#define HI3620_GPIOCLK16 185 +#define HI3620_GPIOCLK17 186 +#define HI3620_GPIOCLK18 187 +#define HI3620_GPIOCLK19 188 +#define HI3620_GPIOCLK20 189 +#define HI3620_GPIOCLK21 190 +#define HI3620_DPHY0_CLK 191 +#define HI3620_DPHY1_CLK 192 +#define HI3620_DPHY2_CLK 193 +#define HI3620_USBPHY_CLK 194 +#define HI3620_ACP_CLK 195 +#define HI3620_PWMCLK0 196 +#define HI3620_PWMCLK1 197 +#define HI3620_UARTCLK0 198 +#define HI3620_UARTCLK1 199 +#define HI3620_UARTCLK2 200 +#define HI3620_UARTCLK3 201 +#define HI3620_UARTCLK4 202 +#define HI3620_SPICLK0 203 +#define HI3620_SPICLK1 204 +#define HI3620_SPICLK2 205 +#define HI3620_I2CCLK0 206 +#define HI3620_I2CCLK1 207 +#define HI3620_I2CCLK2 208 +#define HI3620_I2CCLK3 209 +#define HI3620_SCI_CLK 210 +#define HI3620_DDRC_PER_CLK 211 +#define HI3620_DMAC_CLK 212 +#define HI3620_USB2DVC_CLK 213 +#define HI3620_SD_CLK 214 +#define HI3620_MMC_CLK1 215 +#define HI3620_MMC_CLK2 216 +#define HI3620_MMC_CLK3 217 +#define HI3620_MCU_CLK 218 + +#define HI3620_NR_CLKS 219 + +#endif /* __DTS_HI3620_CLOCK_H */ -- cgit v1.2.3 From 4e5e4705bf69ea450f58fc709ac5888f321a9299 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Wed, 3 Jul 2013 15:35:39 -0400 Subject: thermal: introduce device tree parser This patch introduces a device tree bindings for describing the hardware thermal behavior and limits. Also a parser to read and interpret the data and feed it in the thermal framework is presented. This patch introduces a thermal data parser for device tree. The parsed data is used to build thermal zones and thermal binding parameters. The output data can then be used to deploy thermal policies. This patch adds also documentation regarding this API and how to define tree nodes to use this infrastructure. Note that, in order to be able to have control on the sensor registration on the DT thermal zone, it was required to allow changing the thermal zone .get_temp callback. For this reason, this patch also removes the 'const' modifier from the .ops field of thermal zone devices. Cc: Zhang Rui Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Acked-by: Mark Rutland Signed-off-by: Eduardo Valentin --- .../devicetree/bindings/thermal/thermal.txt | 595 +++++++++++++++ drivers/thermal/Kconfig | 13 + drivers/thermal/Makefile | 1 + drivers/thermal/of-thermal.c | 849 +++++++++++++++++++++ drivers/thermal/thermal_core.c | 9 +- drivers/thermal/thermal_core.h | 9 + include/dt-bindings/thermal/thermal.h | 17 + include/linux/thermal.h | 28 +- 8 files changed, 1518 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/thermal/thermal.txt create mode 100644 drivers/thermal/of-thermal.c create mode 100644 include/dt-bindings/thermal/thermal.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/thermal/thermal.txt b/Documentation/devicetree/bindings/thermal/thermal.txt new file mode 100644 index 000000000000..f5db6b72a36f --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/thermal.txt @@ -0,0 +1,595 @@ +* Thermal Framework Device Tree descriptor + +This file describes a generic binding to provide a way of +defining hardware thermal structure using device tree. +A thermal structure includes thermal zones and their components, +such as trip points, polling intervals, sensors and cooling devices +binding descriptors. + +The target of device tree thermal descriptors is to describe only +the hardware thermal aspects. The thermal device tree bindings are +not about how the system must control or which algorithm or policy +must be taken in place. + +There are five types of nodes involved to describe thermal bindings: +- thermal sensors: devices which may be used to take temperature + measurements. +- cooling devices: devices which may be used to dissipate heat. +- trip points: describe key temperatures at which cooling is recommended. The + set of points should be chosen based on hardware limits. +- cooling maps: used to describe links between trip points and cooling devices; +- thermal zones: used to describe thermal data within the hardware; + +The following is a description of each of these node types. + +* Thermal sensor devices + +Thermal sensor devices are nodes providing temperature sensing capabilities on +thermal zones. Typical devices are I2C ADC converters and bandgaps. These are +nodes providing temperature data to thermal zones. Thermal sensor devices may +control one or more internal sensors. + +Required property: +- #thermal-sensor-cells: Used to provide sensor device specific information + Type: unsigned while referring to it. Typically 0 on thermal sensor + Size: one cell nodes with only one sensor, and at least 1 on nodes + with several internal sensors, in order + to identify uniquely the sensor instances within + the IC. See thermal zone binding for more details + on how consumers refer to sensor devices. + +* Cooling device nodes + +Cooling devices are nodes providing control on power dissipation. There +are essentially two ways to provide control on power dissipation. First +is by means of regulating device performance, which is known as passive +cooling. A typical passive cooling is a CPU that has dynamic voltage and +frequency scaling (DVFS), and uses lower frequencies as cooling states. +Second is by means of activating devices in order to remove +the dissipated heat, which is known as active cooling, e.g. regulating +fan speeds. In both cases, cooling devices shall have a way to determine +the state of cooling in which the device is. + +Any cooling device has a range of cooling states (i.e. different levels +of heat dissipation). For example a fan's cooling states correspond to +the different fan speeds possible. Cooling states are referred to by +single unsigned integers, where larger numbers mean greater heat +dissipation. The precise set of cooling states associated with a device +(as referred to be the cooling-min-state and cooling-max-state +properties) should be defined in a particular device's binding. +For more examples of cooling devices, refer to the example sections below. + +Required properties: +- cooling-min-state: An integer indicating the smallest + Type: unsigned cooling state accepted. Typically 0. + Size: one cell + +- cooling-max-state: An integer indicating the largest + Type: unsigned cooling state accepted. + Size: one cell + +- #cooling-cells: Used to provide cooling device specific information + Type: unsigned while referring to it. Must be at least 2, in order + Size: one cell to specify minimum and maximum cooling state used + in the reference. The first cell is the minimum + cooling state requested and the second cell is + the maximum cooling state requested in the reference. + See Cooling device maps section below for more details + on how consumers refer to cooling devices. + +* Trip points + +The trip node is a node to describe a point in the temperature domain +in which the system takes an action. This node describes just the point, +not the action. + +Required properties: +- temperature: An integer indicating the trip temperature level, + Type: signed in millicelsius. + Size: one cell + +- hysteresis: A low hysteresis value on temperature property (above). + Type: unsigned This is a relative value, in millicelsius. + Size: one cell + +- type: a string containing the trip type. Expected values are: + "active": A trip point to enable active cooling + "passive": A trip point to enable passive cooling + "hot": A trip point to notify emergency + "critical": Hardware not reliable. + Type: string + +* Cooling device maps + +The cooling device maps node is a node to describe how cooling devices +get assigned to trip points of the zone. The cooling devices are expected +to be loaded in the target system. + +Required properties: +- cooling-device: A phandle of a cooling device with its specifier, + Type: phandle + referring to which cooling device is used in this + cooling specifier binding. In the cooling specifier, the first cell + is the minimum cooling state and the second cell + is the maximum cooling state used in this map. +- trip: A phandle of a trip point node within the same thermal + Type: phandle of zone. + trip point node + +Optional property: +- contribution: The cooling contribution to the thermal zone of the + Type: unsigned referred cooling device at the referred trip point. + Size: one cell The contribution is a ratio of the sum + of all cooling contributions within a thermal zone. + +Note: Using the THERMAL_NO_LIMIT (-1UL) constant in the cooling-device phandle +limit specifier means: +(i) - minimum state allowed for minimum cooling state used in the reference. +(ii) - maximum state allowed for maximum cooling state used in the reference. +Refer to include/dt-bindings/thermal/thermal.h for definition of this constant. + +* Thermal zone nodes + +The thermal zone node is the node containing all the required info +for describing a thermal zone, including its cooling device bindings. The +thermal zone node must contain, apart from its own properties, one sub-node +containing trip nodes and one sub-node containing all the zone cooling maps. + +Required properties: +- polling-delay: The maximum number of milliseconds to wait between polls + Type: unsigned when checking this thermal zone. + Size: one cell + +- polling-delay-passive: The maximum number of milliseconds to wait + Type: unsigned between polls when performing passive cooling. + Size: one cell + +- thermal-sensors: A list of thermal sensor phandles and sensor specifier + Type: list of used while monitoring the thermal zone. + phandles + sensor + specifier + +- trips: A sub-node which is a container of only trip point nodes + Type: sub-node required to describe the thermal zone. + +- cooling-maps: A sub-node which is a container of only cooling device + Type: sub-node map nodes, used to describe the relation between trips + and cooling devices. + +Optional property: +- coefficients: An array of integers (one signed cell) containing + Type: array coefficients to compose a linear relation between + Elem size: one cell the sensors listed in the thermal-sensors property. + Elem type: signed Coefficients defaults to 1, in case this property + is not specified. A simple linear polynomial is used: + Z = c0 * x0 + c1 + x1 + ... + c(n-1) * x(n-1) + cn. + + The coefficients are ordered and they match with sensors + by means of sensor ID. Additional coefficients are + interpreted as constant offset. + +Note: The delay properties are bound to the maximum dT/dt (temperature +derivative over time) in two situations for a thermal zone: +(i) - when passive cooling is activated (polling-delay-passive); and +(ii) - when the zone just needs to be monitored (polling-delay) or +when active cooling is activated. + +The maximum dT/dt is highly bound to hardware power consumption and dissipation +capability. The delays should be chosen to account for said max dT/dt, +such that a device does not cross several trip boundaries unexpectedly +between polls. Choosing the right polling delays shall avoid having the +device in temperature ranges that may damage the silicon structures and +reduce silicon lifetime. + +* The thermal-zones node + +The "thermal-zones" node is a container for all thermal zone nodes. It shall +contain only sub-nodes describing thermal zones as in the section +"Thermal zone nodes". The "thermal-zones" node appears under "/". + +* Examples + +Below are several examples on how to use thermal data descriptors +using device tree bindings: + +(a) - CPU thermal zone + +The CPU thermal zone example below describes how to setup one thermal zone +using one single sensor as temperature source and many cooling devices and +power dissipation control sources. + +#include + +cpus { + /* + * Here is an example of describing a cooling device for a DVFS + * capable CPU. The CPU node describes its four OPPs. + * The cooling states possible are 0..3, and they are + * used as OPP indexes. The minimum cooling state is 0, which means + * all four OPPs can be available to the system. The maximum + * cooling state is 3, which means only the lowest OPPs (198MHz@0.85V) + * can be available in the system. + */ + cpu0: cpu@0 { + ... + operating-points = < + /* kHz uV */ + 970000 1200000 + 792000 1100000 + 396000 950000 + 198000 850000 + >; + cooling-min-state = <0>; + cooling-max-state = <3>; + #cooling-cells = <2>; /* min followed by max */ + }; + ... +}; + +&i2c1 { + ... + /* + * A simple fan controller which supports 10 speeds of operation + * (represented as 0-9). + */ + fan0: fan@0x48 { + ... + cooling-min-state = <0>; + cooling-max-state = <9>; + #cooling-cells = <2>; /* min followed by max */ + }; +}; + +ocp { + ... + /* + * A simple IC with a single bandgap temperature sensor. + */ + bandgap0: bandgap@0x0000ED00 { + ... + #thermal-sensor-cells = <0>; + }; +}; + +thermal-zones { + cpu-thermal: cpu-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + thermal-sensors = <&bandgap0>; + + trips { + cpu-alert0: cpu-alert { + temperature = <90000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "active"; + }; + cpu-alert1: cpu-alert { + temperature = <100000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + cpu-crit: cpu-crit { + temperature = <125000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu-alert0>; + cooling-device = <&fan0 THERMAL_NO_LIMITS 4>; + }; + map1 { + trip = <&cpu-alert1>; + cooling-device = <&fan0 5 THERMAL_NO_LIMITS>; + }; + map2 { + trip = <&cpu-alert1>; + cooling-device = + <&cpu0 THERMAL_NO_LIMITS THERMAL_NO_LIMITS>; + }; + }; + }; +}; + +In the example above, the ADC sensor (bandgap0) at address 0x0000ED00 is +used to monitor the zone 'cpu-thermal' using its sole sensor. A fan +device (fan0) is controlled via I2C bus 1, at address 0x48, and has ten +different cooling states 0-9. It is used to remove the heat out of +the thermal zone 'cpu-thermal' using its cooling states +from its minimum to 4, when it reaches trip point 'cpu-alert0' +at 90C, as an example of active cooling. The same cooling device is used at +'cpu-alert1', but from 5 to its maximum state. The cpu@0 device is also +linked to the same thermal zone, 'cpu-thermal', as a passive cooling device, +using all its cooling states at trip point 'cpu-alert1', +which is a trip point at 100C. On the thermal zone 'cpu-thermal', at the +temperature of 125C, represented by the trip point 'cpu-crit', the silicon +is not reliable anymore. + +(b) - IC with several internal sensors + +The example below describes how to deploy several thermal zones based off a +single sensor IC, assuming it has several internal sensors. This is a common +case on SoC designs with several internal IPs that may need different thermal +requirements, and thus may have their own sensor to monitor or detect internal +hotspots in their silicon. + +#include + +ocp { + ... + /* + * A simple IC with several bandgap temperature sensors. + */ + bandgap0: bandgap@0x0000ED00 { + ... + #thermal-sensor-cells = <1>; + }; +}; + +thermal-zones { + cpu-thermal: cpu-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&bandgap0 0>; + + trips { + /* each zone within the SoC may have its own trips */ + cpu-alert: cpu-alert { + temperature = <100000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + cpu-crit: cpu-crit { + temperature = <125000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + /* each zone within the SoC may have its own cooling */ + ... + }; + }; + + gpu-thermal: gpu-thermal { + polling-delay-passive = <120>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&bandgap0 1>; + + trips { + /* each zone within the SoC may have its own trips */ + gpu-alert: gpu-alert { + temperature = <90000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + gpu-crit: gpu-crit { + temperature = <105000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + /* each zone within the SoC may have its own cooling */ + ... + }; + }; + + dsp-thermal: dsp-thermal { + polling-delay-passive = <50>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&bandgap0 2>; + + trips { + /* each zone within the SoC may have its own trips */ + dsp-alert: gpu-alert { + temperature = <90000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + dsp-crit: gpu-crit { + temperature = <135000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + /* each zone within the SoC may have its own cooling */ + ... + }; + }; +}; + +In the example above, there is one bandgap IC which has the capability to +monitor three sensors. The hardware has been designed so that sensors are +placed on different places in the DIE to monitor different temperature +hotspots: one for CPU thermal zone, one for GPU thermal zone and the +other to monitor a DSP thermal zone. + +Thus, there is a need to assign each sensor provided by the bandgap IC +to different thermal zones. This is achieved by means of using the +#thermal-sensor-cells property and using the first cell of the sensor +specifier as sensor ID. In the example, then, is used to +monitor CPU thermal zone, is used to monitor GPU thermal +zone and is used to monitor DSP thermal zone. Each zone +may be uncorrelated, having its own dT/dt requirements, trips +and cooling maps. + + +(c) - Several sensors within one single thermal zone + +The example below illustrates how to use more than one sensor within +one thermal zone. + +#include + +&i2c1 { + ... + /* + * A simple IC with a single temperature sensor. + */ + adc: sensor@0x49 { + ... + #thermal-sensor-cells = <0>; + }; +}; + +ocp { + ... + /* + * A simple IC with a single bandgap temperature sensor. + */ + bandgap0: bandgap@0x0000ED00 { + ... + #thermal-sensor-cells = <0>; + }; +}; + +thermal-zones { + cpu-thermal: cpu-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + thermal-sensors = <&bandgap0>, /* cpu */ + <&adc>; /* pcb north */ + + /* hotspot = 100 * bandgap - 120 * adc + 484 */ + coefficients = <100 -120 484>; + + trips { + ... + }; + + cooling-maps { + ... + }; + }; +}; + +In some cases, there is a need to use more than one sensor to extrapolate +a thermal hotspot in the silicon. The above example illustrates this situation. +For instance, it may be the case that a sensor external to CPU IP may be placed +close to CPU hotspot and together with internal CPU sensor, it is used +to determine the hotspot. Assuming this is the case for the above example, +the hypothetical extrapolation rule would be: + hotspot = 100 * bandgap - 120 * adc + 484 + +In other context, the same idea can be used to add fixed offset. For instance, +consider the hotspot extrapolation rule below: + hotspot = 1 * adc + 6000 + +In the above equation, the hotspot is always 6C higher than what is read +from the ADC sensor. The binding would be then: + thermal-sensors = <&adc>; + + /* hotspot = 1 * adc + 6000 */ + coefficients = <1 6000>; + +(d) - Board thermal + +The board thermal example below illustrates how to setup one thermal zone +with many sensors and many cooling devices. + +#include + +&i2c1 { + ... + /* + * An IC with several temperature sensor. + */ + adc-dummy: sensor@0x50 { + ... + #thermal-sensor-cells = <1>; /* sensor internal ID */ + }; +}; + +thermal-zones { + batt-thermal { + polling-delay-passive = <500>; /* milliseconds */ + polling-delay = <2500>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&adc-dummy 4>; + + trips { + ... + }; + + cooling-maps { + ... + }; + }; + + board-thermal: board-thermal { + polling-delay-passive = <1000>; /* milliseconds */ + polling-delay = <2500>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&adc-dummy 0>, /* pcb top edge */ + <&adc-dummy 1>, /* lcd */ + <&adc-dymmy 2>; /* back cover */ + /* + * An array of coefficients describing the sensor + * linear relation. E.g.: + * z = c1*x1 + c2*x2 + c3*x3 + */ + coefficients = <1200 -345 890>; + + trips { + /* Trips are based on resulting linear equation */ + cpu-trip: cpu-trip { + temperature = <60000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + gpu-trip: gpu-trip { + temperature = <55000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + } + lcd-trip: lcp-trip { + temperature = <53000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + crit-trip: crit-trip { + temperature = <68000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu-trip>; + cooling-device = <&cpu0 0 2>; + contribution = <55>; + }; + map1 { + trip = <&gpu-trip>; + cooling-device = <&gpu0 0 2>; + contribution = <20>; + }; + map2 { + trip = <&lcd-trip>; + cooling-device = <&lcd0 5 10>; + contribution = <15>; + }; + }; + }; +}; + +The above example is a mix of previous examples, a sensor IP with several internal +sensors used to monitor different zones, one of them is composed by several sensors and +with different cooling devices. diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index f35a1f75b15b..a150f8d53322 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -29,6 +29,19 @@ config THERMAL_HWMON Say 'Y' here if you want all thermal sensors to have hwmon sysfs interface too. +config THERMAL_OF + bool + prompt "APIs to parse thermal data out of device tree" + depends on OF + default y + help + This options provides helpers to add the support to + read and parse thermal data definitions out of the + device tree blob. + + Say 'Y' here if you need to build thermal infrastructure + based on device tree. + choice prompt "Default Thermal governor" default THERMAL_DEFAULT_GOV_STEP_WISE diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 584b36319d51..4b03956b929c 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -7,6 +7,7 @@ thermal_sys-y += thermal_core.o # interface to/from other layers providing sensors thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o +thermal_sys-$(CONFIG_THERMAL_OF) += of-thermal.o # governors thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c new file mode 100644 index 000000000000..04b1be7fa018 --- /dev/null +++ b/drivers/thermal/of-thermal.c @@ -0,0 +1,849 @@ +/* + * of-thermal.c - Generic Thermal Management device tree support. + * + * Copyright (C) 2013 Texas Instruments + * Copyright (C) 2013 Eduardo Valentin + * + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "thermal_core.h" + +/*** Private data structures to represent thermal device tree data ***/ + +/** + * struct __thermal_trip - representation of a point in temperature domain + * @np: pointer to struct device_node that this trip point was created from + * @temperature: temperature value in miliCelsius + * @hysteresis: relative hysteresis in miliCelsius + * @type: trip point type + */ + +struct __thermal_trip { + struct device_node *np; + unsigned long int temperature; + unsigned long int hysteresis; + enum thermal_trip_type type; +}; + +/** + * struct __thermal_bind_param - a match between trip and cooling device + * @cooling_device: a pointer to identify the referred cooling device + * @trip_id: the trip point index + * @usage: the percentage (from 0 to 100) of cooling contribution + * @min: minimum cooling state used at this trip point + * @max: maximum cooling state used at this trip point + */ + +struct __thermal_bind_params { + struct device_node *cooling_device; + unsigned int trip_id; + unsigned int usage; + unsigned long min; + unsigned long max; +}; + +/** + * struct __thermal_zone - internal representation of a thermal zone + * @mode: current thermal zone device mode (enabled/disabled) + * @passive_delay: polling interval while passive cooling is activated + * @polling_delay: zone polling interval + * @ntrips: number of trip points + * @trips: an array of trip points (0..ntrips - 1) + * @num_tbps: number of thermal bind params + * @tbps: an array of thermal bind params (0..num_tbps - 1) + * @sensor_data: sensor private data used while reading temperature and trend + * @get_temp: sensor callback to read temperature + * @get_trend: sensor callback to read temperature trend + */ + +struct __thermal_zone { + enum thermal_device_mode mode; + int passive_delay; + int polling_delay; + + /* trip data */ + int ntrips; + struct __thermal_trip *trips; + + /* cooling binding data */ + int num_tbps; + struct __thermal_bind_params *tbps; + + /* sensor interface */ + void *sensor_data; + int (*get_temp)(void *, long *); + int (*get_trend)(void *, long *); +}; + +/*** DT thermal zone device callbacks ***/ + +static int of_thermal_get_temp(struct thermal_zone_device *tz, + unsigned long *temp) +{ + struct __thermal_zone *data = tz->devdata; + + if (!data->get_temp) + return -EINVAL; + + return data->get_temp(data->sensor_data, temp); +} + +static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip, + enum thermal_trend *trend) +{ + struct __thermal_zone *data = tz->devdata; + long dev_trend; + int r; + + if (!data->get_trend) + return -EINVAL; + + r = data->get_trend(data->sensor_data, &dev_trend); + if (r) + return r; + + /* TODO: These intervals might have some thresholds, but in core code */ + if (dev_trend > 0) + *trend = THERMAL_TREND_RAISING; + else if (dev_trend < 0) + *trend = THERMAL_TREND_DROPPING; + else + *trend = THERMAL_TREND_STABLE; + + return 0; +} + +static int of_thermal_bind(struct thermal_zone_device *thermal, + struct thermal_cooling_device *cdev) +{ + struct __thermal_zone *data = thermal->devdata; + int i; + + if (!data || IS_ERR(data)) + return -ENODEV; + + /* find where to bind */ + for (i = 0; i < data->num_tbps; i++) { + struct __thermal_bind_params *tbp = data->tbps + i; + + if (tbp->cooling_device == cdev->np) { + int ret; + + ret = thermal_zone_bind_cooling_device(thermal, + tbp->trip_id, cdev, + tbp->min, + tbp->max); + if (ret) + return ret; + } + } + + return 0; +} + +static int of_thermal_unbind(struct thermal_zone_device *thermal, + struct thermal_cooling_device *cdev) +{ + struct __thermal_zone *data = thermal->devdata; + int i; + + if (!data || IS_ERR(data)) + return -ENODEV; + + /* find where to unbind */ + for (i = 0; i < data->num_tbps; i++) { + struct __thermal_bind_params *tbp = data->tbps + i; + + if (tbp->cooling_device == cdev->np) { + int ret; + + ret = thermal_zone_unbind_cooling_device(thermal, + tbp->trip_id, cdev); + if (ret) + return ret; + } + } + + return 0; +} + +static int of_thermal_get_mode(struct thermal_zone_device *tz, + enum thermal_device_mode *mode) +{ + struct __thermal_zone *data = tz->devdata; + + *mode = data->mode; + + return 0; +} + +static int of_thermal_set_mode(struct thermal_zone_device *tz, + enum thermal_device_mode mode) +{ + struct __thermal_zone *data = tz->devdata; + + mutex_lock(&tz->lock); + + if (mode == THERMAL_DEVICE_ENABLED) + tz->polling_delay = data->polling_delay; + else + tz->polling_delay = 0; + + mutex_unlock(&tz->lock); + + data->mode = mode; + thermal_zone_device_update(tz); + + return 0; +} + +static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip, + enum thermal_trip_type *type) +{ + struct __thermal_zone *data = tz->devdata; + + if (trip >= data->ntrips || trip < 0) + return -EDOM; + + *type = data->trips[trip].type; + + return 0; +} + +static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip, + unsigned long *temp) +{ + struct __thermal_zone *data = tz->devdata; + + if (trip >= data->ntrips || trip < 0) + return -EDOM; + + *temp = data->trips[trip].temperature; + + return 0; +} + +static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip, + unsigned long temp) +{ + struct __thermal_zone *data = tz->devdata; + + if (trip >= data->ntrips || trip < 0) + return -EDOM; + + /* thermal framework should take care of data->mask & (1 << trip) */ + data->trips[trip].temperature = temp; + + return 0; +} + +static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip, + unsigned long *hyst) +{ + struct __thermal_zone *data = tz->devdata; + + if (trip >= data->ntrips || trip < 0) + return -EDOM; + + *hyst = data->trips[trip].hysteresis; + + return 0; +} + +static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip, + unsigned long hyst) +{ + struct __thermal_zone *data = tz->devdata; + + if (trip >= data->ntrips || trip < 0) + return -EDOM; + + /* thermal framework should take care of data->mask & (1 << trip) */ + data->trips[trip].hysteresis = hyst; + + return 0; +} + +static int of_thermal_get_crit_temp(struct thermal_zone_device *tz, + unsigned long *temp) +{ + struct __thermal_zone *data = tz->devdata; + int i; + + for (i = 0; i < data->ntrips; i++) + if (data->trips[i].type == THERMAL_TRIP_CRITICAL) { + *temp = data->trips[i].temperature; + return 0; + } + + return -EINVAL; +} + +static struct thermal_zone_device_ops of_thermal_ops = { + .get_mode = of_thermal_get_mode, + .set_mode = of_thermal_set_mode, + + .get_trip_type = of_thermal_get_trip_type, + .get_trip_temp = of_thermal_get_trip_temp, + .set_trip_temp = of_thermal_set_trip_temp, + .get_trip_hyst = of_thermal_get_trip_hyst, + .set_trip_hyst = of_thermal_set_trip_hyst, + .get_crit_temp = of_thermal_get_crit_temp, + + .bind = of_thermal_bind, + .unbind = of_thermal_unbind, +}; + +/*** sensor API ***/ + +static struct thermal_zone_device * +thermal_zone_of_add_sensor(struct device_node *zone, + struct device_node *sensor, void *data, + int (*get_temp)(void *, long *), + int (*get_trend)(void *, long *)) +{ + struct thermal_zone_device *tzd; + struct __thermal_zone *tz; + + tzd = thermal_zone_get_zone_by_name(zone->name); + if (IS_ERR(tzd)) + return ERR_PTR(-EPROBE_DEFER); + + tz = tzd->devdata; + + mutex_lock(&tzd->lock); + tz->get_temp = get_temp; + tz->get_trend = get_trend; + tz->sensor_data = data; + + tzd->ops->get_temp = of_thermal_get_temp; + tzd->ops->get_trend = of_thermal_get_trend; + mutex_unlock(&tzd->lock); + + return tzd; +} + +/** + * thermal_zone_of_sensor_register - registers a sensor to a DT thermal zone + * @dev: a valid struct device pointer of a sensor device. Must contain + * a valid .of_node, for the sensor node. + * @sensor_id: a sensor identifier, in case the sensor IP has more + * than one sensors + * @data: a private pointer (owned by the caller) that will be passed + * back, when a temperature reading is needed. + * @get_temp: a pointer to a function that reads the sensor temperature. + * @get_trend: a pointer to a function that reads the sensor temperature trend. + * + * This function will search the list of thermal zones described in device + * tree and look for the zone that refer to the sensor device pointed by + * @dev->of_node as temperature providers. For the zone pointing to the + * sensor node, the sensor will be added to the DT thermal zone device. + * + * The thermal zone temperature is provided by the @get_temp function + * pointer. When called, it will have the private pointer @data back. + * + * The thermal zone temperature trend is provided by the @get_trend function + * pointer. When called, it will have the private pointer @data back. + * + * TODO: + * 01 - This function must enqueue the new sensor instead of using + * it as the only source of temperature values. + * + * 02 - There must be a way to match the sensor with all thermal zones + * that refer to it. + * + * Return: On success returns a valid struct thermal_zone_device, + * otherwise, it returns a corresponding ERR_PTR(). Caller must + * check the return value with help of IS_ERR() helper. + */ +struct thermal_zone_device * +thermal_zone_of_sensor_register(struct device *dev, int sensor_id, + void *data, int (*get_temp)(void *, long *), + int (*get_trend)(void *, long *)) +{ + struct device_node *np, *child, *sensor_np; + + np = of_find_node_by_name(NULL, "thermal-zones"); + if (!np) + return ERR_PTR(-ENODEV); + + if (!dev || !dev->of_node) + return ERR_PTR(-EINVAL); + + sensor_np = dev->of_node; + + for_each_child_of_node(np, child) { + struct of_phandle_args sensor_specs; + int ret, id; + + /* For now, thermal framework supports only 1 sensor per zone */ + ret = of_parse_phandle_with_args(child, "thermal-sensors", + "#thermal-sensor-cells", + 0, &sensor_specs); + if (ret) + continue; + + if (sensor_specs.args_count >= 1) { + id = sensor_specs.args[0]; + WARN(sensor_specs.args_count > 1, + "%s: too many cells in sensor specifier %d\n", + sensor_specs.np->name, sensor_specs.args_count); + } else { + id = 0; + } + + if (sensor_specs.np == sensor_np && id == sensor_id) { + of_node_put(np); + return thermal_zone_of_add_sensor(child, sensor_np, + data, + get_temp, + get_trend); + } + } + of_node_put(np); + + return ERR_PTR(-ENODEV); +} +EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_register); + +/** + * thermal_zone_of_sensor_unregister - unregisters a sensor from a DT thermal zone + * @dev: a valid struct device pointer of a sensor device. Must contain + * a valid .of_node, for the sensor node. + * @tzd: a pointer to struct thermal_zone_device where the sensor is registered. + * + * This function removes the sensor callbacks and private data from the + * thermal zone device registered with thermal_zone_of_sensor_register() + * API. It will also silent the zone by remove the .get_temp() and .get_trend() + * thermal zone device callbacks. + * + * TODO: When the support to several sensors per zone is added, this + * function must search the sensor list based on @dev parameter. + * + */ +void thermal_zone_of_sensor_unregister(struct device *dev, + struct thermal_zone_device *tzd) +{ + struct __thermal_zone *tz; + + if (!dev || !tzd || !tzd->devdata) + return; + + tz = tzd->devdata; + + /* no __thermal_zone, nothing to be done */ + if (!tz) + return; + + mutex_lock(&tzd->lock); + tzd->ops->get_temp = NULL; + tzd->ops->get_trend = NULL; + + tz->get_temp = NULL; + tz->get_trend = NULL; + tz->sensor_data = NULL; + mutex_unlock(&tzd->lock); +} +EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister); + +/*** functions parsing device tree nodes ***/ + +/** + * thermal_of_populate_bind_params - parse and fill cooling map data + * @np: DT node containing a cooling-map node + * @__tbp: data structure to be filled with cooling map info + * @trips: array of thermal zone trip points + * @ntrips: number of trip points inside trips. + * + * This function parses a cooling-map type of node represented by + * @np parameter and fills the read data into @__tbp data structure. + * It needs the already parsed array of trip points of the thermal zone + * in consideration. + * + * Return: 0 on success, proper error code otherwise + */ +static int thermal_of_populate_bind_params(struct device_node *np, + struct __thermal_bind_params *__tbp, + struct __thermal_trip *trips, + int ntrips) +{ + struct of_phandle_args cooling_spec; + struct device_node *trip; + int ret, i; + u32 prop; + + /* Default weight. Usage is optional */ + __tbp->usage = 0; + ret = of_property_read_u32(np, "contribution", &prop); + if (ret == 0) + __tbp->usage = prop; + + trip = of_parse_phandle(np, "trip", 0); + if (!trip) { + pr_err("missing trip property\n"); + return -ENODEV; + } + + /* match using device_node */ + for (i = 0; i < ntrips; i++) + if (trip == trips[i].np) { + __tbp->trip_id = i; + break; + } + + if (i == ntrips) { + ret = -ENODEV; + goto end; + } + + ret = of_parse_phandle_with_args(np, "cooling-device", "#cooling-cells", + 0, &cooling_spec); + if (ret < 0) { + pr_err("missing cooling_device property\n"); + goto end; + } + __tbp->cooling_device = cooling_spec.np; + if (cooling_spec.args_count >= 2) { /* at least min and max */ + __tbp->min = cooling_spec.args[0]; + __tbp->max = cooling_spec.args[1]; + } else { + pr_err("wrong reference to cooling device, missing limits\n"); + } + +end: + of_node_put(trip); + + return ret; +} + +/** + * It maps 'enum thermal_trip_type' found in include/linux/thermal.h + * into the device tree binding of 'trip', property type. + */ +static const char * const trip_types[] = { + [THERMAL_TRIP_ACTIVE] = "active", + [THERMAL_TRIP_PASSIVE] = "passive", + [THERMAL_TRIP_HOT] = "hot", + [THERMAL_TRIP_CRITICAL] = "critical", +}; + +/** + * thermal_of_get_trip_type - Get phy mode for given device_node + * @np: Pointer to the given device_node + * @type: Pointer to resulting trip type + * + * The function gets trip type string from property 'type', + * and store its index in trip_types table in @type, + * + * Return: 0 on success, or errno in error case. + */ +static int thermal_of_get_trip_type(struct device_node *np, + enum thermal_trip_type *type) +{ + const char *t; + int err, i; + + err = of_property_read_string(np, "type", &t); + if (err < 0) + return err; + + for (i = 0; i < ARRAY_SIZE(trip_types); i++) + if (!strcasecmp(t, trip_types[i])) { + *type = i; + return 0; + } + + return -ENODEV; +} + +/** + * thermal_of_populate_trip - parse and fill one trip point data + * @np: DT node containing a trip point node + * @trip: trip point data structure to be filled up + * + * This function parses a trip point type of node represented by + * @np parameter and fills the read data into @trip data structure. + * + * Return: 0 on success, proper error code otherwise + */ +static int thermal_of_populate_trip(struct device_node *np, + struct __thermal_trip *trip) +{ + int prop; + int ret; + + ret = of_property_read_u32(np, "temperature", &prop); + if (ret < 0) { + pr_err("missing temperature property\n"); + return ret; + } + trip->temperature = prop; + + ret = of_property_read_u32(np, "hysteresis", &prop); + if (ret < 0) { + pr_err("missing hysteresis property\n"); + return ret; + } + trip->hysteresis = prop; + + ret = thermal_of_get_trip_type(np, &trip->type); + if (ret < 0) { + pr_err("wrong trip type property\n"); + return ret; + } + + /* Required for cooling map matching */ + trip->np = np; + + return 0; +} + +/** + * thermal_of_build_thermal_zone - parse and fill one thermal zone data + * @np: DT node containing a thermal zone node + * + * This function parses a thermal zone type of node represented by + * @np parameter and fills the read data into a __thermal_zone data structure + * and return this pointer. + * + * TODO: Missing properties to parse: thermal-sensor-names and coefficients + * + * Return: On success returns a valid struct __thermal_zone, + * otherwise, it returns a corresponding ERR_PTR(). Caller must + * check the return value with help of IS_ERR() helper. + */ +static struct __thermal_zone * +thermal_of_build_thermal_zone(struct device_node *np) +{ + struct device_node *child = NULL, *gchild; + struct __thermal_zone *tz; + int ret, i; + u32 prop; + + if (!np) { + pr_err("no thermal zone np\n"); + return ERR_PTR(-EINVAL); + } + + tz = kzalloc(sizeof(*tz), GFP_KERNEL); + if (!tz) + return ERR_PTR(-ENOMEM); + + ret = of_property_read_u32(np, "polling-delay-passive", &prop); + if (ret < 0) { + pr_err("missing polling-delay-passive property\n"); + goto free_tz; + } + tz->passive_delay = prop; + + ret = of_property_read_u32(np, "polling-delay", &prop); + if (ret < 0) { + pr_err("missing polling-delay property\n"); + goto free_tz; + } + tz->polling_delay = prop; + + /* trips */ + child = of_get_child_by_name(np, "trips"); + + /* No trips provided */ + if (!child) + goto finish; + + tz->ntrips = of_get_child_count(child); + if (tz->ntrips == 0) /* must have at least one child */ + goto finish; + + tz->trips = kzalloc(tz->ntrips * sizeof(*tz->trips), GFP_KERNEL); + if (!tz->trips) { + ret = -ENOMEM; + goto free_tz; + } + + i = 0; + for_each_child_of_node(child, gchild) { + ret = thermal_of_populate_trip(gchild, &tz->trips[i++]); + if (ret) + goto free_trips; + } + + of_node_put(child); + + /* cooling-maps */ + child = of_get_child_by_name(np, "cooling-maps"); + + /* cooling-maps not provided */ + if (!child) + goto finish; + + tz->num_tbps = of_get_child_count(child); + if (tz->num_tbps == 0) + goto finish; + + tz->tbps = kzalloc(tz->num_tbps * sizeof(*tz->tbps), GFP_KERNEL); + if (!tz->tbps) { + ret = -ENOMEM; + goto free_trips; + } + + i = 0; + for_each_child_of_node(child, gchild) + ret = thermal_of_populate_bind_params(gchild, &tz->tbps[i++], + tz->trips, tz->ntrips); + if (ret) + goto free_tbps; + +finish: + of_node_put(child); + tz->mode = THERMAL_DEVICE_DISABLED; + + return tz; + +free_tbps: + kfree(tz->tbps); +free_trips: + kfree(tz->trips); +free_tz: + kfree(tz); + of_node_put(child); + + return ERR_PTR(ret); +} + +static inline void of_thermal_free_zone(struct __thermal_zone *tz) +{ + kfree(tz->tbps); + kfree(tz->trips); + kfree(tz); +} + +/** + * of_parse_thermal_zones - parse device tree thermal data + * + * Initialization function that can be called by machine initialization + * code to parse thermal data and populate the thermal framework + * with hardware thermal zones info. This function only parses thermal zones. + * Cooling devices and sensor devices nodes are supposed to be parsed + * by their respective drivers. + * + * Return: 0 on success, proper error code otherwise + * + */ +int __init of_parse_thermal_zones(void) +{ + struct device_node *np, *child; + struct __thermal_zone *tz; + struct thermal_zone_device_ops *ops; + + np = of_find_node_by_name(NULL, "thermal-zones"); + if (!np) { + pr_debug("unable to find thermal zones\n"); + return 0; /* Run successfully on systems without thermal DT */ + } + + for_each_child_of_node(np, child) { + struct thermal_zone_device *zone; + struct thermal_zone_params *tzp; + + tz = thermal_of_build_thermal_zone(child); + if (IS_ERR(tz)) { + pr_err("failed to build thermal zone %s: %ld\n", + child->name, + PTR_ERR(tz)); + continue; + } + + ops = kmemdup(&of_thermal_ops, sizeof(*ops), GFP_KERNEL); + if (!ops) + goto exit_free; + + tzp = kzalloc(sizeof(*tzp), GFP_KERNEL); + if (!tzp) { + kfree(ops); + goto exit_free; + } + + /* No hwmon because there might be hwmon drivers registering */ + tzp->no_hwmon = true; + + zone = thermal_zone_device_register(child->name, tz->ntrips, + 0, tz, + ops, tzp, + tz->passive_delay, + tz->polling_delay); + if (IS_ERR(zone)) { + pr_err("Failed to build %s zone %ld\n", child->name, + PTR_ERR(zone)); + kfree(tzp); + kfree(ops); + of_thermal_free_zone(tz); + /* attempting to build remaining zones still */ + } + } + + return 0; + +exit_free: + of_thermal_free_zone(tz); + + /* no memory available, so free what we have built */ + of_thermal_destroy_zones(); + + return -ENOMEM; +} + +/** + * of_thermal_destroy_zones - remove all zones parsed and allocated resources + * + * Finds all zones parsed and added to the thermal framework and remove them + * from the system, together with their resources. + * + */ +void of_thermal_destroy_zones(void) +{ + struct device_node *np, *child; + + np = of_find_node_by_name(NULL, "thermal-zones"); + if (!np) { + pr_err("unable to find thermal zones\n"); + return; + } + + for_each_child_of_node(np, child) { + struct thermal_zone_device *zone; + + zone = thermal_zone_get_zone_by_name(child->name); + if (IS_ERR(zone)) + continue; + + thermal_zone_device_unregister(zone); + kfree(zone->tzp); + kfree(zone->ops); + of_thermal_free_zone(zone->devdata); + } +} diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 0e43dc208fc6..3392fcb92796 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1373,7 +1373,7 @@ static void remove_trip_attrs(struct thermal_zone_device *tz) */ struct thermal_zone_device *thermal_zone_device_register(const char *type, int trips, int mask, void *devdata, - const struct thermal_zone_device_ops *ops, + struct thermal_zone_device_ops *ops, const struct thermal_zone_params *tzp, int passive_delay, int polling_delay) { @@ -1746,8 +1746,14 @@ static int __init thermal_init(void) if (result) goto unregister_class; + result = of_parse_thermal_zones(); + if (result) + goto exit_netlink; + return 0; +exit_netlink: + genetlink_exit(); unregister_governors: thermal_unregister_governors(); unregister_class: @@ -1763,6 +1769,7 @@ error: static void __exit thermal_exit(void) { + of_thermal_destroy_zones(); genetlink_exit(); class_unregister(&thermal_class); thermal_unregister_governors(); diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index 7cf2f6626251..3db339fb636f 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -77,4 +77,13 @@ static inline int thermal_gov_user_space_register(void) { return 0; } static inline void thermal_gov_user_space_unregister(void) {} #endif /* CONFIG_THERMAL_GOV_USER_SPACE */ +/* device tree support */ +#ifdef CONFIG_THERMAL_OF +int of_parse_thermal_zones(void); +void of_thermal_destroy_zones(void); +#else +static inline int of_parse_thermal_zones(void) { return 0; } +static inline void of_thermal_destroy_zones(void) { } +#endif + #endif /* __THERMAL_CORE_H__ */ diff --git a/include/dt-bindings/thermal/thermal.h b/include/dt-bindings/thermal/thermal.h new file mode 100644 index 000000000000..59822a995858 --- /dev/null +++ b/include/dt-bindings/thermal/thermal.h @@ -0,0 +1,17 @@ +/* + * This header provides constants for most thermal bindings. + * + * Copyright (C) 2013 Texas Instruments + * Eduardo Valentin + * + * GPLv2 only + */ + +#ifndef _DT_BINDINGS_THERMAL_THERMAL_H +#define _DT_BINDINGS_THERMAL_THERMAL_H + +/* On cooling devices upper and lower limits */ +#define THERMAL_NO_LIMIT (-1UL) + +#endif + diff --git a/include/linux/thermal.h b/include/linux/thermal.h index b268d3cf7ae3..b780c5b27122 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -143,6 +143,7 @@ struct thermal_cooling_device { int id; char type[THERMAL_NAME_LENGTH]; struct device device; + struct device_node *np; void *devdata; const struct thermal_cooling_device_ops *ops; bool updated; /* true if the cooling device does not need update */ @@ -172,7 +173,7 @@ struct thermal_zone_device { int emul_temperature; int passive; unsigned int forced_passive; - const struct thermal_zone_device_ops *ops; + struct thermal_zone_device_ops *ops; const struct thermal_zone_params *tzp; struct thermal_governor *governor; struct list_head thermal_instances; @@ -242,8 +243,31 @@ struct thermal_genl_event { }; /* Function declarations */ +#ifdef CONFIG_THERMAL_OF +struct thermal_zone_device * +thermal_zone_of_sensor_register(struct device *dev, int id, + void *data, int (*get_temp)(void *, long *), + int (*get_trend)(void *, long *)); +void thermal_zone_of_sensor_unregister(struct device *dev, + struct thermal_zone_device *tz); +#else +static inline struct thermal_zone_device * +thermal_zone_of_sensor_register(struct device *dev, int id, + void *data, int (*get_temp)(void *, long *), + int (*get_trend)(void *, long *)) +{ + return NULL; +} + +static inline +void thermal_zone_of_sensor_unregister(struct device *dev, + struct thermal_zone_device *tz) +{ +} + +#endif struct thermal_zone_device *thermal_zone_device_register(const char *, int, int, - void *, const struct thermal_zone_device_ops *, + void *, struct thermal_zone_device_ops *, const struct thermal_zone_params *, int, int); void thermal_zone_device_unregister(struct thermal_zone_device *); -- cgit v1.2.3 From 77cff5926a14e80d4545be5841d5938b87b654a4 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Mon, 15 Jul 2013 09:09:14 -0400 Subject: cpufreq: cpufreq-cpu0: add dt node parsing for cooling device properties This patch changes the cpufreq-cpu0 driver to consider if a cpu needs cooling (with cpufreq). In case the cooling is needed, the cpu0 device tree node needs to be properly configured with cooling device properties. In case these properties are present,, the driver will load a cpufreq cooling device in the system. The cpufreq-cpu0 driver is not interested in determining how the system should be using the cooling device. The driver is responsible only of loading the cooling device. Describing how the cooling device will be used can be accomplished by setting up a thermal zone that references and is composed by the cpufreq cooling device. Cc: "Rafael J. Wysocki" Cc: Grant Likely Cc: Rob Herring Cc: cpufreq@vger.kernel.org Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: devicetree-discuss@lists.ozlabs.org Acked-by: Viresh Kumar Signed-off-by: Eduardo Valentin --- .../devicetree/bindings/cpufreq/cpufreq-cpu0.txt | 7 +++++++ drivers/cpufreq/Kconfig | 2 +- drivers/cpufreq/cpufreq-cpu0.c | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt index 051f764bedb8..f055515d2b62 100644 --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt @@ -15,6 +15,10 @@ Optional properties: - clock-latency: Specify the possible maximum transition latency for clock, in unit of nanoseconds. - voltage-tolerance: Specify the CPU voltage tolerance in percentage. +- #cooling-cells: +- cooling-min-level: +- cooling-max-level: + Please refer to Documentation/devicetree/bindings/thermal/thermal.txt. Examples: @@ -33,6 +37,9 @@ cpus { 198000 850000 >; clock-latency = <61036>; /* two CLK32 periods */ + #cooling-cells = <2>; + cooling-min-level = <0>; + cooling-max-level = <2>; }; cpu@1 { diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 38093e272377..6b8cde5f98af 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -181,7 +181,7 @@ config CPU_FREQ_GOV_CONSERVATIVE config GENERIC_CPUFREQ_CPU0 tristate "Generic CPU0 cpufreq driver" - depends on HAVE_CLK && REGULATOR && PM_OPP && OF + depends on HAVE_CLK && REGULATOR && PM_OPP && OF && THERMAL && CPU_THERMAL help This adds a generic cpufreq driver for CPU0 frequency management. It supports both uniprocessor (UP) and symmetric multiprocessor (SMP) diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index d4585ce2346c..91c7bb67bc74 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c @@ -13,7 +13,9 @@ #include #include +#include #include +#include #include #include #include @@ -21,6 +23,7 @@ #include #include #include +#include static unsigned int transition_latency; static unsigned int voltage_tolerance; /* in percentage */ @@ -29,6 +32,7 @@ static struct device *cpu_dev; static struct clk *cpu_clk; static struct regulator *cpu_reg; static struct cpufreq_frequency_table *freq_table; +static struct thermal_cooling_device *cdev; static unsigned int cpu0_get_speed(unsigned int cpu) { @@ -201,6 +205,17 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev) goto out_free_table; } + /* + * For now, just loading the cooling device; + * thermal DT code takes care of matching them. + */ + if (of_find_property(np, "#cooling-cells", NULL)) { + cdev = of_cpufreq_cooling_register(np, cpu_present_mask); + if (IS_ERR(cdev)) + pr_err("running cpufreq without cooling device: %ld\n", + PTR_ERR(cdev)); + } + of_node_put(np); return 0; @@ -213,6 +228,7 @@ out_put_node: static int cpu0_cpufreq_remove(struct platform_device *pdev) { + cpufreq_cooling_unregister(cdev); cpufreq_unregister_driver(&cpu0_cpufreq_driver); dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); -- cgit v1.2.3 From 307b96677c98bc444262e3d1a7d26c0ca8a1c6e0 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 17 Jun 2013 23:58:25 +0200 Subject: ARM: integrator: move EBI to the device tree This moves the External Bus Interface (EBI) over to a device tree node and deletes the static mappings from the platform. Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/arm/arm-boards | 8 ++++ arch/arm/boot/dts/integrator.dtsi | 5 +++ arch/arm/mach-integrator/integrator_ap.c | 52 ++++++++++++++---------- arch/arm/mach-integrator/integrator_cp.c | 6 --- 4 files changed, 43 insertions(+), 28 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/arm-boards b/Documentation/devicetree/bindings/arm/arm-boards index 5fac246a9530..3509707f9320 100644 --- a/Documentation/devicetree/bindings/arm/arm-boards +++ b/Documentation/devicetree/bindings/arm/arm-boards @@ -14,6 +14,9 @@ Required nodes: - core-module: the root node to the Integrator platforms must have a core-module with regs and the compatible string "arm,core-module-integrator" +- external-bus-interface: the root node to the Integrator platforms + must have an external bus interface with regs and the + compatible-string "arm,external-bus-interface" Required properties for the core module: - regs: the location and size of the core module registers, one @@ -48,6 +51,11 @@ Required nodes: reg = <0x10000000 0x200>; }; + ebi@12000000 { + compatible = "arm,external-bus-interface"; + reg = <0x12000000 0x100>; + }; + syscon { compatible = "arm,integrator-ap-syscon"; reg = <0x11000000 0x100>; diff --git a/arch/arm/boot/dts/integrator.dtsi b/arch/arm/boot/dts/integrator.dtsi index 0f06f8687b0b..88e3d477bf16 100644 --- a/arch/arm/boot/dts/integrator.dtsi +++ b/arch/arm/boot/dts/integrator.dtsi @@ -10,6 +10,11 @@ reg = <0x10000000 0x200>; }; + ebi@12000000 { + compatible = "arm,external-bus-interface"; + reg = <0x12000000 0x100>; + }; + timer@13000000 { reg = <0x13000000 0x100>; interrupt-parent = <&pic>; diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index a762712bc2f2..cc1d3fe21c4e 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -63,6 +63,8 @@ /* Base address to the AP system controller */ void __iomem *ap_syscon_base; +/* Base address to the external bus interface */ +static void __iomem *ebi_base; /* @@ -73,13 +75,11 @@ void __iomem *ap_syscon_base; * just for now). */ #define VA_IC_BASE __io_address(INTEGRATOR_IC_BASE) -#define VA_EBI_BASE __io_address(INTEGRATOR_EBI_BASE) /* * Logical Physical * ef000000 Cache flush * f1100000 11000000 System controller registers - * f1200000 12000000 EBI registers * f1300000 13000000 Counter/Timer * f1400000 14000000 Interrupt controller * f1600000 16000000 UART 0 @@ -90,11 +90,6 @@ void __iomem *ap_syscon_base; static struct map_desc ap_io_desc[] __initdata __maybe_unused = { { - .virtual = IO_ADDRESS(INTEGRATOR_EBI_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_EBI_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE), .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE), .length = SZ_4K, @@ -168,9 +163,6 @@ device_initcall(irq_syscore_init); /* * Flash handling. */ -#define EBI_CSR1 (VA_EBI_BASE + INTEGRATOR_EBI_CSR1_OFFSET) -#define EBI_LOCK (VA_EBI_BASE + INTEGRATOR_EBI_LOCK_OFFSET) - static int ap_flash_init(struct platform_device *dev) { u32 tmp; @@ -178,13 +170,15 @@ static int ap_flash_init(struct platform_device *dev) writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET); - tmp = readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE; - writel(tmp, EBI_CSR1); + tmp = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET) | + INTEGRATOR_EBI_WRITE_ENABLE; + writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); - if (!(readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) { - writel(0xa05f, EBI_LOCK); - writel(tmp, EBI_CSR1); - writel(0, EBI_LOCK); + if (!(readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET) + & INTEGRATOR_EBI_WRITE_ENABLE)) { + writel(0xa05f, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); + writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); + writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); } return 0; } @@ -196,13 +190,15 @@ static void ap_flash_exit(struct platform_device *dev) writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET); - tmp = readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE; - writel(tmp, EBI_CSR1); + tmp = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET) & + ~INTEGRATOR_EBI_WRITE_ENABLE; + writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); - if (readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) { - writel(0xa05f, EBI_LOCK); - writel(tmp, EBI_CSR1); - writel(0, EBI_LOCK); + if (readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET) & + INTEGRATOR_EBI_WRITE_ENABLE) { + writel(0xa05f, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); + writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET); + writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET); } } @@ -469,11 +465,17 @@ static const struct of_device_id ap_syscon_match[] = { { }, }; +static const struct of_device_id ebi_match[] = { + { .compatible = "arm,external-bus-interface"}, + { }, +}; + static void __init ap_init_of(void) { unsigned long sc_dec; struct device_node *root; struct device_node *syscon; + struct device_node *ebi; struct device *parent; struct soc_device *soc_dev; struct soc_device_attribute *soc_dev_attr; @@ -489,10 +491,16 @@ static void __init ap_init_of(void) syscon = of_find_matching_node(root, ap_syscon_match); if (!syscon) return; + ebi = of_find_matching_node(root, ebi_match); + if (!ebi) + return; ap_syscon_base = of_iomap(syscon, 0); if (!ap_syscon_base) return; + ebi_base = of_iomap(ebi, 0); + if (!ebi_base) + return; ap_sc_id = readl(ap_syscon_base); diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 916c0f345a3a..5e84149d1790 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -64,7 +64,6 @@ static void __iomem *intcp_con_base; /* * Logical Physical - * f1200000 12000000 EBI registers * f1300000 13000000 Counter/Timer * f1400000 14000000 Interrupt controller * f1600000 16000000 UART 0 @@ -76,11 +75,6 @@ static void __iomem *intcp_con_base; static struct map_desc intcp_io_desc[] __initdata __maybe_unused = { { - .virtual = IO_ADDRESS(INTEGRATOR_EBI_BASE), - .pfn = __phys_to_pfn(INTEGRATOR_EBI_BASE), - .length = SZ_4K, - .type = MT_DEVICE - }, { .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE), .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE), .length = SZ_4K, -- cgit v1.2.3 From d0700c5175b0684c9935ca57deae733c2758667c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sun, 13 Oct 2013 07:58:43 -0300 Subject: [media] media: Add pad flag MEDIA_PAD_FL_MUST_CONNECT Pads that set this flag must be connected by an active link for the entity to stream. Signed-off-by: Sakari Ailus Acked-by: Sylwester Nawrocki Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/media-ioc-enum-links.xml | 9 +++++++++ include/uapi/linux/media.h | 1 + 2 files changed, 10 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml index 355df43badc5..cf8548556c7d 100644 --- a/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml +++ b/Documentation/DocBook/media/v4l/media-ioc-enum-links.xml @@ -134,6 +134,15 @@ Output pad, relative to the entity. Output pads source data and are origins of links. + + MEDIA_PAD_FL_MUST_CONNECT + If this flag is set and the pad is linked to any other + pad, then at least one of those links must be enabled for the + entity to be able to stream. There could be temporary reasons + (e.g. device configuration dependent) for the pad to need + enabled links even when this flag isn't set; the absence of the + flag doesn't imply there is none. + diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index ed49574ad757..d847c760e8f0 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h @@ -98,6 +98,7 @@ struct media_entity_desc { #define MEDIA_PAD_FL_SINK (1 << 0) #define MEDIA_PAD_FL_SOURCE (1 << 1) +#define MEDIA_PAD_FL_MUST_CONNECT (1 << 2) struct media_pad_desc { __u32 entity; /* entity ID */ -- cgit v1.2.3 From 3ab72f9156bbcd0b7490e2475448693e90f10299 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 7 Nov 2013 20:56:50 -0600 Subject: dt-bindings: add GIC-400 binding Add "arm,gic-400" compatible property for ARM GIC-400 IP. Signed-off-by: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Acked-by: Kumar Gala --- Documentation/devicetree/bindings/arm/gic.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt index 3dfb0c0384f5..bae0d87a38b2 100644 --- a/Documentation/devicetree/bindings/arm/gic.txt +++ b/Documentation/devicetree/bindings/arm/gic.txt @@ -11,6 +11,7 @@ have PPIs or SGIs. Main node required properties: - compatible : should be one of: + "arm,gic-400" "arm,cortex-a15-gic" "arm,cortex-a9-gic" "arm,cortex-a7-gic" -- cgit v1.2.3 From b0abd6ee9e4f084833da2b50763322522f870f9e Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Sat, 30 Nov 2013 16:26:01 +0100 Subject: misc: bmp085: devicetree irq update. Document irq handling for bmp085. Signed-off-by: Marek Belisko Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/misc/bmp085.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/misc/bmp085.txt b/Documentation/devicetree/bindings/misc/bmp085.txt index 91dfda2e4e11..d7a6deb6b21e 100644 --- a/Documentation/devicetree/bindings/misc/bmp085.txt +++ b/Documentation/devicetree/bindings/misc/bmp085.txt @@ -8,6 +8,8 @@ Optional properties: - temp-measurement-period: temperature measurement period (milliseconds) - default-oversampling: default oversampling value to be used at startup, value range is 0-3 with rising sensitivity. +- interrupt-parent: should be the phandle for the interrupt controller +- interrupts: interrupt mapping for IRQ Example: @@ -17,4 +19,6 @@ pressure@77 { chip-id = <10>; temp-measurement-period = <100>; default-oversampling = <2>; + interrupt-parent = <&gpio0>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; }; -- cgit v1.2.3 From 7637af2e17f18bfe6264d834c6edee7706a0f15c Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 4 Dec 2013 15:19:27 -0700 Subject: ASoC: tegra: add tegra+MAX98090 machine driver Initially, this binding and driver only describe/support playback to headphones and speakers, and capture from the external microphone, with GPIO-based jack detection for the headphone jack only. This driver is useful for the Venice2 board. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- .../bindings/sound/nvidia,tegra-audio-max98090.txt | 51 ++++ sound/soc/tegra/Kconfig | 10 + sound/soc/tegra/Makefile | 2 + sound/soc/tegra/tegra_max98090.c | 275 +++++++++++++++++++++ 4 files changed, 338 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt create mode 100644 sound/soc/tegra/tegra_max98090.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt new file mode 100644 index 000000000000..9c7c55c71370 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt @@ -0,0 +1,51 @@ +NVIDIA Tegra audio complex, with MAX98090 CODEC + +Required properties: +- compatible : "nvidia,tegra-audio-max98090" +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) +- nvidia,model : The user-visible name of this sound complex. +- nvidia,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the MAX98090's pins (as documented in its binding), and the jacks + on the board: + + * Headphones + * Speakers + * Mic Jack + +- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's + connected to the CODEC. +- nvidia,audio-codec : The phandle of the MAX98090 audio codec. + +Optional properties: +- nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in + +Example: + +sound { + compatible = "nvidia,tegra-audio-max98090-venice2", + "nvidia,tegra-audio-max98090"; + nvidia,model = "NVIDIA Tegra Venice2"; + + nvidia,audio-routing = + "Headphones", "HPR", + "Headphones", "HPL", + "Speakers", "SPKR", + "Speakers", "SPKL", + "Mic Jack", "MICBIAS", + "IN34", "Mic Jack"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&acodec>; + + clocks = <&tegra_car TEGRA124_CLK_PLL_A>, + <&tegra_car TEGRA124_CLK_PLL_A_OUT0>, + <&tegra_car TEGRA124_CLK_EXTERN1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; +}; diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 8fc653ca3ab4..65a85f542521 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -116,3 +116,13 @@ config SND_SOC_TEGRA_ALC5632 help Say Y or M here if you want to add support for SoC audio on the Toshiba AC100 netbook. + +config SND_SOC_TEGRA_MAX98090 + tristate "SoC Audio support for Tegra boards using a MAX98090 codec" + depends on SND_SOC_TEGRA && I2C && GPIOLIB + select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC + select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC + select SND_SOC_MAX98090 + help + Say Y or M here if you want to add support for SoC audio on Tegra + boards using the MAX98090 codec, such as Venice2. diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index 21d2550a08a4..5ae588cd96c4 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -24,6 +24,7 @@ snd-soc-tegra-wm8903-objs := tegra_wm8903.o snd-soc-tegra-wm9712-objs := tegra_wm9712.o snd-soc-tegra-trimslice-objs := trimslice.o snd-soc-tegra-alc5632-objs := tegra_alc5632.o +snd-soc-tegra-max98090-objs := tegra_max98090.o obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o @@ -31,3 +32,4 @@ obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o +obj-$(CONFIG_SND_SOC_TEGRA_MAX98090) += snd-soc-tegra-max98090.o diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c new file mode 100644 index 000000000000..0283cfb7c031 --- /dev/null +++ b/sound/soc/tegra/tegra_max98090.c @@ -0,0 +1,275 @@ +/* + * Tegra machine ASoC driver for boards using a MAX90809 CODEC. + * + * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Based on code copyright/by: + * + * Copyright (C) 2010-2012 - NVIDIA, Inc. + * Copyright (C) 2011 The AC100 Kernel Team + * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. + * Copyright 2007 Wolfson Microelectronics PLC. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "tegra_asoc_utils.h" + +#define DRV_NAME "tegra-snd-max98090" + +struct tegra_max98090 { + struct tegra_asoc_utils_data util_data; + int gpio_hp_det; +}; + +static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_card *card = codec->card; + struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card); + int srate, mclk; + int err; + + srate = params_rate(params); + switch (srate) { + case 8000: + case 16000: + case 24000: + case 32000: + case 48000: + case 64000: + case 96000: + mclk = 12288000; + break; + case 11025: + case 22050: + case 44100: + case 88200: + mclk = 11289600; + break; + default: + mclk = 12000000; + break; + } + + err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); + if (err < 0) { + dev_err(card->dev, "Can't configure clocks\n"); + return err; + } + + err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, + SND_SOC_CLOCK_IN); + if (err < 0) { + dev_err(card->dev, "codec_dai clock not set\n"); + return err; + } + + return 0; +} + +static struct snd_soc_ops tegra_max98090_ops = { + .hw_params = tegra_max98090_asoc_hw_params, +}; + +static struct snd_soc_jack tegra_max98090_hp_jack; + +static struct snd_soc_jack_pin tegra_max98090_hp_jack_pins[] = { + { + .pin = "Headphones", + .mask = SND_JACK_HEADPHONE, + }, +}; + +static struct snd_soc_jack_gpio tegra_max98090_hp_jack_gpio = { + .name = "Headphone detection", + .report = SND_JACK_HEADPHONE, + .debounce_time = 150, + .invert = 1, +}; + +static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphones", NULL), + SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), +}; + +static const struct snd_kcontrol_new tegra_max98090_controls[] = { + SOC_DAPM_PIN_SWITCH("Speakers"), +}; + +static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_codec *codec = codec_dai->codec; + struct tegra_max98090 *machine = snd_soc_card_get_drvdata(codec->card); + + if (gpio_is_valid(machine->gpio_hp_det)) { + snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE, + &tegra_max98090_hp_jack); + snd_soc_jack_add_pins(&tegra_max98090_hp_jack, + ARRAY_SIZE(tegra_max98090_hp_jack_pins), + tegra_max98090_hp_jack_pins); + + tegra_max98090_hp_jack_gpio.gpio = machine->gpio_hp_det; + snd_soc_jack_add_gpios(&tegra_max98090_hp_jack, + 1, + &tegra_max98090_hp_jack_gpio); + } + + return 0; +} + +static struct snd_soc_dai_link tegra_max98090_dai = { + .name = "max98090", + .stream_name = "max98090 PCM", + .codec_dai_name = "HiFi", + .init = tegra_max98090_asoc_init, + .ops = &tegra_max98090_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, +}; + +static struct snd_soc_card snd_soc_tegra_max98090 = { + .name = "tegra-max98090", + .owner = THIS_MODULE, + .dai_link = &tegra_max98090_dai, + .num_links = 1, + .controls = tegra_max98090_controls, + .num_controls = ARRAY_SIZE(tegra_max98090_controls), + .dapm_widgets = tegra_max98090_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra_max98090_dapm_widgets), + .fully_routed = true, +}; + +static int tegra_max98090_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct snd_soc_card *card = &snd_soc_tegra_max98090; + struct tegra_max98090 *machine; + int ret; + + machine = devm_kzalloc(&pdev->dev, + sizeof(struct tegra_max98090), GFP_KERNEL); + if (!machine) { + dev_err(&pdev->dev, "Can't allocate tegra_max98090\n"); + return -ENOMEM; + } + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, machine); + + machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); + if (machine->gpio_hp_det == -EPROBE_DEFER) + return -EPROBE_DEFER; + + ret = snd_soc_of_parse_card_name(card, "nvidia,model"); + if (ret) + goto err; + + ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); + if (ret) + goto err; + + tegra_max98090_dai.codec_of_node = of_parse_phandle(np, + "nvidia,audio-codec", 0); + if (!tegra_max98090_dai.codec_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,audio-codec' missing or invalid\n"); + ret = -EINVAL; + goto err; + } + + tegra_max98090_dai.cpu_of_node = of_parse_phandle(np, + "nvidia,i2s-controller", 0); + if (!tegra_max98090_dai.cpu_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,i2s-controller' missing or invalid\n"); + ret = -EINVAL; + goto err; + } + + tegra_max98090_dai.platform_of_node = tegra_max98090_dai.cpu_of_node; + + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); + if (ret) + goto err; + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err_fini_utils; + } + + return 0; + +err_fini_utils: + tegra_asoc_utils_fini(&machine->util_data); +err: + return ret; +} + +static int tegra_max98090_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card); + + snd_soc_jack_free_gpios(&tegra_max98090_hp_jack, 1, + &tegra_max98090_hp_jack_gpio); + + snd_soc_unregister_card(card); + + tegra_asoc_utils_fini(&machine->util_data); + + return 0; +} + +static const struct of_device_id tegra_max98090_of_match[] = { + { .compatible = "nvidia,tegra-audio-max98090", }, + {}, +}; + +static struct platform_driver tegra_max98090_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = tegra_max98090_of_match, + }, + .probe = tegra_max98090_probe, + .remove = tegra_max98090_remove, +}; +module_platform_driver(tegra_max98090_driver); + +MODULE_AUTHOR("Stephen Warren "); +MODULE_DESCRIPTION("Tegra max98090 machine ASoC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, tegra_max98090_of_match); -- cgit v1.2.3 From 308a0f3f24db5e5943ef0aad722e8b3d125dbddb Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 4 Dec 2013 15:19:26 -0700 Subject: ASoC: max98090: add DT binding document for MAX98090 CODEC This binding mainly serves to document the list of input and output pins that may be used in a sound card's audio routing table. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/max98090.txt | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/max98090.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/max98090.txt b/Documentation/devicetree/bindings/sound/max98090.txt new file mode 100644 index 000000000000..e4c8b36dcf89 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/max98090.txt @@ -0,0 +1,43 @@ +MAX98090 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "maxim,max98090". + +- reg : The I2C address of the device. + +- interrupts : The CODEC's interrupt output. + +Pins on the device (for linking into audio routes): + + * MIC1 + * MIC2 + * DMICL + * DMICR + * IN1 + * IN2 + * IN3 + * IN4 + * IN5 + * IN6 + * IN12 + * IN34 + * IN56 + * HPL + * HPR + * SPKL + * SPKR + * RCVL + * RCVR + * MICBIAS + +Example: + +audio-codec@10 { + compatible = "maxim,max98090"; + reg = <0x10>; + interrupt-parent = <&gpio>; + interrupts = ; +}; -- cgit v1.2.3 From d46f421608575a76c1f8b605005b2f9ac9a35db5 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 5 Dec 2013 18:10:05 -0800 Subject: pinctrl: Add documentation for pinctrl-msm8x74 This adds initial documentation for the pinctrl-msm8x74 driver. Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- .../bindings/pinctrl/qcom,msm8x74-pinctrl.txt | 92 ++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/qcom,msm8x74-pinctrl.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8x74-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8x74-pinctrl.txt new file mode 100644 index 000000000000..70ab78fe93c8 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8x74-pinctrl.txt @@ -0,0 +1,92 @@ +Qualcomm MSM8x74 TLMM block + +Required properties: +- compatible: "qcom,msm8x74-pinctrl" +- reg: Should be the base address and length of the TLMM block. +- interrupts: Should be the parent IRQ of the TLMM block. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be two. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells : Should be two. + The first cell is the gpio pin number and the + second cell is used for optional parameters. + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Qualcomm's pin configuration nodes act as a container for an abitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + pins, function, bias-disable, bias-pull-down, bias-pull,up, drive-strength. + +Non-empty subnodes must specify the 'pins' property. +Note that not all properties are valid for all pins. + + +Valid values for qcom,pins are: + gpio0-gpio145 + Supports mux, bias and drive-strength + + sdc1_clk, sdc1_cmd, sdc1_data, sdc2_clk, sdc2_cmd, sdc2_data + Supports bias and drive-strength + +Valid values for qcom,function are: + blsp_i2c2, blsp_i2c6, blsp_i2c11, blsp_spi1, blsp_uart2, blsp_uart8, slimbus + + (Note that this is not yet the complete list of functions) + + + +Example: + + msmgpio: pinctrl@fd510000 { + compatible = "qcom,msm8x74-pinctrl"; + reg = <0xfd510000 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 208 0>; + + pinctrl-names = "default"; + pinctrl-0 = <&uart2_default>; + + uart2_default: uart2_default { + mux { + qcom,pins = "gpio4", "gpio5"; + qcom,function = "blsp_uart2"; + }; + + tx { + qcom,pins = "gpio4"; + drive-strength = <4>; + bias-disable; + }; + + rx { + qcom,pins = "gpio5"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; -- cgit v1.2.3 From f54b311142a92ea2e42598e347b84e1655caf8e3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Dec 2013 22:36:05 -0800 Subject: tcp: auto corking With the introduction of TCP Small Queues, TSO auto sizing, and TCP pacing, we can implement Automatic Corking in the kernel, to help applications doing small write()/sendmsg() to TCP sockets. Idea is to change tcp_push() to check if the current skb payload is under skb optimal size (a multiple of MSS bytes) If under 'size_goal', and at least one packet is still in Qdisc or NIC TX queues, set the TCP Small Queue Throttled bit, so that the push will be delayed up to TX completion time. This delay might allow the application to coalesce more bytes in the skb in following write()/sendmsg()/sendfile() system calls. The exact duration of the delay is depending on the dynamics of the system, and might be zero if no packet for this flow is actually held in Qdisc or NIC TX ring. Using FQ/pacing is a way to increase the probability of autocorking being triggered. Add a new sysctl (/proc/sys/net/ipv4/tcp_autocorking) to control this feature and default it to 1 (enabled) Add a new SNMP counter : nstat -a | grep TcpExtTCPAutoCorking This counter is incremented every time we detected skb was under used and its flush was deferred. Tested: Interesting effects when using line buffered commands under ssh. Excellent performance results in term of cpu usage and total throughput. lpq83:~# echo 1 >/proc/sys/net/ipv4/tcp_autocorking lpq83:~# perf stat ./super_netperf 4 -t TCP_STREAM -H lpq84 -- -m 128 9410.39 Performance counter stats for './super_netperf 4 -t TCP_STREAM -H lpq84 -- -m 128': 35209.439626 task-clock # 2.901 CPUs utilized 2,294 context-switches # 0.065 K/sec 101 CPU-migrations # 0.003 K/sec 4,079 page-faults # 0.116 K/sec 97,923,241,298 cycles # 2.781 GHz [83.31%] 51,832,908,236 stalled-cycles-frontend # 52.93% frontend cycles idle [83.30%] 25,697,986,603 stalled-cycles-backend # 26.24% backend cycles idle [66.70%] 102,225,978,536 instructions # 1.04 insns per cycle # 0.51 stalled cycles per insn [83.38%] 18,657,696,819 branches # 529.906 M/sec [83.29%] 91,679,646 branch-misses # 0.49% of all branches [83.40%] 12.136204899 seconds time elapsed lpq83:~# echo 0 >/proc/sys/net/ipv4/tcp_autocorking lpq83:~# perf stat ./super_netperf 4 -t TCP_STREAM -H lpq84 -- -m 128 6624.89 Performance counter stats for './super_netperf 4 -t TCP_STREAM -H lpq84 -- -m 128': 40045.864494 task-clock # 3.301 CPUs utilized 171 context-switches # 0.004 K/sec 53 CPU-migrations # 0.001 K/sec 4,080 page-faults # 0.102 K/sec 111,340,458,645 cycles # 2.780 GHz [83.34%] 61,778,039,277 stalled-cycles-frontend # 55.49% frontend cycles idle [83.31%] 29,295,522,759 stalled-cycles-backend # 26.31% backend cycles idle [66.67%] 108,654,349,355 instructions # 0.98 insns per cycle # 0.57 stalled cycles per insn [83.34%] 19,552,170,748 branches # 488.244 M/sec [83.34%] 157,875,417 branch-misses # 0.81% of all branches [83.34%] 12.130267788 seconds time elapsed Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 10 ++++++ include/net/tcp.h | 1 + include/uapi/linux/snmp.h | 1 + net/ipv4/proc.c | 1 + net/ipv4/sysctl_net_ipv4.c | 9 +++++ net/ipv4/tcp.c | 63 +++++++++++++++++++++++++++------- 6 files changed, 72 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 3c12d9a7ed00..12ba2cd9f03d 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -156,6 +156,16 @@ tcp_app_win - INTEGER buffer. Value 0 is special, it means that nothing is reserved. Default: 31 +tcp_autocorking - BOOLEAN + Enable TCP auto corking : + When applications do consecutive small write()/sendmsg() system calls, + we try to coalesce these small writes as much as possible, to lower + total amount of sent packets. This is done if at least one prior + packet for the flow is waiting in Qdisc queues or device transmit + queue. Applications can still use TCP_CORK for optimal behavior + when they know how/when to uncork their sockets. + Default : 1 + tcp_available_congestion_control - STRING Shows the available congestion control choices that are registered. More congestion control algorithms may be available as modules, diff --git a/include/net/tcp.h b/include/net/tcp.h index 70e55d200610..f7e1ab2139ef 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -282,6 +282,7 @@ extern int sysctl_tcp_limit_output_bytes; extern int sysctl_tcp_challenge_ack_limit; extern unsigned int sysctl_tcp_notsent_lowat; extern int sysctl_tcp_min_tso_segs; +extern int sysctl_tcp_autocorking; extern atomic_long_t tcp_memory_allocated; extern struct percpu_counter tcp_sockets_allocated; diff --git a/include/uapi/linux/snmp.h b/include/uapi/linux/snmp.h index 1bdb4a39d1e1..bbaba22f2d1b 100644 --- a/include/uapi/linux/snmp.h +++ b/include/uapi/linux/snmp.h @@ -258,6 +258,7 @@ enum LINUX_MIB_TCPFASTOPENCOOKIEREQD, /* TCPFastOpenCookieReqd */ LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES, /* TCPSpuriousRtxHostQueues */ LINUX_MIB_BUSYPOLLRXPACKETS, /* BusyPollRxPackets */ + LINUX_MIB_TCPAUTOCORKING, /* TCPAutoCorking */ __LINUX_MIB_MAX }; diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 4a0335854b89..8ecd7ad959b4 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -279,6 +279,7 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_ITEM("TCPFastOpenCookieReqd", LINUX_MIB_TCPFASTOPENCOOKIEREQD), SNMP_MIB_ITEM("TCPSpuriousRtxHostQueues", LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES), SNMP_MIB_ITEM("BusyPollRxPackets", LINUX_MIB_BUSYPOLLRXPACKETS), + SNMP_MIB_ITEM("TCPAutoCorking", LINUX_MIB_TCPAUTOCORKING), SNMP_MIB_SENTINEL }; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 3d69ec8dac57..38c8ec90ff68 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -732,6 +732,15 @@ static struct ctl_table ipv4_table[] = { .extra1 = &zero, .extra2 = &gso_max_segs, }, + { + .procname = "tcp_autocorking", + .data = &sysctl_tcp_autocorking, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, { .procname = "udp_mem", .data = &sysctl_udp_mem, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c4638e6f0238..0ca87547becb 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -285,6 +285,8 @@ int sysctl_tcp_fin_timeout __read_mostly = TCP_FIN_TIMEOUT; int sysctl_tcp_min_tso_segs __read_mostly = 2; +int sysctl_tcp_autocorking __read_mostly = 1; + struct percpu_counter tcp_orphan_count; EXPORT_SYMBOL_GPL(tcp_orphan_count); @@ -619,19 +621,52 @@ static inline void tcp_mark_urg(struct tcp_sock *tp, int flags) tp->snd_up = tp->write_seq; } -static inline void tcp_push(struct sock *sk, int flags, int mss_now, - int nonagle) +/* If a not yet filled skb is pushed, do not send it if + * we have packets in Qdisc or NIC queues : + * Because TX completion will happen shortly, it gives a chance + * to coalesce future sendmsg() payload into this skb, without + * need for a timer, and with no latency trade off. + * As packets containing data payload have a bigger truesize + * than pure acks (dataless) packets, the last check prevents + * autocorking if we only have an ACK in Qdisc/NIC queues. + */ +static bool tcp_should_autocork(struct sock *sk, struct sk_buff *skb, + int size_goal) { - if (tcp_send_head(sk)) { - struct tcp_sock *tp = tcp_sk(sk); + return skb->len < size_goal && + sysctl_tcp_autocorking && + atomic_read(&sk->sk_wmem_alloc) > skb->truesize; +} + +static void tcp_push(struct sock *sk, int flags, int mss_now, + int nonagle, int size_goal) +{ + struct tcp_sock *tp = tcp_sk(sk); + struct sk_buff *skb; - if (!(flags & MSG_MORE) || forced_push(tp)) - tcp_mark_push(tp, tcp_write_queue_tail(sk)); + if (!tcp_send_head(sk)) + return; + + skb = tcp_write_queue_tail(sk); + if (!(flags & MSG_MORE) || forced_push(tp)) + tcp_mark_push(tp, skb); + + tcp_mark_urg(tp, flags); + + if (tcp_should_autocork(sk, skb, size_goal)) { - tcp_mark_urg(tp, flags); - __tcp_push_pending_frames(sk, mss_now, - (flags & MSG_MORE) ? TCP_NAGLE_CORK : nonagle); + /* avoid atomic op if TSQ_THROTTLED bit is already set */ + if (!test_bit(TSQ_THROTTLED, &tp->tsq_flags)) { + NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAUTOCORKING); + set_bit(TSQ_THROTTLED, &tp->tsq_flags); + } + return; } + + if (flags & MSG_MORE) + nonagle = TCP_NAGLE_CORK; + + __tcp_push_pending_frames(sk, mss_now, nonagle); } static int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, @@ -934,7 +969,8 @@ new_segment: wait_for_sndbuf: set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); wait_for_memory: - tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH); + tcp_push(sk, flags & ~MSG_MORE, mss_now, + TCP_NAGLE_PUSH, size_goal); if ((err = sk_stream_wait_memory(sk, &timeo)) != 0) goto do_error; @@ -944,7 +980,7 @@ wait_for_memory: out: if (copied && !(flags & MSG_SENDPAGE_NOTLAST)) - tcp_push(sk, flags, mss_now, tp->nonagle); + tcp_push(sk, flags, mss_now, tp->nonagle, size_goal); return copied; do_error: @@ -1225,7 +1261,8 @@ wait_for_sndbuf: set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); wait_for_memory: if (copied) - tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH); + tcp_push(sk, flags & ~MSG_MORE, mss_now, + TCP_NAGLE_PUSH, size_goal); if ((err = sk_stream_wait_memory(sk, &timeo)) != 0) goto do_error; @@ -1236,7 +1273,7 @@ wait_for_memory: out: if (copied) - tcp_push(sk, flags, mss_now, tp->nonagle); + tcp_push(sk, flags, mss_now, tp->nonagle, size_goal); release_sock(sk); return copied + copied_syn; -- cgit v1.2.3 From 9f2b0936b877119280c418258413f6fb9a26acd1 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Dec 2013 14:52:16 -0800 Subject: Documentation: update Ethernet PHY devices binding with 'max-speed' The 'max-speed' property is optional but defined in the ePAPR specification and now supported by the Linux Device Tree parsing infrastructure. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/phy.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/phy.txt b/Documentation/devicetree/bindings/net/phy.txt index 7cd18fbfcf71..f648094abc35 100644 --- a/Documentation/devicetree/bindings/net/phy.txt +++ b/Documentation/devicetree/bindings/net/phy.txt @@ -22,6 +22,7 @@ Optional Properties: specifications. If neither of these are specified, the default is to assume clause 22. The compatible list may also contain other elements. +- max-speed: Maximum PHY supported speed (10, 100, 1000...) Example: -- cgit v1.2.3 From 9ba96ae5074c9f15b357919e704ceba2bd34972d Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Fri, 6 Dec 2013 16:13:07 +0200 Subject: usb: omap1: Tahvo USB transceiver driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Tahvo USB transceiver driver. Based on old code from linux-omap tree. The original driver was written by Juha Yrjölä, Tony Lindgren, and Timo Teräs. Signed-off-by: Aaro Koskinen Signed-off-by: Felipe Balbi --- Documentation/ABI/testing/sysfs-platform-tahvo-usb | 16 + drivers/usb/phy/Kconfig | 15 + drivers/usb/phy/Makefile | 1 + drivers/usb/phy/phy-tahvo.c | 463 +++++++++++++++++++++ 4 files changed, 495 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-platform-tahvo-usb create mode 100644 drivers/usb/phy/phy-tahvo.c (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-platform-tahvo-usb b/Documentation/ABI/testing/sysfs-platform-tahvo-usb new file mode 100644 index 000000000000..f6e20ce4b538 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-tahvo-usb @@ -0,0 +1,16 @@ +What: /sys/bus/platform/devices/tahvo-usb/otg_mode +Date: December 2013 +Contact: Aaro Koskinen +Description: + Set or read the current OTG mode. Valid values are "host" and + "peripheral". + + Reading: returns the current mode. + +What: /sys/bus/platform/devices/tahvo-usb/vbus +Date: December 2013 +Contact: Aaro Koskinen +Description: + Read the current VBUS state. + + Reading: returns "on" or "off". diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 0dbab6f5c2d4..4f22762f3d6f 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -152,6 +152,21 @@ config OMAP_OTG This driver can also be built as a module. If so, the module will be called omap-otg. +config TAHVO_USB + tristate "Tahvo USB transceiver driver" + depends on MFD_RETU && EXTCON + select USB_PHY + help + Enable this to support USB transceiver on Tahvo. This is used + at least on Nokia 770. + +config TAHVO_USB_HOST_BY_DEFAULT + depends on TAHVO_USB + boolean "Device in USB host mode by default" + help + Say Y here, if you want the device to enter USB host mode + by default on bootup. + config USB_ISP1301 tristate "NXP ISP1301 USB transceiver support" depends on USB || USB_GADGET diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index 64a9345e5633..9b3be9e0aeb4 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_FSL_USB2_OTG) += phy-fsl-usb.o obj-$(CONFIG_ISP1301_OMAP) += phy-isp1301-omap.o obj-$(CONFIG_MV_U3D_PHY) += phy-mv-u3d-usb.o obj-$(CONFIG_NOP_USB_XCEIV) += phy-generic.o +obj-$(CONFIG_TAHVO_USB) += phy-tahvo.o obj-$(CONFIG_OMAP_CONTROL_USB) += phy-omap-control.o obj-$(CONFIG_AM335X_CONTROL_USB) += phy-am335x-control.o obj-$(CONFIG_AM335X_PHY_USB) += phy-am335x.o diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c new file mode 100644 index 000000000000..8bb833e22d64 --- /dev/null +++ b/drivers/usb/phy/phy-tahvo.c @@ -0,0 +1,463 @@ +/* + * Tahvo USB transceiver driver + * + * Copyright (C) 2005-2006 Nokia Corporation + * + * Parts copied from isp1301_omap.c. + * Copyright (C) 2004 Texas Instruments + * Copyright (C) 2004 David Brownell + * + * Original driver written by Juha Yrjölä, Tony Lindgren and Timo Teräs. + * Modified for Retu/Tahvo MFD by Aaro Koskinen. + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * 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 + +#define DRIVER_NAME "tahvo-usb" + +#define TAHVO_REG_IDSR 0x02 +#define TAHVO_REG_USBR 0x06 + +#define USBR_SLAVE_CONTROL (1 << 8) +#define USBR_VPPVIO_SW (1 << 7) +#define USBR_SPEED (1 << 6) +#define USBR_REGOUT (1 << 5) +#define USBR_MASTER_SW2 (1 << 4) +#define USBR_MASTER_SW1 (1 << 3) +#define USBR_SLAVE_SW (1 << 2) +#define USBR_NSUSPEND (1 << 1) +#define USBR_SEMODE (1 << 0) + +#define TAHVO_MODE_HOST 0 +#define TAHVO_MODE_PERIPHERAL 1 + +struct tahvo_usb { + struct platform_device *pt_dev; + struct usb_phy phy; + int vbus_state; + struct mutex serialize; + struct clk *ick; + int irq; + int tahvo_mode; + struct extcon_dev extcon; +}; + +static const char *tahvo_cable[] = { + "USB-HOST", + "USB", + NULL, +}; + +static ssize_t vbus_state_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct tahvo_usb *tu = dev_get_drvdata(device); + return sprintf(buf, "%s\n", tu->vbus_state ? "on" : "off"); +} +static DEVICE_ATTR(vbus, 0444, vbus_state_show, NULL); + +static void check_vbus_state(struct tahvo_usb *tu) +{ + struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); + int reg, prev_state; + + reg = retu_read(rdev, TAHVO_REG_IDSR); + if (reg & TAHVO_STAT_VBUS) { + switch (tu->phy.state) { + case OTG_STATE_B_IDLE: + /* Enable the gadget driver */ + if (tu->phy.otg->gadget) + usb_gadget_vbus_connect(tu->phy.otg->gadget); + tu->phy.state = OTG_STATE_B_PERIPHERAL; + break; + case OTG_STATE_A_IDLE: + /* + * Session is now valid assuming the USB hub is driving + * Vbus. + */ + tu->phy.state = OTG_STATE_A_HOST; + break; + default: + break; + } + dev_info(&tu->pt_dev->dev, "USB cable connected\n"); + } else { + switch (tu->phy.state) { + case OTG_STATE_B_PERIPHERAL: + if (tu->phy.otg->gadget) + usb_gadget_vbus_disconnect(tu->phy.otg->gadget); + tu->phy.state = OTG_STATE_B_IDLE; + break; + case OTG_STATE_A_HOST: + tu->phy.state = OTG_STATE_A_IDLE; + break; + default: + break; + } + dev_info(&tu->pt_dev->dev, "USB cable disconnected\n"); + } + + prev_state = tu->vbus_state; + tu->vbus_state = reg & TAHVO_STAT_VBUS; + if (prev_state != tu->vbus_state) { + extcon_set_cable_state(&tu->extcon, "USB", tu->vbus_state); + sysfs_notify(&tu->pt_dev->dev.kobj, NULL, "vbus_state"); + } +} + +static void tahvo_usb_become_host(struct tahvo_usb *tu) +{ + struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); + + extcon_set_cable_state(&tu->extcon, "USB-HOST", true); + + /* Power up the transceiver in USB host mode */ + retu_write(rdev, TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND | + USBR_MASTER_SW2 | USBR_MASTER_SW1); + tu->phy.state = OTG_STATE_A_IDLE; + + check_vbus_state(tu); +} + +static void tahvo_usb_stop_host(struct tahvo_usb *tu) +{ + tu->phy.state = OTG_STATE_A_IDLE; +} + +static void tahvo_usb_become_peripheral(struct tahvo_usb *tu) +{ + struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); + + extcon_set_cable_state(&tu->extcon, "USB-HOST", false); + + /* Power up transceiver and set it in USB peripheral mode */ + retu_write(rdev, TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT | + USBR_NSUSPEND | USBR_SLAVE_SW); + tu->phy.state = OTG_STATE_B_IDLE; + + check_vbus_state(tu); +} + +static void tahvo_usb_stop_peripheral(struct tahvo_usb *tu) +{ + if (tu->phy.otg->gadget) + usb_gadget_vbus_disconnect(tu->phy.otg->gadget); + tu->phy.state = OTG_STATE_B_IDLE; +} + +static void tahvo_usb_power_off(struct tahvo_usb *tu) +{ + struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); + + /* Disable gadget controller if any */ + if (tu->phy.otg->gadget) + usb_gadget_vbus_disconnect(tu->phy.otg->gadget); + + /* Power off transceiver */ + retu_write(rdev, TAHVO_REG_USBR, 0); + tu->phy.state = OTG_STATE_UNDEFINED; +} + +static int tahvo_usb_set_suspend(struct usb_phy *dev, int suspend) +{ + struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, phy); + struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); + u16 w; + + dev_dbg(&tu->pt_dev->dev, "%s\n", __func__); + + w = retu_read(rdev, TAHVO_REG_USBR); + if (suspend) + w &= ~USBR_NSUSPEND; + else + w |= USBR_NSUSPEND; + retu_write(rdev, TAHVO_REG_USBR, w); + + return 0; +} + +static int tahvo_usb_set_host(struct usb_otg *otg, struct usb_bus *host) +{ + struct tahvo_usb *tu = container_of(otg->phy, struct tahvo_usb, phy); + + dev_dbg(&tu->pt_dev->dev, "%s %p\n", __func__, host); + + if (otg == NULL) + return -ENODEV; + + mutex_lock(&tu->serialize); + + if (host == NULL) { + if (tu->tahvo_mode == TAHVO_MODE_HOST) + tahvo_usb_power_off(tu); + otg->host = NULL; + mutex_unlock(&tu->serialize); + return 0; + } + + if (tu->tahvo_mode == TAHVO_MODE_HOST) { + otg->host = NULL; + tahvo_usb_become_host(tu); + } + + otg->host = host; + + mutex_unlock(&tu->serialize); + + return 0; +} + +static int tahvo_usb_set_peripheral(struct usb_otg *otg, + struct usb_gadget *gadget) +{ + struct tahvo_usb *tu = container_of(otg->phy, struct tahvo_usb, phy); + + dev_dbg(&tu->pt_dev->dev, "%s %p\n", __func__, gadget); + + if (!otg) + return -ENODEV; + + mutex_lock(&tu->serialize); + + if (!gadget) { + if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL) + tahvo_usb_power_off(tu); + tu->phy.otg->gadget = NULL; + mutex_unlock(&tu->serialize); + return 0; + } + + tu->phy.otg->gadget = gadget; + if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL) + tahvo_usb_become_peripheral(tu); + + mutex_unlock(&tu->serialize); + + return 0; +} + +static irqreturn_t tahvo_usb_vbus_interrupt(int irq, void *_tu) +{ + struct tahvo_usb *tu = _tu; + + mutex_lock(&tu->serialize); + check_vbus_state(tu); + mutex_unlock(&tu->serialize); + + return IRQ_HANDLED; +} + +static ssize_t otg_mode_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct tahvo_usb *tu = dev_get_drvdata(device); + + switch (tu->tahvo_mode) { + case TAHVO_MODE_HOST: + return sprintf(buf, "host\n"); + case TAHVO_MODE_PERIPHERAL: + return sprintf(buf, "peripheral\n"); + } + + return -EINVAL; +} + +static ssize_t otg_mode_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct tahvo_usb *tu = dev_get_drvdata(device); + int r; + + mutex_lock(&tu->serialize); + if (count >= 4 && strncmp(buf, "host", 4) == 0) { + if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL) + tahvo_usb_stop_peripheral(tu); + tu->tahvo_mode = TAHVO_MODE_HOST; + if (tu->phy.otg->host) { + dev_info(device, "HOST mode: host controller present\n"); + tahvo_usb_become_host(tu); + } else { + dev_info(device, "HOST mode: no host controller, powering off\n"); + tahvo_usb_power_off(tu); + } + r = strlen(buf); + } else if (count >= 10 && strncmp(buf, "peripheral", 10) == 0) { + if (tu->tahvo_mode == TAHVO_MODE_HOST) + tahvo_usb_stop_host(tu); + tu->tahvo_mode = TAHVO_MODE_PERIPHERAL; + if (tu->phy.otg->gadget) { + dev_info(device, "PERIPHERAL mode: gadget driver present\n"); + tahvo_usb_become_peripheral(tu); + } else { + dev_info(device, "PERIPHERAL mode: no gadget driver, powering off\n"); + tahvo_usb_power_off(tu); + } + r = strlen(buf); + } else { + r = -EINVAL; + } + mutex_unlock(&tu->serialize); + + return r; +} +static DEVICE_ATTR(otg_mode, 0644, otg_mode_show, otg_mode_store); + +static struct attribute *tahvo_attributes[] = { + &dev_attr_vbus.attr, + &dev_attr_otg_mode.attr, + NULL +}; + +static struct attribute_group tahvo_attr_group = { + .attrs = tahvo_attributes, +}; + +static int tahvo_usb_probe(struct platform_device *pdev) +{ + struct retu_dev *rdev = dev_get_drvdata(pdev->dev.parent); + struct tahvo_usb *tu; + int ret; + + tu = devm_kzalloc(&pdev->dev, sizeof(*tu), GFP_KERNEL); + if (!tu) + return -ENOMEM; + + tu->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*tu->phy.otg), + GFP_KERNEL); + if (!tu->phy.otg) + return -ENOMEM; + + tu->pt_dev = pdev; + + /* Default mode */ +#ifdef CONFIG_TAHVO_USB_HOST_BY_DEFAULT + tu->tahvo_mode = TAHVO_MODE_HOST; +#else + tu->tahvo_mode = TAHVO_MODE_PERIPHERAL; +#endif + + mutex_init(&tu->serialize); + + tu->ick = devm_clk_get(&pdev->dev, "usb_l4_ick"); + if (!IS_ERR(tu->ick)) + clk_enable(tu->ick); + + /* + * Set initial state, so that we generate kevents only on state changes. + */ + tu->vbus_state = retu_read(rdev, TAHVO_REG_IDSR) & TAHVO_STAT_VBUS; + + tu->extcon.name = DRIVER_NAME; + tu->extcon.supported_cable = tahvo_cable; + tu->extcon.dev.parent = &pdev->dev; + + ret = extcon_dev_register(&tu->extcon); + if (ret) { + dev_err(&pdev->dev, "could not register extcon device: %d\n", + ret); + goto err_disable_clk; + } + + /* Set the initial cable state. */ + extcon_set_cable_state(&tu->extcon, "USB-HOST", + tu->tahvo_mode == TAHVO_MODE_HOST); + extcon_set_cable_state(&tu->extcon, "USB", tu->vbus_state); + + /* Create OTG interface */ + tahvo_usb_power_off(tu); + tu->phy.dev = &pdev->dev; + tu->phy.state = OTG_STATE_UNDEFINED; + tu->phy.label = DRIVER_NAME; + tu->phy.set_suspend = tahvo_usb_set_suspend; + + tu->phy.otg->phy = &tu->phy; + tu->phy.otg->set_host = tahvo_usb_set_host; + tu->phy.otg->set_peripheral = tahvo_usb_set_peripheral; + + ret = usb_add_phy(&tu->phy, USB_PHY_TYPE_USB2); + if (ret < 0) { + dev_err(&pdev->dev, "cannot register USB transceiver: %d\n", + ret); + goto err_extcon_unreg; + } + + dev_set_drvdata(&pdev->dev, tu); + + tu->irq = platform_get_irq(pdev, 0); + ret = request_threaded_irq(tu->irq, NULL, tahvo_usb_vbus_interrupt, 0, + "tahvo-vbus", tu); + if (ret) { + dev_err(&pdev->dev, "could not register tahvo-vbus irq: %d\n", + ret); + goto err_remove_phy; + } + + /* Attributes */ + ret = sysfs_create_group(&pdev->dev.kobj, &tahvo_attr_group); + if (ret) { + dev_err(&pdev->dev, "cannot create sysfs group: %d\n", ret); + goto err_free_irq; + } + + return 0; + +err_free_irq: + free_irq(tu->irq, tu); +err_remove_phy: + usb_remove_phy(&tu->phy); +err_extcon_unreg: + extcon_dev_unregister(&tu->extcon); +err_disable_clk: + if (!IS_ERR(tu->ick)) + clk_disable(tu->ick); + + return ret; +} + +static int tahvo_usb_remove(struct platform_device *pdev) +{ + struct tahvo_usb *tu = platform_get_drvdata(pdev); + + sysfs_remove_group(&pdev->dev.kobj, &tahvo_attr_group); + free_irq(tu->irq, tu); + usb_remove_phy(&tu->phy); + extcon_dev_unregister(&tu->extcon); + if (!IS_ERR(tu->ick)) + clk_disable(tu->ick); + + return 0; +} + +static struct platform_driver tahvo_usb_driver = { + .probe = tahvo_usb_probe, + .remove = tahvo_usb_remove, + .driver = { + .name = "tahvo-usb", + .owner = THIS_MODULE, + }, +}; +module_platform_driver(tahvo_usb_driver); + +MODULE_DESCRIPTION("Tahvo USB transceiver driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Juha Yrjölä, Tony Lindgren, and Timo Teräs"); +MODULE_AUTHOR("Aaro Koskinen "); -- cgit v1.2.3 From 0d74c42f788caf3cad727c61c490d9459bc8918b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 5 Dec 2013 14:54:38 -0800 Subject: ether_addr_equal: Optimize implementation, remove unused compare_ether_addr Add a new check for CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS to reduce the number of or's used in the ether_addr_equal comparison to very slightly improve function performance. Simplify the ether_addr_equal_64bits implementation. Integrate and remove the zap_last_2bytes helper as it's now used only once. Remove the now unused compare_ether_addr function. Update the unaligned-memory-access documentation to remove the compare_ether_addr description and show how unaligned accesses could occur with ether_addr_equal. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- Documentation/unaligned-memory-access.txt | 28 +++++++++++------ include/linux/etherdevice.h | 51 +++++++++++-------------------- 2 files changed, 37 insertions(+), 42 deletions(-) (limited to 'Documentation') diff --git a/Documentation/unaligned-memory-access.txt b/Documentation/unaligned-memory-access.txt index f866c72291bf..a445da098bc6 100644 --- a/Documentation/unaligned-memory-access.txt +++ b/Documentation/unaligned-memory-access.txt @@ -137,24 +137,34 @@ Code that causes unaligned access ================================= With the above in mind, let's move onto a real life example of a function -that can cause an unaligned memory access. The following function adapted +that can cause an unaligned memory access. The following function taken from include/linux/etherdevice.h is an optimized routine to compare two ethernet MAC addresses for equality. -unsigned int compare_ether_addr(const u8 *addr1, const u8 *addr2) +bool ether_addr_equal(const u8 *addr1, const u8 *addr2) { - const u16 *a = (const u16 *) addr1; - const u16 *b = (const u16 *) addr2; +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS + u32 fold = ((*(const u32 *)addr1) ^ (*(const u32 *)addr2)) | + ((*(const u16 *)(addr1 + 4)) ^ (*(const u16 *)(addr2 + 4))); + + return fold == 0; +#else + const u16 *a = (const u16 *)addr1; + const u16 *b = (const u16 *)addr2; return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0; +#endif } -In the above function, the reference to a[0] causes 2 bytes (16 bits) to -be read from memory starting at address addr1. Think about what would happen -if addr1 was an odd address such as 0x10003. (Hint: it'd be an unaligned -access.) +In the above function, when the hardware has efficient unaligned access +capability, there is no issue with this code. But when the hardware isn't +able to access memory on arbitrary boundaries, the reference to a[0] causes +2 bytes (16 bits) to be read from memory starting at address addr1. + +Think about what would happen if addr1 was an odd address such as 0x10003. +(Hint: it'd be an unaligned access.) Despite the potential unaligned access problems with the above function, it -is included in the kernel anyway but is understood to only work on +is included in the kernel anyway but is understood to only work normally on 16-bit-aligned addresses. It is up to the caller to ensure this alignment or not use this function at all. This alignment-unsafe function is still useful as it is a decent optimization for the cases when you can ensure alignment, diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index fc4a9aa7dd82..3526e819d7ae 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef __KERNEL__ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev); @@ -210,41 +211,27 @@ static inline void eth_hw_addr_inherit(struct net_device *dst, memcpy(dst->dev_addr, src->dev_addr, ETH_ALEN); } -/** - * compare_ether_addr - Compare two Ethernet addresses - * @addr1: Pointer to a six-byte array containing the Ethernet address - * @addr2: Pointer other six-byte array containing the Ethernet address - * - * Compare two Ethernet addresses, returns 0 if equal, non-zero otherwise. - * Unlike memcmp(), it doesn't return a value suitable for sorting. - */ -static inline unsigned compare_ether_addr(const u8 *addr1, const u8 *addr2) -{ - const u16 *a = (const u16 *) addr1; - const u16 *b = (const u16 *) addr2; - - BUILD_BUG_ON(ETH_ALEN != 6); - return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0; -} - /** * ether_addr_equal - Compare two Ethernet addresses * @addr1: Pointer to a six-byte array containing the Ethernet address * @addr2: Pointer other six-byte array containing the Ethernet address * * Compare two Ethernet addresses, returns true if equal + * + * Please note: addr1 & addr2 must both be aligned to u16. */ static inline bool ether_addr_equal(const u8 *addr1, const u8 *addr2) { - return !compare_ether_addr(addr1, addr2); -} +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + u32 fold = ((*(const u32 *)addr1) ^ (*(const u32 *)addr2)) | + ((*(const u16 *)(addr1 + 4)) ^ (*(const u16 *)(addr2 + 4))); -static inline unsigned long zap_last_2bytes(unsigned long value) -{ -#ifdef __BIG_ENDIAN - return value >> 16; + return fold == 0; #else - return value << 16; + const u16 *a = (const u16 *)addr1; + const u16 *b = (const u16 *)addr2; + + return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) == 0; #endif } @@ -265,16 +252,14 @@ static inline unsigned long zap_last_2bytes(unsigned long value) static inline bool ether_addr_equal_64bits(const u8 addr1[6+2], const u8 addr2[6+2]) { -#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - unsigned long fold = ((*(unsigned long *)addr1) ^ - (*(unsigned long *)addr2)); - - if (sizeof(fold) == 8) - return zap_last_2bytes(fold) == 0; +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 + u64 fold = (*(const u64 *)addr1) ^ (*(const u64 *)addr2); - fold |= zap_last_2bytes((*(unsigned long *)(addr1 + 4)) ^ - (*(unsigned long *)(addr2 + 4))); - return fold == 0; +#ifdef __BIG_ENDIAN + return (fold >> 16) == 0; +#else + return (fold << 16) == 0; +#endif #else return ether_addr_equal(addr1, addr2); #endif -- cgit v1.2.3 From 35a5fe695b07ae899510ad76fdf0aeaef85fe951 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 5 Dec 2013 17:38:00 -0700 Subject: kobject: remove kset from sysfs immediately in kset_unregister() There's no "unlink from sysfs" interface for ksets, so I think callers of kset_unregister() expect the kset to be removed from sysfs immediately, without waiting for the last reference to be released. This patch makes the sysfs removal happen immediately, so the caller may create a new kset with the same name as soon as kset_unregister() returns. Without this, every caller has to call "kobject_del(&kset->kobj)" first unless it knows it will never create a new kset with the same name. This sometimes shows up on module unload and reload, where the reload fails because it tries to create a kobject with the same name as one from the original load that still exists. CONFIG_DEBUG_KOBJECT_RELEASE=y makes this problem easier to hit. Signed-off-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman --- Documentation/kobject.txt | 5 ++++- lib/kobject.c | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt index c5182bb2c16c..f87241dfed87 100644 --- a/Documentation/kobject.txt +++ b/Documentation/kobject.txt @@ -342,7 +342,10 @@ kset use: When you are finished with the kset, call: void kset_unregister(struct kset *kset); -to destroy it. +to destroy it. This removes the kset from sysfs and decrements its reference +count. When the reference count goes to zero, the kset will be released. +Because other references to the kset may still exist, the release may happen +after kset_unregister() returns. An example of using a kset can be seen in the samples/kobject/kset-example.c file in the kernel tree. diff --git a/lib/kobject.c b/lib/kobject.c index 1d110dc95db5..98b45bb33c8d 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -855,6 +855,7 @@ void kset_unregister(struct kset *k) { if (!k) return; + kobject_del(&k->kobj); kobject_put(&k->kobj); } -- cgit v1.2.3 From 9b015e5a95c54171b72b83e7d4ffb60489d867b4 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Fri, 8 Nov 2013 13:00:22 +0400 Subject: ARM: i.MX5x: Add SAHARA clock for i.MX5x CPUs Patch adds missing Security Accelerator (SAHARA) clock for i.MX5x CPUs. Signed-off-by: Alexander Shiyan Signed-off-by: Shawn Guo --- Documentation/devicetree/bindings/clock/imx5-clock.txt | 1 + arch/arm/mach-imx/clk-imx51-imx53.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/imx5-clock.txt b/Documentation/devicetree/bindings/clock/imx5-clock.txt index 4c029a8739d3..3716b36c1440 100644 --- a/Documentation/devicetree/bindings/clock/imx5-clock.txt +++ b/Documentation/devicetree/bindings/clock/imx5-clock.txt @@ -198,6 +198,7 @@ clocks and IDs. spdif1_gate 184 spdif_ipg_gate 185 ocram 186 + sahara_ipg_gate 187 Examples (for mx53): diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c index af8fd0861459..3d91172a9554 100644 --- a/arch/arm/mach-imx/clk-imx51-imx53.c +++ b/arch/arm/mach-imx/clk-imx51-imx53.c @@ -122,7 +122,7 @@ enum imx5_clks { srtc_gate, pata_gate, sata_gate, spdif_xtal_sel, spdif0_sel, spdif1_sel, spdif0_pred, spdif0_podf, spdif1_pred, spdif1_podf, spdif0_com_s, spdif1_com_sel, spdif0_gate, spdif1_gate, spdif_ipg_gate, - ocram, clk_max + ocram, sahara_ipg_gate, clk_max }; static struct clk *clk[clk_max]; @@ -285,6 +285,7 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil, spdif0_com_sel, ARRAY_SIZE(spdif0_com_sel), CLK_SET_RATE_PARENT); clk[spdif0_gate] = imx_clk_gate2("spdif0_gate", "spdif0_com_sel", MXC_CCM_CCGR5, 26); clk[spdif_ipg_gate] = imx_clk_gate2("spdif_ipg_gate", "ipg", MXC_CCM_CCGR5, 30); + clk[sahara_ipg_gate] = imx_clk_gate2("sahara_ipg_gate", "ipg", MXC_CCM_CCGR4, 14); for (i = 0; i < ARRAY_SIZE(clk); i++) if (IS_ERR(clk[i])) -- cgit v1.2.3 From 28c9a8b357c1c889389594cf3a8f37be4a982776 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 15 Nov 2013 10:58:40 +0100 Subject: ARM: at91/dt: binding: add precision to AIC documentation In response to the "undocumented compatible strings" message, here is a patch which is adding the precision of two "chips" that should be used for the "atmel,-aic" compatibility string. Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD --- Documentation/devicetree/bindings/arm/atmel-aic.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/atmel-aic.txt b/Documentation/devicetree/bindings/arm/atmel-aic.txt index ad031211b5b8..2742e9cfd6b1 100644 --- a/Documentation/devicetree/bindings/arm/atmel-aic.txt +++ b/Documentation/devicetree/bindings/arm/atmel-aic.txt @@ -2,6 +2,7 @@ Required properties: - compatible: Should be "atmel,-aic" + can be "at91rm9200" or "sama5d3" - interrupt-controller: Identifies the node as an interrupt controller. - interrupt-parent: For single AIC system, it is an empty property. - #interrupt-cells: The number of cells to define the interrupts. It should be 3. -- cgit v1.2.3 From 20b4e4fa8451542c1dbbdfb14e8579fe5f2c79fc Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 15 Nov 2013 11:03:23 +0100 Subject: ARM: at91/dt: binding: add missing compatibility string in SDRAM/DDR documentation The "atmel,at91rm9200-sdramc" was missing from binding documentation. Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD --- Documentation/devicetree/bindings/arm/atmel-at91.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 1196290082d1..d2170e780f0b 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -50,7 +50,8 @@ Example: }; RAMC SDRAM/DDR Controller required properties: -- compatible: Should be "atmel,at91sam9260-sdramc", +- compatible: Should be "atmel,at91rm9200-sdramc", + "atmel,at91sam9260-sdramc", "atmel,at91sam9g45-ddramc", - reg: Should contain registers location and length For at91sam9263 and at91sam9g45 you must specify 2 entries. -- cgit v1.2.3 From ad824783fb23bbc8295cffb6214b3b82d25f7d4a Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 3 Dec 2013 12:20:11 +0900 Subject: gpio: better lookup method for platform GPIOs Change the format of the platform GPIO lookup tables to make them less confusing and improve lookup efficiency. The previous format was a single linked-list that required to compare the device name and function ID of every single GPIO defined for each lookup. Switch that to a list of per-device tables, so that the lookup can be done in two steps, omitting the GPIOs that are not relevant for a particular device. The matching rules are now defined as follows: - The device name must match *exactly*, and can be NULL for GPIOs not assigned to a particular device, - If the function ID in the lookup table is NULL, the con_id argument of gpiod_get() will not be used for lookup. However, if it is defined, it must match exactly. - The index must always match. Signed-off-by: Alexandre Courbot Acked-by: Mika Westerberg Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- Documentation/gpio/board.txt | 28 ++++++----- drivers/gpio/gpiolib.c | 108 +++++++++++++++++++++++-------------------- include/linux/gpio/driver.h | 21 ++++----- 3 files changed, 85 insertions(+), 72 deletions(-) (limited to 'Documentation') diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt index 0d03506f2cc5..ba169faad5c6 100644 --- a/Documentation/gpio/board.txt +++ b/Documentation/gpio/board.txt @@ -72,10 +72,11 @@ where - chip_label is the label of the gpiod_chip instance providing the GPIO - chip_hwnum is the hardware number of the GPIO within the chip - - dev_id is the identifier of the device that will make use of this GPIO. If - NULL, the GPIO will be available to all devices. + - dev_id is the identifier of the device that will make use of this GPIO. It + can be NULL, in which case it will be matched for calls to gpiod_get() + with a NULL device. - con_id is the name of the GPIO function from the device point of view. It - can be NULL. + can be NULL, in which case it will match any function. - idx is the index of the GPIO within the function. - flags is defined to specify the following properties: * GPIOF_ACTIVE_LOW - to configure the GPIO as active-low @@ -86,18 +87,23 @@ In the future, these flags might be extended to support more properties. Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0. -A lookup table can then be defined as follows: +A lookup table can then be defined as follows, with an empty entry defining its +end: - struct gpiod_lookup gpios_table[] = { - GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW), - }; +struct gpiod_lookup_table gpios_table = { + .dev_id = "foo.0", + .table = { + GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW), + { }, + }, +}; And the table can be added by the board code as follows: - gpiod_add_table(gpios_table, ARRAY_SIZE(gpios_table)); + gpiod_add_lookup_table(&gpios_table); The driver controlling "foo.0" will then be able to obtain its GPIOs as follows: diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 44a232701179..4eb262a31777 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2260,18 +2260,14 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); /** - * gpiod_add_table() - register GPIO device consumers - * @table: array of consumers to register - * @num: number of consumers in table + * gpiod_add_lookup_table() - register GPIO device consumers + * @table: table of consumers to register */ -void gpiod_add_table(struct gpiod_lookup *table, size_t size) +void gpiod_add_lookup_table(struct gpiod_lookup_table *table) { mutex_lock(&gpio_lookup_lock); - while (size--) { - list_add_tail(&table->list, &gpio_lookup_list); - table++; - } + list_add_tail(&table->list, &gpio_lookup_list); mutex_unlock(&gpio_lookup_lock); } @@ -2327,72 +2323,84 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, return desc; } -static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, - unsigned int idx, - enum gpio_lookup_flags *flags) +static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev) { const char *dev_id = dev ? dev_name(dev) : NULL; - struct gpio_desc *desc = ERR_PTR(-ENODEV); - unsigned int match, best = 0; - struct gpiod_lookup *p; + struct gpiod_lookup_table *table; mutex_lock(&gpio_lookup_lock); - list_for_each_entry(p, &gpio_lookup_list, list) { - match = 0; + list_for_each_entry(table, &gpio_lookup_list, list) { + if (table->dev_id && dev_id) { + /* + * Valid strings on both ends, must be identical to have + * a match + */ + if (!strcmp(table->dev_id, dev_id)) + goto found; + } else { + /* + * One of the pointers is NULL, so both must be to have + * a match + */ + if (dev_id == table->dev_id) + goto found; + } + } + table = NULL; - if (p->dev_id) { - if (!dev_id || strcmp(p->dev_id, dev_id)) - continue; +found: + mutex_unlock(&gpio_lookup_lock); + return table; +} - match += 2; - } +static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, + unsigned int idx, + enum gpio_lookup_flags *flags) +{ + struct gpio_desc *desc = ERR_PTR(-ENODEV); + struct gpiod_lookup_table *table; + struct gpiod_lookup *p; - if (p->con_id) { - if (!con_id || strcmp(p->con_id, con_id)) - continue; + table = gpiod_find_lookup_table(dev); + if (!table) + return desc; - match += 1; - } + for (p = &table->table[0]; p->chip_label; p++) { + struct gpio_chip *chip; + /* idx must always match exactly */ if (p->idx != idx) continue; - if (match > best) { - struct gpio_chip *chip; - - chip = find_chip_by_name(p->chip_label); - - if (!chip) { - dev_warn(dev, "cannot find GPIO chip %s\n", - p->chip_label); - continue; - } + /* If the lookup entry has a con_id, require exact match */ + if (p->con_id && (!con_id || strcmp(p->con_id, con_id))) + continue; - if (chip->ngpio <= p->chip_hwnum) { - dev_warn(dev, "GPIO chip %s has %d GPIOs\n", - chip->label, chip->ngpio); - continue; - } + chip = find_chip_by_name(p->chip_label); - desc = gpio_to_desc(chip->base + p->chip_hwnum); - *flags = p->flags; + if (!chip) { + dev_warn(dev, "cannot find GPIO chip %s\n", + p->chip_label); + continue; + } - if (match != 3) - best = match; - else - break; + if (chip->ngpio <= p->chip_hwnum) { + dev_warn(dev, "GPIO chip %s has %d GPIOs\n", + chip->label, chip->ngpio); + continue; } - } - mutex_unlock(&gpio_lookup_lock); + desc = gpiochip_offset_to_desc(chip, p->chip_hwnum); + *flags = p->flags; + } return desc; } /** * gpio_get - obtain a GPIO for a given GPIO function - * @dev: GPIO consumer + * @dev: GPIO consumer, can be NULL for system-global GPIOs * @con_id: function within the GPIO consumer * * Return the GPIO descriptor corresponding to the function con_id of device diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index c849676c6787..44c66b29a2d9 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -141,7 +141,6 @@ enum gpio_lookup_flags { * platform data. */ struct gpiod_lookup { - struct list_head list; /* * name of the chip the GPIO belongs to */ @@ -150,10 +149,6 @@ struct gpiod_lookup { * hardware number (i.e. relative to the chip) of the GPIO */ u16 chip_hwnum; - /* - * name of device that can claim this GPIO - */ - const char *dev_id; /* * name of the GPIO from the device's point of view */ @@ -168,28 +163,32 @@ struct gpiod_lookup { enum gpio_lookup_flags flags; }; +struct gpiod_lookup_table { + struct list_head list; + const char *dev_id; + struct gpiod_lookup table[]; +}; + /* * Simple definition of a single GPIO under a con_id */ -#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _dev_id, _con_id, _flags) \ - GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _dev_id, _con_id, 0, _flags) +#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _con_id, _flags) \ + GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, 0, _flags) /* * Use this macro if you need to have several GPIOs under the same con_id. * Each GPIO needs to use a different index and can be accessed using * gpiod_get_index() */ -#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _dev_id, _con_id, _idx, \ - _flags) \ +#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, _idx, _flags) \ { \ .chip_label = _chip_label, \ .chip_hwnum = _chip_hwnum, \ - .dev_id = _dev_id, \ .con_id = _con_id, \ .idx = _idx, \ .flags = _flags, \ } -void gpiod_add_table(struct gpiod_lookup *table, size_t size); +void gpiod_add_lookup_table(struct gpiod_lookup_table *table); #endif -- cgit v1.2.3 From 0c64bc1b5eace5f48dec7305b83ee4d613d58c94 Mon Sep 17 00:00:00 2001 From: John Whitmore Date: Fri, 6 Dec 2013 13:33:50 +0000 Subject: spi: Correction to typos in Documentation/spi/spi-summary Just a few simple typo corrections. Signed-off-by: John Whitmore Signed-off-by: Mark Brown --- Documentation/spi/spi-summary | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary index f21edb983413..f72e0d1e0da8 100644 --- a/Documentation/spi/spi-summary +++ b/Documentation/spi/spi-summary @@ -34,7 +34,7 @@ SPI slave functions are usually not interoperable between vendors - It may also be used to stream data in either direction (half duplex), or both of them at the same time (full duplex). - - Some devices may use eight bit words. Others may different word + - Some devices may use eight bit words. Others may use different word lengths, such as streams of 12-bit or 20-bit digital samples. - Words are usually sent with their most significant bit (MSB) first, @@ -121,7 +121,7 @@ active. So the master must set the clock to inactive before selecting a slave, and the slave can tell the chosen polarity by sampling the clock level when its select line goes active. That's why many devices support for example both modes 0 and 3: they don't care about polarity, -and alway clock data in/out on rising clock edges. +and always clock data in/out on rising clock edges. How do these driver programming interfaces work? @@ -139,7 +139,7 @@ a command and then reading its response. There are two types of SPI driver, here called: - Controller drivers ... controllers may be built in to System-On-Chip + Controller drivers ... controllers may be built into System-On-Chip processors, and often support both Master and Slave roles. These drivers touch hardware registers and may use DMA. Or they can be PIO bitbangers, needing just GPIO pins. @@ -548,7 +548,7 @@ SPI MASTER METHODS DEPRECATED METHODS master->transfer(struct spi_device *spi, struct spi_message *message) - This must not sleep. Its responsibility is arrange that the + This must not sleep. Its responsibility is to arrange that the transfer happens and its complete() callback is issued. The two will normally happen later, after other transfers complete, and if the controller is idle it will need to be kickstarted. This -- cgit v1.2.3 From 00e6cb2aed48a86e97a244c6f96ac1f934e2272c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 6 Dec 2013 11:02:49 +0100 Subject: dt: Add bindings documentation for the ADI AXI-I2S controller This patch adds the devicetree documentation for the ADI AXI-SPDIF audio controller. The controller has: * One set of memory mapped register * Two clocks, one for the memory mapped register interface, one used as the audio reference clock * One DMA interface each for the transmit and receive data Signed-off-by: Lars-Peter Clausen Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Stephen Warren Cc: Ian Campbell Cc: devicetree@vger.kernel.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/adi,axi-i2s.txt | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/adi,axi-i2s.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/adi,axi-i2s.txt b/Documentation/devicetree/bindings/sound/adi,axi-i2s.txt new file mode 100644 index 000000000000..5875ca459ed1 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,axi-i2s.txt @@ -0,0 +1,31 @@ +ADI AXI-I2S controller + +Required properties: + - compatible : Must be "adi,axi-i2s-1.00.a" + - reg : Must contain I2S core's registers location and length + - clocks : Pairs of phandle and specifier referencing the controller's clocks. + The controller expects two clocks, the clock used for the AXI interface and + the clock used as the sampling rate reference clock sample. + - clock-names : "axi" for the clock to the AXI interface, "ref" for the sample + rate reference clock. + - dmas: Pairs of phandle and specifier for the DMA channels that are used by + the core. The core expects two dma channels, one for transmit and one for + receive. + - dma-names : "tx" for the transmit channel, "rx" for the receive channel. + +For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties +please check: + * resource-names.txt + * clock/clock-bindings.txt + * dma/dma.txt + +Example: + + i2s: i2s@0x77600000 { + compatible = "adi,axi-i2s-1.00.a"; + reg = <0x77600000 0x1000>; + clocks = <&clk 15>, <&audio_clock>; + clock-names = "axi", "ref"; + dmas = <&ps7_dma 0>, <&ps7_dma 1>; + dma-names = "tx", "rx"; + }; -- cgit v1.2.3 From d7b528eff9277b83b315500f44ade178035ed0d1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 6 Dec 2013 11:02:51 +0100 Subject: dt: Add bindings documentation for the ADI AXI-SPDIF audio controller This patch adds the devicetree documentation for the ADI AXI-SPDIF audio controller. The controller has: * One set of memory mapped register * Two clocks, one for the memory mapped register interface, one used as the audio reference clock * A DMA interface for the transmit data Signed-off-by: Lars-Peter Clausen Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Stephen Warren Cc: Ian Campbell Cc: devicetree@vger.kernel.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/adi,axi-spdif-tx.txt | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/adi,axi-spdif-tx.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/adi,axi-spdif-tx.txt b/Documentation/devicetree/bindings/sound/adi,axi-spdif-tx.txt new file mode 100644 index 000000000000..46f344965313 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,axi-spdif-tx.txt @@ -0,0 +1,30 @@ +ADI AXI-SPDIF controller + +Required properties: + - compatible : Must be "adi,axi-spdif-1.00.a" + - reg : Must contain SPDIF core's registers location and length + - clocks : Pairs of phandle and specifier referencing the controller's clocks. + The controller expects two clocks, the clock used for the AXI interface and + the clock used as the sampling rate reference clock sample. + - clock-names: "axi" for the clock to the AXI interface, "ref" for the sample + rate reference clock. + - dmas: Pairs of phandle and specifier for the DMA channel that is used by + the core. The core expects one dma channel for transmit. + - dma-names : Must be "tx" + +For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties +please check: + * resource-names.txt + * clock/clock-bindings.txt + * dma/dma.txt + +Example: + + spdif: spdif@0x77400000 { + compatible = "adi,axi-spdif-tx-1.00.a"; + reg = <0x77600000 0x1000>; + clocks = <&clk 15>, <&audio_clock>; + clock-names = "axi", "ref"; + dmas = <&ps7_dma 0>; + dma-names = "tx"; + }; -- cgit v1.2.3 From ba1271bb05f81a1f4b26ab7a87771147d6f3185e Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Thu, 5 Dec 2013 13:39:05 +0200 Subject: spi: gpio: clarify gpio chipselect language Commit 743179849015 (of_spi: add generic binding support to specify cs gpio) introduced generic binding for gpio chip-select. The cs_gpio struct field, however, is an internal implementation detail of the Linux SPI subsystem, and should not be mentioned in the device tree binding documentation. Mention the previously defined cs-gpios master node property instead. Signed-off-by: Baruch Siach Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-bus.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/spi-bus.txt b/Documentation/devicetree/bindings/spi/spi-bus.txt index 800dafe5b01b..e5a4d1b4acfe 100644 --- a/Documentation/devicetree/bindings/spi/spi-bus.txt +++ b/Documentation/devicetree/bindings/spi/spi-bus.txt @@ -67,7 +67,7 @@ only 1(SINGLE), 2(DUAL) and 4(QUAD). Dual/Quad mode is not allowed when 3-wire mode is used. If a gpio chipselect is used for the SPI slave the gpio number will be passed -via the cs_gpio +via the SPI master node cs-gpios property. SPI example for an MPC5200 SPI bus: spi@f00 { -- cgit v1.2.3 From d346a3fae3ff1d99f5d0c819bf86edf9094a26a1 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 6 Dec 2013 11:36:17 +0100 Subject: packet: introduce PACKET_QDISC_BYPASS socket option This patch introduces a PACKET_QDISC_BYPASS socket option, that allows for using a similar xmit() function as in pktgen instead of taking the dev_queue_xmit() path. This can be very useful when PF_PACKET applications are required to be used in a similar scenario as pktgen, but with full, flexible packet payload that needs to be provided, for example. On default, nothing changes in behaviour for normal PF_PACKET TX users, so everything stays as is for applications. New users, however, can now set PACKET_QDISC_BYPASS if needed to prevent own packets from i) reentering packet_rcv() and ii) to directly push the frame to the driver. In doing so we can increase pps (here 64 byte packets) for PF_PACKET a bit: # CPUs -- QDISC_BYPASS -- qdisc path -- qdisc path[**] 1 CPU == 1,509,628 pps -- 1,208,708 -- 1,247,436 2 CPUs == 3,198,659 pps -- 2,536,012 -- 1,605,779 3 CPUs == 4,787,992 pps -- 3,788,740 -- 1,735,610 4 CPUs == 6,173,956 pps -- 4,907,799 -- 1,909,114 5 CPUs == 7,495,676 pps -- 5,956,499 -- 2,014,422 6 CPUs == 9,001,496 pps -- 7,145,064 -- 2,155,261 7 CPUs == 10,229,776 pps -- 8,190,596 -- 2,220,619 8 CPUs == 11,040,732 pps -- 9,188,544 -- 2,241,879 9 CPUs == 12,009,076 pps -- 10,275,936 -- 2,068,447 10 CPUs == 11,380,052 pps -- 11,265,337 -- 1,578,689 11 CPUs == 11,672,676 pps -- 11,845,344 -- 1,297,412 [...] 20 CPUs == 11,363,192 pps -- 11,014,933 -- 1,245,081 [**]: qdisc path with packet_rcv(), how probably most people seem to use it (hopefully not anymore if not needed) The test was done using a modified trafgen, sending a simple static 64 bytes packet, on all CPUs. The trick in the fast "qdisc path" case, is to avoid reentering packet_rcv() by setting the RAW socket protocol to zero, like: socket(PF_PACKET, SOCK_RAW, 0); Tradeoffs are documented as well in this patch, clearly, if queues are busy, we will drop more packets, tc disciplines are ignored, and these packets are not visible to taps anymore. For a pktgen like scenario, we argue that this is acceptable. The pointer to the xmit function has been placed in packet socket structure hole between cached_dev and prot_hook that is hot anyway as we're working on cached_dev in each send path. Done in joint work together with Jesper Dangaard Brouer. Signed-off-by: Daniel Borkmann Signed-off-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- Documentation/networking/packet_mmap.txt | 21 ++++++++ include/uapi/linux/if_packet.h | 1 + net/packet/af_packet.c | 91 +++++++++++++++++++++++++++----- net/packet/internal.h | 1 + 4 files changed, 102 insertions(+), 12 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt index 8e48e3b14227..4288ffafba9f 100644 --- a/Documentation/networking/packet_mmap.txt +++ b/Documentation/networking/packet_mmap.txt @@ -952,6 +952,27 @@ int main(int argc, char **argp) return 0; } +------------------------------------------------------------------------------- ++ PACKET_QDISC_BYPASS +------------------------------------------------------------------------------- + +If there is a requirement to load the network with many packets in a similar +fashion as pktgen does, you might set the following option after socket +creation: + + int one = 1; + setsockopt(fd, SOL_PACKET, PACKET_QDISC_BYPASS, &one, sizeof(one)); + +This has the side-effect, that packets sent through PF_PACKET will bypass the +kernel's qdisc layer and are forcedly pushed to the driver directly. Meaning, +packet are not buffered, tc disciplines are ignored, increased loss can occur +and such packets are also not visible to other PF_PACKET sockets anymore. So, +you have been warned; generally, this can be useful for stress testing various +components of a system. + +On default, PACKET_QDISC_BYPASS is disabled and needs to be explicitly enabled +on PF_PACKET sockets. + ------------------------------------------------------------------------------- + PACKET_TIMESTAMP ------------------------------------------------------------------------------- diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h index dbf06667394b..1e24aa701cbd 100644 --- a/include/uapi/linux/if_packet.h +++ b/include/uapi/linux/if_packet.h @@ -51,6 +51,7 @@ struct sockaddr_ll { #define PACKET_TIMESTAMP 17 #define PACKET_FANOUT 18 #define PACKET_TX_HAS_OFF 19 +#define PACKET_QDISC_BYPASS 20 #define PACKET_FANOUT_HASH 0 #define PACKET_FANOUT_LB 1 diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index e4171dd98590..9d70f1349926 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -237,6 +237,48 @@ struct packet_skb_cb { static void __fanout_unlink(struct sock *sk, struct packet_sock *po); static void __fanout_link(struct sock *sk, struct packet_sock *po); +static int packet_direct_xmit(struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + const struct net_device_ops *ops = dev->netdev_ops; + netdev_features_t features; + struct netdev_queue *txq; + u16 queue_map; + int ret; + + if (unlikely(!netif_running(dev) || + !netif_carrier_ok(dev))) { + kfree_skb(skb); + return NET_XMIT_DROP; + } + + features = netif_skb_features(skb); + if (skb_needs_linearize(skb, features) && + __skb_linearize(skb)) { + kfree_skb(skb); + return NET_XMIT_DROP; + } + + queue_map = skb_get_queue_mapping(skb); + txq = netdev_get_tx_queue(dev, queue_map); + + __netif_tx_lock_bh(txq); + if (unlikely(netif_xmit_frozen_or_stopped(txq))) { + ret = NETDEV_TX_BUSY; + kfree_skb(skb); + goto out; + } + + ret = ops->ndo_start_xmit(skb, dev); + if (likely(dev_xmit_complete(ret))) + txq_trans_update(txq); + else + kfree_skb(skb); +out: + __netif_tx_unlock_bh(txq); + return ret; +} + static struct net_device *packet_cached_dev_get(struct packet_sock *po) { struct net_device *dev; @@ -261,6 +303,16 @@ static void packet_cached_dev_reset(struct packet_sock *po) RCU_INIT_POINTER(po->cached_dev, NULL); } +static bool packet_use_direct_xmit(const struct packet_sock *po) +{ + return po->xmit == packet_direct_xmit; +} + +static u16 packet_pick_tx_queue(struct net_device *dev) +{ + return (u16) smp_processor_id() % dev->real_num_tx_queues; +} + /* register_prot_hook must be invoked with the po->bind_lock held, * or from a context in which asynchronous accesses to the packet * socket is not possible (packet_create()). @@ -1994,9 +2046,10 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, skb_reserve(skb, hlen); skb_reset_network_header(skb); - skb_probe_transport_header(skb, 0); - if (po->tp_tx_has_off) { + if (!packet_use_direct_xmit(po)) + skb_probe_transport_header(skb, 0); + if (unlikely(po->tp_tx_has_off)) { int off_min, off_max, off; off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll); off_max = po->tx_ring.frame_size - tp_len; @@ -2166,12 +2219,13 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) } } + skb_set_queue_mapping(skb, packet_pick_tx_queue(dev)); skb->destructor = tpacket_destruct_skb; __packet_set_status(po, ph, TP_STATUS_SENDING); atomic_inc(&po->tx_ring.pending); status = TP_STATUS_SEND_REQUEST; - err = dev_queue_xmit(skb); + err = po->xmit(skb); if (unlikely(err > 0)) { err = net_xmit_errno(err); if (err && __packet_get_status(po, ph) == @@ -2230,8 +2284,7 @@ static struct sk_buff *packet_alloc_skb(struct sock *sk, size_t prepad, return skb; } -static int packet_snd(struct socket *sock, - struct msghdr *msg, size_t len) +static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name; @@ -2376,6 +2429,7 @@ static int packet_snd(struct socket *sock, skb->dev = dev; skb->priority = sk->sk_priority; skb->mark = sk->sk_mark; + skb_set_queue_mapping(skb, packet_pick_tx_queue(dev)); if (po->has_vnet_hdr) { if (vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { @@ -2396,16 +2450,12 @@ static int packet_snd(struct socket *sock, len += vnet_hdr_len; } - skb_probe_transport_header(skb, reserve); - + if (!packet_use_direct_xmit(po)) + skb_probe_transport_header(skb, reserve); if (unlikely(extra_len == 4)) skb->no_fcs = 1; - /* - * Now send it - */ - - err = dev_queue_xmit(skb); + err = po->xmit(skb); if (err > 0 && (err = net_xmit_errno(err)) != 0) goto out_unlock; @@ -2427,6 +2477,7 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, { struct sock *sk = sock->sk; struct packet_sock *po = pkt_sk(sk); + if (po->tx_ring.pg_vec) return tpacket_snd(po, msg); else @@ -2641,6 +2692,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, po = pkt_sk(sk); sk->sk_family = PF_PACKET; po->num = proto; + po->xmit = dev_queue_xmit; packet_cached_dev_reset(po); @@ -3220,6 +3272,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv po->tp_tx_has_off = !!val; return 0; } + case PACKET_QDISC_BYPASS: + { + int val; + + if (optlen != sizeof(val)) + return -EINVAL; + if (copy_from_user(&val, optval, sizeof(val))) + return -EFAULT; + + po->xmit = val ? packet_direct_xmit : dev_queue_xmit; + return 0; + } default: return -ENOPROTOOPT; } @@ -3312,6 +3376,9 @@ static int packet_getsockopt(struct socket *sock, int level, int optname, case PACKET_TX_HAS_OFF: val = po->tp_tx_has_off; break; + case PACKET_QDISC_BYPASS: + val = packet_use_direct_xmit(po); + break; default: return -ENOPROTOOPT; } diff --git a/net/packet/internal.h b/net/packet/internal.h index 1035fa2d909c..0a87d7b36c9e 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h @@ -114,6 +114,7 @@ struct packet_sock { unsigned int tp_tx_has_off:1; unsigned int tp_tstamp; struct net_device __rcu *cached_dev; + int (*xmit)(struct sk_buff *skb); struct packet_type prot_hook ____cacheline_aligned_in_smp; }; -- cgit v1.2.3 From 87aa9f9c61ad56d505641681812e92ad976f8608 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:34 -0800 Subject: net: phy: consolidate PHY reset in phy_init_hw() There are quite a lot of drivers touching a PHY device MII_BMCR register to reset the PHY without taking care of: 1) ensuring that BMCR_RESET is cleared after a given timeout 2) the PHY state machine resuming to the proper state and re-applying potentially changed settings such as auto-negotiation Introduce phy_poll_reset() which will take care of polling the MII_BMCR for the BMCR_RESET bit to be cleared after a given timeout or return a timeout error code. In order to make sure the PHY is in a correct state, phy_init_hw() first issues a software reset through MII_BMCR and then applies any fixups. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- Documentation/networking/phy.txt | 3 ++- drivers/net/phy/phy.c | 5 ++-- drivers/net/phy/phy_device.c | 56 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt index d5b1a3935245..ebf270719402 100644 --- a/Documentation/networking/phy.txt +++ b/Documentation/networking/phy.txt @@ -255,7 +255,8 @@ Writing a PHY driver config_init: configures PHY into a sane state after a reset. For instance, a Davicom PHY requires descrambling disabled. - probe: Does any setup needed by the driver + probe: Allocate phy->priv, optionally refuse to bind. + PHY may not have been reset or had fixups run yet. suspend/resume: power management config_aneg: Changes the speed/duplex/negotiation settings read_status: Reads the current speed/duplex/negotiation settings diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 5d7101b3b604..e3dd69100da8 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -318,6 +318,7 @@ int phy_mii_ioctl(struct phy_device *phydev, { struct mii_ioctl_data *mii_data = if_mii(ifr); u16 val = mii_data->val_in; + int ret = 0; switch (cmd) { case SIOCGMIIPHY: @@ -362,7 +363,7 @@ int phy_mii_ioctl(struct phy_device *phydev, if (mii_data->reg_num == MII_BMCR && val & BMCR_RESET) - phy_init_hw(phydev); + ret = phy_init_hw(phydev); break; case SIOCSHWTSTAMP: @@ -374,7 +375,7 @@ int phy_mii_ioctl(struct phy_device *phydev, return -EOPNOTSUPP; } - return 0; + return ret; } EXPORT_SYMBOL(phy_mii_ioctl); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 6db36595eac9..5a619f0dcf73 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -364,7 +364,11 @@ int phy_device_register(struct phy_device *phydev) phydev->bus->phy_map[phydev->addr] = phydev; /* Run all of the fixups for this PHY */ - phy_scan_fixups(phydev); + err = phy_init_hw(phydev); + if (err) { + pr_err("PHY %d failed to initialize\n", phydev->addr); + goto out; + } err = device_add(&phydev->dev); if (err) { @@ -497,6 +501,47 @@ void phy_disconnect(struct phy_device *phydev) } EXPORT_SYMBOL(phy_disconnect); +/** + * phy_poll_reset - Safely wait until a PHY reset has properly completed + * @phydev: The PHY device to poll + * + * Description: According to IEEE 802.3, Section 2, Subsection 22.2.4.1.1, as + * published in 2008, a PHY reset may take up to 0.5 seconds. The MII BMCR + * register must be polled until the BMCR_RESET bit clears. + * + * Furthermore, any attempts to write to PHY registers may have no effect + * or even generate MDIO bus errors until this is complete. + * + * Some PHYs (such as the Marvell 88E1111) don't entirely conform to the + * standard and do not fully reset after the BMCR_RESET bit is set, and may + * even *REQUIRE* a soft-reset to properly restart autonegotiation. In an + * effort to support such broken PHYs, this function is separate from the + * standard phy_init_hw() which will zero all the other bits in the BMCR + * and reapply all driver-specific and board-specific fixups. + */ +static int phy_poll_reset(struct phy_device *phydev) +{ + /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */ + unsigned int retries = 12; + int ret; + + do { + msleep(50); + ret = phy_read(phydev, MII_BMCR); + if (ret < 0) + return ret; + } while (ret & BMCR_RESET && --retries); + if (ret & BMCR_RESET) + return -ETIMEDOUT; + + /* + * Some chips (smsc911x) may still need up to another 1ms after the + * BMCR_RESET bit is cleared before they are usable. + */ + msleep(1); + return 0; +} + int phy_init_hw(struct phy_device *phydev) { int ret; @@ -504,12 +549,21 @@ int phy_init_hw(struct phy_device *phydev) if (!phydev->drv || !phydev->drv->config_init) return 0; + ret = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (ret < 0) + return ret; + + ret = phy_poll_reset(phydev); + if (ret < 0) + return ret; + ret = phy_scan_fixups(phydev); if (ret < 0) return ret; return phydev->drv->config_init(phydev); } +EXPORT_SYMBOL(phy_init_hw); /** * phy_attach_direct - attach a network device to a given PHY device pointer -- cgit v1.2.3 From a42efd97f7471c78617c6329ed39919e2f31a7cc Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 14 Nov 2013 11:35:19 +0200 Subject: ASoC: davinci: kconfig: Prepare for AM43xx support AM43xx have the same McASP IP as AM33xx and both platform uses eDMA. Modify the Kconfig so it will be possible to add audio support for AM43xx based boards later. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt | 2 +- sound/soc/davinci/Kconfig | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index ed785b3f67be..1eed972d4719 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -4,7 +4,7 @@ Required properties: - compatible : "ti,dm646x-mcasp-audio" : for DM646x platforms "ti,da830-mcasp-audio" : for both DA830 & DA850 platforms - "ti,am33xx-mcasp-audio" : for AM33xx platforms (AM33xx, TI81xx) + "ti,am33xx-mcasp-audio" : for AM33xx platforms (AM33xx, AM43xx, TI81xx) - reg : Should contain reg specifiers for the entries in the reg-names property. - reg-names : Should contain: diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index be667719d44e..a8ec1fc3e4d0 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -1,6 +1,6 @@ config SND_DAVINCI_SOC - tristate "SoC Audio for the TI DAVINCI or AM33XX chip" - depends on ARCH_DAVINCI || SOC_AM33XX + tristate "SoC Audio for TI DAVINCI or AM33XX/AM43XX chips" + depends on ARCH_DAVINCI || SOC_AM33XX || SOC_AM43XX config SND_DAVINCI_SOC_I2S tristate -- cgit v1.2.3 From 453c499028bf2ecf3b31ccb7c3657fe1b0b28943 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 14 Nov 2013 11:35:34 +0200 Subject: ASoC: davinci-mcasp: Support for McASP version found in DRA7xx The IP in DRA7xx is similar to the IP found in TI81xxAM3xxx/AM4xxx type of SoCs but it is is integrated with sDMA instead of eDMA. The suitable pcm driver for DRA7xx is the omap-pcm driver which is using dmaengine. In the driver we can configure both dma related structures used for eDMA and sDMA. The only thing we need to make sure that we set the correct dma_data at startup with snd_soc_dai_set_dma_data() Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- .../bindings/sound/davinci-mcasp-audio.txt | 1 + include/linux/platform_data/davinci_asp.h | 1 + sound/soc/davinci/davinci-mcasp.c | 52 +++++++++++++++++++--- 3 files changed, 47 insertions(+), 7 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index 1eed972d4719..990fa71ce804 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -5,6 +5,7 @@ Required properties: "ti,dm646x-mcasp-audio" : for DM646x platforms "ti,da830-mcasp-audio" : for both DA830 & DA850 platforms "ti,am33xx-mcasp-audio" : for AM33xx platforms (AM33xx, AM43xx, TI81xx) + "ti,dra7-mcasp-audio" : for DRA7xx platforms - reg : Should contain reg specifiers for the entries in the reg-names property. - reg-names : Should contain: diff --git a/include/linux/platform_data/davinci_asp.h b/include/linux/platform_data/davinci_asp.h index 689a856b86f9..5245992b0367 100644 --- a/include/linux/platform_data/davinci_asp.h +++ b/include/linux/platform_data/davinci_asp.h @@ -92,6 +92,7 @@ enum { MCASP_VERSION_1 = 0, /* DM646x */ MCASP_VERSION_2, /* DA8xx/OMAPL1x */ MCASP_VERSION_3, /* TI81xx/AM33xx */ + MCASP_VERSION_4, /* DRA7xxx */ }; enum mcbsp_clk_input_pin { diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 93f2e294d649..fc8c13d2f31e 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -31,12 +31,14 @@ #include #include #include +#include #include "davinci-pcm.h" #include "davinci-mcasp.h" struct davinci_mcasp { struct davinci_pcm_dma_params dma_params[2]; + struct snd_dmaengine_dai_dma_data dma_data[2]; void __iomem *base; u32 fifo_base; struct device *dev; @@ -458,7 +460,9 @@ static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream, u8 max_active_serializers = (channels + slots - 1) / slots; u32 reg; /* Default configuration */ - mcasp_set_bits(mcasp->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); + if (mcasp->version != MCASP_VERSION_4) + mcasp_set_bits(mcasp->base + DAVINCI_MCASP_PWREMUMGT_REG, + MCASP_SOFT); /* All PINS as McASP */ mcasp_set_reg(mcasp->base + DAVINCI_MCASP_PFUNC_REG, 0x00000000); @@ -605,6 +609,8 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[substream->stream]; + struct snd_dmaengine_dai_dma_data *dma_data = + &mcasp->dma_data[substream->stream]; int word_length; u8 fifo_level; u8 slots = mcasp->tdm_slots; @@ -666,6 +672,8 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, dma_params->acnt = dma_params->data_type; dma_params->fifo_level = fifo_level; + dma_data->maxburst = fifo_level; + davinci_config_channel_size(mcasp, word_length); return 0; @@ -711,7 +719,12 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); - snd_soc_dai_set_dma_data(dai, substream, mcasp->dma_params); + if (mcasp->version == MCASP_VERSION_4) + snd_soc_dai_set_dma_data(dai, substream, + &mcasp->dma_data[substream->stream]); + else + snd_soc_dai_set_dma_data(dai, substream, mcasp->dma_params); + return 0; } @@ -794,6 +807,13 @@ static struct snd_platform_data omap2_mcasp_pdata = { .version = MCASP_VERSION_3, }; +static struct snd_platform_data dra7_mcasp_pdata = { + .tx_dma_offset = 0x200, + .rx_dma_offset = 0x284, + .asp_chan_q = EVENTQ_0, + .version = MCASP_VERSION_4, +}; + static const struct of_device_id mcasp_dt_ids[] = { { .compatible = "ti,dm646x-mcasp-audio", @@ -807,6 +827,10 @@ static const struct of_device_id mcasp_dt_ids[] = { .compatible = "ti,am33xx-mcasp-audio", .data = &omap2_mcasp_pdata, }, + { + .compatible = "ti,dra7-mcasp-audio", + .data = &dra7_mcasp_pdata, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mcasp_dt_ids); @@ -999,6 +1023,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev) else dma_data->dma_addr = mem->start + pdata->tx_dma_offset; + /* Unconditional dmaengine stuff */ + mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_data->dma_addr; + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (res) dma_data->channel = res->start; @@ -1015,6 +1042,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev) else dma_data->dma_addr = mem->start + pdata->rx_dma_offset; + /* Unconditional dmaengine stuff */ + mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_data->dma_addr; + if (mcasp->version < MCASP_VERSION_3) { mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE; /* dma_data->dma_addr is pointing to the data port address */ @@ -1029,6 +1059,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev) else dma_data->channel = pdata->rx_dma_channel; + /* Unconditional dmaengine stuff */ + mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx"; + mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = "rx"; + dev_set_drvdata(&pdev->dev, mcasp); ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, &davinci_mcasp_dai[pdata->op_mode], 1); @@ -1036,10 +1070,12 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (ret != 0) goto err_release_clk; - ret = davinci_soc_platform_register(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - goto err_unregister_component; + if (mcasp->version != MCASP_VERSION_4) { + ret = davinci_soc_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "register PCM failed: %d\n", ret); + goto err_unregister_component; + } } return 0; @@ -1054,9 +1090,11 @@ err_release_clk: static int davinci_mcasp_remove(struct platform_device *pdev) { + struct davinci_mcasp *mcasp = dev_get_drvdata(&pdev->dev); snd_soc_unregister_component(&pdev->dev); - davinci_soc_platform_unregister(&pdev->dev); + if (mcasp->version != MCASP_VERSION_4) + davinci_soc_platform_unregister(&pdev->dev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); -- cgit v1.2.3 From ae726e93946403b14f8cad20d5cbd22d015c9106 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 14 Nov 2013 11:35:35 +0200 Subject: ASoC: davinci-mcasp: Support for fck reparenting Optional DT property to specify the desired parent clock for the McASP fck clock. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- .../bindings/sound/davinci-mcasp-audio.txt | 3 +- sound/soc/davinci/davinci-mcasp.c | 44 ++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index 990fa71ce804..569b26c4a81e 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -37,7 +37,8 @@ Optional properties: - pinctrl-0: Should specify pin control group used for this controller. - pinctrl-names: Should contain only one value - "default", for more details please refer to pinctrl-bindings.txt - +- fck_parent : Should contain a valid clock name which will be used as parent + for the McASP fck Example: diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 8ec879548488..b7858bfa0295 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -823,6 +824,46 @@ static const struct of_device_id mcasp_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, mcasp_dt_ids); +static int mcasp_reparent_fck(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct clk *gfclk, *parent_clk; + const char *parent_name; + int ret; + + if (!node) + return 0; + + parent_name = of_get_property(node, "fck_parent", NULL); + if (!parent_name) + return 0; + + gfclk = clk_get(&pdev->dev, "fck"); + if (IS_ERR(gfclk)) { + dev_err(&pdev->dev, "failed to get fck\n"); + return PTR_ERR(gfclk); + } + + parent_clk = clk_get(NULL, parent_name); + if (IS_ERR(parent_clk)) { + dev_err(&pdev->dev, "failed to get parent clock\n"); + ret = PTR_ERR(parent_clk); + goto err1; + } + + ret = clk_set_parent(gfclk, parent_clk); + if (ret) { + dev_err(&pdev->dev, "failed to reparent fck\n"); + goto err2; + } + +err2: + clk_put(parent_clk); +err1: + clk_put(gfclk); + return ret; +} + static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( struct platform_device *pdev) { @@ -1052,6 +1093,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev) mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = "rx"; dev_set_drvdata(&pdev->dev, mcasp); + + mcasp_reparent_fck(pdev); + ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, &davinci_mcasp_dai[pdata->op_mode], 1); -- cgit v1.2.3 From dbb4e67fe7088f963007453ee07e453c4e1fab28 Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Sat, 23 Nov 2013 16:26:52 -0500 Subject: clk: keystone: use clkod register bits for postdiv DDR3A/B, ARM and PA PLL controllers have clkod register bits for configuring postdiv values. So use it instead of using fixed post dividers for these pll controllers. Assume that if fixed-postdiv attribute is not present, use clkod register value for pistdiv. Also update the Documentation of bindings to reflect the same. Cc: Mike Turquette Signed-off-by: Santosh Shilimkar --- .../devicetree/bindings/clock/keystone-pll.txt | 8 ++++---- drivers/clk/keystone/pll.c | 24 ++++++++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/keystone-pll.txt b/Documentation/devicetree/bindings/clock/keystone-pll.txt index 12bd72605a31..225990f79b7c 100644 --- a/Documentation/devicetree/bindings/clock/keystone-pll.txt +++ b/Documentation/devicetree/bindings/clock/keystone-pll.txt @@ -17,13 +17,14 @@ Required properties: - reg - pll control0 and pll multipler registers - reg-names : control and multiplier. The multiplier is applicable only for main pll clock -- fixed-postdiv : fixed post divider value +- fixed-postdiv : fixed post divider value. If absent, use clkod register bits + for postdiv Example: mainpllclk: mainpllclk@2310110 { #clock-cells = <0>; compatible = "ti,keystone,main-pll-clock"; - clocks = <&refclkmain>; + clocks = <&refclksys>; reg = <0x02620350 4>, <0x02310110 4>; reg-names = "control", "multiplier"; fixed-postdiv = <2>; @@ -32,11 +33,10 @@ Example: papllclk: papllclk@2620358 { #clock-cells = <0>; compatible = "ti,keystone,pll-clock"; - clocks = <&refclkmain>; + clocks = <&refclkpass>; clock-output-names = "pa-pll-clk"; reg = <0x02620358 4>; reg-names = "control"; - fixed-postdiv = <6>; }; Required properties: diff --git a/drivers/clk/keystone/pll.c b/drivers/clk/keystone/pll.c index 47a1bd9f1726..0dd8a4b12747 100644 --- a/drivers/clk/keystone/pll.c +++ b/drivers/clk/keystone/pll.c @@ -24,6 +24,8 @@ #define MAIN_PLLM_HIGH_MASK 0x7f000 #define PLLM_HIGH_SHIFT 6 #define PLLD_MASK 0x3f +#define CLKOD_MASK 0x780000 +#define CLKOD_SHIFT 19 /** * struct clk_pll_data - pll data structure @@ -41,7 +43,10 @@ * @pllm_upper_mask: multiplier upper mask * @pllm_upper_shift: multiplier upper shift * @plld_mask: divider mask - * @postdiv: Post divider + * @clkod_mask: output divider mask + * @clkod_shift: output divider shift + * @plld_mask: divider mask + * @postdiv: Fixed post divider */ struct clk_pll_data { bool has_pllctrl; @@ -53,6 +58,8 @@ struct clk_pll_data { u32 pllm_upper_mask; u32 pllm_upper_shift; u32 plld_mask; + u32 clkod_mask; + u32 clkod_shift; u32 postdiv; }; @@ -90,7 +97,13 @@ static unsigned long clk_pllclk_recalc(struct clk_hw *hw, mult |= ((val & pll_data->pllm_upper_mask) >> pll_data->pllm_upper_shift); prediv = (val & pll_data->plld_mask); - postdiv = pll_data->postdiv; + + if (!pll_data->has_pllctrl) + /* read post divider from od bits*/ + postdiv = ((val & pll_data->clkod_mask) >> + pll_data->clkod_shift) + 1; + else + postdiv = pll_data->postdiv; rate /= (prediv + 1); rate = (rate * (mult + 1)); @@ -155,8 +168,11 @@ static void __init _of_pll_clk_init(struct device_node *node, bool pllctrl) } parent_name = of_clk_get_parent_name(node, 0); - if (of_property_read_u32(node, "fixed-postdiv", &pll_data->postdiv)) - goto out; + if (of_property_read_u32(node, "fixed-postdiv", &pll_data->postdiv)) { + /* assume the PLL has output divider register bits */ + pll_data->clkod_mask = CLKOD_MASK; + pll_data->clkod_shift = CLKOD_SHIFT; + } i = of_property_match_string(node, "reg-names", "control"); pll_data->pll_ctl0 = of_iomap(node, i); -- cgit v1.2.3 From 8a38db133358f9370e6bb453371e630495c59070 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 5 Dec 2013 15:38:19 -0300 Subject: [media] doc: no singing Stop that, stop that! You're not going to do a song while I'm here. Signed-off-by: Kees Cook Signed-off-by: Mauro Carvalho Chehab --- Documentation/cgroups/resource_counter.txt | 2 +- Documentation/video4linux/si476x.txt | 2 +- arch/score/lib/checksum.S | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/cgroups/resource_counter.txt b/Documentation/cgroups/resource_counter.txt index c4d99ed0b418..caa6d662b230 100644 --- a/Documentation/cgroups/resource_counter.txt +++ b/Documentation/cgroups/resource_counter.txt @@ -95,7 +95,7 @@ to work with it. f. u64 res_counter_uncharge_until (struct res_counter *rc, struct res_counter *top, - unsinged long val) + unsigned long val) Almost same as res_cunter_uncharge() but propagation of uncharge stops when rc == top. This is useful when kill a res_coutner in diff --git a/Documentation/video4linux/si476x.txt b/Documentation/video4linux/si476x.txt index 2f9b4875ab8a..616607955aaf 100644 --- a/Documentation/video4linux/si476x.txt +++ b/Documentation/video4linux/si476x.txt @@ -147,7 +147,7 @@ The drivers exposes following files: -------------------------------------------------------------------- 0x12 | readfreq | Current tuned frequency -------------------------------------------------------------------- - 0x14 | freqoff | Singed frequency offset in units of + 0x14 | freqoff | Signed frequency offset in units of | | 2ppm -------------------------------------------------------------------- 0x15 | rssi | Signed value of RSSI in dBuV diff --git a/arch/score/lib/checksum.S b/arch/score/lib/checksum.S index 706157edc7d5..1141f2b4a501 100644 --- a/arch/score/lib/checksum.S +++ b/arch/score/lib/checksum.S @@ -137,7 +137,7 @@ ENTRY(csum_partial) ldi r25, 0 mv r10, r5 cmpi.c r5, 0x8 - blt small_csumcpy /* < 8(singed) bytes to copy */ + blt small_csumcpy /* < 8(signed) bytes to copy */ cmpi.c r5, 0x0 beq out andri.c r25, src, 0x1 /* odd buffer? */ -- cgit v1.2.3 From 4bd8eabc29e17d9b29cee16077e1621e209a1b27 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 19 Nov 2013 09:50:48 -0500 Subject: nfsd4: update 4.1 nfsd status documentation This has gone a little stale. Reported-by: Christoph Hellwig Reviewed-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- Documentation/filesystems/nfs/nfs41-server.txt | 42 +++++++++----------------- 1 file changed, 14 insertions(+), 28 deletions(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/nfs/nfs41-server.txt b/Documentation/filesystems/nfs/nfs41-server.txt index 01c2db769791..b930ad087780 100644 --- a/Documentation/filesystems/nfs/nfs41-server.txt +++ b/Documentation/filesystems/nfs/nfs41-server.txt @@ -5,11 +5,11 @@ Server support for minorversion 1 can be controlled using the by reading this file will contain either "+4.1" or "-4.1" correspondingly. -Currently, server support for minorversion 1 is disabled by default. -It can be enabled at run time by writing the string "+4.1" to +Currently, server support for minorversion 1 is enabled by default. +It can be disabled at run time by writing the string "-4.1" to the /proc/fs/nfsd/versions control file. Note that to write this -control file, the nfsd service must be taken down. Use your user-mode -nfs-utils to set this up; see rpc.nfsd(8) +control file, the nfsd service must be taken down. You can use rpc.nfsd +for this; see rpc.nfsd(8). (Warning: older servers will interpret "+4.1" and "-4.1" as "+4" and "-4", respectively. Therefore, code meant to work on both new and old @@ -29,29 +29,6 @@ are still under development out of tree. See http://wiki.linux-nfs.org/wiki/index.php/PNFS_prototype_design for more information. -The current implementation is intended for developers only: while it -does support ordinary file operations on clients we have tested against -(including the linux client), it is incomplete in ways which may limit -features unexpectedly, cause known bugs in rare cases, or cause -interoperability problems with future clients. Known issues: - - - gss support is questionable: currently mounts with kerberos - from a linux client are possible, but we aren't really - conformant with the spec (for example, we don't use kerberos - on the backchannel correctly). - - We do not support SSV, which provides security for shared - client-server state (thus preventing unauthorized tampering - with locks and opens, for example). It is mandatory for - servers to support this, though no clients use it yet. - -In addition, some limitations are inherited from the current NFSv4 -implementation: - - - Incomplete delegation enforcement: if a file is renamed or - unlinked by a local process, a client holding a delegation may - continue to indefinitely allow opens of the file under the old - name. - The table below, taken from the NFSv4.1 document, lists the operations that are mandatory to implement (REQ), optional (OPT), and NFSv4.0 operations that are required not to implement (MNI) @@ -169,6 +146,16 @@ NS*| CB_WANTS_CANCELLED | OPT | FDELG, | Section 20.10 | Implementation notes: +SSV: +* The spec claims this is mandatory, but we don't actually know of any + implementations, so we're ignoring it for now. The server returns + NFS4ERR_ENCR_ALG_UNSUPP on EXCHANGE_ID, which should be future-proof. + +GSS on the backchannel: +* Again, theoretically required but not widely implemented (in + particular, the current Linux client doesn't request it). We return + NFS4ERR_ENCR_ALG_UNSUPP on CREATE_SESSION. + DELEGPURGE: * mandatory only for servers that support CLAIM_DELEGATE_PREV and/or CLAIM_DELEG_PREV_FH (which allows clients to keep delegations that @@ -176,7 +163,6 @@ DELEGPURGE: now. EXCHANGE_ID: -* only SP4_NONE state protection supported * implementation ids are ignored CREATE_SESSION: -- cgit v1.2.3 From a8b1c0193602b7ecdeaa7aa8c15c9c3da33244c8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 4 Dec 2013 13:22:37 +0100 Subject: Documentation: start documenting driver design patterns After realizing that we tend to tell developers the same thing over and over, let's attempt to document some commin design patterns used in the device drivers. The idea is that this can be extended so I just start out with two well-known design patterns. Cc: Rob Landley Cc: Mark Brown Cc: Arnd Bergmann Cc: Grant Likely Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-model/design-patterns.txt | 116 +++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 Documentation/driver-model/design-patterns.txt (limited to 'Documentation') diff --git a/Documentation/driver-model/design-patterns.txt b/Documentation/driver-model/design-patterns.txt new file mode 100644 index 000000000000..9ef8c1684558 --- /dev/null +++ b/Documentation/driver-model/design-patterns.txt @@ -0,0 +1,116 @@ + +Device Driver Design Patterns +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This document describes a few common design patterns found in device drivers. +It is likely that subsystem maintainers will ask driver developers to +conform to these design patterns. + +1. State Container +2. container_of() + + +1. State Container +~~~~~~~~~~~~~~~~~~ + +While the kernel contains a few device drivers that assume that they will +only be probed() once on a certain system (singletons), it is custom to assume +that the device the driver binds to will appear in several instances. This +means that the probe() function and all callbacks need to be reentrant. + +The most common way to achieve this is to use the state container design +pattern. It usually has this form: + +struct foo { + spinlock_t lock; /* Example member */ + (...) +}; + +static int foo_probe(...) +{ + struct foo *foo; + + foo = devm_kzalloc(dev, sizeof(*foo), GFP_KERNEL); + if (!foo) + return -ENOMEM; + spin_lock_init(&foo->lock); + (...) +} + +This will create an instance of struct foo in memory every time probe() is +called. This is our state container for this instance of the device driver. +Of course it is then necessary to always pass this instance of the +state around to all functions that need access to the state and its members. + +For example, if the driver is registering an interrupt handler, you would +pass around a pointer to struct foo like this: + +static irqreturn_t foo_handler(int irq, void *arg) +{ + struct foo *foo = arg; + (...) +} + +static int foo_probe(...) +{ + struct foo *foo; + + (...) + ret = request_irq(irq, foo_handler, 0, "foo", foo); +} + +This way you always get a pointer back to the correct instance of foo in +your interrupt handler. + + +2. container_of() +~~~~~~~~~~~~~~~~~ + +Continuing on the above example we add a offloaded work: + +struct foo { + spinlock_t lock; + struct workqueue_struct *wq; + struct work_struct offload; + (...) +}; + +static void foo_work(struct work_struct *work) +{ + struct foo *foo = container_of(work, struct foo, offload); + + (...) +} + +static irqreturn_t foo_handler(int irq, void *arg) +{ + struct foo *foo = arg; + + queue_work(foo->wq, &foo->offload); + (...) +} + +static int foo_probe(...) +{ + struct foo *foo; + + foo->wq = create_singlethread_workqueue("foo-wq"); + INIT_WORK(&foo->offload, foo_work); + (...) +} + +The design pattern is the same for a a hrtimer or something similar that will +return a single argument which is a pointer to a struct member in the +callback. + +container_of() is a macro defined in + +What container_of() does is to obtain a pointer to the containing struct from +a pointer to a member by a simple subtraction using the offsetof() macro from +standard C, which allows something similar to object oriented behaviours. +Notice that the contained member must not be a pointer, but an actual member +for this to work. + +We can see here that we avoid having global pointers to our struct foo * +instance this way, while still keeping the number of parameters passed to the +work function to a single pointer. -- cgit v1.2.3 From 937d9f5511a5507e517ecdbd48ac8185ea78ab7e Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Fri, 6 Dec 2013 18:04:42 +0900 Subject: Documentation: HOWTO: Update broken links to tpp Sites for 'The Perfect Patch' which described on HOWTO document(kerneltrap.org and userweb.kernel.org) are down. Change those links to the copy at ozlabs. Signed-off-by: SeongJae Park Signed-off-by: Greg Kroah-Hartman --- Documentation/HOWTO | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/HOWTO b/Documentation/HOWTO index 27faae3e3846..57cf5efb044d 100644 --- a/Documentation/HOWTO +++ b/Documentation/HOWTO @@ -112,7 +112,7 @@ required reading: Other excellent descriptions of how to create patches properly are: "The Perfect Patch" - http://kerneltrap.org/node/3737 + http://www.ozlabs.org/~akpm/stuff/tpp.txt "Linux kernel patch submission format" http://linux.yyz.us/patch-format.html @@ -579,7 +579,7 @@ all time. It should describe the patch completely, containing: For more details on what this should all look like, please see the ChangeLog section of the document: "The Perfect Patch" - http://userweb.kernel.org/~akpm/stuff/tpp.txt + http://www.ozlabs.org/~akpm/stuff/tpp.txt -- cgit v1.2.3 From 2f533715a7e47f59b9e81b7a0a673aa2d59b62ee Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Fri, 6 Dec 2013 18:04:43 +0900 Subject: Documentation: ko_KR: Update broken link to tpp Links for 'The Perfect Patch' which described on HOWTO document is broken. Change those links to the copy at ozlabs. Signed-off-by: SeongJae Park Signed-off-by: Greg Kroah-Hartman --- Documentation/ko_KR/HOWTO | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ko_KR/HOWTO b/Documentation/ko_KR/HOWTO index 680e64635958..d61a45acff4e 100644 --- a/Documentation/ko_KR/HOWTO +++ b/Documentation/ko_KR/HOWTO @@ -122,7 +122,7 @@ mtk.manpages@gmail.com의 메인테이너에게 보낼 것을 권장한다. 올바른 패치들을 만드는 법에 관한 훌륭한 다른 문서들이 있다. "The Perfect Patch" - http://userweb.kernel.org/~akpm/stuff/tpp.txt + http://www.ozlabs.org/~akpm/stuff/tpp.txt "Linux kernel patch submission format" http://linux.yyz.us/patch-format.html @@ -597,7 +597,7 @@ Pat이라는 이름을 가진 여자가 있을 수도 있는 것이다. 리눅 이것이 무엇인지 더 자세한 것을 알고 싶다면 다음 문서의 ChageLog 항을 봐라. "The Perfect Patch" - http://userweb.kernel.org/~akpm/stuff/tpp.txt + http://www.ozlabs.org/~akpm/stuff/tpp.txt -- cgit v1.2.3 From 7aca5a7f4911044b45c1b35defb4f7f225dd5686 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Fri, 6 Dec 2013 18:04:44 +0900 Subject: Documentation: zh_CN: Update broken link to tpp Links for 'The Perfect Patch' which described on HOWTO document is broken. Change those links to the copy at ozlabs. Signed-off-by: SeongJae Park Signed-off-by: Greg Kroah-Hartman --- Documentation/zh_CN/HOWTO | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/zh_CN/HOWTO b/Documentation/zh_CN/HOWTO index 7fba5aab9ef9..6c914aa87e71 100644 --- a/Documentation/zh_CN/HOWTO +++ b/Documentation/zh_CN/HOWTO @@ -112,7 +112,7 @@ Linux内核代码中包含有大量的文档。这些文档对于学习如何与 其他关于如何正确地生成补丁的优秀文档包括: "The Perfect Patch" - http://userweb.kernel.org/~akpm/stuff/tpp.txt + http://www.ozlabs.org/~akpm/stuff/tpp.txt "Linux kernel patch submission format" http://linux.yyz.us/patch-format.html @@ -515,7 +515,7 @@ Linux内核社区并不喜欢一下接收大段的代码。修改需要被恰当 想了解它具体应该看起来像什么,请查阅以下文档中的“ChangeLog”章节: “The Perfect Patch” - http://userweb.kernel.org/~akpm/stuff/tpp.txt + http://www.ozlabs.org/~akpm/stuff/tpp.txt 这些事情有时候做起来很难。要在任何方面都做到完美可能需要好几年时间。这是 -- cgit v1.2.3 From 4fc6069e7df873bda9baabe0fa9f0be23363159a Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Fri, 6 Dec 2013 18:04:45 +0900 Subject: Documentation: ja_JP: Update broken link to tpp Links for 'The Perfect Patch' which described on HOWTO document is broken. Change those links to the copy at ozlabs. Signed-off-by: SeongJae Park Signed-off-by: Greg Kroah-Hartman --- Documentation/ja_JP/HOWTO | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ja_JP/HOWTO b/Documentation/ja_JP/HOWTO index 8148a47fc70e..0091a8215ac1 100644 --- a/Documentation/ja_JP/HOWTO +++ b/Documentation/ja_JP/HOWTO @@ -149,7 +149,7 @@ linux-api@ver.kernel.org に送ることを勧めます。 この他にパッチを作る方法についてのよくできた記述は- "The Perfect Patch" - http://userweb.kernel.org/~akpm/stuff/tpp.txt + http://www.ozlabs.org/~akpm/stuff/tpp.txt "Linux kernel patch submission format" http://linux.yyz.us/patch-format.html @@ -622,7 +622,7 @@ Linux カーネルコミュニティは、一度に大量のコードの塊を これについて全てがどのようにあるべきかについての詳細は、以下のドキュメ ントの ChangeLog セクションを見てください- "The Perfect Patch" - http://userweb.kernel.org/~akpm/stuff/tpp.txt + http://www.ozlabs.org/~akpm/stuff/tpp.txt これらのどれもが、時にはとても困難です。これらの慣例を完璧に実施するに は数年かかるかもしれません。これは継続的な改善のプロセスであり、そのた -- cgit v1.2.3 From 7e941a7999fe5ece856c066ba94c929870e30fe0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 10 Jul 2013 12:05:06 -0300 Subject: [media] v4l: Add media format codes for AHSV8888 on 32-bit busses Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/subdev-formats.xml | 157 +++++++++++++++++++++ include/uapi/linux/v4l2-mediabus.h | 3 + 2 files changed, 160 insertions(+) (limited to 'Documentation') diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index f72c1cc93a9b..bfaef5078eb8 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -2491,6 +2491,163 @@ +

+ HSV/HSL Formats + + Those formats transfer pixel data as RGB values in a cylindrical-coordinate + system using Hue-Saturation-Value or Hue-Saturation-Lightness components. The + format code is made of the following information. + + The hue, saturation, value or lightness and optional alpha + components order code, as encoded in a pixel sample. The only currently + supported value is AHSV. + + The number of bits per component, for each component. The values + can be different for all components. The only currently supported value is 8888. + + The number of bus samples per pixel. Pixels that are wider than + the bus width must be transferred in multiple samples. The only currently + supported value is 1. + The bus width. + For formats where the total number of bits per pixel is smaller + than the number of bus samples per pixel times the bus width, a padding + value stating if the bytes are padded in their most high order bits + (PADHI) or low order bits (PADLO). + For formats where the number of bus samples per pixel is larger + than 1, an endianness value stating if the pixel is transferred MSB first + (BE) or LSB first (LE). + + + + The following table lists existing HSV/HSL formats. + + + HSV/HSL formats + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Identifier + Code + + Data organization + + + + + Bit + 31 + 30 + 29 + 28 + 27 + 26 + 25 + 24 + 23 + 22 + 21 + 20 + 19 + 18 + 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0 + + + + + V4L2_MBUS_FMT_AHSV8888_1X32 + 0x6001 + + a7 + a6 + a5 + a4 + a3 + a2 + a1 + a0 + h7 + h6 + h5 + h4 + h3 + h2 + h1 + h0 + s7 + s6 + s5 + s4 + s3 + s2 + s1 + s0 + v7 + v6 + v5 + v4 + v3 + v2 + v1 + v0 + + + +
+
+
JPEG Compressed Formats diff --git a/include/uapi/linux/v4l2-mediabus.h b/include/uapi/linux/v4l2-mediabus.h index a9601257bb43..b5c3aab6e82c 100644 --- a/include/uapi/linux/v4l2-mediabus.h +++ b/include/uapi/linux/v4l2-mediabus.h @@ -110,6 +110,9 @@ enum v4l2_mbus_pixelcode { /* S5C73M3 sensor specific interleaved UYVY and JPEG */ V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8 = 0x5001, + + /* HSV - next is 0x6002 */ + V4L2_MBUS_FMT_AHSV8888_1X32 = 0x6001, }; /** -- cgit v1.2.3 From d9101fca3d572b8675b7fe3f4ef9f6f99bbf4364 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 13 Nov 2013 11:15:02 +0100 Subject: KVM: s390: diagnose call documentation Add some further documentation on the DIAGNOSE calls we support. Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- Documentation/virtual/kvm/hypercalls.txt | 3 ++ Documentation/virtual/kvm/s390-diag.txt | 80 ++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 Documentation/virtual/kvm/s390-diag.txt (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/hypercalls.txt b/Documentation/virtual/kvm/hypercalls.txt index 022198e389d7..d922d73efa7b 100644 --- a/Documentation/virtual/kvm/hypercalls.txt +++ b/Documentation/virtual/kvm/hypercalls.txt @@ -17,6 +17,9 @@ S390: S390 uses diagnose instruction as hypercall (0x500) along with hypercall number in R1. + For further information on the S390 diagnose call as supported by KVM, + refer to Documentation/virtual/kvm/s390-diag.txt. + PowerPC: It uses R3-R10 and hypercall number in R11. R4-R11 are used as output registers. Return value is placed in R3. diff --git a/Documentation/virtual/kvm/s390-diag.txt b/Documentation/virtual/kvm/s390-diag.txt new file mode 100644 index 000000000000..f1de4fbade15 --- /dev/null +++ b/Documentation/virtual/kvm/s390-diag.txt @@ -0,0 +1,80 @@ +The s390 DIAGNOSE call on KVM +============================= + +KVM on s390 supports the DIAGNOSE call for making hypercalls, both for +native hypercalls and for selected hypercalls found on other s390 +hypervisors. + +Note that bits are numbered as by the usual s390 convention (most significant +bit on the left). + + +General remarks +--------------- + +DIAGNOSE calls by the guest cause a mandatory intercept. This implies +all supported DIAGNOSE calls need to be handled by either KVM or its +userspace. + +All DIAGNOSE calls supported by KVM use the RS-a format: + +-------------------------------------- +| '83' | R1 | R3 | B2 | D2 | +-------------------------------------- +0 8 12 16 20 31 + +The second-operand address (obtained by the base/displacement calculation) +is not used to address data. Instead, bits 48-63 of this address specify +the function code, and bits 0-47 are ignored. + +The supported DIAGNOSE function codes vary by the userspace used. For +DIAGNOSE function codes not specific to KVM, please refer to the +documentation for the s390 hypervisors defining them. + + +DIAGNOSE function code 'X'500' - KVM virtio functions +----------------------------------------------------- + +If the function code specifies 0x500, various virtio-related functions +are performed. + +General register 1 contains the virtio subfunction code. Supported +virtio subfunctions depend on KVM's userspace. Generally, userspace +provides either s390-virtio (subcodes 0-2) or virtio-ccw (subcode 3). + +Upon completion of the DIAGNOSE instruction, general register 2 contains +the function's return code, which is either a return code or a subcode +specific value. + +Subcode 0 - s390-virtio notification and early console printk + Handled by userspace. + +Subcode 1 - s390-virtio reset + Handled by userspace. + +Subcode 2 - s390-virtio set status + Handled by userspace. + +Subcode 3 - virtio-ccw notification + Handled by either userspace or KVM (ioeventfd case). + + General register 2 contains a subchannel-identification word denoting + the subchannel of the virtio-ccw proxy device to be notified. + + General register 3 contains the number of the virtqueue to be notified. + + General register 4 contains a 64bit identifier for KVM usage (the + kvm_io_bus cookie). If general register 4 does not contain a valid + identifier, it is ignored. + + After completion of the DIAGNOSE call, general register 2 may contain + a 64bit identifier (in the kvm_io_bus cookie case). + + See also the virtio standard for a discussion of this hypercall. + + +DIAGNOSE function code 'X'501 - KVM breakpoint +---------------------------------------------- + +If the function code specifies 0x501, breakpoint functions may be performed. +This function code is handled by userspace. -- cgit v1.2.3 From d8f64797c5ff3351a54830bba2cbc7e0b00e4613 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 6 Nov 2013 14:00:25 -0700 Subject: ARM: tegra: add missing clock documentation to DT bindings Many of the Tegra DT binding documents say nothing about the clocks or clock-names properties, yet those are present and required in DT files. This patch simply updates the documentation file to match the implicit definition of the binding, based on real-world DT content. All Tegra bindings that mention clocks are updated to have consistent wording and formatting of the clock-related properties. Signed-off-by: Stephen Warren Acked-By: Terje Bergstrom --- .../bindings/arm/tegra/nvidia,tegra20-pmc.txt | 1 + .../devicetree/bindings/dma/tegra20-apbdma.txt | 3 ++ .../bindings/gpu/nvidia,tegra20-host1x.txt | 59 ++++++++++++++++++++++ .../devicetree/bindings/i2c/nvidia,tegra20-i2c.txt | 14 ++--- .../bindings/input/nvidia,tegra20-kbc.txt | 3 ++ .../bindings/mmc/nvidia,tegra20-sdhci.txt | 3 ++ .../devicetree/bindings/nvec/nvidia,nvec.txt | 8 +++ .../bindings/pci/nvidia,tegra20-pcie.txt | 14 ++--- .../devicetree/bindings/pwm/nvidia,tegra20-pwm.txt | 3 ++ .../devicetree/bindings/rtc/nvidia,tegra20-rtc.txt | 3 ++ .../bindings/serial/nvidia,tegra20-hsuart.txt | 3 ++ .../bindings/sound/nvidia,tegra-audio-alc5632.txt | 7 +-- .../bindings/sound/nvidia,tegra-audio-rt5640.txt | 7 +-- .../bindings/sound/nvidia,tegra-audio-wm8753.txt | 7 +-- .../bindings/sound/nvidia,tegra-audio-wm8903.txt | 7 +-- .../bindings/sound/nvidia,tegra-audio-wm9712.txt | 7 +-- .../bindings/sound/nvidia,tegra20-ac97.txt | 4 ++ .../bindings/sound/nvidia,tegra20-i2s.txt | 3 ++ .../bindings/sound/nvidia,tegra30-ahub.txt | 21 ++++++-- .../bindings/sound/nvidia,tegra30-i2s.txt | 5 +- .../bindings/spi/nvidia,tegra114-spi.txt | 8 ++- .../bindings/spi/nvidia,tegra20-sflash.txt | 4 +- .../bindings/spi/nvidia,tegra20-slink.txt | 4 +- .../bindings/timer/nvidia,tegra20-timer.txt | 3 ++ .../bindings/timer/nvidia,tegra30-timer.txt | 3 ++ .../bindings/usb/nvidia,tegra20-ehci.txt | 3 +- arch/arm/boot/dts/tegra20.dtsi | 4 +- arch/arm/boot/dts/tegra30.dtsi | 4 +- 28 files changed, 173 insertions(+), 42 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt index 1608a54e90e1..68ac65f82a1c 100644 --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt @@ -9,6 +9,7 @@ Required properties: - compatible : Should contain "nvidia,tegra-pmc". - reg : Offset and length of the register set for the device - clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. - clock-names : Must include the following entries: "pclk" (The Tegra clock of that name), "clk32k_in" (The 32KHz clock input to Tegra). diff --git a/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt index 90fa7da525b8..e0a68b972891 100644 --- a/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt +++ b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt @@ -5,6 +5,8 @@ Required properties: - reg: Should contain DMA registers location and length. This shuld include all of the per-channel registers. - interrupts: Should contain all of the per-channel DMA interrupts. +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. Examples: @@ -27,4 +29,5 @@ apbdma: dma@6000a000 { 0 149 0x04 0 150 0x04 0 151 0x04 >; + clocks = <&tegra_car 34>; }; diff --git a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt index b4fa934ae3a2..8b4367f86b95 100644 --- a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt @@ -9,6 +9,8 @@ Required properties: - #size-cells: The number of cells used to represent the size of an address range in the host1x address space. Should be 1. - ranges: The mapping of the host1x address space to the CPU address space. +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. The host1x top-level node defines a number of children, each representing one of the following host1x client modules: @@ -19,6 +21,8 @@ of the following host1x client modules: - compatible: "nvidia,tegra-mpe" - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. - vi: video input @@ -26,6 +30,8 @@ of the following host1x client modules: - compatible: "nvidia,tegra-vi" - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. - epp: encoder pre-processor @@ -33,6 +39,8 @@ of the following host1x client modules: - compatible: "nvidia,tegra-epp" - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. - isp: image signal processor @@ -40,6 +48,8 @@ of the following host1x client modules: - compatible: "nvidia,tegra-isp" - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. - gr2d: 2D graphics engine @@ -47,12 +57,21 @@ of the following host1x client modules: - compatible: "nvidia,tegra-gr2d" - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. - gr3d: 3D graphics engine Required properties: - compatible: "nvidia,tegra-gr3d" - reg: Physical base address and length of the controller's registers. + - clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names: Must include the following entries: + (This property may be omitted if the only clock in the list is "3d") + - 3d + This MUST be the first entry. + - 3d2 (Only required on SoCs with two 3D clocks) - dc: display controller @@ -60,6 +79,12 @@ of the following host1x client modules: - compatible: "nvidia,tegra-dc" - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. + - clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names: Must include the following entries: + - dc + This MUST be the first entry. + - parent Each display controller node has a child node, named "rgb", that represents the RGB output associated with the controller. It can take the following @@ -76,6 +101,12 @@ of the following host1x client modules: - interrupts: The interrupt outputs from the controller. - vdd-supply: regulator for supply voltage - pll-supply: regulator for PLL + - clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names: Must include the following entries: + - hdmi + This MUST be the first entry. + - parent Optional properties: - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing @@ -88,12 +119,20 @@ of the following host1x client modules: - compatible: "nvidia,tegra-tvo" - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. - dsi: display serial interface Required properties: - compatible: "nvidia,tegra-dsi" - reg: Physical base address and length of the controller's registers. + - clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names: Must include the following entries: + - dsi + This MUST be the first entry. + - parent Example: @@ -105,6 +144,7 @@ Example: reg = <0x50000000 0x00024000>; interrupts = <0 65 0x04 /* mpcore syncpt */ 0 67 0x04>; /* mpcore general */ + clocks = <&tegra_car TEGRA20_CLK_HOST1X>; #address-cells = <1>; #size-cells = <1>; @@ -115,41 +155,50 @@ Example: compatible = "nvidia,tegra20-mpe"; reg = <0x54040000 0x00040000>; interrupts = <0 68 0x04>; + clocks = <&tegra_car TEGRA20_CLK_MPE>; }; vi { compatible = "nvidia,tegra20-vi"; reg = <0x54080000 0x00040000>; interrupts = <0 69 0x04>; + clocks = <&tegra_car TEGRA20_CLK_VI>; }; epp { compatible = "nvidia,tegra20-epp"; reg = <0x540c0000 0x00040000>; interrupts = <0 70 0x04>; + clocks = <&tegra_car TEGRA20_CLK_EPP>; }; isp { compatible = "nvidia,tegra20-isp"; reg = <0x54100000 0x00040000>; interrupts = <0 71 0x04>; + clocks = <&tegra_car TEGRA20_CLK_ISP>; }; gr2d { compatible = "nvidia,tegra20-gr2d"; reg = <0x54140000 0x00040000>; interrupts = <0 72 0x04>; + clocks = <&tegra_car TEGRA20_CLK_GR2D>; }; gr3d { compatible = "nvidia,tegra20-gr3d"; reg = <0x54180000 0x00040000>; + clocks = <&tegra_car TEGRA20_CLK_GR3D>; }; dc@54200000 { compatible = "nvidia,tegra20-dc"; reg = <0x54200000 0x00040000>; interrupts = <0 73 0x04>; + clocks = <&tegra_car TEGRA20_CLK_DISP1>, + <&tegra_car TEGRA20_CLK_PLL_P>; + clock-names = "disp1", "parent"; rgb { status = "disabled"; @@ -160,6 +209,9 @@ Example: compatible = "nvidia,tegra20-dc"; reg = <0x54240000 0x00040000>; interrupts = <0 74 0x04>; + clocks = <&tegra_car TEGRA20_CLK_DISP2>, + <&tegra_car TEGRA20_CLK_PLL_P>; + clock-names = "disp2", "parent"; rgb { status = "disabled"; @@ -170,6 +222,9 @@ Example: compatible = "nvidia,tegra20-hdmi"; reg = <0x54280000 0x00040000>; interrupts = <0 75 0x04>; + clocks = <&tegra_car TEGRA20_CLK_HDMI>, + <&tegra_car TEGRA20_CLK_PLL_D_OUT0>; + clock-names = "hdmi", "parent"; status = "disabled"; }; @@ -177,12 +232,16 @@ Example: compatible = "nvidia,tegra20-tvo"; reg = <0x542c0000 0x00040000>; interrupts = <0 76 0x04>; + clocks = <&tegra_car TEGRA20_CLK_TVO>; status = "disabled"; }; dsi { compatible = "nvidia,tegra20-dsi"; reg = <0x54300000 0x00040000>; + clocks = <&tegra_car TEGRA20_CLK_DSI>, + <&tegra_car TEGRA20_CLK_PLL_D_OUT0>; + clock-names = "dsi", "parent"; status = "disabled"; }; }; diff --git a/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt b/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt index ef77cc7a0e46..173fbaab687b 100644 --- a/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt +++ b/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt @@ -39,12 +39,14 @@ Required properties: - interrupts: Should contain I2C controller interrupts. - address-cells: Address cells for I2C device address. - size-cells: Size of the I2C device address. -- clocks: Clock ID as per - Documentation/devicetree/bindings/clock/tegra.txt - for I2C controller. -- clock-names: Name of the clock: - Tegra20/Tegra30 I2C controller: "div-clk and "fast-clk". - Tegra114 I2C controller: "div-clk". +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + Tegra20/Tegra30: + - div-clk + - fast-clk + Tegra114: + - div-clk Example: diff --git a/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt b/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt index 2995fae7ee47..7d5a53dd77d1 100644 --- a/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt +++ b/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt @@ -13,6 +13,8 @@ Required properties: array of pin numbers which is used as column. - linux,keymap: The keymap for keys as described in the binding document devicetree/bindings/input/matrix-keymap.txt. +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. Optional properties, in addition to those specified by the shared matrix-keyboard bindings: @@ -31,6 +33,7 @@ keyboard: keyboard { compatible = "nvidia,tegra20-kbc"; reg = <0x7000e200 0x100>; interrupts = <0 85 0x04>; + clocks = <&tegra_car 36>; nvidia,ghost-filter; nvidia,debounce-delay-ms = <640>; nvidia,kbc-row-pins = <0 1 2>; /* pin 0, 1, 2 as rows */ diff --git a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt index c6d7b11db9eb..f727902a9e8d 100644 --- a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt @@ -8,6 +8,8 @@ by mmc.txt and the properties used by the sdhci-tegra driver. Required properties: - compatible : Should be "nvidia,-sdhci" +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. Optional properties: - power-gpios : Specify GPIOs for power control @@ -18,6 +20,7 @@ sdhci@c8000200 { compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000200 0x200>; interrupts = <47>; + clocks = <&tegra_car 14>; cd-gpios = <&gpio 69 0>; /* gpio PI5 */ wp-gpios = <&gpio 57 0>; /* gpio PH1 */ power-gpios = <&gpio 155 0>; /* gpio PT3 */ diff --git a/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt b/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt index 5aeee53ff9f4..a97fe575ca29 100644 --- a/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt +++ b/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt @@ -7,3 +7,11 @@ Required properties: - clock-frequency : the frequency of the i2c bus - gpios : the gpio used for ec request - slave-addr: the i2c address of the slave controller +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + Tegra20/Tegra30: + - div-clk + - fast-clk + Tegra114: + - div-clk diff --git a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt index 6b7510775c50..9e22da7393a3 100644 --- a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt +++ b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt @@ -42,14 +42,14 @@ Required properties: - 0xc2000000: prefetchable memory region Please refer to the standard PCI bus binding document for a more detailed explanation. -- clocks: List of clock inputs of the controller. Must contain an entry for - each entry in the clock-names property. +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. - clock-names: Must include the following entries: - "pex": The Tegra clock of that name - "afi": The Tegra clock of that name - "pcie_xclk": The Tegra clock of that name - "pll_e": The Tegra clock of that name - "cml": The Tegra clock of that name (not required for Tegra20) + - pex + - afi + - pcie_xclk + - pll_e + - cml (not required for Tegra20) Root ports are defined as subnodes of the PCIe controller node. diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt index c3fc57af8772..f28128717dcc 100644 --- a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt +++ b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt @@ -7,6 +7,8 @@ Required properties: - reg: physical base address and length of the controller's registers - #pwm-cells: should be 2. See pwm.txt in this directory for a description of the cells format. +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. Example: @@ -14,4 +16,5 @@ Example: compatible = "nvidia,tegra20-pwm"; reg = <0x7000a000 0x100>; #pwm-cells = <2>; + clocks = <&tegra_car 17>; }; diff --git a/Documentation/devicetree/bindings/rtc/nvidia,tegra20-rtc.txt b/Documentation/devicetree/bindings/rtc/nvidia,tegra20-rtc.txt index 93f45e9dce7c..652d1ff2e8be 100644 --- a/Documentation/devicetree/bindings/rtc/nvidia,tegra20-rtc.txt +++ b/Documentation/devicetree/bindings/rtc/nvidia,tegra20-rtc.txt @@ -9,6 +9,8 @@ Required properties: - compatible : should be "nvidia,tegra20-rtc". - reg : Specifies base physical address and size of the registers. - interrupts : A single interrupt specifier. +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. Example: @@ -16,4 +18,5 @@ timer { compatible = "nvidia,tegra20-rtc"; reg = <0x7000e000 0x100>; interrupts = <0 2 0x04>; + clocks = <&tegra_car 4>; }; diff --git a/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt b/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt index 392a4493eebd..11eb6e71ddd6 100644 --- a/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt +++ b/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt @@ -6,6 +6,8 @@ Required properties: - interrupts: Should contain UART controller interrupts. - nvidia,dma-request-selector : The Tegra DMA controller's phandle and request selector for this UART controller. +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. Optional properties: - nvidia,enable-modem-interrupt: Enable modem interrupts. Should be enable @@ -20,5 +22,6 @@ serial@70006000 { interrupts = <0 36 0x04>; nvidia,dma-request-selector = <&apbdma 8>; nvidia,enable-modem-interrupt; + clocks = <&tegra_car 6>; status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt index 8b8903ef0800..57f40f93453e 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt @@ -3,10 +3,11 @@ NVIDIA Tegra audio complex Required properties: - compatible : "nvidia,tegra-audio-alc5632" - clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. - clock-names : Must include the following entries: - "pll_a" (The Tegra clock of that name), - "pll_a_out0" (The Tegra clock of that name), - "mclk" (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) - nvidia,model : The user-visible name of this sound complex. - nvidia,audio-routing : A list of the connections between audio components. Each entry is a pair of strings, the first being the connection's sink, diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt index dc6224994d69..7788808dcd0b 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt @@ -3,10 +3,11 @@ NVIDIA Tegra audio complex, with RT5640 CODEC Required properties: - compatible : "nvidia,tegra-audio-rt5640" - clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. - clock-names : Must include the following entries: - "pll_a" (The Tegra clock of that name), - "pll_a_out0" (The Tegra clock of that name), - "mclk" (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) - nvidia,model : The user-visible name of this sound complex. - nvidia,audio-routing : A list of the connections between audio components. Each entry is a pair of strings, the first being the connection's sink, diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt index aab6ce0ad2fc..96f6a57dd6b4 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt @@ -3,10 +3,11 @@ NVIDIA Tegra audio complex Required properties: - compatible : "nvidia,tegra-audio-wm8753" - clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. - clock-names : Must include the following entries: - "pll_a" (The Tegra clock of that name), - "pll_a_out0" (The Tegra clock of that name), - "mclk" (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) - nvidia,model : The user-visible name of this sound complex. - nvidia,audio-routing : A list of the connections between audio components. Each entry is a pair of strings, the first being the connection's sink, diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt index 4b44dfb6ca0d..b795d282818d 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt @@ -3,10 +3,11 @@ NVIDIA Tegra audio complex Required properties: - compatible : "nvidia,tegra-audio-wm8903" - clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. - clock-names : Must include the following entries: - "pll_a" (The Tegra clock of that name), - "pll_a_out0" (The Tegra clock of that name), - "mclk" (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) - nvidia,model : The user-visible name of this sound complex. - nvidia,audio-routing : A list of the connections between audio components. Each entry is a pair of strings, the first being the connection's sink, diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt index ad589b163639..436f6cd9d07c 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt @@ -3,10 +3,11 @@ NVIDIA Tegra audio complex Required properties: - compatible : "nvidia,tegra-audio-wm9712" - clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. - clock-names : Must include the following entries: - "pll_a" (The Tegra clock of that name), - "pll_a_out0" (The Tegra clock of that name), - "mclk" (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) - nvidia,model : The user-visible name of this sound complex. - nvidia,audio-routing : A list of the connections between audio components. Each entry is a pair of strings, the first being the connection's sink, diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt index c1454979c1ef..37f4ebf5b184 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt @@ -4,12 +4,15 @@ Required properties: - compatible : "nvidia,tegra20-ac97" - reg : Should contain AC97 controller registers location and length - interrupts : Should contain AC97 interrupt +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. - nvidia,dma-request-selector : The Tegra DMA controller's phandle and request selector for the AC97 controller - nvidia,codec-reset-gpio : The Tegra GPIO controller's phandle and the number of the GPIO used to reset the external AC97 codec - nvidia,codec-sync-gpio : The Tegra GPIO controller's phandle and the number of the GPIO corresponding with the AC97 DAP _FS line + Example: ac97@70002000 { @@ -19,4 +22,5 @@ ac97@70002000 { nvidia,dma-request-selector = <&apbdma 12>; nvidia,codec-reset-gpio = <&gpio 170 0>; nvidia,codec-sync-gpio = <&gpio 120 0>; + clocks = <&tegra_car 3>; }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt index 0df2b5c816e3..ba0c9452916d 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt @@ -4,6 +4,8 @@ Required properties: - compatible : "nvidia,tegra20-i2s" - reg : Should contain I2S registers location and length - interrupts : Should contain I2S interrupt +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. - nvidia,dma-request-selector : The Tegra DMA controller's phandle and request selector for this I2S controller @@ -14,4 +16,5 @@ i2s@70002800 { reg = <0x70002800 0x200>; interrupts = < 45 >; nvidia,dma-request-selector = < &apbdma 2 >; + clocks = <&tegra_car 11>; }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt index 0e5c12c66523..7299eeadd588 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt @@ -12,11 +12,24 @@ Required properties: If a single entry is present, the request selectors for the channels are assumed to be contiguous, and increment from this value. If multiple values are given, one value must be given per channel. -- clocks : Must contain an entry for each required entry in clock-names. +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. - clock-names : Must include the following entries: - - Tegra30: Requires d_audio, apbif, i2s0, i2s1, i2s2, i2s3, i2s4, dam0, - dam1, dam2, spdif_in. - - Tegra114: Additionally requires amx, adx. + Tegra30 and later: + - d_audio + - apbif + - i2s0 + - i2s1 + - i2s2 + - i2s3 + - i2s4 + - dam0 + - dam1 + - dam2 + - spdif_in + Tegra114 and later additionally require: + - amx + - adx - ranges : The bus address mapping for the configlink register bus. Can be empty since the mapping is 1:1. - #address-cells : For the configlink bus. Should be <1>; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt index dfa6c037124a..7a3112bc135c 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt @@ -3,13 +3,16 @@ NVIDIA Tegra30 I2S controller Required properties: - compatible : "nvidia,tegra30-i2s" - reg : Should contain I2S registers location and length +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. - nvidia,ahub-cif-ids : The list of AHUB CIF IDs for this port, rx (playback) first, tx (capture) second. See nvidia,tegra30-ahub.txt for values. Example: -i2s@70002800 { +i2s@70080300 { compatible = "nvidia,tegra30-i2s"; reg = <0x70080300 0x100>; nvidia,ahub-cif-ids = <4 4>; + clocks = <&tegra_car 11>; }; diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt index 91ff771c7e77..d4f2d534934b 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt @@ -6,8 +6,10 @@ Required properties: - interrupts: Should contain SPI interrupts. - nvidia,dma-request-selector : The Tegra DMA controller's phandle and request selector for this SPI controller. -- This is also require clock named "spi" as per binding document - Documentation/devicetree/bindings/clock/clock-bindings.txt +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - spi Recommended properties: - spi-max-frequency: Definition as per @@ -22,5 +24,7 @@ spi@7000d600 { spi-max-frequency = <25000000>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 44>; + clock-names = "spi"; status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt index 7b53da5cb75b..66e16c7f5939 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt @@ -6,6 +6,8 @@ Required properties: - interrupts: Should contain SFLASH interrupts. - nvidia,dma-request-selector : The Tegra DMA controller's phandle and request selector for this SFLASH controller. +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. Recommended properties: - spi-max-frequency: Definition as per @@ -21,6 +23,6 @@ spi@7000c380 { spi-max-frequency = <25000000>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 43>; status = "disabled"; }; - diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt index eefe15e3d95e..0e6e94eb2b2a 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt @@ -6,6 +6,8 @@ Required properties: - interrupts: Should contain SLINK interrupts. - nvidia,dma-request-selector : The Tegra DMA controller's phandle and request selector for this SLINK controller. +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. Recommended properties: - spi-max-frequency: Definition as per @@ -21,6 +23,6 @@ spi@7000d600 { spi-max-frequency = <25000000>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 44>; status = "disabled"; }; - diff --git a/Documentation/devicetree/bindings/timer/nvidia,tegra20-timer.txt b/Documentation/devicetree/bindings/timer/nvidia,tegra20-timer.txt index e019fdc38773..4a864bd10d3d 100644 --- a/Documentation/devicetree/bindings/timer/nvidia,tegra20-timer.txt +++ b/Documentation/devicetree/bindings/timer/nvidia,tegra20-timer.txt @@ -8,6 +8,8 @@ Required properties: - compatible : should be "nvidia,tegra20-timer". - reg : Specifies base physical address and size of the registers. - interrupts : A list of 4 interrupts; one per timer channel. +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. Example: @@ -18,4 +20,5 @@ timer { 0 1 0x04 0 41 0x04 0 42 0x04>; + clocks = <&tegra_car 132>; }; diff --git a/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt b/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt index 906109d4c593..b5082a1cf461 100644 --- a/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt +++ b/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt @@ -10,6 +10,8 @@ Required properties: - reg : Specifies base physical address and size of the registers. - interrupts : A list of 6 interrupts; one per each of timer channels 1 through 5, and one for the shared interrupt for the remaining channels. +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. timer { compatible = "nvidia,tegra30-timer", "nvidia,tegra20-timer"; @@ -20,4 +22,5 @@ timer { 0 42 0x04 0 121 0x04 0 122 0x04>; + clocks = <&tegra_car 214>; }; diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt index df0933043a5b..b98d0bdfa248 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt @@ -8,7 +8,8 @@ and additions : Required properties : - compatible : Should be "nvidia,tegra20-ehci". - nvidia,phy : phandle of the PHY that the controller is connected to. - - clocks : Contains a single entry which defines the USB controller's clock. + - clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. Optional properties: - nvidia,needs-double-reset : boolean is to be set for some of the Tegra20 diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index df40b54fd8bc..4eaeab3866bc 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -75,7 +75,7 @@ interrupts = ; clocks = <&tegra_car TEGRA20_CLK_DISP1>, <&tegra_car TEGRA20_CLK_PLL_P>; - clock-names = "disp1", "parent"; + clock-names = "dc", "parent"; rgb { status = "disabled"; @@ -88,7 +88,7 @@ interrupts = ; clocks = <&tegra_car TEGRA20_CLK_DISP2>, <&tegra_car TEGRA20_CLK_PLL_P>; - clock-names = "disp2", "parent"; + clock-names = "dc", "parent"; rgb { status = "disabled"; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 2bd55cfd88ad..6e0e5a3611ee 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -147,7 +147,7 @@ interrupts = ; clocks = <&tegra_car TEGRA30_CLK_DISP1>, <&tegra_car TEGRA30_CLK_PLL_P>; - clock-names = "disp1", "parent"; + clock-names = "dc", "parent"; rgb { status = "disabled"; @@ -160,7 +160,7 @@ interrupts = ; clocks = <&tegra_car TEGRA30_CLK_DISP2>, <&tegra_car TEGRA30_CLK_PLL_P>; - clock-names = "disp2", "parent"; + clock-names = "dc", "parent"; rgb { status = "disabled"; -- cgit v1.2.3 From 07999587b7bbedbb6556c94f70227a99e66f19aa Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 7 Nov 2013 10:11:27 -0700 Subject: ARM: tegra: document reset properties in DT bindings Update all the Tegra DT bindings to require resets/reset-names properties where the HW module has reset inputs. Remove any entries from clocks or clock-names that were only required to identify reset inputs, rather than referring to real clocks. This is a DT-ABI-incompatible change. It is the first of two changes required for me to consider the Tegra DT bindings as stable, the other being conversion to the common DMA DT bindings. Signed-off-by: Stephen Warren Acked-By: Terje Bergstrom --- .../bindings/clock/nvidia,tegra114-car.txt | 4 ++ .../bindings/clock/nvidia,tegra124-car.txt | 4 ++ .../bindings/clock/nvidia,tegra20-car.txt | 4 ++ .../bindings/clock/nvidia,tegra30-car.txt | 4 ++ .../devicetree/bindings/dma/tegra20-apbdma.txt | 6 +++ .../bindings/gpu/nvidia,tegra20-host1x.txt | 63 ++++++++++++++++++++++ .../devicetree/bindings/i2c/nvidia,tegra20-i2c.txt | 6 +++ .../bindings/input/nvidia,tegra20-kbc.txt | 6 +++ .../bindings/mmc/nvidia,tegra20-sdhci.txt | 6 +++ .../devicetree/bindings/nvec/nvidia,nvec.txt | 4 ++ .../bindings/pci/nvidia,tegra20-pcie.txt | 14 +++-- .../devicetree/bindings/pwm/nvidia,tegra20-pwm.txt | 6 +++ .../bindings/serial/nvidia,tegra20-hsuart.txt | 6 +++ .../bindings/sound/nvidia,tegra20-ac97.txt | 6 +++ .../bindings/sound/nvidia,tegra20-i2s.txt | 6 +++ .../bindings/sound/nvidia,tegra30-ahub.txt | 17 ++++-- .../bindings/sound/nvidia,tegra30-i2s.txt | 6 +++ .../bindings/spi/nvidia,tegra114-spi.txt | 6 +++ .../bindings/spi/nvidia,tegra20-sflash.txt | 6 +++ .../bindings/spi/nvidia,tegra20-slink.txt | 6 +++ .../bindings/usb/nvidia,tegra20-ehci.txt | 4 ++ 21 files changed, 181 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt index 0c80c2677104..9acea9d93160 100644 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt @@ -15,6 +15,9 @@ Required properties : In clock consumers, this cell represents the clock ID exposed by the CAR. The assignments may be found in header file . +- #reset-cells : Should be 1. + In clock consumers, this cell represents the bit number in the CAR's + array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. Example SoC include file: @@ -23,6 +26,7 @@ Example SoC include file: compatible = "nvidia,tegra114-car"; reg = <0x60006000 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; usb@c5004000 { diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt index 1a91ec60dee5..ded5d6212c84 100644 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt @@ -15,6 +15,9 @@ Required properties : In clock consumers, this cell represents the clock ID exposed by the CAR. The assignments may be found in header file . +- #reset-cells : Should be 1. + In clock consumers, this cell represents the bit number in the CAR's + array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. Example SoC include file: @@ -23,6 +26,7 @@ Example SoC include file: compatible = "nvidia,tegra124-car"; reg = <0x60006000 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; usb@c5004000 { diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt index fcfed5bf73fb..6c5901b503d0 100644 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt @@ -15,6 +15,9 @@ Required properties : In clock consumers, this cell represents the clock ID exposed by the CAR. The assignments may be found in header file . +- #reset-cells : Should be 1. + In clock consumers, this cell represents the bit number in the CAR's + array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. Example SoC include file: @@ -23,6 +26,7 @@ Example SoC include file: compatible = "nvidia,tegra20-car"; reg = <0x60006000 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; usb@c5004000 { diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt index 0f714081e986..63618cde12df 100644 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt @@ -15,6 +15,9 @@ Required properties : In clock consumers, this cell represents the clock ID exposed by the CAR. The assignments may be found in header file . +- #reset-cells : Should be 1. + In clock consumers, this cell represents the bit number in the CAR's + array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. Example SoC include file: @@ -23,6 +26,7 @@ Example SoC include file: compatible = "nvidia,tegra30-car"; reg = <0x60006000 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; usb@c5004000 { diff --git a/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt index e0a68b972891..e0b166a7f04a 100644 --- a/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt +++ b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt @@ -7,6 +7,10 @@ Required properties: - interrupts: Should contain all of the per-channel DMA interrupts. - clocks: Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - dma Examples: @@ -30,4 +34,6 @@ apbdma: dma@6000a000 { 0 150 0x04 0 151 0x04 >; clocks = <&tegra_car 34>; + resets = <&tegra_car 34>; + reset-names = "dma"; }; diff --git a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt index 8b4367f86b95..ab45c02aa658 100644 --- a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt @@ -11,6 +11,10 @@ Required properties: - ranges: The mapping of the host1x address space to the CPU address space. - clocks: Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - host1x The host1x top-level node defines a number of children, each representing one of the following host1x client modules: @@ -23,6 +27,10 @@ of the following host1x client modules: - interrupts: The interrupt outputs from the controller. - clocks: Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - mpe - vi: video input @@ -32,6 +40,10 @@ of the following host1x client modules: - interrupts: The interrupt outputs from the controller. - clocks: Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - vi - epp: encoder pre-processor @@ -41,6 +53,10 @@ of the following host1x client modules: - interrupts: The interrupt outputs from the controller. - clocks: Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - epp - isp: image signal processor @@ -50,6 +66,10 @@ of the following host1x client modules: - interrupts: The interrupt outputs from the controller. - clocks: Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - isp - gr2d: 2D graphics engine @@ -59,6 +79,10 @@ of the following host1x client modules: - interrupts: The interrupt outputs from the controller. - clocks: Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - 2d - gr3d: 3D graphics engine @@ -72,6 +96,11 @@ of the following host1x client modules: - 3d This MUST be the first entry. - 3d2 (Only required on SoCs with two 3D clocks) + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - 3d + - 3d2 (Only required on SoCs with two 3D clocks) - dc: display controller @@ -85,6 +114,10 @@ of the following host1x client modules: - dc This MUST be the first entry. - parent + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - dc Each display controller node has a child node, named "rgb", that represents the RGB output associated with the controller. It can take the following @@ -107,6 +140,10 @@ of the following host1x client modules: - hdmi This MUST be the first entry. - parent + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - hdmi Optional properties: - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing @@ -133,6 +170,10 @@ of the following host1x client modules: - dsi This MUST be the first entry. - parent + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - dsi Example: @@ -145,6 +186,8 @@ Example: interrupts = <0 65 0x04 /* mpcore syncpt */ 0 67 0x04>; /* mpcore general */ clocks = <&tegra_car TEGRA20_CLK_HOST1X>; + resets = <&tegra_car 28>; + reset-names = "host1x"; #address-cells = <1>; #size-cells = <1>; @@ -156,6 +199,8 @@ Example: reg = <0x54040000 0x00040000>; interrupts = <0 68 0x04>; clocks = <&tegra_car TEGRA20_CLK_MPE>; + resets = <&tegra_car 60>; + reset-names = "mpe"; }; vi { @@ -163,6 +208,8 @@ Example: reg = <0x54080000 0x00040000>; interrupts = <0 69 0x04>; clocks = <&tegra_car TEGRA20_CLK_VI>; + resets = <&tegra_car 100>; + reset-names = "vi"; }; epp { @@ -170,6 +217,8 @@ Example: reg = <0x540c0000 0x00040000>; interrupts = <0 70 0x04>; clocks = <&tegra_car TEGRA20_CLK_EPP>; + resets = <&tegra_car 19>; + reset-names = "epp"; }; isp { @@ -177,6 +226,8 @@ Example: reg = <0x54100000 0x00040000>; interrupts = <0 71 0x04>; clocks = <&tegra_car TEGRA20_CLK_ISP>; + resets = <&tegra_car 23>; + reset-names = "isp"; }; gr2d { @@ -184,12 +235,16 @@ Example: reg = <0x54140000 0x00040000>; interrupts = <0 72 0x04>; clocks = <&tegra_car TEGRA20_CLK_GR2D>; + resets = <&tegra_car 21>; + reset-names = "2d"; }; gr3d { compatible = "nvidia,tegra20-gr3d"; reg = <0x54180000 0x00040000>; clocks = <&tegra_car TEGRA20_CLK_GR3D>; + resets = <&tegra_car 24>; + reset-names = "3d"; }; dc@54200000 { @@ -199,6 +254,8 @@ Example: clocks = <&tegra_car TEGRA20_CLK_DISP1>, <&tegra_car TEGRA20_CLK_PLL_P>; clock-names = "disp1", "parent"; + resets = <&tegra_car 27>; + reset-names = "dc"; rgb { status = "disabled"; @@ -212,6 +269,8 @@ Example: clocks = <&tegra_car TEGRA20_CLK_DISP2>, <&tegra_car TEGRA20_CLK_PLL_P>; clock-names = "disp2", "parent"; + resets = <&tegra_car 26>; + reset-names = "dc"; rgb { status = "disabled"; @@ -225,6 +284,8 @@ Example: clocks = <&tegra_car TEGRA20_CLK_HDMI>, <&tegra_car TEGRA20_CLK_PLL_D_OUT0>; clock-names = "hdmi", "parent"; + resets = <&tegra_car 51>; + reset-names = "hdmi"; status = "disabled"; }; @@ -242,6 +303,8 @@ Example: clocks = <&tegra_car TEGRA20_CLK_DSI>, <&tegra_car TEGRA20_CLK_PLL_D_OUT0>; clock-names = "dsi", "parent"; + resets = <&tegra_car 48>; + reset-names = "dsi"; status = "disabled"; }; }; diff --git a/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt b/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt index 173fbaab687b..10d2afdb76f4 100644 --- a/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt +++ b/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt @@ -47,6 +47,10 @@ Required properties: - fast-clk Tegra114: - div-clk +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - i2c Example: @@ -58,5 +62,7 @@ Example: #size-cells = <0>; clocks = <&tegra_car 12>, <&tegra_car 124>; clock-names = "div-clk", "fast-clk"; + resets = <&tegra_car 12>; + reset-names = "i2c"; status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt b/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt index 7d5a53dd77d1..0382b8bd69c6 100644 --- a/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt +++ b/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt @@ -15,6 +15,10 @@ Required properties: devicetree/bindings/input/matrix-keymap.txt. - clocks: Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - kbc Optional properties, in addition to those specified by the shared matrix-keyboard bindings: @@ -34,6 +38,8 @@ keyboard: keyboard { reg = <0x7000e200 0x100>; interrupts = <0 85 0x04>; clocks = <&tegra_car 36>; + resets = <&tegra_car 36>; + reset-names = "kbc"; nvidia,ghost-filter; nvidia,debounce-delay-ms = <640>; nvidia,kbc-row-pins = <0 1 2>; /* pin 0, 1, 2 as rows */ diff --git a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt index f727902a9e8d..f357c16ea815 100644 --- a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt @@ -10,6 +10,10 @@ Required properties: - compatible : Should be "nvidia,-sdhci" - clocks : Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - sdhci Optional properties: - power-gpios : Specify GPIOs for power control @@ -21,6 +25,8 @@ sdhci@c8000200 { reg = <0xc8000200 0x200>; interrupts = <47>; clocks = <&tegra_car 14>; + resets = <&tegra_car 14>; + reset-names = "sdhci"; cd-gpios = <&gpio 69 0>; /* gpio PI5 */ wp-gpios = <&gpio 57 0>; /* gpio PH1 */ power-gpios = <&gpio 155 0>; /* gpio PT3 */ diff --git a/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt b/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt index a97fe575ca29..5ae601e7f51f 100644 --- a/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt +++ b/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt @@ -15,3 +15,7 @@ Required properties: - fast-clk Tegra114: - div-clk +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - i2c diff --git a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt index 9e22da7393a3..24cee06915c9 100644 --- a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt +++ b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt @@ -47,9 +47,14 @@ Required properties: - clock-names: Must include the following entries: - pex - afi - - pcie_xclk - pll_e - cml (not required for Tegra20) +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - pex + - afi + - pcie_x Root ports are defined as subnodes of the PCIe controller node. @@ -91,9 +96,10 @@ SoC DTSI: 0x82000000 0 0xa0000000 0xa0000000 0 0x10000000 /* non-prefetchable memory */ 0xc2000000 0 0xb0000000 0xb0000000 0 0x10000000>; /* prefetchable memory */ - clocks = <&tegra_car 70>, <&tegra_car 72>, <&tegra_car 74>, - <&tegra_car 118>; - clock-names = "pex", "afi", "pcie_xclk", "pll_e"; + clocks = <&tegra_car 70>, <&tegra_car 72>, <&tegra_car 118>; + clock-names = "pex", "afi", "pll_e"; + resets = <&tegra_car 70>, <&tegra_car 72>, <&tegra_car 74>; + reset-names = "pex", "afi", "pcie_x"; status = "disabled"; pci@1,0 { diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt index f28128717dcc..c7ea9d4a988b 100644 --- a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt +++ b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt @@ -9,6 +9,10 @@ Required properties: the cells format. - clocks: Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - pwm Example: @@ -17,4 +21,6 @@ Example: reg = <0x7000a000 0x100>; #pwm-cells = <2>; clocks = <&tegra_car 17>; + resets = <&tegra_car 17>; + reset-names = "pwm"; }; diff --git a/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt b/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt index 11eb6e71ddd6..74ebd4c2f99d 100644 --- a/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt +++ b/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt @@ -8,6 +8,10 @@ Required properties: request selector for this UART controller. - clocks: Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - serial Optional properties: - nvidia,enable-modem-interrupt: Enable modem interrupts. Should be enable @@ -23,5 +27,7 @@ serial@70006000 { nvidia,dma-request-selector = <&apbdma 8>; nvidia,enable-modem-interrupt; clocks = <&tegra_car 6>; + resets = <&tegra_car 6>; + reset-names = "serial"; status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt index 37f4ebf5b184..2b6817f6e40e 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt @@ -6,6 +6,10 @@ Required properties: - interrupts : Should contain AC97 interrupt - clocks : Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - ac97 - nvidia,dma-request-selector : The Tegra DMA controller's phandle and request selector for the AC97 controller - nvidia,codec-reset-gpio : The Tegra GPIO controller's phandle and the number @@ -23,4 +27,6 @@ ac97@70002000 { nvidia,codec-reset-gpio = <&gpio 170 0>; nvidia,codec-sync-gpio = <&gpio 120 0>; clocks = <&tegra_car 3>; + resets = <&tegra_car 3>; + reset-names = "ac97"; }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt index ba0c9452916d..8b070aeca3db 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt @@ -6,6 +6,10 @@ Required properties: - interrupts : Should contain I2S interrupt - clocks : Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - i2s - nvidia,dma-request-selector : The Tegra DMA controller's phandle and request selector for this I2S controller @@ -17,4 +21,6 @@ i2s@70002800 { interrupts = < 45 >; nvidia,dma-request-selector = < &apbdma 2 >; clocks = <&tegra_car 11>; + resets = <&tegra_car 11>; + reset-names = "i2s"; }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt index 7299eeadd588..60d59a54ca07 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt @@ -15,6 +15,11 @@ Required properties: - clocks : Must contain an entry for each entry in clock-names. See ../clocks/clock-bindings.txt for details. - clock-names : Must include the following entries: + - d_audio + - apbif +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: Tegra30 and later: - d_audio - apbif @@ -26,7 +31,7 @@ Required properties: - dam0 - dam1 - dam2 - - spdif_in + - spdif Tegra114 and later additionally require: - amx - adx @@ -48,13 +53,15 @@ ahub@70080000 { reg = <0x70080000 0x200 0x70080200 0x100>; interrupts = < 0 103 0x04 >; nvidia,dma-request-selector = <&apbdma 1>; - clocks = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>, + clocks = <&tegra_car 106>, <&tegra_car 107>; + clock-names = "d_audio", "apbif"; + resets = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>, <&tegra_car 11>, <&tegra_car 18>, <&tegra_car 101>, <&tegra_car 102>, <&tegra_car 108>, <&tegra_car 109>, - <&tegra_car 110>, <&tegra_car 162>; - clock-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", + <&tegra_car 110>, <&tegra_car 10>; + reset-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", "i2s3", "i2s4", "dam0", "dam1", "dam2", - "spdif_in"; + "spdif"; ranges; #address-cells = <1>; #size-cells = <1>; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt index 7a3112bc135c..0c113ffe3814 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt @@ -5,6 +5,10 @@ Required properties: - reg : Should contain I2S registers location and length - clocks : Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - i2s - nvidia,ahub-cif-ids : The list of AHUB CIF IDs for this port, rx (playback) first, tx (capture) second. See nvidia,tegra30-ahub.txt for values. @@ -15,4 +19,6 @@ i2s@70080300 { reg = <0x70080300 0x100>; nvidia,ahub-cif-ids = <4 4>; clocks = <&tegra_car 11>; + resets = <&tegra_car 11>; + reset-names = "i2s"; }; diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt index d4f2d534934b..fcd9f67999de 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt @@ -10,6 +10,10 @@ Required properties: See ../clocks/clock-bindings.txt for details. - clock-names : Must include the following entries: - spi +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - spi Recommended properties: - spi-max-frequency: Definition as per @@ -26,5 +30,7 @@ spi@7000d600 { #size-cells = <0>; clocks = <&tegra_car 44>; clock-names = "spi"; + resets = <&tegra_car 44>; + reset-names = "spi"; status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt index 66e16c7f5939..e144f144717f 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt @@ -8,6 +8,10 @@ Required properties: request selector for this SFLASH controller. - clocks : Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - spi Recommended properties: - spi-max-frequency: Definition as per @@ -24,5 +28,7 @@ spi@7000c380 { #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car 43>; + resets = <&tegra_car 43>; + reset-names = "spi"; status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt index 0e6e94eb2b2a..9393e28f444b 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt @@ -8,6 +8,10 @@ Required properties: request selector for this SLINK controller. - clocks : Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - spi Recommended properties: - spi-max-frequency: Definition as per @@ -24,5 +28,7 @@ spi@7000d600 { #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car 44>; + resets = <&tegra_car 44>; + reset-names = "spi"; status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt index b98d0bdfa248..3dc9140e3dfb 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt @@ -10,6 +10,10 @@ Required properties : - nvidia,phy : phandle of the PHY that the controller is connected to. - clocks : Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. + - resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names : Must include the following entries: + - usb Optional properties: - nvidia,needs-double-reset : boolean is to be set for some of the Tegra20 -- cgit v1.2.3 From ed520c90b3c0453e687404c6028366fdb593d35e Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 11 Nov 2013 13:04:19 -0700 Subject: ARM: tegra: document use of standard DMA DT bindings Update all the Tegra DT bindings to require the standard dmas/dma-names properties rather than non-standard nvidia,dma-request-selector property. This is a DT-ABI-incompatible change. It is the second of two changes required for me to consider the Tegra DT bindings as stable, the other being the previous conversion to the common reset bindings. Signed-off-by: Stephen Warren --- .../devicetree/bindings/dma/tegra20-apbdma.txt | 5 +++++ .../devicetree/bindings/i2c/nvidia,tegra20-i2c.txt | 7 +++++++ .../bindings/serial/nvidia,tegra20-hsuart.txt | 10 +++++++--- .../devicetree/bindings/sound/nvidia,tegra20-ac97.txt | 14 +++++++++----- .../devicetree/bindings/sound/nvidia,tegra20-i2s.txt | 14 +++++++++----- .../devicetree/bindings/sound/nvidia,tegra30-ahub.txt | 18 +++++++++++++----- .../devicetree/bindings/spi/nvidia,tegra114-spi.txt | 14 +++++++++----- .../devicetree/bindings/spi/nvidia,tegra20-sflash.txt | 10 +++++++--- .../devicetree/bindings/spi/nvidia,tegra20-slink.txt | 10 +++++++--- 9 files changed, 73 insertions(+), 29 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt index e0b166a7f04a..c6908e7c42cc 100644 --- a/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt +++ b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt @@ -11,6 +11,10 @@ Required properties: See ../reset/reset.txt for details. - reset-names : Must include the following entries: - dma +- #dma-cells : Must be <1>. This dictates the length of DMA specifiers in + client nodes' dmas properties. The specifier represents the DMA request + select value for the peripheral. For more details, consult the Tegra TRM's + documentation of the APB DMA channel control register REQ_SEL field. Examples: @@ -36,4 +40,5 @@ apbdma: dma@6000a000 { clocks = <&tegra_car 34>; resets = <&tegra_car 34>; reset-names = "dma"; + #dma-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt b/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt index 10d2afdb76f4..87507e9ce6db 100644 --- a/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt +++ b/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt @@ -51,6 +51,11 @@ Required properties: See ../reset/reset.txt for details. - reset-names: Must include the following entries: - i2c +- dmas: Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names: Must include the following entries: + - rx + - tx Example: @@ -64,5 +69,7 @@ Example: clock-names = "div-clk", "fast-clk"; resets = <&tegra_car 12>; reset-names = "i2c"; + dmas = <&apbdma 16>, <&apbdma 16>; + dma-names = "rx", "tx"; status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt b/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt index 74ebd4c2f99d..845850caf088 100644 --- a/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt +++ b/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt @@ -4,14 +4,17 @@ Required properties: - compatible : should be "nvidia,tegra30-hsuart", "nvidia,tegra20-hsuart". - reg: Should contain UART controller registers location and length. - interrupts: Should contain UART controller interrupts. -- nvidia,dma-request-selector : The Tegra DMA controller's phandle and - request selector for this UART controller. - clocks: Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. - resets : Must contain an entry for each entry in reset-names. See ../reset/reset.txt for details. - reset-names : Must include the following entries: - serial +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx Optional properties: - nvidia,enable-modem-interrupt: Enable modem interrupts. Should be enable @@ -24,10 +27,11 @@ serial@70006000 { reg = <0x70006000 0x40>; reg-shift = <2>; interrupts = <0 36 0x04>; - nvidia,dma-request-selector = <&apbdma 8>; nvidia,enable-modem-interrupt; clocks = <&tegra_car 6>; resets = <&tegra_car 6>; reset-names = "serial"; + dmas = <&apbdma 8>, <&apbdma 8>; + dma-names = "rx", "tx"; status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt index 2b6817f6e40e..eaf00102d92c 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt @@ -4,14 +4,17 @@ Required properties: - compatible : "nvidia,tegra20-ac97" - reg : Should contain AC97 controller registers location and length - interrupts : Should contain AC97 interrupt -- clocks : Must contain one entry, for the module clock. - See ../clocks/clock-bindings.txt for details. - resets : Must contain an entry for each entry in reset-names. See ../reset/reset.txt for details. - reset-names : Must include the following entries: - ac97 -- nvidia,dma-request-selector : The Tegra DMA controller's phandle and - request selector for the AC97 controller +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. - nvidia,codec-reset-gpio : The Tegra GPIO controller's phandle and the number of the GPIO used to reset the external AC97 codec - nvidia,codec-sync-gpio : The Tegra GPIO controller's phandle and the number @@ -23,10 +26,11 @@ ac97@70002000 { compatible = "nvidia,tegra20-ac97"; reg = <0x70002000 0x200>; interrupts = <0 81 0x04>; - nvidia,dma-request-selector = <&apbdma 12>; nvidia,codec-reset-gpio = <&gpio 170 0>; nvidia,codec-sync-gpio = <&gpio 120 0>; clocks = <&tegra_car 3>; resets = <&tegra_car 3>; reset-names = "ac97"; + dmas = <&apbdma 12>, <&apbdma 12>; + dma-names = "rx", "tx"; }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt index 8b070aeca3db..dc30c6bfbe95 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt @@ -4,14 +4,17 @@ Required properties: - compatible : "nvidia,tegra20-i2s" - reg : Should contain I2S registers location and length - interrupts : Should contain I2S interrupt -- clocks : Must contain one entry, for the module clock. - See ../clocks/clock-bindings.txt for details. - resets : Must contain an entry for each entry in reset-names. See ../reset/reset.txt for details. - reset-names : Must include the following entries: - i2s -- nvidia,dma-request-selector : The Tegra DMA controller's phandle and - request selector for this I2S controller +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. Example: @@ -19,8 +22,9 @@ i2s@70002800 { compatible = "nvidia,tegra20-i2s"; reg = <0x70002800 0x200>; interrupts = < 45 >; - nvidia,dma-request-selector = < &apbdma 2 >; clocks = <&tegra_car 11>; resets = <&tegra_car 11>; reset-names = "i2s"; + dmas = <&apbdma 21>, <&apbdma 21>; + dma-names = "rx", "tx"; }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt index 60d59a54ca07..32de7ec789aa 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt @@ -7,11 +7,6 @@ Required properties: - Tegra30 requires 2 entries, for the APBIF and AHUB/AUDIO register blocks. - Tegra114 requires an additional entry, for the APBIF2 register block. - interrupts : Should contain AHUB interrupt -- nvidia,dma-request-selector : A list of the DMA channel specifiers. Each - entry contains the Tegra DMA controller's phandle and request selector. - If a single entry is present, the request selectors for the channels are - assumed to be contiguous, and increment from this value. - If multiple values are given, one value must be given per channel. - clocks : Must contain an entry for each entry in clock-names. See ../clocks/clock-bindings.txt for details. - clock-names : Must include the following entries: @@ -37,6 +32,14 @@ Required properties: - adx - ranges : The bus address mapping for the configlink register bus. Can be empty since the mapping is 1:1. +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx0 .. rx + - tx0 .. tx + ... where n is: + Tegra30: 3 + Tegra114, Tegra124: 9 - #address-cells : For the configlink bus. Should be <1>; - #size-cells : For the configlink bus. Should be <1>. @@ -62,6 +65,11 @@ ahub@70080000 { reset-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", "i2s3", "i2s4", "dam0", "dam1", "dam2", "spdif"; + dmas = <&apbdma 1>, <&apbdma 1>; + <&apbdma 2>, <&apbdma 2>; + <&apbdma 3>, <&apbdma 3>; + <&apbdma 4>, <&apbdma 4>; + dma-names = "rx0", "tx0", "rx1", "tx1", "rx2", "tx2", "rx3", "tx3"; ranges; #address-cells = <1>; #size-cells = <1>; diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt index fcd9f67999de..7ea701e07dc2 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt @@ -4,16 +4,19 @@ Required properties: - compatible : should be "nvidia,tegra114-spi". - reg: Should contain SPI registers location and length. - interrupts: Should contain SPI interrupts. -- nvidia,dma-request-selector : The Tegra DMA controller's phandle and - request selector for this SPI controller. -- clocks : Must contain an entry for each entry in clock-names. - See ../clocks/clock-bindings.txt for details. - clock-names : Must include the following entries: - spi - resets : Must contain an entry for each entry in reset-names. See ../reset/reset.txt for details. - reset-names : Must include the following entries: - spi +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. Recommended properties: - spi-max-frequency: Definition as per @@ -24,7 +27,6 @@ spi@7000d600 { compatible = "nvidia,tegra114-spi"; reg = <0x7000d600 0x200>; interrupts = <0 82 0x04>; - nvidia,dma-request-selector = <&apbdma 16>; spi-max-frequency = <25000000>; #address-cells = <1>; #size-cells = <0>; @@ -32,5 +34,7 @@ spi@7000d600 { clock-names = "spi"; resets = <&tegra_car 44>; reset-names = "spi"; + dmas = <&apbdma 16>, <&apbdma 16>; + dma-names = "rx", "tx"; status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt index e144f144717f..bdf08e6dec9b 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt @@ -4,14 +4,17 @@ Required properties: - compatible : should be "nvidia,tegra20-sflash". - reg: Should contain SFLASH registers location and length. - interrupts: Should contain SFLASH interrupts. -- nvidia,dma-request-selector : The Tegra DMA controller's phandle and - request selector for this SFLASH controller. - clocks : Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. - resets : Must contain an entry for each entry in reset-names. See ../reset/reset.txt for details. - reset-names : Must include the following entries: - spi +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx Recommended properties: - spi-max-frequency: Definition as per @@ -23,12 +26,13 @@ spi@7000c380 { compatible = "nvidia,tegra20-sflash"; reg = <0x7000c380 0x80>; interrupts = <0 39 0x04>; - nvidia,dma-request-selector = <&apbdma 16>; spi-max-frequency = <25000000>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car 43>; resets = <&tegra_car 43>; reset-names = "spi"; + dmas = <&apbdma 11>, <&apbdma 11>; + dma-names = "rx", "tx"; status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt index 9393e28f444b..5db9144a33c8 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt @@ -4,14 +4,17 @@ Required properties: - compatible : should be "nvidia,tegra20-slink", "nvidia,tegra30-slink". - reg: Should contain SLINK registers location and length. - interrupts: Should contain SLINK interrupts. -- nvidia,dma-request-selector : The Tegra DMA controller's phandle and - request selector for this SLINK controller. - clocks : Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. - resets : Must contain an entry for each entry in reset-names. See ../reset/reset.txt for details. - reset-names : Must include the following entries: - spi +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx Recommended properties: - spi-max-frequency: Definition as per @@ -23,12 +26,13 @@ spi@7000d600 { compatible = "nvidia,tegra20-slink"; reg = <0x7000d600 0x200>; interrupts = <0 82 0x04>; - nvidia,dma-request-selector = <&apbdma 16>; spi-max-frequency = <25000000>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car 44>; resets = <&tegra_car 44>; reset-names = "spi"; + dmas = <&apbdma 16>, <&apbdma 16>; + dma-names = "rx", "tx"; status = "disabled"; }; -- cgit v1.2.3 From 7924cd5e0b3acaeafd0d7628d9e9fb8488b8fb13 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 11 Dec 2013 23:43:45 +0100 Subject: filter: doc: improve BPF documentation This patch significantly updates the BPF documentation and describes its internal architecture, Linux extensions, and handling of the kernel's BPF and JIT engine, plus documents how development can be facilitated with the help of bpf_dbg, bpf_asm, bpf_jit_disasm. Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- Documentation/networking/filter.txt | 608 +++++++++++++++++++++++++++++++++--- 1 file changed, 561 insertions(+), 47 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt index cdb3e40b9d14..a06b48d2f5cc 100644 --- a/Documentation/networking/filter.txt +++ b/Documentation/networking/filter.txt @@ -1,49 +1,563 @@ -filter.txt: Linux Socket Filtering -Written by: Jay Schulist +Linux Socket Filtering aka Berkeley Packet Filter (BPF) +======================================================= Introduction -============ - - Linux Socket Filtering is derived from the Berkeley -Packet Filter. There are some distinct differences between -the BSD and Linux Kernel Filtering. - -Linux Socket Filtering (LSF) allows a user-space program to -attach a filter onto any socket and allow or disallow certain -types of data to come through the socket. LSF follows exactly -the same filter code structure as the BSD Berkeley Packet Filter -(BPF), so referring to the BSD bpf.4 manpage is very helpful in -creating filters. - -LSF is much simpler than BPF. One does not have to worry about -devices or anything like that. You simply create your filter -code, send it to the kernel via the SO_ATTACH_FILTER option and -if your filter code passes the kernel check on it, you then -immediately begin filtering data on that socket. - -You can also detach filters from your socket via the -SO_DETACH_FILTER option. This will probably not be used much -since when you close a socket that has a filter on it the -filter is automagically removed. The other less common case -may be adding a different filter on the same socket where you had another -filter that is still running: the kernel takes care of removing -the old one and placing your new one in its place, assuming your -filter has passed the checks, otherwise if it fails the old filter -will remain on that socket. - -SO_LOCK_FILTER option allows to lock the filter attached to a -socket. Once set, a filter cannot be removed or changed. This allows -one process to setup a socket, attach a filter, lock it then drop -privileges and be assured that the filter will be kept until the -socket is closed. - -Examples -======== - -Ioctls- -setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter)); -setsockopt(sockfd, SOL_SOCKET, SO_DETACH_FILTER, &value, sizeof(value)); -setsockopt(sockfd, SOL_SOCKET, SO_LOCK_FILTER, &value, sizeof(value)); - -See the BSD bpf.4 manpage and the BSD Packet Filter paper written by -Steven McCanne and Van Jacobson of Lawrence Berkeley Laboratory. +------------ + +Linux Socket Filtering (LSF) is derived from the Berkeley Packet Filter. +Though there are some distinct differences between the BSD and Linux +Kernel filtering, but when we speak of BPF or LSF in Linux context, we +mean the very same mechanism of filtering in the Linux kernel. + +BPF allows a user-space program to attach a filter onto any socket and +allow or disallow certain types of data to come through the socket. LSF +follows exactly the same filter code structure as BSD's BPF, so referring +to the BSD bpf.4 manpage is very helpful in creating filters. + +On Linux, BPF is much simpler than on BSD. One does not have to worry +about devices or anything like that. You simply create your filter code, +send it to the kernel via the SO_ATTACH_FILTER option and if your filter +code passes the kernel check on it, you then immediately begin filtering +data on that socket. + +You can also detach filters from your socket via the SO_DETACH_FILTER +option. This will probably not be used much since when you close a socket +that has a filter on it the filter is automagically removed. The other +less common case may be adding a different filter on the same socket where +you had another filter that is still running: the kernel takes care of +removing the old one and placing your new one in its place, assuming your +filter has passed the checks, otherwise if it fails the old filter will +remain on that socket. + +SO_LOCK_FILTER option allows to lock the filter attached to a socket. Once +set, a filter cannot be removed or changed. This allows one process to +setup a socket, attach a filter, lock it then drop privileges and be +assured that the filter will be kept until the socket is closed. + +The biggest user of this construct might be libpcap. Issuing a high-level +filter command like `tcpdump -i em1 port 22` passes through the libpcap +internal compiler that generates a structure that can eventually be loaded +via SO_ATTACH_FILTER to the kernel. `tcpdump -i em1 port 22 -ddd` +displays what is being placed into this structure. + +Although we were only speaking about sockets here, BPF in Linux is used +in many more places. There's xt_bpf for netfilter, cls_bpf in the kernel +qdisc layer, SECCOMP-BPF (SECure COMPuting [1]), and lots of other places +such as team driver, PTP code, etc where BPF is being used. + + [1] Documentation/prctl/seccomp_filter.txt + +Original BPF paper: + +Steven McCanne and Van Jacobson. 1993. The BSD packet filter: a new +architecture for user-level packet capture. In Proceedings of the +USENIX Winter 1993 Conference Proceedings on USENIX Winter 1993 +Conference Proceedings (USENIX'93). USENIX Association, Berkeley, +CA, USA, 2-2. [http://www.tcpdump.org/papers/bpf-usenix93.pdf] + +Structure +--------- + +User space applications include which contains the +following relevant structures: + +struct sock_filter { /* Filter block */ + __u16 code; /* Actual filter code */ + __u8 jt; /* Jump true */ + __u8 jf; /* Jump false */ + __u32 k; /* Generic multiuse field */ +}; + +Such a structure is assembled as an array of 4-tuples, that contains +a code, jt, jf and k value. jt and jf are jump offsets and k a generic +value to be used for a provided code. + +struct sock_fprog { /* Required for SO_ATTACH_FILTER. */ + unsigned short len; /* Number of filter blocks */ + struct sock_filter __user *filter; +}; + +For socket filtering, a pointer to this structure (as shown in +follow-up example) is being passed to the kernel through setsockopt(2). + +Example +------- + +#include +#include +#include +#include +/* ... */ + +/* From the example above: tcpdump -i em1 port 22 -dd */ +struct sock_filter code[] = { + { 0x28, 0, 0, 0x0000000c }, + { 0x15, 0, 8, 0x000086dd }, + { 0x30, 0, 0, 0x00000014 }, + { 0x15, 2, 0, 0x00000084 }, + { 0x15, 1, 0, 0x00000006 }, + { 0x15, 0, 17, 0x00000011 }, + { 0x28, 0, 0, 0x00000036 }, + { 0x15, 14, 0, 0x00000016 }, + { 0x28, 0, 0, 0x00000038 }, + { 0x15, 12, 13, 0x00000016 }, + { 0x15, 0, 12, 0x00000800 }, + { 0x30, 0, 0, 0x00000017 }, + { 0x15, 2, 0, 0x00000084 }, + { 0x15, 1, 0, 0x00000006 }, + { 0x15, 0, 8, 0x00000011 }, + { 0x28, 0, 0, 0x00000014 }, + { 0x45, 6, 0, 0x00001fff }, + { 0xb1, 0, 0, 0x0000000e }, + { 0x48, 0, 0, 0x0000000e }, + { 0x15, 2, 0, 0x00000016 }, + { 0x48, 0, 0, 0x00000010 }, + { 0x15, 0, 1, 0x00000016 }, + { 0x06, 0, 0, 0x0000ffff }, + { 0x06, 0, 0, 0x00000000 }, +}; + +struct sock_fprog bpf = { + .len = ARRAY_SIZE(code), + .filter = code, +}; + +sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); +if (sock < 0) + /* ... bail out ... */ + +ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)); +if (ret < 0) + /* ... bail out ... */ + +/* ... */ +close(sock); + +The above example code attaches a socket filter for a PF_PACKET socket +in order to let all IPv4/IPv6 packets with port 22 pass. The rest will +be dropped for this socket. + +The setsockopt(2) call to SO_DETACH_FILTER doesn't need any arguments +and SO_LOCK_FILTER for preventing the filter to be detached, takes an +integer value with 0 or 1. + +Note that socket filters are not restricted to PF_PACKET sockets only, +but can also be used on other socket families. + +Summary of system calls: + + * setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &val, sizeof(val)); + * setsockopt(sockfd, SOL_SOCKET, SO_DETACH_FILTER, &val, sizeof(val)); + * setsockopt(sockfd, SOL_SOCKET, SO_LOCK_FILTER, &val, sizeof(val)); + +Normally, most use cases for socket filtering on packet sockets will be +covered by libpcap in high-level syntax, so as an application developer +you should stick to that. libpcap wraps its own layer around all that. + +Unless i) using/linking to libpcap is not an option, ii) the required BPF +filters use Linux extensions that are not supported by libpcap's compiler, +iii) a filter might be more complex and not cleanly implementable with +libpcap's compiler, or iv) particular filter codes should be optimized +differently than libpcap's internal compiler does; then in such cases +writing such a filter "by hand" can be of an alternative. For example, +xt_bpf and cls_bpf users might have requirements that could result in +more complex filter code, or one that cannot be expressed with libpcap +(e.g. different return codes for various code paths). Moreover, BPF JIT +implementors may wish to manually write test cases and thus need low-level +access to BPF code as well. + +BPF engine and instruction set +------------------------------ + +Under tools/net/ there's a small helper tool called bpf_asm which can +be used to write low-level filters for example scenarios mentioned in the +previous section. Asm-like syntax mentioned here has been implemented in +bpf_asm and will be used for further explanations (instead of dealing with +less readable opcodes directly, principles are the same). The syntax is +closely modelled after Steven McCanne's and Van Jacobson's BPF paper. + +The BPF architecture consists of the following basic elements: + + Element Description + + A 32 bit wide accumulator + X 32 bit wide X register + M[] 16 x 32 bit wide misc registers aka "scratch memory + store", addressable from 0 to 15 + +A program, that is translated by bpf_asm into "opcodes" is an array that +consists of the following elements (as already mentioned): + + op:16, jt:8, jf:8, k:32 + +The element op is a 16 bit wide opcode that has a particular instruction +encoded. jt and jf are two 8 bit wide jump targets, one for condition +"jump if true", the other one "jump if false". Eventually, element k +contains a miscellaneous argument that can be interpreted in different +ways depending on the given instruction in op. + +The instruction set consists of load, store, branch, alu, miscellaneous +and return instructions that are also represented in bpf_asm syntax. This +table lists all bpf_asm instructions available resp. what their underlying +opcodes as defined in linux/filter.h stand for: + + Instruction Addressing mode Description + + ld 1, 2, 3, 4, 10 Load word into A + ldi 4 Load word into A + ldh 1, 2 Load half-word into A + ldb 1, 2 Load byte into A + ldx 3, 4, 5, 10 Load word into X + ldxi 4 Load word into X + ldxb 5 Load byte into X + + st 3 Store A into M[] + stx 3 Store X into M[] + + jmp 6 Jump to label + ja 6 Jump to label + jeq 7, 8 Jump on k == A + jneq 8 Jump on k != A + jne 8 Jump on k != A + jlt 8 Jump on k < A + jle 8 Jump on k <= A + jgt 7, 8 Jump on k > A + jge 7, 8 Jump on k >= A + jset 7, 8 Jump on k & A + + add 0, 4 A + + sub 0, 4 A - + mul 0, 4 A * + div 0, 4 A / + mod 0, 4 A % + neg 0, 4 !A + and 0, 4 A & + or 0, 4 A | + xor 0, 4 A ^ + lsh 0, 4 A << + rsh 0, 4 A >> + + tax Copy A into X + txa Copy X into A + + ret 4, 9 Return + +The next table shows addressing formats from the 2nd column: + + Addressing mode Syntax Description + + 0 x/%x Register X + 1 [k] BHW at byte offset k in the packet + 2 [x + k] BHW at the offset X + k in the packet + 3 M[k] Word at offset k in M[] + 4 #k Literal value stored in k + 5 4*([k]&0xf) Lower nibble * 4 at byte offset k in the packet + 6 L Jump label L + 7 #k,Lt,Lf Jump to Lt if true, otherwise jump to Lf + 8 #k,Lt Jump to Lt if predicate is true + 9 a/%a Accumulator A + 10 extension BPF extension + +The Linux kernel also has a couple of BPF extensions that are used along +with the class of load instructions by "overloading" the k argument with +a negative offset + a particular extension offset. The result of such BPF +extensions are loaded into A. + +Possible BPF extensions are shown in the following table: + + Extension Description + + len skb->len + proto skb->protocol + type skb->pkt_type + poff Payload start offset + ifidx skb->dev->ifindex + nla Netlink attribute of type X with offset A + nlan Nested Netlink attribute of type X with offset A + mark skb->mark + queue skb->queue_mapping + hatype skb->dev->type + rxhash skb->rxhash + cpu raw_smp_processor_id() + vlan_tci vlan_tx_tag_get(skb) + vlan_pr vlan_tx_tag_present(skb) + +These extensions can also be prefixed with '#'. +Examples for low-level BPF: + +** ARP packets: + + ldh [12] + jne #0x806, drop + ret #-1 + drop: ret #0 + +** IPv4 TCP packets: + + ldh [12] + jne #0x800, drop + ldb [23] + jneq #6, drop + ret #-1 + drop: ret #0 + +** (Accelerated) VLAN w/ id 10: + + ld vlan_tci + jneq #10, drop + ret #-1 + drop: ret #0 + +** SECCOMP filter example: + + ld [4] /* offsetof(struct seccomp_data, arch) */ + jne #0xc000003e, bad /* AUDIT_ARCH_X86_64 */ + ld [0] /* offsetof(struct seccomp_data, nr) */ + jeq #15, good /* __NR_rt_sigreturn */ + jeq #231, good /* __NR_exit_group */ + jeq #60, good /* __NR_exit */ + jeq #0, good /* __NR_read */ + jeq #1, good /* __NR_write */ + jeq #5, good /* __NR_fstat */ + jeq #9, good /* __NR_mmap */ + jeq #14, good /* __NR_rt_sigprocmask */ + jeq #13, good /* __NR_rt_sigaction */ + jeq #35, good /* __NR_nanosleep */ + bad: ret #0 /* SECCOMP_RET_KILL */ + good: ret #0x7fff0000 /* SECCOMP_RET_ALLOW */ + +The above example code can be placed into a file (here called "foo"), and +then be passed to the bpf_asm tool for generating opcodes, output that xt_bpf +and cls_bpf understands and can directly be loaded with. Example with above +ARP code: + +$ ./bpf_asm foo +4,40 0 0 12,21 0 1 2054,6 0 0 4294967295,6 0 0 0, + +In copy and paste C-like output: + +$ ./bpf_asm -c foo +{ 0x28, 0, 0, 0x0000000c }, +{ 0x15, 0, 1, 0x00000806 }, +{ 0x06, 0, 0, 0xffffffff }, +{ 0x06, 0, 0, 0000000000 }, + +In particular, as usage with xt_bpf or cls_bpf can result in more complex BPF +filters that might not be obvious at first, it's good to test filters before +attaching to a live system. For that purpose, there's a small tool called +bpf_dbg under tools/net/ in the kernel source directory. This debugger allows +for testing BPF filters against given pcap files, single stepping through the +BPF code on the pcap's packets and to do BPF machine register dumps. + +Starting bpf_dbg is trivial and just requires issuing: + +# ./bpf_dbg + +In case input and output do not equal stdin/stdout, bpf_dbg takes an +alternative stdin source as a first argument, and an alternative stdout +sink as a second one, e.g. `./bpf_dbg test_in.txt test_out.txt`. + +Other than that, a particular libreadline configuration can be set via +file "~/.bpf_dbg_init" and the command history is stored in the file +"~/.bpf_dbg_history". + +Interaction in bpf_dbg happens through a shell that also has auto-completion +support (follow-up example commands starting with '>' denote bpf_dbg shell). +The usual workflow would be to ... + +> load bpf 6,40 0 0 12,21 0 3 2048,48 0 0 23,21 0 1 1,6 0 0 65535,6 0 0 0 + Loads a BPF filter from standard output of bpf_asm, or transformed via + e.g. `tcpdump -iem1 -ddd port 22 | tr '\n' ','`. Note that for JIT + debugging (next section), this command creates a temporary socket and + loads the BPF code into the kernel. Thus, this will also be useful for + JIT developers. + +> load pcap foo.pcap + Loads standard tcpdump pcap file. + +> run [] +bpf passes:1 fails:9 + Runs through all packets from a pcap to account how many passes and fails + the filter will generate. A limit of packets to traverse can be given. + +> disassemble +l0: ldh [12] +l1: jeq #0x800, l2, l5 +l2: ldb [23] +l3: jeq #0x1, l4, l5 +l4: ret #0xffff +l5: ret #0 + Prints out BPF code disassembly. + +> dump +/* { op, jt, jf, k }, */ +{ 0x28, 0, 0, 0x0000000c }, +{ 0x15, 0, 3, 0x00000800 }, +{ 0x30, 0, 0, 0x00000017 }, +{ 0x15, 0, 1, 0x00000001 }, +{ 0x06, 0, 0, 0x0000ffff }, +{ 0x06, 0, 0, 0000000000 }, + Prints out C-style BPF code dump. + +> breakpoint 0 +breakpoint at: l0: ldh [12] +> breakpoint 1 +breakpoint at: l1: jeq #0x800, l2, l5 + ... + Sets breakpoints at particular BPF instructions. Issuing a `run` command + will walk through the pcap file continuing from the current packet and + break when a breakpoint is being hit (another `run` will continue from + the currently active breakpoint executing next instructions): + + > run + -- register dump -- + pc: [0] <-- program counter + code: [40] jt[0] jf[0] k[12] <-- plain BPF code of current instruction + curr: l0: ldh [12] <-- disassembly of current instruction + A: [00000000][0] <-- content of A (hex, decimal) + X: [00000000][0] <-- content of X (hex, decimal) + M[0,15]: [00000000][0] <-- folded content of M (hex, decimal) + -- packet dump -- <-- Current packet from pcap (hex) + len: 42 + 0: 00 19 cb 55 55 a4 00 14 a4 43 78 69 08 06 00 01 + 16: 08 00 06 04 00 01 00 14 a4 43 78 69 0a 3b 01 26 + 32: 00 00 00 00 00 00 0a 3b 01 01 + (breakpoint) + > + +> breakpoint +breakpoints: 0 1 + Prints currently set breakpoints. + +> step [-, +] + Performs single stepping through the BPF program from the current pc + offset. Thus, on each step invocation, above register dump is issued. + This can go forwards and backwards in time, a plain `step` will break + on the next BPF instruction, thus +1. (No `run` needs to be issued here.) + +> select + Selects a given packet from the pcap file to continue from. Thus, on + the next `run` or `step`, the BPF program is being evaluated against + the user pre-selected packet. Numbering starts just as in Wireshark + with index 1. + +> quit +# + Exits bpf_dbg. + +JIT compiler +------------ + +The Linux kernel has a built-in BPF JIT compiler for x86_64, SPARC, PowerPC, +ARM and s390 and can be enabled through CONFIG_BPF_JIT. The JIT compiler is +transparently invoked for each attached filter from user space or for internal +kernel users if it has been previously enabled by root: + + echo 1 > /proc/sys/net/core/bpf_jit_enable + +For JIT developers, doing audits etc, each compile run can output the generated +opcode image into the kernel log via: + + echo 2 > /proc/sys/net/core/bpf_jit_enable + +Example output from dmesg: + +[ 3389.935842] flen=6 proglen=70 pass=3 image=ffffffffa0069c8f +[ 3389.935847] JIT code: 00000000: 55 48 89 e5 48 83 ec 60 48 89 5d f8 44 8b 4f 68 +[ 3389.935849] JIT code: 00000010: 44 2b 4f 6c 4c 8b 87 d8 00 00 00 be 0c 00 00 00 +[ 3389.935850] JIT code: 00000020: e8 1d 94 ff e0 3d 00 08 00 00 75 16 be 17 00 00 +[ 3389.935851] JIT code: 00000030: 00 e8 28 94 ff e0 83 f8 01 75 07 b8 ff ff 00 00 +[ 3389.935852] JIT code: 00000040: eb 02 31 c0 c9 c3 + +In the kernel source tree under tools/net/, there's bpf_jit_disasm for +generating disassembly out of the kernel log's hexdump: + +# ./bpf_jit_disasm +70 bytes emitted from JIT compiler (pass:3, flen:6) +ffffffffa0069c8f + : + 0: push %rbp + 1: mov %rsp,%rbp + 4: sub $0x60,%rsp + 8: mov %rbx,-0x8(%rbp) + c: mov 0x68(%rdi),%r9d + 10: sub 0x6c(%rdi),%r9d + 14: mov 0xd8(%rdi),%r8 + 1b: mov $0xc,%esi + 20: callq 0xffffffffe0ff9442 + 25: cmp $0x800,%eax + 2a: jne 0x0000000000000042 + 2c: mov $0x17,%esi + 31: callq 0xffffffffe0ff945e + 36: cmp $0x1,%eax + 39: jne 0x0000000000000042 + 3b: mov $0xffff,%eax + 40: jmp 0x0000000000000044 + 42: xor %eax,%eax + 44: leaveq + 45: retq + +Issuing option `-o` will "annotate" opcodes to resulting assembler +instructions, which can be very useful for JIT developers: + +# ./bpf_jit_disasm -o +70 bytes emitted from JIT compiler (pass:3, flen:6) +ffffffffa0069c8f + : + 0: push %rbp + 55 + 1: mov %rsp,%rbp + 48 89 e5 + 4: sub $0x60,%rsp + 48 83 ec 60 + 8: mov %rbx,-0x8(%rbp) + 48 89 5d f8 + c: mov 0x68(%rdi),%r9d + 44 8b 4f 68 + 10: sub 0x6c(%rdi),%r9d + 44 2b 4f 6c + 14: mov 0xd8(%rdi),%r8 + 4c 8b 87 d8 00 00 00 + 1b: mov $0xc,%esi + be 0c 00 00 00 + 20: callq 0xffffffffe0ff9442 + e8 1d 94 ff e0 + 25: cmp $0x800,%eax + 3d 00 08 00 00 + 2a: jne 0x0000000000000042 + 75 16 + 2c: mov $0x17,%esi + be 17 00 00 00 + 31: callq 0xffffffffe0ff945e + e8 28 94 ff e0 + 36: cmp $0x1,%eax + 83 f8 01 + 39: jne 0x0000000000000042 + 75 07 + 3b: mov $0xffff,%eax + b8 ff ff 00 00 + 40: jmp 0x0000000000000044 + eb 02 + 42: xor %eax,%eax + 31 c0 + 44: leaveq + c9 + 45: retq + c3 + +For BPF JIT developers, bpf_jit_disasm, bpf_asm and bpf_dbg provides a useful +toolchain for developing and testing the kernel's JIT compiler. + +Misc +---- + +Also trinity, the Linux syscall fuzzer, has built-in support for BPF and +SECCOMP-BPF kernel fuzzing. + +Written by +---------- + +The document was written in the hope that it is found useful and in order +to give potential BPF hackers or security auditors a better overview of +the underlying architecture. + +Jay Schulist +Daniel Borkmann -- cgit v1.2.3 From a3b7a0c84d56bc50d33428f302778104b7164ba2 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Wed, 11 Dec 2013 14:33:13 +0200 Subject: dt-bindings: fix example of allwinner interrupt controller The documented value of #interrupt-cells is 1. Signed-off-by: Baruch Siach Signed-off-by: Maxime Ripard --- .../devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt index 3d3b2b91e333..32cec4b26cd0 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun4i-ic.txt @@ -14,5 +14,5 @@ intc: interrupt-controller { compatible = "allwinner,sun4i-ic"; reg = <0x01c20400 0x400>; interrupt-controller; - #interrupt-cells = <2>; + #interrupt-cells = <1>; }; -- cgit v1.2.3 From be943c7d27b14dbd700770d2fd6c704be95a0ec9 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Mon, 14 Oct 2013 17:52:38 +0200 Subject: crypto: atmel-aes - add support for Device Tree Add support for Device Tree and use of the DMA DT API to get the needed channels. Documentation is added for these DT nodes. Initial code by: Nicolas Royer and Eukrea. Signed-off-by: Nicolas Ferre Acked-by: Herbert Xu --- .../devicetree/bindings/crypto/atmel-crypto.txt | 23 ++++ drivers/crypto/atmel-aes.c | 143 ++++++++++++++------- 2 files changed, 117 insertions(+), 49 deletions(-) create mode 100644 Documentation/devicetree/bindings/crypto/atmel-crypto.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/crypto/atmel-crypto.txt b/Documentation/devicetree/bindings/crypto/atmel-crypto.txt new file mode 100644 index 000000000000..d273f0ba549e --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/atmel-crypto.txt @@ -0,0 +1,23 @@ +* Atmel HW cryptographic accelerators + +These are the HW cryptographic accelerators found on some Atmel products. + +* Advanced Encryption Standard (AES) + +Required properties: +- compatible : Should be "atmel,at91sam9g46-aes". +- reg: Should contain AES registers location and length. +- interrupts: Should contain the IRQ line for the AES. +- dmas: List of two DMA specifiers as described in + atmel-dma.txt and dma.txt files. +- dma-names: Contains one identifier string for each DMA specifier + in the dmas property. + +Example: +aes@f8038000 { + compatible = "atmel,at91sam9g46-aes"; + reg = <0xf8038000 0x100>; + interrupts = <43 4 0>; + dmas = <&dma1 2 18>, + <&dma1 2 19>; + dma-names = "tx", "rx"; diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index c1efd910d97b..d7c9e317423c 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include #include "atmel-aes-regs.h" #define CFB8_BLOCK_SIZE 1 @@ -747,59 +749,50 @@ static int atmel_aes_dma_init(struct atmel_aes_dev *dd, struct crypto_platform_data *pdata) { int err = -ENOMEM; - dma_cap_mask_t mask_in, mask_out; + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + /* Try to grab 2 DMA channels */ + dd->dma_lch_in.chan = dma_request_slave_channel_compat(mask, + atmel_aes_filter, &pdata->dma_slave->rxdata, dd->dev, "tx"); + if (!dd->dma_lch_in.chan) + goto err_dma_in; + + dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV; + dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base + + AES_IDATAR(0); + dd->dma_lch_in.dma_conf.src_maxburst = dd->caps.max_burst_size; + dd->dma_lch_in.dma_conf.src_addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; + dd->dma_lch_in.dma_conf.dst_maxburst = dd->caps.max_burst_size; + dd->dma_lch_in.dma_conf.dst_addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; + dd->dma_lch_in.dma_conf.device_fc = false; + + dd->dma_lch_out.chan = dma_request_slave_channel_compat(mask, + atmel_aes_filter, &pdata->dma_slave->txdata, dd->dev, "rx"); + if (!dd->dma_lch_out.chan) + goto err_dma_out; + + dd->dma_lch_out.dma_conf.direction = DMA_DEV_TO_MEM; + dd->dma_lch_out.dma_conf.src_addr = dd->phys_base + + AES_ODATAR(0); + dd->dma_lch_out.dma_conf.src_maxburst = dd->caps.max_burst_size; + dd->dma_lch_out.dma_conf.src_addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; + dd->dma_lch_out.dma_conf.dst_maxburst = dd->caps.max_burst_size; + dd->dma_lch_out.dma_conf.dst_addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; + dd->dma_lch_out.dma_conf.device_fc = false; - if (pdata && pdata->dma_slave->txdata.dma_dev && - pdata->dma_slave->rxdata.dma_dev) { - - /* Try to grab 2 DMA channels */ - dma_cap_zero(mask_in); - dma_cap_set(DMA_SLAVE, mask_in); - - dd->dma_lch_in.chan = dma_request_channel(mask_in, - atmel_aes_filter, &pdata->dma_slave->rxdata); - - if (!dd->dma_lch_in.chan) - goto err_dma_in; - - dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV; - dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base + - AES_IDATAR(0); - dd->dma_lch_in.dma_conf.src_maxburst = dd->caps.max_burst_size; - dd->dma_lch_in.dma_conf.src_addr_width = - DMA_SLAVE_BUSWIDTH_4_BYTES; - dd->dma_lch_in.dma_conf.dst_maxburst = dd->caps.max_burst_size; - dd->dma_lch_in.dma_conf.dst_addr_width = - DMA_SLAVE_BUSWIDTH_4_BYTES; - dd->dma_lch_in.dma_conf.device_fc = false; - - dma_cap_zero(mask_out); - dma_cap_set(DMA_SLAVE, mask_out); - dd->dma_lch_out.chan = dma_request_channel(mask_out, - atmel_aes_filter, &pdata->dma_slave->txdata); - - if (!dd->dma_lch_out.chan) - goto err_dma_out; - - dd->dma_lch_out.dma_conf.direction = DMA_DEV_TO_MEM; - dd->dma_lch_out.dma_conf.src_addr = dd->phys_base + - AES_ODATAR(0); - dd->dma_lch_out.dma_conf.src_maxburst = dd->caps.max_burst_size; - dd->dma_lch_out.dma_conf.src_addr_width = - DMA_SLAVE_BUSWIDTH_4_BYTES; - dd->dma_lch_out.dma_conf.dst_maxburst = dd->caps.max_burst_size; - dd->dma_lch_out.dma_conf.dst_addr_width = - DMA_SLAVE_BUSWIDTH_4_BYTES; - dd->dma_lch_out.dma_conf.device_fc = false; - - return 0; - } else { - return -ENODEV; - } + return 0; err_dma_out: dma_release_channel(dd->dma_lch_in.chan); err_dma_in: + dev_warn(dd->dev, "no DMA channel available\n"); return err; } @@ -1261,6 +1254,47 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd) } } +#if defined(CONFIG_OF) +static const struct of_device_id atmel_aes_dt_ids[] = { + { .compatible = "atmel,at91sam9g46-aes" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, atmel_aes_dt_ids); + +static struct crypto_platform_data *atmel_aes_of_init(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct crypto_platform_data *pdata; + + if (!np) { + dev_err(&pdev->dev, "device node not found\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "could not allocate memory for pdata\n"); + return ERR_PTR(-ENOMEM); + } + + pdata->dma_slave = devm_kzalloc(&pdev->dev, + sizeof(*(pdata->dma_slave)), + GFP_KERNEL); + if (!pdata->dma_slave) { + dev_err(&pdev->dev, "could not allocate memory for dma_slave\n"); + devm_kfree(&pdev->dev, pdata); + return ERR_PTR(-ENOMEM); + } + + return pdata; +} +#else +static inline struct crypto_platform_data *atmel_aes_of_init(struct platform_device *pdev) +{ + return ERR_PTR(-EINVAL); +} +#endif + static int atmel_aes_probe(struct platform_device *pdev) { struct atmel_aes_dev *aes_dd; @@ -1272,6 +1306,14 @@ static int atmel_aes_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; if (!pdata) { + pdata = atmel_aes_of_init(pdev); + if (IS_ERR(pdata)) { + err = PTR_ERR(pdata); + goto aes_dd_err; + } + } + + if (!pdata->dma_slave) { err = -ENXIO; goto aes_dd_err; } @@ -1358,7 +1400,9 @@ static int atmel_aes_probe(struct platform_device *pdev) if (err) goto err_algs; - dev_info(dev, "Atmel AES\n"); + dev_info(dev, "Atmel AES - Using %s, %s for DMA transfers\n", + dma_chan_name(aes_dd->dma_lch_in.chan), + dma_chan_name(aes_dd->dma_lch_out.chan)); return 0; @@ -1424,6 +1468,7 @@ static struct platform_driver atmel_aes_driver = { .driver = { .name = "atmel_aes", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(atmel_aes_dt_ids), }, }; -- cgit v1.2.3 From 84c8976b643af63150072e6c3e5f156dd6f9c910 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 15 Oct 2013 12:14:58 +0200 Subject: crypto: atmel-tdes - add support for Device Tree Add support for Device Tree and use of the DMA DT API to get the channels if needed. Documentation is added for these DT nodes. Initial code by: Nicolas Royer and Eukrea. Signed-off-by: Nicolas Ferre Acked-by: Herbert Xu --- .../devicetree/bindings/crypto/atmel-crypto.txt | 23 ++++ drivers/crypto/atmel-tdes.c | 143 ++++++++++++++------- 2 files changed, 117 insertions(+), 49 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/crypto/atmel-crypto.txt b/Documentation/devicetree/bindings/crypto/atmel-crypto.txt index d273f0ba549e..9a24fd900614 100644 --- a/Documentation/devicetree/bindings/crypto/atmel-crypto.txt +++ b/Documentation/devicetree/bindings/crypto/atmel-crypto.txt @@ -21,3 +21,26 @@ aes@f8038000 { dmas = <&dma1 2 18>, <&dma1 2 19>; dma-names = "tx", "rx"; + +* Triple Data Encryption Standard (Triple DES) + +Required properties: +- compatible : Should be "atmel,at91sam9g46-tdes". +- reg: Should contain TDES registers location and length. +- interrupts: Should contain the IRQ line for the TDES. + +Optional properties: +- dmas: List of two DMA specifiers as described in + atmel-dma.txt and dma.txt files. +- dma-names: Contains one identifier string for each DMA specifier + in the dmas property. + +Example: +tdes@f803c000 { + compatible = "atmel,at91sam9g46-tdes"; + reg = <0xf803c000 0x100>; + interrupts = <44 4 0>; + dmas = <&dma1 2 20>, + <&dma1 2 21>; + dma-names = "tx", "rx"; +}; diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c index 4a99564a08e6..6cde5b530c69 100644 --- a/drivers/crypto/atmel-tdes.c +++ b/drivers/crypto/atmel-tdes.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -716,59 +717,50 @@ static int atmel_tdes_dma_init(struct atmel_tdes_dev *dd, struct crypto_platform_data *pdata) { int err = -ENOMEM; - dma_cap_mask_t mask_in, mask_out; + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + /* Try to grab 2 DMA channels */ + dd->dma_lch_in.chan = dma_request_slave_channel_compat(mask, + atmel_tdes_filter, &pdata->dma_slave->rxdata, dd->dev, "tx"); + if (!dd->dma_lch_in.chan) + goto err_dma_in; + + dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV; + dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base + + TDES_IDATA1R; + dd->dma_lch_in.dma_conf.src_maxburst = 1; + dd->dma_lch_in.dma_conf.src_addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; + dd->dma_lch_in.dma_conf.dst_maxburst = 1; + dd->dma_lch_in.dma_conf.dst_addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; + dd->dma_lch_in.dma_conf.device_fc = false; + + dd->dma_lch_out.chan = dma_request_slave_channel_compat(mask, + atmel_tdes_filter, &pdata->dma_slave->txdata, dd->dev, "rx"); + if (!dd->dma_lch_out.chan) + goto err_dma_out; + + dd->dma_lch_out.dma_conf.direction = DMA_DEV_TO_MEM; + dd->dma_lch_out.dma_conf.src_addr = dd->phys_base + + TDES_ODATA1R; + dd->dma_lch_out.dma_conf.src_maxburst = 1; + dd->dma_lch_out.dma_conf.src_addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; + dd->dma_lch_out.dma_conf.dst_maxburst = 1; + dd->dma_lch_out.dma_conf.dst_addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; + dd->dma_lch_out.dma_conf.device_fc = false; - if (pdata && pdata->dma_slave->txdata.dma_dev && - pdata->dma_slave->rxdata.dma_dev) { - - /* Try to grab 2 DMA channels */ - dma_cap_zero(mask_in); - dma_cap_set(DMA_SLAVE, mask_in); - - dd->dma_lch_in.chan = dma_request_channel(mask_in, - atmel_tdes_filter, &pdata->dma_slave->rxdata); - - if (!dd->dma_lch_in.chan) - goto err_dma_in; - - dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV; - dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base + - TDES_IDATA1R; - dd->dma_lch_in.dma_conf.src_maxburst = 1; - dd->dma_lch_in.dma_conf.src_addr_width = - DMA_SLAVE_BUSWIDTH_4_BYTES; - dd->dma_lch_in.dma_conf.dst_maxburst = 1; - dd->dma_lch_in.dma_conf.dst_addr_width = - DMA_SLAVE_BUSWIDTH_4_BYTES; - dd->dma_lch_in.dma_conf.device_fc = false; - - dma_cap_zero(mask_out); - dma_cap_set(DMA_SLAVE, mask_out); - dd->dma_lch_out.chan = dma_request_channel(mask_out, - atmel_tdes_filter, &pdata->dma_slave->txdata); - - if (!dd->dma_lch_out.chan) - goto err_dma_out; - - dd->dma_lch_out.dma_conf.direction = DMA_DEV_TO_MEM; - dd->dma_lch_out.dma_conf.src_addr = dd->phys_base + - TDES_ODATA1R; - dd->dma_lch_out.dma_conf.src_maxburst = 1; - dd->dma_lch_out.dma_conf.src_addr_width = - DMA_SLAVE_BUSWIDTH_4_BYTES; - dd->dma_lch_out.dma_conf.dst_maxburst = 1; - dd->dma_lch_out.dma_conf.dst_addr_width = - DMA_SLAVE_BUSWIDTH_4_BYTES; - dd->dma_lch_out.dma_conf.device_fc = false; - - return 0; - } else { - return -ENODEV; - } + return 0; err_dma_out: dma_release_channel(dd->dma_lch_in.chan); err_dma_in: + dev_warn(dd->dev, "no DMA channel available\n"); return err; } @@ -1317,6 +1309,47 @@ static void atmel_tdes_get_cap(struct atmel_tdes_dev *dd) } } +#if defined(CONFIG_OF) +static const struct of_device_id atmel_tdes_dt_ids[] = { + { .compatible = "atmel,at91sam9g46-tdes" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, atmel_tdes_dt_ids); + +static struct crypto_platform_data *atmel_tdes_of_init(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct crypto_platform_data *pdata; + + if (!np) { + dev_err(&pdev->dev, "device node not found\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "could not allocate memory for pdata\n"); + return ERR_PTR(-ENOMEM); + } + + pdata->dma_slave = devm_kzalloc(&pdev->dev, + sizeof(*(pdata->dma_slave)), + GFP_KERNEL); + if (!pdata->dma_slave) { + dev_err(&pdev->dev, "could not allocate memory for dma_slave\n"); + devm_kfree(&pdev->dev, pdata); + return ERR_PTR(-ENOMEM); + } + + return pdata; +} +#else /* CONFIG_OF */ +static inline struct crypto_platform_data *atmel_tdes_of_init(struct platform_device *pdev) +{ + return ERR_PTR(-EINVAL); +} +#endif + static int atmel_tdes_probe(struct platform_device *pdev) { struct atmel_tdes_dev *tdes_dd; @@ -1399,13 +1432,24 @@ static int atmel_tdes_probe(struct platform_device *pdev) if (tdes_dd->caps.has_dma) { pdata = pdev->dev.platform_data; if (!pdata) { - dev_err(&pdev->dev, "platform data not available\n"); + pdata = atmel_tdes_of_init(pdev); + if (IS_ERR(pdata)) { + dev_err(&pdev->dev, "platform data not available\n"); + err = PTR_ERR(pdata); + goto err_pdata; + } + } + if (!pdata->dma_slave) { err = -ENXIO; goto err_pdata; } err = atmel_tdes_dma_init(tdes_dd, pdata); if (err) goto err_tdes_dma; + + dev_info(dev, "using %s, %s for DMA transfers\n", + dma_chan_name(tdes_dd->dma_lch_in.chan), + dma_chan_name(tdes_dd->dma_lch_out.chan)); } spin_lock(&atmel_tdes.lock); @@ -1487,6 +1531,7 @@ static struct platform_driver atmel_tdes_driver = { .driver = { .name = "atmel_tdes", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(atmel_tdes_dt_ids), }, }; -- cgit v1.2.3 From abfe7ae407c44de51f0fec8d87d448c7c27e1285 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 15 Oct 2013 15:36:34 +0200 Subject: crypto: atmel-sha - add support for Device Tree Add support for Device Tree and use of the DMA DT API to get the channels if needed. Documentation is added for these DT nodes. Initial code by: Nicolas Royer and Eukrea. Signed-off-by: Nicolas Ferre Acked-by: Herbert Xu --- .../devicetree/bindings/crypto/atmel-crypto.txt | 22 +++++ drivers/crypto/atmel-sha.c | 99 ++++++++++++++++------ 2 files changed, 97 insertions(+), 24 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/crypto/atmel-crypto.txt b/Documentation/devicetree/bindings/crypto/atmel-crypto.txt index 9a24fd900614..f2aab3dc2b52 100644 --- a/Documentation/devicetree/bindings/crypto/atmel-crypto.txt +++ b/Documentation/devicetree/bindings/crypto/atmel-crypto.txt @@ -44,3 +44,25 @@ tdes@f803c000 { <&dma1 2 21>; dma-names = "tx", "rx"; }; + +* Secure Hash Algorithm (SHA) + +Required properties: +- compatible : Should be "atmel,at91sam9g46-sha". +- reg: Should contain SHA registers location and length. +- interrupts: Should contain the IRQ line for the SHA. + +Optional properties: +- dmas: One DMA specifiers as described in + atmel-dma.txt and dma.txt files. +- dma-names: Contains one identifier string for each DMA specifier + in the dmas property. Only one "tx" string needed. + +Example: +sha@f8034000 { + compatible = "atmel,at91sam9g46-sha"; + reg = <0xf8034000 0x100>; + interrupts = <42 4 0>; + dmas = <&dma1 2 17>; + dma-names = "tx"; +}; diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index eaed8bf183bc..ecfdf727cc36 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -1263,32 +1264,29 @@ static int atmel_sha_dma_init(struct atmel_sha_dev *dd, int err = -ENOMEM; dma_cap_mask_t mask_in; - if (pdata && pdata->dma_slave->rxdata.dma_dev) { - /* Try to grab DMA channel */ - dma_cap_zero(mask_in); - dma_cap_set(DMA_SLAVE, mask_in); + /* Try to grab DMA channel */ + dma_cap_zero(mask_in); + dma_cap_set(DMA_SLAVE, mask_in); - dd->dma_lch_in.chan = dma_request_channel(mask_in, - atmel_sha_filter, &pdata->dma_slave->rxdata); - - if (!dd->dma_lch_in.chan) - return err; - - dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV; - dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base + - SHA_REG_DIN(0); - dd->dma_lch_in.dma_conf.src_maxburst = 1; - dd->dma_lch_in.dma_conf.src_addr_width = - DMA_SLAVE_BUSWIDTH_4_BYTES; - dd->dma_lch_in.dma_conf.dst_maxburst = 1; - dd->dma_lch_in.dma_conf.dst_addr_width = - DMA_SLAVE_BUSWIDTH_4_BYTES; - dd->dma_lch_in.dma_conf.device_fc = false; - - return 0; + dd->dma_lch_in.chan = dma_request_slave_channel_compat(mask_in, + atmel_sha_filter, &pdata->dma_slave->rxdata, dd->dev, "tx"); + if (!dd->dma_lch_in.chan) { + dev_warn(dd->dev, "no DMA channel available\n"); + return err; } - return -ENODEV; + dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV; + dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base + + SHA_REG_DIN(0); + dd->dma_lch_in.dma_conf.src_maxburst = 1; + dd->dma_lch_in.dma_conf.src_addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; + dd->dma_lch_in.dma_conf.dst_maxburst = 1; + dd->dma_lch_in.dma_conf.dst_addr_width = + DMA_SLAVE_BUSWIDTH_4_BYTES; + dd->dma_lch_in.dma_conf.device_fc = false; + + return 0; } static void atmel_sha_dma_cleanup(struct atmel_sha_dev *dd) @@ -1326,6 +1324,48 @@ static void atmel_sha_get_cap(struct atmel_sha_dev *dd) } } +#if defined(CONFIG_OF) +static const struct of_device_id atmel_sha_dt_ids[] = { + { .compatible = "atmel,at91sam9g46-sha" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, atmel_sha_dt_ids); + +static struct crypto_platform_data *atmel_sha_of_init(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct crypto_platform_data *pdata; + + if (!np) { + dev_err(&pdev->dev, "device node not found\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "could not allocate memory for pdata\n"); + return ERR_PTR(-ENOMEM); + } + + pdata->dma_slave = devm_kzalloc(&pdev->dev, + sizeof(*(pdata->dma_slave)), + GFP_KERNEL); + if (!pdata->dma_slave) { + dev_err(&pdev->dev, "could not allocate memory for dma_slave\n"); + devm_kfree(&pdev->dev, pdata); + return ERR_PTR(-ENOMEM); + } + + return pdata; +} +#else /* CONFIG_OF */ +static inline struct crypto_platform_data *atmel_sha_of_init(struct platform_device *dev) +{ + return ERR_PTR(-EINVAL); +} +#endif + static int atmel_sha_probe(struct platform_device *pdev) { struct atmel_sha_dev *sha_dd; @@ -1402,13 +1442,23 @@ static int atmel_sha_probe(struct platform_device *pdev) if (sha_dd->caps.has_dma) { pdata = pdev->dev.platform_data; if (!pdata) { - dev_err(&pdev->dev, "platform data not available\n"); + pdata = atmel_sha_of_init(pdev); + if (IS_ERR(pdata)) { + dev_err(&pdev->dev, "platform data not available\n"); + err = PTR_ERR(pdata); + goto err_pdata; + } + } + if (!pdata->dma_slave) { err = -ENXIO; goto err_pdata; } err = atmel_sha_dma_init(sha_dd, pdata); if (err) goto err_sha_dma; + + dev_info(dev, "using %s for DMA transfers\n", + dma_chan_name(sha_dd->dma_lch_in.chan)); } spin_lock(&atmel_sha.lock); @@ -1483,6 +1533,7 @@ static struct platform_driver atmel_sha_driver = { .driver = { .name = "atmel_sha", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(atmel_sha_dt_ids), }, }; -- cgit v1.2.3 From 2a3cf6a3599e901528d3e0025a1bd0722a8d3575 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 11 Dec 2013 11:32:28 +0900 Subject: gpiolib: return -ENOENT if no GPIO mapping exists Some devices drivers make use of optional GPIO parameters. For such drivers, it is important to discriminate between the case where no GPIO mapping has been defined for the function they are requesting, and the case where a mapping exists but an error occured while resolving it or when acquiring the GPIO. This patch changes the family of gpiod_get() functions such that they will return -ENOENT if and only if no GPIO mapping is defined for the requested function. Other error codes are used when an actual error occured during the GPIO resolution. Signed-off-by: Alexandre Courbot Reviewed-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Linus Walleij --- Documentation/gpio/consumer.txt | 6 +++++- drivers/gpio/gpiolib.c | 34 +++++++++++++++++----------------- 2 files changed, 22 insertions(+), 18 deletions(-) (limited to 'Documentation') diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt index 07c74a3765a0..e42f77d8d4ca 100644 --- a/Documentation/gpio/consumer.txt +++ b/Documentation/gpio/consumer.txt @@ -38,7 +38,11 @@ device that displays digits), an additional index argument can be specified: const char *con_id, unsigned int idx) Both functions return either a valid GPIO descriptor, or an error code checkable -with IS_ERR(). They will never return a NULL pointer. +with IS_ERR() (they will never return a NULL pointer). -ENOENT will be returned +if and only if no GPIO has been assigned to the device/function/index triplet, +other error codes are used for cases where a GPIO has been assigned but an error +occured while trying to acquire it. This is useful to discriminate between mere +errors and an absence of GPIO for optional GPIO parameters. Device-managed variants of these functions are also defined: diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 12e47dfabd8d..c0b06a9adad9 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2367,7 +2367,7 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) { - struct gpio_desc *desc = ERR_PTR(-ENODEV); + struct gpio_desc *desc = ERR_PTR(-ENOENT); struct gpiod_lookup_table *table; struct gpiod_lookup *p; @@ -2389,19 +2389,22 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, chip = find_chip_by_name(p->chip_label); if (!chip) { - dev_warn(dev, "cannot find GPIO chip %s\n", - p->chip_label); - continue; + dev_err(dev, "cannot find GPIO chip %s\n", + p->chip_label); + return ERR_PTR(-ENODEV); } if (chip->ngpio <= p->chip_hwnum) { - dev_warn(dev, "GPIO chip %s has %d GPIOs\n", - chip->label, chip->ngpio); - continue; + dev_err(dev, + "requested GPIO %d is out of range [0..%d] for chip %s\n", + idx, chip->ngpio, chip->label); + return ERR_PTR(-EINVAL); } desc = gpiochip_offset_to_desc(chip, p->chip_hwnum); *flags = p->flags; + + return desc; } return desc; @@ -2413,7 +2416,8 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, * @con_id: function within the GPIO consumer * * Return the GPIO descriptor corresponding to the function con_id of device - * dev, or an IS_ERR() condition if an error occured. + * dev, -ENOENT if no GPIO has been assigned to the requested function, or + * another IS_ERR() code if an error occured while trying to acquire the GPIO. */ struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id) { @@ -2430,7 +2434,9 @@ EXPORT_SYMBOL_GPL(gpiod_get); * This variant of gpiod_get() allows to access GPIOs other than the first * defined one for functions that define several GPIOs. * - * Return a valid GPIO descriptor, or an IS_ERR() condition in case of error. + * Return a valid GPIO descriptor, -ENOENT if no GPIO has been assigned to the + * requested function and/or index, or another IS_ERR() code if an error + * occured while trying to acquire the GPIO. */ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, const char *con_id, @@ -2455,15 +2461,9 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, * Either we are not using DT or ACPI, or their lookup did not return * a result. In that case, use platform lookup as a fallback. */ - if (!desc || IS_ERR(desc)) { - struct gpio_desc *pdesc; - + if (!desc || desc == ERR_PTR(-ENOENT)) { dev_dbg(dev, "using lookup tables for GPIO lookup"); - pdesc = gpiod_find(dev, con_id, idx, &flags); - - /* If used as fallback, do not replace the previous error */ - if (!IS_ERR(pdesc) || !desc) - desc = pdesc; + desc = gpiod_find(dev, con_id, idx, &flags); } if (IS_ERR(desc)) { -- cgit v1.2.3 From b658499f0f0f4ebf21d09c7da62a46f66ffa67cb Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 3 Dec 2013 15:15:36 +0100 Subject: usb: gadget: FunctionFS: add configfs support Add support for using FunctionFS in configfs-based USB gadgets. [ balbi@ti.com : removed redefinition of VERBOSE_DEBUG and few trailing whitespaces ] Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- Documentation/ABI/testing/configfs-usb-gadget-ffs | 9 +++ drivers/usb/gadget/Kconfig | 12 ++++ drivers/usb/gadget/f_fs.c | 80 ++++++++++++++++++++++- drivers/usb/gadget/u_fs.h | 3 + 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-ffs (limited to 'Documentation') diff --git a/Documentation/ABI/testing/configfs-usb-gadget-ffs b/Documentation/ABI/testing/configfs-usb-gadget-ffs new file mode 100644 index 000000000000..14343e237e83 --- /dev/null +++ b/Documentation/ABI/testing/configfs-usb-gadget-ffs @@ -0,0 +1,9 @@ +What: /config/usb-gadget/gadget/functions/ffs.name +Date: Nov 2013 +KenelVersion: 3.13 +Description: The purpose of this directory is to create and remove it. + + A corresponding USB function instance is created/removed. + There are no attributes here. + + All parameters are set through FunctionFS. diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 97eb540ddef2..0ae2e6559397 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -701,6 +701,18 @@ config USB_CONFIGFS_F_LB_SS test software, like the "usbtest" driver, to put your hardware and its driver through a basic set of functional tests. +config USB_CONFIGFS_F_FS + boolean "Function filesystem (FunctionFS)" + depends on USB_CONFIGFS + select USB_F_FS + help + The Function Filesystem (FunctionFS) lets one create USB + composite functions in user space in the same way GadgetFS + lets one create USB gadgets in user space. This allows creation + of composite gadgets such that some of the functions are + implemented in kernel space (for instance Ethernet, serial or + mass storage) and other are implemented in user space. + config USB_ZERO tristate "Gadget Zero (DEVELOPMENT)" select USB_LIBCOMPOSITE diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 9c8c74c25f1e..12a64e1c31ef 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -29,6 +29,7 @@ #include #include "u_fs.h" +#include "configfs.h" #define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */ @@ -161,6 +162,7 @@ DEFINE_MUTEX(ffs_lock); EXPORT_SYMBOL(ffs_lock); static struct ffs_dev *ffs_find_dev(const char *name); +static int _ffs_name_dev(struct ffs_dev *dev, const char *name); static void *ffs_acquire_dev(const char *dev_name); static void ffs_release_dev(struct ffs_data *ffs_data); static int ffs_ready(struct ffs_data *ffs); @@ -2261,7 +2263,7 @@ static struct ffs_dev *_ffs_find_dev(const char *name) if (strcmp(dev->name, name) == 0) return dev; } - + return NULL; } @@ -2295,6 +2297,31 @@ static struct ffs_dev *ffs_find_dev(const char *name) return _ffs_find_dev(name); } +/* Configfs support *********************************************************/ + +static inline struct f_fs_opts *to_ffs_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_fs_opts, + func_inst.group); +} + +static void ffs_attr_release(struct config_item *item) +{ + struct f_fs_opts *opts = to_ffs_opts(item); + + usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations ffs_item_ops = { + .release = ffs_attr_release, +}; + +static struct config_item_type ffs_func_type = { + .ct_item_ops = &ffs_item_ops, + .ct_owner = THIS_MODULE, +}; + + /* Function registration interface ******************************************/ static void ffs_free_inst(struct usb_function_instance *f) @@ -2308,6 +2335,44 @@ static void ffs_free_inst(struct usb_function_instance *f) kfree(opts); } +#define MAX_INST_NAME_LEN 40 + +static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) +{ + struct f_fs_opts *opts; + char *ptr; + const char *tmp; + int name_len, ret; + + name_len = strlen(name) + 1; + if (name_len > MAX_INST_NAME_LEN) + return -ENAMETOOLONG; + + ptr = kstrndup(name, name_len, GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + opts = to_f_fs_opts(fi); + tmp = NULL; + + ffs_dev_lock(); + + tmp = opts->dev->name_allocated ? opts->dev->name : NULL; + ret = _ffs_name_dev(opts->dev, ptr); + if (ret) { + kfree(ptr); + ffs_dev_unlock(); + return ret; + } + opts->dev->name_allocated = true; + + ffs_dev_unlock(); + + kfree(tmp); + + return 0; +} + static struct usb_function_instance *ffs_alloc_inst(void) { struct f_fs_opts *opts; @@ -2317,6 +2382,7 @@ static struct usb_function_instance *ffs_alloc_inst(void) if (!opts) return ERR_PTR(-ENOMEM); + opts->func_inst.set_inst_name = ffs_set_inst_name; opts->func_inst.free_func_inst = ffs_free_inst; ffs_dev_lock(); dev = ffs_alloc_dev(); @@ -2326,7 +2392,10 @@ static struct usb_function_instance *ffs_alloc_inst(void) return ERR_CAST(dev); } opts->dev = dev; + dev->opts = opts; + config_group_init_type_name(&opts->func_inst.group, "", + &ffs_func_type); return &opts->func_inst; } @@ -2484,6 +2553,8 @@ EXPORT_SYMBOL(ffs_single_dev); void ffs_free_dev(struct ffs_dev *dev) { list_del(&dev->entry); + if (dev->name_allocated) + kfree(dev->name); kfree(dev); if (list_empty(&ffs_devices)) functionfs_cleanup(); @@ -2572,6 +2643,13 @@ static void ffs_closed(struct ffs_data *ffs) if (ffs_obj->ffs_closed_callback) ffs_obj->ffs_closed_callback(ffs); + + if (!ffs_obj->opts || ffs_obj->opts->no_configfs + || !ffs_obj->opts->func_inst.group.cg_item.ci_parent) + goto done; + + unregister_gadget_item(ffs_obj->opts-> + func_inst.group.cg_item.ci_parent->ci_parent); done: ffs_dev_unlock(); } diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h index 09313750f913..bc2d3718219b 100644 --- a/drivers/usb/gadget/u_fs.h +++ b/drivers/usb/gadget/u_fs.h @@ -35,13 +35,16 @@ #define ENTER() pr_vdebug("%s()\n", __func__) +struct f_fs_opts; struct ffs_dev { const char *name; + bool name_allocated; bool mounted; bool desc_ready; bool single; struct ffs_data *ffs_data; + struct f_fs_opts *opts; struct list_head entry; int (*ffs_ready_callback)(struct ffs_data *ffs); -- cgit v1.2.3 From f1d6ff7939b4444079170adc2bba1f551e7f65ea Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 4 Dec 2013 11:13:01 -0700 Subject: ASoC: tegra: update module reset list for Tegra124 Tegra124 adds a number of extra modules into the configlink bus, which must be taken out of reset before the bus is used. Update the AHUB driver to know about these extra modules (the AHUB HW module hosts the configlink bus). Based-on-work-by: Arun Shamanna Lakshmi Based-on-work-by: Songhee Baek Signed-off-by: Stephen Warren Acked-by: Mark Brown --- This patch depends on "ASoC: tegra: use reset framework" to compile, which is ack'd and slated to go through a (large) topic branch in the Tegra tree. So, we can either: a) Merge that Tegra topic branch into the ASoC tree, then apply this. Note that I haven't created the topic branch yet, since I'm still waiting for DMA dependencies to be applied. b) Apply this change to the Tegra tree too. This change isn't directly related to the changes in the Tegra tree; it just makes use of the new reset controller feature that's introduced there. --- .../bindings/sound/nvidia,tegra30-ahub.txt | 9 +++++++++ sound/soc/tegra/tegra30_ahub.c | 20 ++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt index 32de7ec789aa..946e2ac46091 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt @@ -30,6 +30,15 @@ Required properties: Tegra114 and later additionally require: - amx - adx + Tegra124 and later additionally require: + - amx1 + - adx1 + - afc0 + - afc1 + - afc2 + - afc3 + - afc4 + - afc5 - ranges : The bus address mapping for the configlink register bus. Can be empty since the mapping is 1:1. - dmas : Must contain an entry for each entry in clock-names. diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index 342cd4fff0a5..d6f4c9940e0c 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -335,9 +335,13 @@ EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source); #define MOD_LIST_MASK_TEGRA30 BIT(0) #define MOD_LIST_MASK_TEGRA114 BIT(1) +#define MOD_LIST_MASK_TEGRA124 BIT(2) #define MOD_LIST_MASK_TEGRA30_OR_LATER \ - (MOD_LIST_MASK_TEGRA30 | MOD_LIST_MASK_TEGRA114) + (MOD_LIST_MASK_TEGRA30 | MOD_LIST_MASK_TEGRA114 | \ + MOD_LIST_MASK_TEGRA124) +#define MOD_LIST_MASK_TEGRA114_OR_LATER \ + (MOD_LIST_MASK_TEGRA114 | MOD_LIST_MASK_TEGRA124) static const struct { const char *rst_name; @@ -352,8 +356,16 @@ static const struct { { "dam1", MOD_LIST_MASK_TEGRA30_OR_LATER }, { "dam2", MOD_LIST_MASK_TEGRA30_OR_LATER }, { "spdif", MOD_LIST_MASK_TEGRA30_OR_LATER }, - { "amx", MOD_LIST_MASK_TEGRA114 }, - { "adx", MOD_LIST_MASK_TEGRA114 }, + { "amx", MOD_LIST_MASK_TEGRA114_OR_LATER }, + { "adx", MOD_LIST_MASK_TEGRA114_OR_LATER }, + { "amx1", MOD_LIST_MASK_TEGRA124 }, + { "adx1", MOD_LIST_MASK_TEGRA124 }, + { "afc0", MOD_LIST_MASK_TEGRA124 }, + { "afc1", MOD_LIST_MASK_TEGRA124 }, + { "afc2", MOD_LIST_MASK_TEGRA124 }, + { "afc3", MOD_LIST_MASK_TEGRA124 }, + { "afc4", MOD_LIST_MASK_TEGRA124 }, + { "afc5", MOD_LIST_MASK_TEGRA124 }, }; #define LAST_REG(name) \ @@ -492,7 +504,7 @@ static struct tegra30_ahub_soc_data soc_data_tegra114 = { }; static struct tegra30_ahub_soc_data soc_data_tegra124 = { - .mod_list_mask = MOD_LIST_MASK_TEGRA114, + .mod_list_mask = MOD_LIST_MASK_TEGRA124, .set_audio_cif = tegra124_ahub_set_cif, }; -- cgit v1.2.3 From 70c8f01a357ac74d223a632659787396fef1e649 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 11 Dec 2013 04:26:26 +0100 Subject: sh-pfc: Support GPIO to IRQ mapping specified IRQ resources On non-DT platforms IRQ controllers associated with the GPIOs have a fixed IRQ base value known at compile time. The sh-pfc driver translates GPIO number to IRQ numbers using a hardcoded table. This mechanism breaks on DT platforms, as the IRQ base values are dynamic in that case. Fix this by specifying IRQs associated with GPIOs in IRQ resources, populated automatically from the device tree. When IRQ resources are specified the driver requires one IRQ resource per GPIO able to generate an interrupt, and uses the translation table to compute the IRQ resource offset instead of the IRQ number. Cc: devicetree@vger.kernel.org Signed-off-by: Laurent Pinchart Acked-by: Magnus Damm Signed-off-by: Linus Walleij --- .../bindings/pinctrl/renesas,pfc-pinctrl.txt | 14 +++++ drivers/pinctrl/sh-pfc/core.c | 69 +++++++++++++++++----- drivers/pinctrl/sh-pfc/core.h | 2 + drivers/pinctrl/sh-pfc/gpio.c | 14 ++++- 4 files changed, 82 insertions(+), 17 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt index d5dac7b843a9..35d2e1f186f0 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt @@ -26,6 +26,11 @@ Optional properties: - #gpio-range-cells: Mandatory when the PFC doesn't handle GPIO, forbidden otherwise. Should be 3. + - interrupts-extended: Specify the interrupts associated with external + IRQ pins. This property is mandatory when the PFC handles GPIOs and + forbidden otherwise. When specified, it must contain one interrupt per + external IRQ, sorted by external IRQ number. + The PFC node also acts as a container for pin configuration nodes. Please refer to pinctrl-bindings.txt in this directory for the definition of the term "pin configuration node" and for the common pinctrl bindings used by client devices. @@ -103,6 +108,15 @@ Example 1: SH73A0 (SH-Mobile AG5) pin controller node <0xe605801c 0x1c>; gpio-controller; #gpio-cells = <2>; + interrupts-extended = + <&irqpin0 0 0>, <&irqpin0 1 0>, <&irqpin0 2 0>, <&irqpin0 3 0>, + <&irqpin0 4 0>, <&irqpin0 5 0>, <&irqpin0 6 0>, <&irqpin0 7 0>, + <&irqpin1 0 0>, <&irqpin1 1 0>, <&irqpin1 2 0>, <&irqpin1 3 0>, + <&irqpin1 4 0>, <&irqpin1 5 0>, <&irqpin1 6 0>, <&irqpin1 7 0>, + <&irqpin2 0 0>, <&irqpin2 1 0>, <&irqpin2 2 0>, <&irqpin2 3 0>, + <&irqpin2 4 0>, <&irqpin2 5 0>, <&irqpin2 6 0>, <&irqpin2 7 0>, + <&irqpin3 0 0>, <&irqpin3 1 0>, <&irqpin3 2 0>, <&irqpin3 3 0>, + <&irqpin3 4 0>, <&irqpin3 5 0>, <&irqpin3 6 0>, <&irqpin3 7 0>; }; Example 2: A GPIO LED node that references a GPIO diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index 7831f078a5ef..b9b464d0578c 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -26,30 +26,67 @@ #include "core.h" -static int sh_pfc_ioremap(struct sh_pfc *pfc, struct platform_device *pdev) +static int sh_pfc_map_resources(struct sh_pfc *pfc, + struct platform_device *pdev) { + unsigned int num_windows = 0; + unsigned int num_irqs = 0; + struct sh_pfc_window *windows; + unsigned int *irqs = NULL; struct resource *res; - unsigned int k; + unsigned int i; + + /* Count the MEM and IRQ resources. */ + for (i = 0; i < pdev->num_resources; ++i) { + switch (resource_type(&pdev->resource[i])) { + case IORESOURCE_MEM: + num_windows++; + break; + + case IORESOURCE_IRQ: + num_irqs++; + break; + } + } - if (pdev->num_resources == 0) + if (num_windows == 0) return -EINVAL; - pfc->windows = devm_kzalloc(pfc->dev, pdev->num_resources * - sizeof(*pfc->windows), GFP_NOWAIT); - if (!pfc->windows) + /* Allocate memory windows and IRQs arrays. */ + windows = devm_kzalloc(pfc->dev, num_windows * sizeof(*windows), + GFP_KERNEL); + if (windows == NULL) return -ENOMEM; - pfc->num_windows = pdev->num_resources; + pfc->num_windows = num_windows; + pfc->windows = windows; - for (k = 0, res = pdev->resource; k < pdev->num_resources; k++, res++) { - WARN_ON(resource_type(res) != IORESOURCE_MEM); - pfc->windows[k].phys = res->start; - pfc->windows[k].size = resource_size(res); - pfc->windows[k].virt = - devm_ioremap_nocache(pfc->dev, res->start, - resource_size(res)); - if (!pfc->windows[k].virt) + if (num_irqs) { + irqs = devm_kzalloc(pfc->dev, num_irqs * sizeof(*irqs), + GFP_KERNEL); + if (irqs == NULL) return -ENOMEM; + + pfc->num_irqs = num_irqs; + pfc->irqs = irqs; + } + + /* Fill them. */ + for (i = 0, res = pdev->resource; i < pdev->num_resources; i++, res++) { + switch (resource_type(res)) { + case IORESOURCE_MEM: + windows->phys = res->start; + windows->size = resource_size(res); + windows->virt = devm_ioremap_resource(pfc->dev, res); + if (IS_ERR(windows->virt)) + return -ENOMEM; + windows++; + break; + + case IORESOURCE_IRQ: + *irqs++ = res->start; + break; + } } return 0; @@ -482,7 +519,7 @@ static int sh_pfc_probe(struct platform_device *pdev) pfc->info = info; pfc->dev = &pdev->dev; - ret = sh_pfc_ioremap(pfc, pdev); + ret = sh_pfc_map_resources(pfc, pdev); if (unlikely(ret < 0)) return ret; diff --git a/drivers/pinctrl/sh-pfc/core.h b/drivers/pinctrl/sh-pfc/core.h index a83b7472e674..b7b0e6ccf305 100644 --- a/drivers/pinctrl/sh-pfc/core.h +++ b/drivers/pinctrl/sh-pfc/core.h @@ -38,6 +38,8 @@ struct sh_pfc { unsigned int num_windows; struct sh_pfc_window *windows; + unsigned int num_irqs; + unsigned int *irqs; struct sh_pfc_pin_range *ranges; unsigned int nr_ranges; diff --git a/drivers/pinctrl/sh-pfc/gpio.c b/drivers/pinctrl/sh-pfc/gpio.c index 6a21349fb116..63480815e1af 100644 --- a/drivers/pinctrl/sh-pfc/gpio.c +++ b/drivers/pinctrl/sh-pfc/gpio.c @@ -211,11 +211,17 @@ static int gpio_pin_to_irq(struct gpio_chip *gc, unsigned offset) for (k = 0; gpios[k] >= 0; k++) { if (gpios[k] == offset) - return pfc->info->gpio_irq[i].irq; + goto found; } } return -ENOSYS; + +found: + if (pfc->num_irqs) + return pfc->irqs[i]; + else + return pfc->info->gpio_irq[i].irq; } static int gpio_pin_setup(struct sh_pfc_chip *chip) @@ -357,6 +363,12 @@ int sh_pfc_register_gpiochip(struct sh_pfc *pfc) if (i == pfc->num_windows) return 0; + /* If we have IRQ resources make sure their number is correct. */ + if (pfc->num_irqs && pfc->num_irqs != pfc->info->gpio_irq_size) { + dev_err(pfc->dev, "invalid number of IRQ resources\n"); + return -EINVAL; + } + /* Register the real GPIOs chip. */ chip = sh_pfc_add_gpiochip(pfc, gpio_pin_setup, &pfc->windows[i]); if (IS_ERR(chip)) -- cgit v1.2.3 From 49a9ac222c73794df9282a75a6b4ef06d3b93f9d Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 10 Dec 2013 12:40:55 +0530 Subject: pinctrl: tegra: Add devicetree binding document for Tegra124 This device tree binding document describes the Tegra124 pincontrol DT bindings. This document lists all valid properties, names, mux options of Tegra124 pins. Changes from V1: - Referred the dt-binding header file on describing the nodes. Changes from V2: - Rewording reg properties. - drop drv_type as it is not applicable. Signed-off-by: Laxman Dewangan Acked-by: Stephen Warren Signed-off-by: Linus Walleij --- .../bindings/pinctrl/nvidia,tegra124-pinmux.txt | 144 +++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt new file mode 100644 index 000000000000..6464bf769460 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-pinmux.txt @@ -0,0 +1,144 @@ +NVIDIA Tegra124 pinmux controller + +The Tegra124 pinctrl binding is very similar to the Tegra20 and Tegra30 +pinctrl binding, as described in nvidia,tegra20-pinmux.txt and +nvidia,tegra30-pinmux.txt. In fact, this document assumes that binding as +a baseline, and only documents the differences between the two bindings. + +Required properties: +- compatible: "nvidia,tegra124-pinmux" +- reg: Should contain a list of base address and size pairs for: + -- first entry - the drive strength and pad control registers. + -- second entry - the pinmux registers + +Tegra124 adds the following optional properties for pin configuration subnodes. +The macros for options are defined in the + include/dt-binding/pinctrl/pinctrl-tegra.h. +- nvidia,enable-input: Integer. Enable the pin's input path. + enable :TEGRA_PIN_ENABLE0 and + disable or output only: TEGRA_PIN_DISABLE. +- nvidia,open-drain: Integer. + enable: TEGRA_PIN_ENABLE. + disable: TEGRA_PIN_DISABLE. +- nvidia,lock: Integer. Lock the pin configuration against further changes + until reset. + enable: TEGRA_PIN_ENABLE. + disable: TEGRA_PIN_DISABLE. +- nvidia,io-reset: Integer. Reset the IO path. + enable: TEGRA_PIN_ENABLE. + disable: TEGRA_PIN_DISABLE. +- nvidia,rcv-sel: Integer. Select VIL/VIH receivers. + normal: TEGRA_PIN_DISABLE + high: TEGRA_PIN_ENABLE + +Please refer the Tegra TRM for complete details regarding which groups +support which functionality. + +Valid values for pin and group names are: + + per-pin mux groups: + + These all support nvidia,function, nvidia,tristate, nvidia,pull, + nvidia,enable-input. Some support nvidia,lock nvidia,open-drain, + nvidia,io-reset and nvidia,rcv-sel. + + ulpi_data0_po1, ulpi_data1_po2, ulpi_data2_po3, ulpi_data3_po4, + ulpi_data4_po5, ulpi_data5_po6, ulpi_data6_po7, ulpi_data7_po0, + ulpi_clk_py0, ulpi_dir_py1, ulpi_nxt_py2, ulpi_stp_py3, dap3_fs_pp0, + dap3_din_pp1, dap3_dout_pp2, dap3_sclk_pp3, pv0, pv1, sdmmc1_clk_pz0, + sdmmc1_cmd_pz1, sdmmc1_dat3_py4, sdmmc1_dat2_py5, sdmmc1_dat1_py6, + sdmmc1_dat0_py7, clk2_out_pw5, clk2_req_pcc5, hdmi_int_pn7, ddc_scl_pv4, + ddc_sda_pv5, uart2_rxd_pc3, uart2_txd_pc2, uart2_rts_n_pj6, + uart2_cts_n_pj5, uart3_txd_pw6, uart3_rxd_pw7, uart3_cts_n_pa1, + uart3_rts_n_pc0, pu0, pu1, pu2, pu3, pu4, pu5, pu6, gen1_i2c_scl_pc4, + gen1_i2c_sda_pc5, dap4_fs_pp4, dap4_din_pp5, dap4_dout_pp6, + dap4_sclk_pp7, clk3_out_pee0, clk3_req_pee1, pc7, pi5, pi7, pk0, pk1, + pj0, pj2, pk3, pk4, pk2, pi3, pi6, pg0, pg1, pg2, pg3, pg4, pg5, pg6, + pg7, ph0, ph1, ph2, ph3, ph4, ph5, ph6, ph7, pj7, pb0, pb1, pk7, pi0, + pi1, pi2, pi4, gen2_i2c_scl_pt5, gen2_i2c_sda_pt6, sdmmc4_clk_pcc4, + sdmmc4_cmd_pt7, sdmmc4_dat0_paa0, sdmmc4_dat1_paa1, sdmmc4_dat2_paa2, + sdmmc4_dat3_paa3, sdmmc4_dat4_paa4, sdmmc4_dat5_paa5, sdmmc4_dat6_paa6, + sdmmc4_dat7_paa7, cam_mclk_pcc0, pcc1, pbb0, cam_i2c_scl_pbb1, + cam_i2c_sda_pbb2, pbb3, pbb4, pbb5, pbb6, pbb7, pcc2, jtag_rtck, + pwr_i2c_scl_pz6, pwr_i2c_sda_pz7, kb_row0_pr0, kb_row1_pr1, kb_row2_pr2, + kb_row3_pr3, kb_row4_pr4, kb_row5_pr5, kb_row6_pr6, kb_row7_pr7, + kb_row8_ps0, kb_row9_ps1, kb_row10_ps2, kb_row11_ps3, kb_row12_ps4, + kb_row13_ps5, kb_row14_ps6, kb_row15_ps7, kb_col0_pq0, kb_col1_pq1, + kb_col2_pq2, kb_col3_pq3, kb_col4_pq4, kb_col5_pq5, kb_col6_pq6, + kb_col7_pq7, clk_32k_out_pa0, core_pwr_req, cpu_pwr_req, pwr_int_n, + clk_32k_in, owr, dap1_fs_pn0, dap1_din_pn1, dap1_dout_pn2, + dap1_sclk_pn3, dap_mclk1_req_pee2, dap_mclk1_pw4, spdif_in_pk6, + spdif_out_pk5, dap2_fs_pa2, dap2_din_pa4, dap2_dout_pa5, dap2_sclk_pa3, + dvfs_pwm_px0, gpio_x1_aud_px1, gpio_x3_aud_px3, dvfs_clk_px2, + gpio_x4_aud_px4, gpio_x5_aud_px5, gpio_x6_aud_px6, gpio_x7_aud_px7, + sdmmc3_clk_pa6, sdmmc3_cmd_pa7, sdmmc3_dat0_pb7, sdmmc3_dat1_pb6, + sdmmc3_dat2_pb5, sdmmc3_dat3_pb4, pex_l0_rst_n_pdd1, + pex_l0_clkreq_n_pdd2, pex_wake_n_pdd3, pex_l1_rst_n_pdd5, + pex_l1_clkreq_n_pdd6, hdmi_cec_pee3, sdmmc1_wp_n_pv3, + sdmmc3_cd_n_pv2, gpio_w2_aud_pw2, gpio_w3_aud_pw3, usb_vbus_en0_pn4, + usb_vbus_en1_pn5, sdmmc3_clk_lb_out_pee4, sdmmc3_clk_lb_in_pee5, + gmi_clk_lb, reset_out_n, kb_row16_pt0, kb_row17_pt1, usb_vbus_en2_pff1, + pff2, dp_hpd_pff0, + + drive groups: + + These all support nvidia,pull-down-strength, nvidia,pull-up-strength, + nvidia,slew-rate-rising, nvidia,slew-rate-falling. Most but not all + support nvidia,high-speed-mode, nvidia,schmitt, nvidia,low-power-mode + and nvidia,drive-type. + + ao1, ao2, at1, at2, at3, at4, at5, cdev1, cdev2, dap1, dap2, dap3, dap4, + dbg, sdio3, spi, uaa, uab, uart2, uart3, sdio1, ddc, gma, gme, gmf, gmg, + gmh, owr, uda, gpv, dev3, cec, usb_vbus_en, ao3, ao0, hv0, sdio4, ao4. + +Valid values for nvidia,functions are: + + blink, cec, cldvfs, clk12, cpu, dap, dap1, dap2, dev3, displaya, + displaya_alt, displayb, dtv, extperiph1, extperiph2, extperiph3, + gmi, gmi_alt, hda, hsi, i2c1, i2c2, i2c3, i2c4, i2cpwr, i2s0, + i2s1, i2s2, i2s3, i2s4, irda, kbc, owr, pmi, pwm0, pwm1, pwm2, pwm3, + pwron, reset_out_n, rsvd1, rsvd2, rsvd3, rsvd4, sdmmc1, sdmmc2, sdmmc3, + sdmmc4, soc, spdif, spi1, spi2, spi3, spi4, spi5, spi6, trace, uarta, + uartb, uartc, uartd, ulpi, usb, vgp1, vgp2, vgp3, vgp4, vgp5, vgp6, + vi, vi_alt1, vi_alt3, vimclk2, vimclk2_alt, sata, ccla, pe0, pe, pe1, + dp, rtck, sys, clk tmds. + +Example: + + pinmux: pinmux { + compatible = "nvidia,tegra124-pinmux"; + reg = <0x70000868 0x164 /* Pad control registers */ + 0x70003000 0x434>; /* PinMux registers */ + }; + +Example pinmux entries: + + pinctrl { + sdmmc4_default: pinmux { + sdmmc4_clk_pcc4 { + nvidia,pins = "sdmmc4_clk_pcc4", + nvidia,function = "sdmmc4"; + nvidia,pull = ; + nvidia,tristate = ; + }; + + sdmmc4_dat0_paa0 { + nvidia,pins = "sdmmc4_dat0_paa0", + "sdmmc4_dat1_paa1", + "sdmmc4_dat2_paa2", + "sdmmc4_dat3_paa3", + "sdmmc4_dat4_paa4", + "sdmmc4_dat5_paa5", + "sdmmc4_dat6_paa6", + "sdmmc4_dat7_paa7"; + nvidia,function = "sdmmc4"; + nvidia,pull = ; + nvidia,tristate = ; + }; + }; + }; + + sdhci@78000400 { + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc4_default>; + }; -- cgit v1.2.3 From 08c36762db9a0223a5477441bd93650b474aa9c8 Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Mon, 9 Dec 2013 14:43:23 -0500 Subject: ARM: dts: keystone: Add usb phy devicetree bindings Added device tree support for TI's Keystone USB PHY driver and updated the Documentation with device tree binding information. Signed-off-by: WingMan Kwok Signed-off-by: Santosh Shilimkar --- .../devicetree/bindings/usb/keystone-phy.txt | 20 ++++++++++++++++++++ arch/arm/boot/dts/keystone.dtsi | 8 ++++++++ 2 files changed, 28 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/keystone-phy.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/keystone-phy.txt b/Documentation/devicetree/bindings/usb/keystone-phy.txt new file mode 100644 index 000000000000..f37b3a86341d --- /dev/null +++ b/Documentation/devicetree/bindings/usb/keystone-phy.txt @@ -0,0 +1,20 @@ +TI Keystone USB PHY + +Required properties: + - compatible: should be "ti,keystone-usbphy". + - #address-cells, #size-cells : should be '1' if the device has sub-nodes + with 'reg' property. + - reg : Address and length of the usb phy control register set. + +The main purpose of this PHY driver is to enable the USB PHY reference clock +gate on the Keystone SOC for both the USB2 and USB3 PHY. Otherwise it is just +an NOP PHY driver. Hence this node is referenced as both the usb2 and usb3 +phy node in the USB Glue layer driver node. + +usb_phy: usb_phy@2620738 { + compatible = "ti,keystone-usbphy"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x2620738 32>; + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/keystone.dtsi b/arch/arm/boot/dts/keystone.dtsi index f6d6d9e5effd..276bea999ef4 100644 --- a/arch/arm/boot/dts/keystone.dtsi +++ b/arch/arm/boot/dts/keystone.dtsi @@ -181,5 +181,13 @@ interrupts = ; clocks = <&clkspi>; }; + + usb_phy: usb_phy@2620738 { + compatible = "ti,keystone-usbphy"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x2620738 32>; + status = "disabled"; + }; }; }; -- cgit v1.2.3 From 732079567da4942b7b4929deff8f236926d0b3eb Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Mon, 9 Dec 2013 17:25:12 -0500 Subject: ARM: dts: keystone: Add usb devicetree bindings Added device tree support for TI's Keystone USB driver and updated the Documentation with device tree binding information. Signed-off-by: WingMan Kwok Signed-off-by: Santosh Shilimkar --- .../devicetree/bindings/usb/keystone-usb.txt | 42 ++++++++++++++++++++++ arch/arm/boot/dts/k2hk-evm.dts | 8 +++++ arch/arm/boot/dts/keystone.dtsi | 19 ++++++++++ 3 files changed, 69 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/keystone-usb.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/keystone-usb.txt b/Documentation/devicetree/bindings/usb/keystone-usb.txt new file mode 100644 index 000000000000..60527d335b58 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/keystone-usb.txt @@ -0,0 +1,42 @@ +TI Keystone Soc USB Controller + +DWC3 GLUE + +Required properties: + - compatible: should be "ti,keystone-dwc3". + - #address-cells, #size-cells : should be '1' if the device has sub-nodes + with 'reg' property. + - reg : Address and length of the register set for the USB subsystem on + the SOC. + - interrupts : The irq number of this device that is used to interrupt the + MPU. + - ranges: allows valid 1:1 translation between child's address space and + parent's address space. + - clocks: Clock IDs array as required by the controller. + - clock-names: names of clocks correseponding to IDs in the clock property. + +Sub-nodes: +The dwc3 core should be added as subnode to Keystone DWC3 glue. +- dwc3 : + The binding details of dwc3 can be found in: + Documentation/devicetree/bindings/usb/dwc3.txt + +Example: + usb: usb@2680000 { + compatible = "ti,keystone-dwc3"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x2680000 0x10000>; + clocks = <&clkusb>; + clock-names = "usb"; + interrupts = ; + ranges; + status = "disabled"; + + dwc3@2690000 { + compatible = "synopsys,dwc3"; + reg = <0x2690000 0x70000>; + interrupts = ; + usb-phy = <&usb_phy>, <&usb_phy>; + }; + }; diff --git a/arch/arm/boot/dts/k2hk-evm.dts b/arch/arm/boot/dts/k2hk-evm.dts index 15b3a95f5e3a..eaefdfef65c3 100644 --- a/arch/arm/boot/dts/k2hk-evm.dts +++ b/arch/arm/boot/dts/k2hk-evm.dts @@ -53,3 +53,11 @@ }; }; }; + +&usb_phy { + status = "okay"; +}; + +&usb { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/keystone.dtsi b/arch/arm/boot/dts/keystone.dtsi index 276bea999ef4..b4202907a27b 100644 --- a/arch/arm/boot/dts/keystone.dtsi +++ b/arch/arm/boot/dts/keystone.dtsi @@ -189,5 +189,24 @@ reg = <0x2620738 32>; status = "disabled"; }; + + usb: usb@2680000 { + compatible = "ti,keystone-dwc3"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x2680000 0x10000>; + clocks = <&clkusb>; + clock-names = "usb"; + interrupts = ; + ranges; + status = "disabled"; + + dwc3@2690000 { + compatible = "synopsys,dwc3"; + reg = <0x2690000 0x70000>; + interrupts = ; + usb-phy = <&usb_phy>, <&usb_phy>; + }; + }; }; }; -- cgit v1.2.3 From 10cdfe9f327ab8d120cf6957e58c6203e3a53847 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 6 Nov 2013 13:14:19 +0100 Subject: clk: shmobile: Add R-Car Gen2 clocks support The R-Car Gen2 SoCs (R8A7790 and R8A7791) have several clocks that are too custom to be supported in a generic driver. Those clocks can be divided in two categories: - Fixed rate clocks with multiplier and divisor set according to boot mode configuration - Custom divider clocks with SoC-specific divider values This driver supports both. Signed-off-by: Laurent Pinchart Acked-by: Kumar Gala Signed-off-by: Mike Turquette --- .../clock/renesas,rcar-gen2-cpg-clocks.txt | 32 +++ drivers/clk/Makefile | 1 + drivers/clk/shmobile/Makefile | 5 + drivers/clk/shmobile/clk-rcar-gen2.c | 298 +++++++++++++++++++++ include/linux/clk/shmobile.h | 19 ++ 5 files changed, 355 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt create mode 100644 drivers/clk/shmobile/Makefile create mode 100644 drivers/clk/shmobile/clk-rcar-gen2.c create mode 100644 include/linux/clk/shmobile.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt new file mode 100644 index 000000000000..7b41c2fe54db --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt @@ -0,0 +1,32 @@ +* Renesas R-Car Gen2 Clock Pulse Generator (CPG) + +The CPG generates core clocks for the R-Car Gen2 SoCs. It includes three PLLs +and several fixed ratio dividers. + +Required Properties: + + - compatible: Must be one of + - "renesas,r8a7790-cpg-clocks" for the r8a7790 CPG + - "renesas,r8a7791-cpg-clocks" for the r8a7791 CPG + - "renesas,rcar-gen2-cpg-clocks" for the generic R-Car Gen2 CPG + + - reg: Base address and length of the memory resource used by the CPG + + - clocks: Reference to the parent clock + - #clock-cells: Must be 1 + - clock-output-names: The names of the clocks. Supported clocks are "main", + "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1" and "z" + + +Example +------- + + cpg_clocks: cpg_clocks@e6150000 { + compatible = "renesas,r8a7790-cpg-clocks", + "renesas,rcar-gen2-cpg-clocks"; + reg = <0 0xe6150000 0 0x1000>; + clocks = <&extal_clk>; + #clock-cells = <1>; + clock-output-names = "main", "pll0, "pll1", "pll3", + "lb", "qspi", "sdh", "sd0", "sd1", "z"; + }; diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 7a10bc9a23e7..8dd1339be98b 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_PLAT_SAMSUNG) += samsung/ obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ +obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += shmobile/ obj-$(CONFIG_X86) += x86/ diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile new file mode 100644 index 000000000000..d0a9034a7946 --- /dev/null +++ b/drivers/clk/shmobile/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o +obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o + +# for emply built-in.o +obj-n := dummy diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c new file mode 100644 index 000000000000..a59ec217a124 --- /dev/null +++ b/drivers/clk/shmobile/clk-rcar-gen2.c @@ -0,0 +1,298 @@ +/* + * rcar_gen2 Core CPG Clocks + * + * Copyright (C) 2013 Ideas On Board SPRL + * + * Contact: Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rcar_gen2_cpg { + struct clk_onecell_data data; + spinlock_t lock; + void __iomem *reg; +}; + +#define CPG_SDCKCR 0x00000074 +#define CPG_PLL0CR 0x000000d8 +#define CPG_FRQCRC 0x000000e0 +#define CPG_FRQCRC_ZFC_MASK (0x1f << 8) +#define CPG_FRQCRC_ZFC_SHIFT 8 + +/* ----------------------------------------------------------------------------- + * Z Clock + * + * Traits of this clock: + * prepare - clk_prepare only ensures that parents are prepared + * enable - clk_enable only ensures that parents are enabled + * rate - rate is adjustable. clk->rate = parent->rate * mult / 32 + * parent - fixed parent. No clk_set_parent support + */ + +struct cpg_z_clk { + struct clk_hw hw; + void __iomem *reg; +}; + +#define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw) + +static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct cpg_z_clk *zclk = to_z_clk(hw); + unsigned int mult; + unsigned int val; + + val = (clk_readl(zclk->reg) & CPG_FRQCRC_ZFC_MASK) + >> CPG_FRQCRC_ZFC_SHIFT; + mult = 32 - val; + + return div_u64((u64)parent_rate * mult, 32); +} + +static long cpg_z_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long prate = *parent_rate; + unsigned int mult; + + if (!prate) + prate = 1; + + mult = div_u64((u64)rate * 32, prate); + mult = clamp(mult, 1U, 32U); + + return *parent_rate / 32 * mult; +} + +static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct cpg_z_clk *zclk = to_z_clk(hw); + unsigned int mult; + u32 val; + + mult = div_u64((u64)rate * 32, parent_rate); + mult = clamp(mult, 1U, 32U); + + val = clk_readl(zclk->reg); + val &= ~CPG_FRQCRC_ZFC_MASK; + val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT; + clk_writel(val, zclk->reg); + + return 0; +} + +static const struct clk_ops cpg_z_clk_ops = { + .recalc_rate = cpg_z_clk_recalc_rate, + .round_rate = cpg_z_clk_round_rate, + .set_rate = cpg_z_clk_set_rate, +}; + +static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg) +{ + static const char *parent_name = "pll0"; + struct clk_init_data init; + struct cpg_z_clk *zclk; + struct clk *clk; + + zclk = kzalloc(sizeof(*zclk), GFP_KERNEL); + if (!zclk) + return ERR_PTR(-ENOMEM); + + init.name = "z"; + init.ops = &cpg_z_clk_ops; + init.flags = 0; + init.parent_names = &parent_name; + init.num_parents = 1; + + zclk->reg = cpg->reg + CPG_FRQCRC; + zclk->hw.init = &init; + + clk = clk_register(NULL, &zclk->hw); + if (IS_ERR(clk)) + kfree(zclk); + + return clk; +} + +/* ----------------------------------------------------------------------------- + * CPG Clock Data + */ + +/* + * MD EXTAL PLL0 PLL1 PLL3 + * 14 13 19 (MHz) *1 *1 + *--------------------------------------------------- + * 0 0 0 15 x 1 x172/2 x208/2 x106 + * 0 0 1 15 x 1 x172/2 x208/2 x88 + * 0 1 0 20 x 1 x130/2 x156/2 x80 + * 0 1 1 20 x 1 x130/2 x156/2 x66 + * 1 0 0 26 / 2 x200/2 x240/2 x122 + * 1 0 1 26 / 2 x200/2 x240/2 x102 + * 1 1 0 30 / 2 x172/2 x208/2 x106 + * 1 1 1 30 / 2 x172/2 x208/2 x88 + * + * *1 : Table 7.6 indicates VCO ouput (PLLx = VCO/2) + */ +#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 12) | \ + (((md) & BIT(13)) >> 12) | \ + (((md) & BIT(19)) >> 19)) +struct cpg_pll_config { + unsigned int extal_div; + unsigned int pll1_mult; + unsigned int pll3_mult; +}; + +static const struct cpg_pll_config cpg_pll_configs[8] __initconst = { + { 1, 208, 106 }, { 1, 208, 88 }, { 1, 156, 80 }, { 1, 156, 66 }, + { 2, 240, 122 }, { 2, 240, 102 }, { 2, 208, 106 }, { 2, 208, 88 }, +}; + +/* SDHI divisors */ +static const struct clk_div_table cpg_sdh_div_table[] = { + { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, + { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 }, + { 8, 24 }, { 10, 36 }, { 11, 48 }, { 0, 0 }, +}; + +static const struct clk_div_table cpg_sd01_div_table[] = { + { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 }, + { 10, 36 }, { 11, 48 }, { 12, 10 }, { 0, 0 }, +}; + +/* ----------------------------------------------------------------------------- + * Initialization + */ + +static u32 cpg_mode __initdata; + +static struct clk * __init +rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg, + const struct cpg_pll_config *config, + const char *name) +{ + const struct clk_div_table *table = NULL; + const char *parent_name = "main"; + unsigned int shift; + unsigned int mult = 1; + unsigned int div = 1; + + if (!strcmp(name, "main")) { + parent_name = of_clk_get_parent_name(np, 0); + div = config->extal_div; + } else if (!strcmp(name, "pll0")) { + /* PLL0 is a configurable multiplier clock. Register it as a + * fixed factor clock for now as there's no generic multiplier + * clock implementation and we currently have no need to change + * the multiplier value. + */ + u32 value = clk_readl(cpg->reg + CPG_PLL0CR); + mult = ((value >> 24) & ((1 << 7) - 1)) + 1; + } else if (!strcmp(name, "pll1")) { + mult = config->pll1_mult / 2; + } else if (!strcmp(name, "pll3")) { + mult = config->pll3_mult; + } else if (!strcmp(name, "lb")) { + div = cpg_mode & BIT(18) ? 36 : 24; + } else if (!strcmp(name, "qspi")) { + div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2) + ? 16 : 20; + } else if (!strcmp(name, "sdh")) { + table = cpg_sdh_div_table; + shift = 8; + } else if (!strcmp(name, "sd0")) { + table = cpg_sd01_div_table; + shift = 4; + } else if (!strcmp(name, "sd1")) { + table = cpg_sd01_div_table; + shift = 0; + } else if (!strcmp(name, "z")) { + return cpg_z_clk_register(cpg); + } else { + return ERR_PTR(-EINVAL); + } + + if (!table) + return clk_register_fixed_factor(NULL, name, parent_name, 0, + mult, div); + else + return clk_register_divider_table(NULL, name, parent_name, 0, + cpg->reg + CPG_SDCKCR, shift, + 4, 0, table, &cpg->lock); +} + +static void __init rcar_gen2_cpg_clocks_init(struct device_node *np) +{ + const struct cpg_pll_config *config; + struct rcar_gen2_cpg *cpg; + struct clk **clks; + unsigned int i; + int num_clks; + + num_clks = of_property_count_strings(np, "clock-output-names"); + if (num_clks < 0) { + pr_err("%s: failed to count clocks\n", __func__); + return; + } + + cpg = kzalloc(sizeof(*cpg), GFP_KERNEL); + clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL); + if (cpg == NULL || clks == NULL) { + /* We're leaking memory on purpose, there's no point in cleaning + * up as the system won't boot anyway. + */ + pr_err("%s: failed to allocate cpg\n", __func__); + return; + } + + spin_lock_init(&cpg->lock); + + cpg->data.clks = clks; + cpg->data.clk_num = num_clks; + + cpg->reg = of_iomap(np, 0); + if (WARN_ON(cpg->reg == NULL)) + return; + + config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)]; + + for (i = 0; i < num_clks; ++i) { + const char *name; + struct clk *clk; + + of_property_read_string_index(np, "clock-output-names", i, + &name); + + clk = rcar_gen2_cpg_register_clock(np, cpg, config, name); + if (IS_ERR(clk)) + pr_err("%s: failed to register %s %s clock (%ld)\n", + __func__, np->name, name, PTR_ERR(clk)); + else + cpg->data.clks[i] = clk; + } + + of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data); +} +CLK_OF_DECLARE(rcar_gen2_cpg_clks, "renesas,rcar-gen2-cpg-clocks", + rcar_gen2_cpg_clocks_init); + +void __init rcar_gen2_clocks_init(u32 mode) +{ + cpg_mode = mode; + + of_clk_init(NULL); +} diff --git a/include/linux/clk/shmobile.h b/include/linux/clk/shmobile.h new file mode 100644 index 000000000000..f9bf080a1123 --- /dev/null +++ b/include/linux/clk/shmobile.h @@ -0,0 +1,19 @@ +/* + * Copyright 2013 Ideas On Board SPRL + * + * Contact: Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __LINUX_CLK_SHMOBILE_H_ +#define __LINUX_CLK_SHMOBILE_H_ + +#include + +void rcar_gen2_clocks_init(u32 mode); + +#endif -- cgit v1.2.3 From abe844aa5bb50444ac3e02aed89b431823d6ad56 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 17 Oct 2013 23:54:07 +0200 Subject: clk: shmobile: Add DIV6 clock support DIV6 clocks are divider gate clocks controlled through a single register. The divider is expressed on 6 bits, hence the name, and can take values from 1/1 to 1/64. Those clocks are found on Renesas ARM SoCs. Signed-off-by: Laurent Pinchart Signed-off-by: Mike Turquette --- .../bindings/clock/renesas,cpg-div6-clocks.txt | 28 ++++ drivers/clk/shmobile/Makefile | 1 + drivers/clk/shmobile/clk-div6.c | 185 +++++++++++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt create mode 100644 drivers/clk/shmobile/clk-div6.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt new file mode 100644 index 000000000000..952e373178d2 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt @@ -0,0 +1,28 @@ +* Renesas CPG DIV6 Clock + +The CPG DIV6 clocks are variable factor clocks provided by the Clock Pulse +Generator (CPG). They clock input is divided by a configurable factor from 1 +to 64. + +Required Properties: + + - compatible: Must be one of the following + - "renesas,r8a7790-div6-clock" for R8A7790 (R-Car H2) DIV6 clocks + - "renesas,r8a7791-div6-clock" for R8A7791 (R-Car M2) DIV6 clocks + - "renesas,cpg-div6-clock" for generic DIV6 clocks + - reg: Base address and length of the memory resource used by the DIV6 clock + - clocks: Reference to the parent clock + - #clock-cells: Must be 0 + - clock-output-names: The name of the clock as a free-form string + + +Example +------- + + sd2_clk: sd2_clk@e6150078 { + compatible = "renesas,r8a7790-div6-clock", "renesas,cpg-div6-clock"; + reg = <0 0xe6150078 0 4>; + clocks = <&pll1_div2_clk>; + #clock-cells = <0>; + clock-output-names = "sd2"; + }; diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile index d0a9034a7946..2e4a1197aa0a 100644 --- a/drivers/clk/shmobile/Makefile +++ b/drivers/clk/shmobile/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o +obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o # for emply built-in.o obj-n := dummy diff --git a/drivers/clk/shmobile/clk-div6.c b/drivers/clk/shmobile/clk-div6.c new file mode 100644 index 000000000000..aac4756ec52e --- /dev/null +++ b/drivers/clk/shmobile/clk-div6.c @@ -0,0 +1,185 @@ +/* + * r8a7790 Common Clock Framework support + * + * Copyright (C) 2013 Renesas Solutions Corp. + * + * Contact: Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define CPG_DIV6_CKSTP BIT(8) +#define CPG_DIV6_DIV(d) ((d) & 0x3f) +#define CPG_DIV6_DIV_MASK 0x3f + +/** + * struct div6_clock - MSTP gating clock + * @hw: handle between common and hardware-specific interfaces + * @reg: IO-remapped register + * @div: divisor value (1-64) + */ +struct div6_clock { + struct clk_hw hw; + void __iomem *reg; + unsigned int div; +}; + +#define to_div6_clock(_hw) container_of(_hw, struct div6_clock, hw) + +static int cpg_div6_clock_enable(struct clk_hw *hw) +{ + struct div6_clock *clock = to_div6_clock(hw); + + clk_writel(CPG_DIV6_DIV(clock->div - 1), clock->reg); + + return 0; +} + +static void cpg_div6_clock_disable(struct clk_hw *hw) +{ + struct div6_clock *clock = to_div6_clock(hw); + + /* DIV6 clocks require the divisor field to be non-zero when stopping + * the clock. + */ + clk_writel(CPG_DIV6_CKSTP | CPG_DIV6_DIV(CPG_DIV6_DIV_MASK), + clock->reg); +} + +static int cpg_div6_clock_is_enabled(struct clk_hw *hw) +{ + struct div6_clock *clock = to_div6_clock(hw); + + return !(clk_readl(clock->reg) & CPG_DIV6_CKSTP); +} + +static unsigned long cpg_div6_clock_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct div6_clock *clock = to_div6_clock(hw); + unsigned int div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1; + + return parent_rate / div; +} + +static unsigned int cpg_div6_clock_calc_div(unsigned long rate, + unsigned long parent_rate) +{ + unsigned int div; + + div = DIV_ROUND_CLOSEST(parent_rate, rate); + return clamp_t(unsigned int, div, 1, 64); +} + +static long cpg_div6_clock_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned int div = cpg_div6_clock_calc_div(rate, *parent_rate); + + return *parent_rate / div; +} + +static int cpg_div6_clock_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct div6_clock *clock = to_div6_clock(hw); + unsigned int div = cpg_div6_clock_calc_div(rate, parent_rate); + + clock->div = div; + + /* Only program the new divisor if the clock isn't stopped. */ + if (!(clk_readl(clock->reg) & CPG_DIV6_CKSTP)) + clk_writel(CPG_DIV6_DIV(clock->div - 1), clock->reg); + + return 0; +} + +static const struct clk_ops cpg_div6_clock_ops = { + .enable = cpg_div6_clock_enable, + .disable = cpg_div6_clock_disable, + .is_enabled = cpg_div6_clock_is_enabled, + .recalc_rate = cpg_div6_clock_recalc_rate, + .round_rate = cpg_div6_clock_round_rate, + .set_rate = cpg_div6_clock_set_rate, +}; + +static void __init cpg_div6_clock_init(struct device_node *np) +{ + struct clk_init_data init; + struct div6_clock *clock; + const char *parent_name; + const char *name; + struct clk *clk; + int ret; + + clock = kzalloc(sizeof(*clock), GFP_KERNEL); + if (!clock) { + pr_err("%s: failed to allocate %s DIV6 clock\n", + __func__, np->name); + return; + } + + /* Remap the clock register and read the divisor. Disabling the + * clock overwrites the divisor, so we need to cache its value for the + * enable operation. + */ + clock->reg = of_iomap(np, 0); + if (clock->reg == NULL) { + pr_err("%s: failed to map %s DIV6 clock register\n", + __func__, np->name); + goto error; + } + + clock->div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1; + + /* Parse the DT properties. */ + ret = of_property_read_string(np, "clock-output-names", &name); + if (ret < 0) { + pr_err("%s: failed to get %s DIV6 clock output name\n", + __func__, np->name); + goto error; + } + + parent_name = of_clk_get_parent_name(np, 0); + if (parent_name == NULL) { + pr_err("%s: failed to get %s DIV6 clock parent name\n", + __func__, np->name); + goto error; + } + + /* Register the clock. */ + init.name = name; + init.ops = &cpg_div6_clock_ops; + init.flags = CLK_IS_BASIC; + init.parent_names = &parent_name; + init.num_parents = 1; + + clock->hw.init = &init; + + clk = clk_register(NULL, &clock->hw); + if (IS_ERR(clk)) { + pr_err("%s: failed to register %s DIV6 clock (%ld)\n", + __func__, np->name, PTR_ERR(clk)); + goto error; + } + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + + return; + +error: + if (clock->reg) + iounmap(clock->reg); + kfree(clock); +} +CLK_OF_DECLARE(cpg_div6_clk, "renesas,cpg-div6-clock", cpg_div6_clock_init); -- cgit v1.2.3 From f94859c215b6d977794108a1a9a101239e393c09 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 17 Oct 2013 23:54:07 +0200 Subject: clk: shmobile: Add MSTP clock support MSTP clocks are gate clocks controlled through a register that handles up to 32 clocks. The register is often sparsely populated. Those clocks are found on Renesas ARM SoCs. Signed-off-by: Laurent Pinchart Signed-off-by: Mike Turquette --- .../bindings/clock/renesas,cpg-mstp-clocks.txt | 51 +++++ drivers/clk/shmobile/Makefile | 1 + drivers/clk/shmobile/clk-mstp.c | 229 +++++++++++++++++++++ 3 files changed, 281 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt create mode 100644 drivers/clk/shmobile/clk-mstp.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt new file mode 100644 index 000000000000..a6a352c2771e --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt @@ -0,0 +1,51 @@ +* Renesas CPG Module Stop (MSTP) Clocks + +The CPG can gate SoC device clocks. The gates are organized in groups of up to +32 gates. + +This device tree binding describes a single 32 gate clocks group per node. +Clocks are referenced by user nodes by the MSTP node phandle and the clock +index in the group, from 0 to 31. + +Required Properties: + + - compatible: Must be one of the following + - "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks + - "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2) MSTP gate clocks + - "renesas,cpg-mstp-clock" for generic MSTP gate clocks + - reg: Base address and length of the I/O mapped registers used by the MSTP + clocks. The first register is the clock control register and is mandatory. + The second register is the clock status register and is optional when not + implemented in hardware. + - clocks: Reference to the parent clocks, one per output clock. The parents + must appear in the same order as the output clocks. + - #clock-cells: Must be 1 + - clock-output-names: The name of the clocks as free-form strings + - renesas,indices: Indices of the gate clocks into the group (0 to 31) + +The clocks, clock-output-names and renesas,indices properties contain one +entry per gate clock. The MSTP groups are sparsely populated. Unimplemented +gate clocks must not be declared. + + +Example +------- + + #include + + mstp3_clks: mstp3_clks@e615013c { + compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; + reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>; + clocks = <&cp_clk>, <&mmc1_clk>, <&sd3_clk>, <&sd2_clk>, + <&cpg_clocks R8A7790_CLK_SD1>, <&cpg_clocks R8A7790_CLK_SD0>, + <&mmc0_clk>; + #clock-cells = <1>; + clock-output-names = + "tpu0", "mmcif1", "sdhi3", "sdhi2", + "sdhi1", "sdhi0", "mmcif0"; + renesas,clock-indices = < + R8A7790_CLK_TPU0 R8A7790_CLK_MMCIF1 R8A7790_CLK_SDHI3 + R8A7790_CLK_SDHI2 R8A7790_CLK_SDHI1 R8A7790_CLK_SDHI0 + R8A7790_CLK_MMCIF0 + >; + }; diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile index 2e4a1197aa0a..706adc6ae70c 100644 --- a/drivers/clk/shmobile/Makefile +++ b/drivers/clk/shmobile/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o +obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-mstp.o # for emply built-in.o obj-n := dummy diff --git a/drivers/clk/shmobile/clk-mstp.c b/drivers/clk/shmobile/clk-mstp.c new file mode 100644 index 000000000000..e576b60de20e --- /dev/null +++ b/drivers/clk/shmobile/clk-mstp.c @@ -0,0 +1,229 @@ +/* + * R-Car MSTP clocks + * + * Copyright (C) 2013 Ideas On Board SPRL + * + * Contact: Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +#include +#include +#include +#include +#include +#include + +/* + * MSTP clocks. We can't use standard gate clocks as we need to poll on the + * status register when enabling the clock. + */ + +#define MSTP_MAX_CLOCKS 32 + +/** + * struct mstp_clock_group - MSTP gating clocks group + * + * @data: clocks in this group + * @smstpcr: module stop control register + * @mstpsr: module stop status register (optional) + * @lock: protects writes to SMSTPCR + */ +struct mstp_clock_group { + struct clk_onecell_data data; + void __iomem *smstpcr; + void __iomem *mstpsr; + spinlock_t lock; +}; + +/** + * struct mstp_clock - MSTP gating clock + * @hw: handle between common and hardware-specific interfaces + * @bit_index: control bit index + * @group: MSTP clocks group + */ +struct mstp_clock { + struct clk_hw hw; + u32 bit_index; + struct mstp_clock_group *group; +}; + +#define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw) + +static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) +{ + struct mstp_clock *clock = to_mstp_clock(hw); + struct mstp_clock_group *group = clock->group; + u32 bitmask = BIT(clock->bit_index); + unsigned long flags; + unsigned int i; + u32 value; + + spin_lock_irqsave(&group->lock, flags); + + value = clk_readl(group->smstpcr); + if (enable) + value &= ~bitmask; + else + value |= bitmask; + clk_writel(value, group->smstpcr); + + spin_unlock_irqrestore(&group->lock, flags); + + if (!enable || !group->mstpsr) + return 0; + + for (i = 1000; i > 0; --i) { + if (!(clk_readl(group->mstpsr) & bitmask)) + break; + cpu_relax(); + } + + if (!i) { + pr_err("%s: failed to enable %p[%d]\n", __func__, + group->smstpcr, clock->bit_index); + return -ETIMEDOUT; + } + + return 0; +} + +static int cpg_mstp_clock_enable(struct clk_hw *hw) +{ + return cpg_mstp_clock_endisable(hw, true); +} + +static void cpg_mstp_clock_disable(struct clk_hw *hw) +{ + cpg_mstp_clock_endisable(hw, false); +} + +static int cpg_mstp_clock_is_enabled(struct clk_hw *hw) +{ + struct mstp_clock *clock = to_mstp_clock(hw); + struct mstp_clock_group *group = clock->group; + u32 value; + + if (group->mstpsr) + value = clk_readl(group->mstpsr); + else + value = clk_readl(group->smstpcr); + + return !!(value & BIT(clock->bit_index)); +} + +static const struct clk_ops cpg_mstp_clock_ops = { + .enable = cpg_mstp_clock_enable, + .disable = cpg_mstp_clock_disable, + .is_enabled = cpg_mstp_clock_is_enabled, +}; + +static struct clk * __init +cpg_mstp_clock_register(const char *name, const char *parent_name, + unsigned int index, struct mstp_clock_group *group) +{ + struct clk_init_data init; + struct mstp_clock *clock; + struct clk *clk; + + clock = kzalloc(sizeof(*clock), GFP_KERNEL); + if (!clock) { + pr_err("%s: failed to allocate MSTP clock.\n", __func__); + return ERR_PTR(-ENOMEM); + } + + init.name = name; + init.ops = &cpg_mstp_clock_ops; + init.flags = CLK_IS_BASIC; + init.parent_names = &parent_name; + init.num_parents = 1; + + clock->bit_index = index; + clock->group = group; + clock->hw.init = &init; + + clk = clk_register(NULL, &clock->hw); + + if (IS_ERR(clk)) + kfree(clock); + + return clk; +} + +static void __init cpg_mstp_clocks_init(struct device_node *np) +{ + struct mstp_clock_group *group; + struct clk **clks; + unsigned int i; + + group = kzalloc(sizeof(*group), GFP_KERNEL); + clks = kzalloc(MSTP_MAX_CLOCKS * sizeof(*clks), GFP_KERNEL); + if (group == NULL || clks == NULL) { + kfree(group); + kfree(clks); + pr_err("%s: failed to allocate group\n", __func__); + return; + } + + spin_lock_init(&group->lock); + group->data.clks = clks; + + group->smstpcr = of_iomap(np, 0); + group->mstpsr = of_iomap(np, 1); + + if (group->smstpcr == NULL) { + pr_err("%s: failed to remap SMSTPCR\n", __func__); + kfree(group); + kfree(clks); + return; + } + + for (i = 0; i < MSTP_MAX_CLOCKS; ++i) { + const char *parent_name; + const char *name; + u32 clkidx; + int ret; + + /* Skip clocks with no name. */ + ret = of_property_read_string_index(np, "clock-output-names", + i, &name); + if (ret < 0 || strlen(name) == 0) + continue; + + parent_name = of_clk_get_parent_name(np, i); + ret = of_property_read_u32_index(np, "renesas,clock-indices", i, + &clkidx); + if (parent_name == NULL || ret < 0) + break; + + if (clkidx >= MSTP_MAX_CLOCKS) { + pr_err("%s: invalid clock %s %s index %u)\n", + __func__, np->name, name, clkidx); + continue; + } + + clks[clkidx] = cpg_mstp_clock_register(name, parent_name, i, + group); + if (!IS_ERR(clks[clkidx])) { + group->data.clk_num = max(group->data.clk_num, clkidx); + /* + * Register a clkdev to let board code retrieve the + * clock by name and register aliases for non-DT + * devices. + * + * FIXME: Remove this when all devices that require a + * clock will be instantiated from DT. + */ + clk_register_clkdev(clks[clkidx], name, NULL); + } else { + pr_err("%s: failed to register %s %s clock (%ld)\n", + __func__, np->name, name, PTR_ERR(clks[clkidx])); + } + } + + of_clk_add_provider(np, of_clk_src_onecell_get, &group->data); +} +CLK_OF_DECLARE(cpg_mstp_clks, "renesas,cpg-mstp-clocks", cpg_mstp_clocks_init); -- cgit v1.2.3 From 350d71b94fc9ed4ba9a349786f928aa5e594adc1 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Mon, 9 Sep 2013 14:01:20 +0200 Subject: irqchip: add DesignWare APB ICTL interrupt controller This adds an irqchip driver and corresponding devicetree binding for the secondary interrupt controllers based on Synopsys DesignWare IP dw_apb_ictl. Signed-off-by: Sebastian Hesselbarth Reviewed-by: Mark Rutland Reviewed-by: Jisheng Zhang Reviewed-by: Thomas Gleixner --- .../interrupt-controller/snps,dw-apb-ictl.txt | 32 +++++ drivers/irqchip/Kconfig | 4 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-dw-apb-ictl.c | 150 +++++++++++++++++++++ 4 files changed, 187 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/snps,dw-apb-ictl.txt create mode 100644 drivers/irqchip/irq-dw-apb-ictl.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/interrupt-controller/snps,dw-apb-ictl.txt b/Documentation/devicetree/bindings/interrupt-controller/snps,dw-apb-ictl.txt new file mode 100644 index 000000000000..492911744ca3 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/snps,dw-apb-ictl.txt @@ -0,0 +1,32 @@ +Synopsys DesignWare APB interrupt controller (dw_apb_ictl) + +Synopsys DesignWare provides interrupt controller IP for APB known as +dw_apb_ictl. The IP is used as secondary interrupt controller in some SoCs with +APB bus, e.g. Marvell Armada 1500. + +Required properties: +- compatible: shall be "snps,dw-apb-ictl" +- reg: physical base address of the controller and length of memory mapped + region starting with ENABLE_LOW register +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: number of cells to encode an interrupt-specifier, shall be 1 +- interrupts: interrupt reference to primary interrupt controller +- interrupt-parent: (optional) reference specific primary interrupt controller + +The interrupt sources map to the corresponding bits in the interrupt +registers, i.e. +- 0 maps to bit 0 of low interrupts, +- 1 maps to bit 1 of low interrupts, +- 32 maps to bit 0 of high interrupts, +- 33 maps to bit 1 of high interrupts, +- (optional) fast interrupts start at 64. + +Example: + aic: interrupt-controller@3000 { + compatible = "snps,dw-apb-ictl"; + reg = <0x3000 0xc00>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = ; + }; diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 3792a1aa52b8..940638ddc982 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -30,6 +30,10 @@ config ARM_VIC_NR The maximum number of VICs available in the system, for power management. +config DW_APB_ICTL + bool + select IRQ_DOMAIN + config IMGPDC_IRQ bool select GENERIC_IRQ_CHIP diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index c60b9010b152..6427323af4c3 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_ARCH_MMP) += irq-mmp.o obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o obj-$(CONFIG_ARCH_MXS) += irq-mxs.o obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o +obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o obj-$(CONFIG_METAG) += irq-metag-ext.o obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o obj-$(CONFIG_ARCH_MOXART) += irq-moxart.o diff --git a/drivers/irqchip/irq-dw-apb-ictl.c b/drivers/irqchip/irq-dw-apb-ictl.c new file mode 100644 index 000000000000..31e231e1f566 --- /dev/null +++ b/drivers/irqchip/irq-dw-apb-ictl.c @@ -0,0 +1,150 @@ +/* + * Synopsys DW APB ICTL irqchip driver. + * + * Sebastian Hesselbarth + * + * based on GPL'ed 2.6 kernel sources + * (c) Marvell International Ltd. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include + +#include "irqchip.h" + +#define APB_INT_ENABLE_L 0x00 +#define APB_INT_ENABLE_H 0x04 +#define APB_INT_MASK_L 0x08 +#define APB_INT_MASK_H 0x0c +#define APB_INT_FINALSTATUS_L 0x30 +#define APB_INT_FINALSTATUS_H 0x34 + +static void dw_apb_ictl_handler(unsigned int irq, struct irq_desc *desc) +{ + struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip_generic *gc = irq_get_handler_data(irq); + struct irq_domain *d = gc->private; + u32 stat; + int n; + + chained_irq_enter(chip, desc); + + for (n = 0; n < gc->num_ct; n++) { + stat = readl_relaxed(gc->reg_base + + APB_INT_FINALSTATUS_L + 4 * n); + while (stat) { + u32 hwirq = ffs(stat) - 1; + generic_handle_irq(irq_find_mapping(d, + gc->irq_base + hwirq + 32 * n)); + stat &= ~(1 << hwirq); + } + } + + chained_irq_exit(chip, desc); +} + +static int __init dw_apb_ictl_init(struct device_node *np, + struct device_node *parent) +{ + unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; + struct resource r; + struct irq_domain *domain; + struct irq_chip_generic *gc; + void __iomem *iobase; + int ret, nrirqs, irq; + u32 reg; + + /* Map the parent interrupt for the chained handler */ + irq = irq_of_parse_and_map(np, 0); + if (irq <= 0) { + pr_err("%s: unable to parse irq\n", np->full_name); + return -EINVAL; + } + + ret = of_address_to_resource(np, 0, &r); + if (ret) { + pr_err("%s: unable to get resource\n", np->full_name); + return ret; + } + + if (!request_mem_region(r.start, resource_size(&r), np->full_name)) { + pr_err("%s: unable to request mem region\n", np->full_name); + return -ENOMEM; + } + + iobase = ioremap(r.start, resource_size(&r)); + if (!iobase) { + pr_err("%s: unable to map resource\n", np->full_name); + ret = -ENOMEM; + goto err_release; + } + + /* + * DW IP can be configured to allow 2-64 irqs. We can determine + * the number of irqs supported by writing into enable register + * and look for bits not set, as corresponding flip-flops will + * have been removed by sythesis tool. + */ + + /* mask and enable all interrupts */ + writel(~0, iobase + APB_INT_MASK_L); + writel(~0, iobase + APB_INT_MASK_H); + writel(~0, iobase + APB_INT_ENABLE_L); + writel(~0, iobase + APB_INT_ENABLE_H); + + reg = readl(iobase + APB_INT_ENABLE_H); + if (reg) + nrirqs = 32 + fls(reg); + else + nrirqs = fls(readl(iobase + APB_INT_ENABLE_L)); + + domain = irq_domain_add_linear(np, nrirqs, + &irq_generic_chip_ops, NULL); + if (!domain) { + pr_err("%s: unable to add irq domain\n", np->full_name); + ret = -ENOMEM; + goto err_unmap; + } + + ret = irq_alloc_domain_generic_chips(domain, 32, (nrirqs > 32) ? 2 : 1, + np->name, handle_level_irq, clr, 0, + IRQ_GC_INIT_MASK_CACHE); + if (ret) { + pr_err("%s: unable to alloc irq domain gc\n", np->full_name); + goto err_unmap; + } + + gc = irq_get_domain_generic_chip(domain, 0); + gc->private = domain; + gc->reg_base = iobase; + + gc->chip_types[0].regs.mask = APB_INT_MASK_L; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit; + + if (nrirqs > 32) { + gc->chip_types[1].regs.mask = APB_INT_MASK_H; + gc->chip_types[1].chip.irq_mask = irq_gc_mask_set_bit; + gc->chip_types[1].chip.irq_unmask = irq_gc_mask_clr_bit; + } + + irq_set_handler_data(irq, gc); + irq_set_chained_handler(irq, dw_apb_ictl_handler); + + return 0; + +err_unmap: + iounmap(iobase); +err_release: + release_mem_region(r.start, resource_size(&r)); + return ret; +} +IRQCHIP_DECLARE(dw_apb_ictl, + "snps,dw-apb-ictl", dw_apb_ictl_init); -- cgit v1.2.3 From d68185d1aef9b8d3801ff656ec3089503119e936 Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Mon, 9 Sep 2013 14:07:11 +0200 Subject: ARM: add Marvell Berlin SoC familiy to Marvell doc This adds known facts and rumors about the Marvell Berlin (88DE3xxx) SoC family to the Marvell SoC documentation. Signed-off-by: Sebastian Hesselbarth Reviewed-by: Jason Cooper Reviewed-by: Thomas Petazzoni Reviewed-by: Arnd Bergmann --- Documentation/arm/Marvell/README | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'Documentation') diff --git a/Documentation/arm/Marvell/README b/Documentation/arm/Marvell/README index da0151db9964..5a930c1528ad 100644 --- a/Documentation/arm/Marvell/README +++ b/Documentation/arm/Marvell/README @@ -211,6 +211,30 @@ MMP/MMP2 family (communication processor) Linux kernel mach directory: arch/arm/mach-mmp Linux kernel plat directory: arch/arm/plat-pxa +Berlin family (Digital Entertainment) +------------------------------------- + + Flavors: + 88DE3005, Armada 1500-mini + Design name: BG2CD + Core: ARM Cortex-A9, PL310 L2CC + Homepage: http://www.marvell.com/digital-entertainment/armada-1500-mini/ + 88DE3100, Armada 1500 + Design name: BG2 + Core: Marvell PJ4B (ARMv7), Tauros3 L2CC + Homepage: http://www.marvell.com/digital-entertainment/armada-1500/ + Product Brief: http://www.marvell.com/digital-entertainment/armada-1500/assets/Marvell-ARMADA-1500-Product-Brief.pdf + 88DE???? + Design name: BG3 + Core: ARM Cortex-A15, CA15 integrated L2CC + + Homepage: http://www.marvell.com/digital-entertainment/ + Directory: arch/arm/mach-berlin + + Comments: + * This line of SoCs is based on Marvell Sheeva or ARM Cortex CPUs + with Synopsys DesignWare (IRQ, GPIO, Timers, ...) and PXA IP (SDHCI, USB, ETH, ...). + Long-term plans --------------- -- cgit v1.2.3 From 2440946c29a37ee616a92152972a3772bd2f293c Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Mon, 9 Sep 2013 14:17:52 +0200 Subject: ARM: add Armada 1500 and Sony NSZ-GS7 device tree files This adds very basic device tree files for the Marvell Armada 1500 SoC (Berlin BG2) and the Sony NSZ-GS7 GoogleTV board. Currently, SoC only has nodes for cpus, some clocks, l2 cache controller, local timer, apb timers, uart, and interrupt controllers. The Sony NSZ-GS7 is a GoogleTV consumer device comprising the Armada 1500 SoC above. Signed-off-by: Sebastian Hesselbarth Reviewed-by: Jason Cooper Reviewed-by: Thomas Petazzoni Reviewed-by: Arnd Bergmann Reviewed-by: Jisheng Zhang --- .../devicetree/bindings/arm/marvell,berlin.txt | 24 +++ arch/arm/boot/dts/Makefile | 2 + arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts | 29 +++ arch/arm/boot/dts/berlin2.dtsi | 227 +++++++++++++++++++++ 4 files changed, 282 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/marvell,berlin.txt create mode 100644 arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts create mode 100644 arch/arm/boot/dts/berlin2.dtsi (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/marvell,berlin.txt b/Documentation/devicetree/bindings/arm/marvell,berlin.txt new file mode 100644 index 000000000000..737afa5f8148 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/marvell,berlin.txt @@ -0,0 +1,24 @@ +Marvell Berlin SoC Family Device Tree Bindings +--------------------------------------------------------------- + +Boards with a SoC of the Marvell Berlin family, e.g. Armada 1500 +shall have the following properties: + +* Required root node properties: +compatible: must contain "marvell,berlin" + +In addition, the above compatible shall be extended with the specific +SoC and board used. Currently known SoC compatibles are: + "marvell,berlin2" for Marvell Armada 1500 (BG2, 88DE3100), + "marvell,berlin2cd" for Marvell Armada 1500-mini (BG2CD, 88DE3005) + "marvell,berlin2ct" for Marvell Armada ? (BG2CT, 88DE????) + "marvell,berlin3" for Marvell Armada ? (BG3, 88DE????) + +* Example: + +/ { + model = "Sony NSZ-GS7"; + compatible = "sony,nsz-gs7", "marvell,berlin2", "marvell,berlin"; + + ... +} diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index d57c1a65b24f..7d06d64e2953 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -45,6 +45,8 @@ dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb dtb-$(CONFIG_ARCH_BCM_MOBILE) += bcm11351-brt.dtb \ bcm28155-ap.dtb dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb +dtb-$(CONFIG_ARCH_BERLIN) += \ + berlin2-sony-nsz-gs7.dtb dtb-$(CONFIG_ARCH_DAVINCI) += da850-enbw-cmc.dtb \ da850-evm.dtb dtb-$(CONFIG_ARCH_DOVE) += dove-cm-a510.dtb \ diff --git a/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts b/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts new file mode 100644 index 000000000000..c72bfd468d10 --- /dev/null +++ b/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts @@ -0,0 +1,29 @@ +/* + * Device Tree file for Sony NSZ-GS7 + * + * Sebastian Hesselbarth + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +/dts-v1/; + +#include "berlin2.dtsi" + +/ { + model = "Sony NSZ-GS7"; + compatible = "sony,nsz-gs7", "marvell,berlin2", "marvell,berlin"; + + chosen { + bootargs = "console=ttyS0,115200 earlyprintk"; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x40000000>; /* 1 GB */ + }; +}; + +&uart0 { status = "okay"; }; diff --git a/arch/arm/boot/dts/berlin2.dtsi b/arch/arm/boot/dts/berlin2.dtsi new file mode 100644 index 000000000000..56a1af2f1052 --- /dev/null +++ b/arch/arm/boot/dts/berlin2.dtsi @@ -0,0 +1,227 @@ +/* + * Device Tree Include file for Marvell Armada 1500 (Berlin BG2) SoC + * + * Sebastian Hesselbarth + * + * based on GPL'ed 2.6 kernel sources + * (c) Marvell International Ltd. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include "skeleton.dtsi" +#include + +/ { + model = "Marvell Armada 1500 (BG2) SoC"; + compatible = "marvell,berlin2", "marvell,berlin"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "marvell,pj4b"; + device_type = "cpu"; + next-level-cache = <&l2>; + reg = <0>; + }; + + cpu@1 { + compatible = "marvell,pj4b"; + device_type = "cpu"; + next-level-cache = <&l2>; + reg = <1>; + }; + }; + + clocks { + smclk: sysmgr-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; + + cfgclk: cfg-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + }; + + sysclk: system-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <400000000>; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&gic>; + + ranges = <0 0xf7000000 0x1000000>; + + l2: l2-cache-controller@ac0000 { + compatible = "marvell,tauros3-cache", "arm,pl310-cache"; + reg = <0xac0000 0x1000>; + cache-unified; + cache-level = <2>; + }; + + gic: interrupt-controller@ad1000 { + compatible = "arm,cortex-a9-gic"; + reg = <0xad1000 0x1000>, <0xad0100 0x0100>; + interrupt-controller; + #interrupt-cells = <3>; + }; + + local-timer@ad0600 { + compatible = "arm,cortex-a9-twd-timer"; + reg = <0xad0600 0x20>; + interrupts = ; + clocks = <&sysclk>; + }; + + apb@e80000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0 0xe80000 0x10000>; + interrupt-parent = <&aic>; + + timer0: timer@2c00 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c00 0x14>; + interrupts = <8>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "okay"; + }; + + timer1: timer@2c14 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c14 0x14>; + interrupts = <9>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "okay"; + }; + + timer2: timer@2c28 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c28 0x14>; + interrupts = <10>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer3: timer@2c3c { + compatible = "snps,dw-apb-timer"; + reg = <0x2c3c 0x14>; + interrupts = <11>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer4: timer@2c50 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c50 0x14>; + interrupts = <12>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer5: timer@2c64 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c64 0x14>; + interrupts = <13>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer6: timer@2c78 { + compatible = "snps,dw-apb-timer"; + reg = <0x2c78 0x14>; + interrupts = <14>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer7: timer@2c8c { + compatible = "snps,dw-apb-timer"; + reg = <0x2c8c 0x14>; + interrupts = <15>; + clocks = <&cfgclk>; + clock-names = "timer"; + status = "disabled"; + }; + + aic: interrupt-controller@3000 { + compatible = "snps,dw-apb-ictl"; + reg = <0x3000 0xc00>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = ; + }; + }; + + apb@fc0000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0 0xfc0000 0x10000>; + interrupt-parent = <&sic>; + + uart0: serial@9000 { + compatible = "snps,dw-apb-uart"; + reg = <0x9000 0x100>; + reg-shift = <2>; + reg-io-width = <1>; + interrupts = <8>; + clocks = <&smclk>; + status = "disabled"; + }; + + uart1: serial@a000 { + compatible = "snps,dw-apb-uart"; + reg = <0xa000 0x100>; + reg-shift = <2>; + reg-io-width = <1>; + interrupts = <9>; + clocks = <&smclk>; + status = "disabled"; + }; + + uart2: serial@b000 { + compatible = "snps,dw-apb-uart"; + reg = <0xb000 0x100>; + reg-shift = <2>; + reg-io-width = <1>; + interrupts = <10>; + clocks = <&smclk>; + status = "disabled"; + }; + + sic: interrupt-controller@e000 { + compatible = "snps,dw-apb-ictl"; + reg = <0xe000 0x400>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = ; + }; + }; + }; +}; -- cgit v1.2.3 From 92e112fdbb3cb55b43390426501a7efacd893b96 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 13 Dec 2013 11:36:22 -0700 Subject: PCI/checkpatch: Deprecate DEFINE_PCI_DEVICE_TABLE Prefer use of the direct definition of struct pci_device_id instead of indirection via macro DEFINE_PCI_DEVICE_TABLE. Update the PCI documentation to deprecate DEFINE_PCI_DEVICE_TABLE. Update checkpatch adding --fix option. Signed-off-by: Joe Perches Signed-off-by: Bjorn Helgaas Reviewed-by: Jingoo Han --- Documentation/PCI/pci.txt | 6 ++++-- include/linux/pci.h | 3 +-- scripts/checkpatch.pl | 11 +++++++---- 3 files changed, 12 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/PCI/pci.txt b/Documentation/PCI/pci.txt index 6f458564d625..9518006f6675 100644 --- a/Documentation/PCI/pci.txt +++ b/Documentation/PCI/pci.txt @@ -123,8 +123,10 @@ initialization with a pointer to a structure describing the driver The ID table is an array of struct pci_device_id entries ending with an -all-zero entry; use of the macro DEFINE_PCI_DEVICE_TABLE is the preferred -method of declaring the table. Each entry consists of: +all-zero entry. Definitions with static const are generally preferred. +Use of the deprecated macro DEFINE_PCI_DEVICE_TABLE should be avoided. + +Each entry consists of: vendor,device Vendor and device ID to match (or PCI_ANY_ID) diff --git a/include/linux/pci.h b/include/linux/pci.h index 1084a15175e0..88674b0947fb 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -634,8 +634,7 @@ struct pci_driver { * DEFINE_PCI_DEVICE_TABLE - macro used to describe a pci device table * @_table: device table name * - * This macro is used to create a struct pci_device_id array (a device table) - * in a generic manner. + * This macro is deprecated and should not be used in new code. */ #define DEFINE_PCI_DEVICE_TABLE(_table) \ const struct pci_device_id _table[] diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 9c9810030377..9fb30b15c9dc 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2634,10 +2634,13 @@ sub process { $herecurr); } -# check for declarations of struct pci_device_id - if ($line =~ /\bstruct\s+pci_device_id\s+\w+\s*\[\s*\]\s*\=\s*\{/) { - WARN("DEFINE_PCI_DEVICE_TABLE", - "Use DEFINE_PCI_DEVICE_TABLE for struct pci_device_id\n" . $herecurr); +# check for uses of DEFINE_PCI_DEVICE_TABLE + if ($line =~ /\bDEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=/) { + if (WARN("DEFINE_PCI_DEVICE_TABLE", + "Prefer struct pci_device_id over deprecated DEFINE_PCI_DEVICE_TABLE\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/\b(?:static\s+|)DEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=\s*/static const struct pci_device_id $1\[\] = /; + } } # check for new typedefs, only function parameters and sparse annotations -- cgit v1.2.3 From db2299e4548267dafc1177a315a0f5c2761cfa50 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sun, 24 Nov 2013 15:30:47 +0900 Subject: of: add vendor prefix for Trusted Logic Mobility Add the "tlm" prefix for Trusted Logic Mobility. Signed-off-by: Alexandre Courbot Signed-off-by: Stephen Warren --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index ce95ed1c6d3e..30261c831097 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -71,6 +71,7 @@ st STMicroelectronics ste ST-Ericsson stericsson ST-Ericsson ti Texas Instruments +tlm Trusted Logic Mobility toshiba Toshiba Corporation toumaz Toumaz v3 V3 Semiconductor -- cgit v1.2.3 From fb2947c74b422f8aaef844128d20bc7c641356ea Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sun, 24 Nov 2013 15:30:48 +0900 Subject: of: add Trusted Foundations bindings documentation Add the Device Tree bindings documentation for the Trusted Foundation secure monitor. Signed-off-by: Alexandre Courbot Signed-off-by: Stephen Warren --- .../arm/firmware/tlm,trusted-foundations.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/firmware/tlm,trusted-foundations.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/firmware/tlm,trusted-foundations.txt b/Documentation/devicetree/bindings/arm/firmware/tlm,trusted-foundations.txt new file mode 100644 index 000000000000..780d0392a66b --- /dev/null +++ b/Documentation/devicetree/bindings/arm/firmware/tlm,trusted-foundations.txt @@ -0,0 +1,20 @@ +Trusted Foundations +------------------- + +Boards that use the Trusted Foundations secure monitor can signal its +presence by declaring a node compatible with "tlm,trusted-foundations" +under the /firmware/ node + +Required properties: +- compatible: "tlm,trusted-foundations" +- tlm,version-major: major version number of Trusted Foundations firmware +- tlm,version-minor: minor version number of Trusted Foundations firmware + +Example: + firmware { + trusted-foundations { + compatible = "tlm,trusted-foundations"; + tlm,version-major = <2>; + tlm,version-minor = <8>; + }; + }; -- cgit v1.2.3 From 1a5de3aeb015e495b7ffe03186cc598f17d8ad88 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sun, 24 Nov 2013 15:30:49 +0900 Subject: ARM: tegra: add support for Trusted Foundations Register the firmware operations for Trusted Foundations if the device tree indicates it is active on the device. Signed-off-by: Alexandre Courbot Reviewed-by: Tomasz Figa Reviewed-by: Stephen Warren Signed-off-by: Stephen Warren --- Documentation/devicetree/bindings/arm/tegra.txt | 5 +++++ arch/arm/mach-tegra/Kconfig | 1 + arch/arm/mach-tegra/tegra.c | 2 ++ 3 files changed, 8 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/tegra.txt b/Documentation/devicetree/bindings/arm/tegra.txt index ed9c85334436..558ed4b4ef39 100644 --- a/Documentation/devicetree/bindings/arm/tegra.txt +++ b/Documentation/devicetree/bindings/arm/tegra.txt @@ -32,3 +32,8 @@ board-specific compatible values: nvidia,whistler toradex,colibri_t20-512 toradex,iris + +Trusted Foundations +------------------------------------------- +Tegra supports the Trusted Foundation secure monitor. See the +"tlm,trusted-foundations" binding's documentation for more details. diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 09e740f58b27..00b85fd9285d 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -2,6 +2,7 @@ config ARCH_TEGRA bool "NVIDIA Tegra" if ARCH_MULTI_V7 select ARCH_HAS_CPUFREQ select ARCH_REQUIRE_GPIOLIB + select ARCH_SUPPORTS_TRUSTED_FOUNDATIONS select ARM_GIC select CLKSRC_MMIO select CLKSRC_OF diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index 73368176c6e8..09a1f8d98ca2 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "apbio.h" #include "board.h" @@ -90,6 +91,7 @@ static void __init tegra_init_cache(void) static void __init tegra_init_early(void) { + of_register_trusted_foundations(); tegra_apb_io_init(); tegra_init_fuse(); tegra_cpu_reset_handler_init(); -- cgit v1.2.3 From 92ca6a8ce97e07206d474da5477d8da4e41bad6c Mon Sep 17 00:00:00 2001 From: Takashi Yoshii Date: Tue, 8 Oct 2013 14:32:17 +0900 Subject: clk: emev2: Add support for emev2 SMU clocks with DT Device tree clock binding document for EMMA Mobile EV2 SMU, And Common clock framework based implementation of it. Following nodes are defined to describe clock tree. - renesas,emev2-smu - renesas,emev2-smu-clkdiv - renesas,emev2-smu-gclk These bindings are designed manually based on 19UH0037EJ1000_SMU : System Management Unit User's Manual So far, reparent is not implemented, and is fixed to index #0. Clock tree description is not included, and should be provided by device-tree. Signed-off-by: Takashi Yoshii Acked-by: Magnus Damm Signed-off-by: Simon Horman --- .../devicetree/bindings/clock/emev2-clock.txt | 98 +++++++++++++++++++ drivers/clk/shmobile/Makefile | 2 +- drivers/clk/shmobile/clk-emev2.c | 104 +++++++++++++++++++++ 3 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/clock/emev2-clock.txt create mode 100644 drivers/clk/shmobile/clk-emev2.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/emev2-clock.txt b/Documentation/devicetree/bindings/clock/emev2-clock.txt new file mode 100644 index 000000000000..60bbb1a8c69a --- /dev/null +++ b/Documentation/devicetree/bindings/clock/emev2-clock.txt @@ -0,0 +1,98 @@ +Device tree Clock bindings for Renesas EMMA Mobile EV2 + +This binding uses the common clock binding. + +* SMU +System Management Unit described in user's manual R19UH0037EJ1000_SMU. +This is not a clock provider, but clocks under SMU depend on it. + +Required properties: +- compatible: Should be "renesas,emev2-smu" +- reg: Address and Size of SMU registers + +* SMU_CLKDIV +Function block with an input mux and a divider, which corresponds to +"Serial clock generator" in fig."Clock System Overview" of the manual, +and "xxx frequency division setting register" (XXXCLKDIV) registers. +This makes internal (neither input nor output) clock that is provided +to input of xxxGCLK block. + +Required properties: +- compatible: Should be "renesas,emev2-smu-clkdiv" +- reg: Byte offset from SMU base and Bit position in the register +- clocks: Parent clocks. Input clocks as described in clock-bindings.txt +- #clock-cells: Should be <0> + +* SMU_GCLK +Clock gating node shown as "Clock stop processing block" in the +fig."Clock System Overview" of the manual. +Registers are "xxx clock gate control register" (XXXGCLKCTRL). + +Required properties: +- compatible: Should be "renesas,emev2-smu-gclk" +- reg: Byte offset from SMU base and Bit position in the register +- clocks: Input clock as described in clock-bindings.txt +- #clock-cells: Should be <0> + +Example of provider: + +usia_u0_sclkdiv: usia_u0_sclkdiv { + compatible = "renesas,emev2-smu-clkdiv"; + reg = <0x610 0>; + clocks = <&pll3_fo>, <&pll4_fo>, <&pll1_fo>, <&osc1_fo>; + #clock-cells = <0>; +}; + +usia_u0_sclk: usia_u0_sclk { + compatible = "renesas,emev2-smu-gclk"; + reg = <0x4a0 1>; + clocks = <&usia_u0_sclkdiv>; + #clock-cells = <0>; +}; + +Example of consumer: + +uart@e1020000 { + compatible = "renesas,em-uart"; + reg = <0xe1020000 0x38>; + interrupts = <0 8 0>; + clocks = <&usia_u0_sclk>; + clock-names = "sclk"; +}; + +Example of clock-tree description: + + This describes a clock path in the clock tree + c32ki -> pll3_fo -> usia_u0_sclkdiv -> usia_u0_sclk + +smu@e0110000 { + compatible = "renesas,emev2-smu"; + reg = <0xe0110000 0x10000>; + #address-cells = <2>; + #size-cells = <0>; + + c32ki: c32ki { + compatible = "fixed-clock"; + clock-frequency = <32768>; + #clock-cells = <0>; + }; + pll3_fo: pll3_fo { + compatible = "fixed-factor-clock"; + clocks = <&c32ki>; + clock-div = <1>; + clock-mult = <7000>; + #clock-cells = <0>; + }; + usia_u0_sclkdiv: usia_u0_sclkdiv { + compatible = "renesas,emev2-smu-clkdiv"; + reg = <0x610 0>; + clocks = <&pll3_fo>; + #clock-cells = <0>; + }; + usia_u0_sclk: usia_u0_sclk { + compatible = "renesas,emev2-smu-gclk"; + reg = <0x4a0 1>; + clocks = <&usia_u0_sclkdiv>; + #clock-cells = <0>; + }; +}; diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile index 706adc6ae70c..9ecef140dba7 100644 --- a/drivers/clk/shmobile/Makefile +++ b/drivers/clk/shmobile/Makefile @@ -1,7 +1,7 @@ +obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-mstp.o - # for emply built-in.o obj-n := dummy diff --git a/drivers/clk/shmobile/clk-emev2.c b/drivers/clk/shmobile/clk-emev2.c new file mode 100644 index 000000000000..6c7c929c7765 --- /dev/null +++ b/drivers/clk/shmobile/clk-emev2.c @@ -0,0 +1,104 @@ +/* + * EMMA Mobile EV2 common clock framework support + * + * Copyright (C) 2013 Takashi Yoshii + * Copyright (C) 2012 Magnus Damm + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include + +/* EMEV2 SMU registers */ +#define USIAU0_RSTCTRL 0x094 +#define USIBU1_RSTCTRL 0x0ac +#define USIBU2_RSTCTRL 0x0b0 +#define USIBU3_RSTCTRL 0x0b4 +#define STI_RSTCTRL 0x124 +#define STI_CLKSEL 0x688 + +static DEFINE_SPINLOCK(lock); + +/* not pretty, but hey */ +void __iomem *smu_base; + +static void __init emev2_smu_write(unsigned long value, int offs) +{ + BUG_ON(!smu_base || (offs >= PAGE_SIZE)); + writel_relaxed(value, smu_base + offs); +} + +static const struct of_device_id smu_id[] __initconst = { + { .compatible = "renesas,emev2-smu", }, + {}, +}; + +static void __init emev2_smu_init(void) +{ + struct device_node *np; + + np = of_find_matching_node(NULL, smu_id); + BUG_ON(!np); + smu_base = of_iomap(np, 0); + BUG_ON(!smu_base); + of_node_put(np); + + /* setup STI timer to run on 32.768 kHz and deassert reset */ + emev2_smu_write(0, STI_CLKSEL); + emev2_smu_write(1, STI_RSTCTRL); + + /* deassert reset for UART0->UART3 */ + emev2_smu_write(2, USIAU0_RSTCTRL); + emev2_smu_write(2, USIBU1_RSTCTRL); + emev2_smu_write(2, USIBU2_RSTCTRL); + emev2_smu_write(2, USIBU3_RSTCTRL); +} + +static void __init emev2_smu_clkdiv_init(struct device_node *np) +{ + u32 reg[2]; + struct clk *clk; + const char *parent_name = of_clk_get_parent_name(np, 0); + if (WARN_ON(of_property_read_u32_array(np, "reg", reg, 2))) + return; + if (!smu_base) + emev2_smu_init(); + clk = clk_register_divider(NULL, np->name, parent_name, 0, + smu_base + reg[0], reg[1], 8, 0, &lock); + of_clk_add_provider(np, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, np->name, NULL); + pr_debug("## %s %s %p\n", __func__, np->name, clk); +} +CLK_OF_DECLARE(emev2_smu_clkdiv, "renesas,emev2-smu-clkdiv", + emev2_smu_clkdiv_init); + +static void __init emev2_smu_gclk_init(struct device_node *np) +{ + u32 reg[2]; + struct clk *clk; + const char *parent_name = of_clk_get_parent_name(np, 0); + if (WARN_ON(of_property_read_u32_array(np, "reg", reg, 2))) + return; + if (!smu_base) + emev2_smu_init(); + clk = clk_register_gate(NULL, np->name, parent_name, 0, + smu_base + reg[0], reg[1], 0, &lock); + of_clk_add_provider(np, of_clk_src_simple_get, clk); + clk_register_clkdev(clk, np->name, NULL); + pr_debug("## %s %s %p\n", __func__, np->name, clk); +} +CLK_OF_DECLARE(emev2_smu_gclk, "renesas,emev2-smu-gclk", emev2_smu_gclk_init); -- cgit v1.2.3 From 1459c837036a44e2dcf14a9452ed330201fb23b5 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Sat, 21 Sep 2013 16:40:39 -0700 Subject: clk: si570: Add a driver for SI570 oscillators Add a driver for SILabs 570, 571, 598, 599 programmable oscillators. The devices generate low-jitter clock signals and are reprogrammable via an I2C interface. Reviewed-by: Guenter Roeck Signed-off-by: Soren Brinkmann Signed-off-by: Mike Turquette --- .../devicetree/bindings/clock/silabs,si570.txt | 39 ++ drivers/clk/Kconfig | 10 + drivers/clk/Makefile | 1 + drivers/clk/clk-si570.c | 531 +++++++++++++++++++++ 4 files changed, 581 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/silabs,si570.txt create mode 100644 drivers/clk/clk-si570.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/silabs,si570.txt b/Documentation/devicetree/bindings/clock/silabs,si570.txt new file mode 100644 index 000000000000..c09f21e1d98f --- /dev/null +++ b/Documentation/devicetree/bindings/clock/silabs,si570.txt @@ -0,0 +1,39 @@ +Binding for Silicon Labs 570, 571, 598 and 599 programmable +I2C clock generators. + +Reference +This binding uses the common clock binding[1]. Details about the devices can be +found in the data sheets[2][3]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Si570/571 Data Sheet + http://www.silabs.com/Support%20Documents/TechnicalDocs/si570.pdf +[3] Si598/599 Data Sheet + http://www.silabs.com/Support%20Documents/TechnicalDocs/si598-99.pdf + +Required properties: + - compatible: Shall be one of "silabs,si570", "silabs,si571", + "silabs,si598", "silabs,si599" + - reg: I2C device address. + - #clock-cells: From common clock bindings: Shall be 0. + - factory-fout: Factory set default frequency. This frequency is part specific. + The correct frequency for the part used has to be provided in + order to generate the correct output frequencies. For more + details, please refer to the data sheet. + - temperature-stability: Temperature stability of the device in PPM. Should be + one of: 7, 20, 50 or 100. + +Optional properties: + - clock-output-names: From common clock bindings. Recommended to be "si570". + - clock-frequency: Output frequency to generate. This defines the output + frequency set during boot. It can be reprogrammed during + runtime through the common clock framework. + +Example: + si570: clock-generator@5d { + #clock-cells = <0>; + compatible = "silabs,si570"; + temperature-stability = <50>; + reg = <0x5d>; + factory-fout = <156250000>; + }; diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 5c51115081b3..3089f05ba661 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -64,6 +64,16 @@ config COMMON_CLK_SI5351 This driver supports Silicon Labs 5351A/B/C programmable clock generators. +config COMMON_CLK_SI570 + tristate "Clock driver for SiLabs 570 and compatible devices" + depends on I2C + depends on OF + select REGMAP_I2C + help + ---help--- + This driver supports Silicon Labs 570/571/598/599 programmable + clock generators. + config COMMON_CLK_S2MPS11 tristate "Clock driver for S2MPS11 MFD" depends on MFD_SEC_CORE diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 2460afd59405..6705d9a82cbc 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o +obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o diff --git a/drivers/clk/clk-si570.c b/drivers/clk/clk-si570.c new file mode 100644 index 000000000000..5d0ac9f8e1ee --- /dev/null +++ b/drivers/clk/clk-si570.c @@ -0,0 +1,531 @@ +/* + * Driver for Silicon Labs Si570/Si571 Programmable XO/VCXO + * + * Copyright (C) 2010, 2011 Ericsson AB. + * Copyright (C) 2011 Guenter Roeck. + * Copyright (C) 2011 - 2013 Xilinx Inc. + * + * Author: Guenter Roeck + * Sören Brinkmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +/* Si570 registers */ +#define SI570_REG_HS_N1 7 +#define SI570_REG_N1_RFREQ0 8 +#define SI570_REG_RFREQ1 9 +#define SI570_REG_RFREQ2 10 +#define SI570_REG_RFREQ3 11 +#define SI570_REG_RFREQ4 12 +#define SI570_REG_CONTROL 135 +#define SI570_REG_FREEZE_DCO 137 +#define SI570_DIV_OFFSET_7PPM 6 + +#define HS_DIV_SHIFT 5 +#define HS_DIV_MASK 0xe0 +#define HS_DIV_OFFSET 4 +#define N1_6_2_MASK 0x1f +#define N1_1_0_MASK 0xc0 +#define RFREQ_37_32_MASK 0x3f + +#define SI570_MIN_FREQ 10000000L +#define SI570_MAX_FREQ 1417500000L +#define SI598_MAX_FREQ 525000000L + +#define FDCO_MIN 4850000000LL +#define FDCO_MAX 5670000000LL + +#define SI570_CNTRL_RECALL (1 << 0) +#define SI570_CNTRL_FREEZE_M (1 << 5) +#define SI570_CNTRL_NEWFREQ (1 << 6) + +#define SI570_FREEZE_DCO (1 << 4) + +/** + * struct clk_si570: + * @hw: Clock hw struct + * @regmap: Device's regmap + * @div_offset: Rgister offset for dividers + * @max_freq: Maximum frequency for this device + * @fxtal: Factory xtal frequency + * @n1: Clock divider N1 + * @hs_div: Clock divider HSDIV + * @rfreq: Clock multiplier RFREQ + * @frequency: Current output frequency + * @i2c_client: I2C client pointer + */ +struct clk_si570 { + struct clk_hw hw; + struct regmap *regmap; + unsigned int div_offset; + u64 max_freq; + u64 fxtal; + unsigned int n1; + unsigned int hs_div; + u64 rfreq; + u64 frequency; + struct i2c_client *i2c_client; +}; +#define to_clk_si570(_hw) container_of(_hw, struct clk_si570, hw) + +enum clk_si570_variant { + si57x, + si59x +}; + +/** + * si570_get_divs() - Read clock dividers from HW + * @data: Pointer to struct clk_si570 + * @rfreq: Fractional multiplier (output) + * @n1: Divider N1 (output) + * @hs_div: Divider HSDIV (output) + * Returns 0 on success, negative errno otherwise. + * + * Retrieve clock dividers and multipliers from the HW. + */ +static int si570_get_divs(struct clk_si570 *data, u64 *rfreq, + unsigned int *n1, unsigned int *hs_div) +{ + int err; + u8 reg[6]; + u64 tmp; + + err = regmap_bulk_read(data->regmap, SI570_REG_HS_N1 + data->div_offset, + reg, ARRAY_SIZE(reg)); + if (err) + return err; + + *hs_div = ((reg[0] & HS_DIV_MASK) >> HS_DIV_SHIFT) + HS_DIV_OFFSET; + *n1 = ((reg[0] & N1_6_2_MASK) << 2) + ((reg[1] & N1_1_0_MASK) >> 6) + 1; + /* Handle invalid cases */ + if (*n1 > 1) + *n1 &= ~1; + + tmp = reg[1] & RFREQ_37_32_MASK; + tmp = (tmp << 8) + reg[2]; + tmp = (tmp << 8) + reg[3]; + tmp = (tmp << 8) + reg[4]; + tmp = (tmp << 8) + reg[5]; + *rfreq = tmp; + + return 0; +} + +/** + * si570_get_defaults() - Get default values + * @data: Driver data structure + * @fout: Factory frequency output + * Returns 0 on success, negative errno otherwise. + */ +static int si570_get_defaults(struct clk_si570 *data, u64 fout) +{ + int err; + u64 fdco; + + regmap_write(data->regmap, SI570_REG_CONTROL, SI570_CNTRL_RECALL); + + err = si570_get_divs(data, &data->rfreq, &data->n1, &data->hs_div); + if (err) + return err; + + /* + * Accept optional precision loss to avoid arithmetic overflows. + * Acceptable per Silicon Labs Application Note AN334. + */ + fdco = fout * data->n1 * data->hs_div; + if (fdco >= (1LL << 36)) + data->fxtal = div64_u64(fdco << 24, data->rfreq >> 4); + else + data->fxtal = div64_u64(fdco << 28, data->rfreq); + + data->frequency = fout; + + return 0; +} + +/** + * si570_update_rfreq() - Update clock multiplier + * @data: Driver data structure + * Passes on regmap_bulk_write() return value. + */ +static int si570_update_rfreq(struct clk_si570 *data) +{ + u8 reg[5]; + + reg[0] = ((data->n1 - 1) << 6) | + ((data->rfreq >> 32) & RFREQ_37_32_MASK); + reg[1] = (data->rfreq >> 24) & 0xff; + reg[2] = (data->rfreq >> 16) & 0xff; + reg[3] = (data->rfreq >> 8) & 0xff; + reg[4] = data->rfreq & 0xff; + + return regmap_bulk_write(data->regmap, SI570_REG_N1_RFREQ0 + + data->div_offset, reg, ARRAY_SIZE(reg)); +} + +/** + * si570_calc_divs() - Caluclate clock dividers + * @frequency: Target frequency + * @data: Driver data structure + * @out_rfreq: RFREG fractional multiplier (output) + * @out_n1: Clock divider N1 (output) + * @out_hs_div: Clock divider HSDIV (output) + * Returns 0 on success, negative errno otherwise. + * + * Calculate the clock dividers (@out_hs_div, @out_n1) and clock multiplier + * (@out_rfreq) for a given target @frequency. + */ +static int si570_calc_divs(unsigned long frequency, struct clk_si570 *data, + u64 *out_rfreq, unsigned int *out_n1, unsigned int *out_hs_div) +{ + int i; + unsigned int n1, hs_div; + u64 fdco, best_fdco = ULLONG_MAX; + static const uint8_t si570_hs_div_values[] = { 11, 9, 7, 6, 5, 4 }; + + for (i = 0; i < ARRAY_SIZE(si570_hs_div_values); i++) { + hs_div = si570_hs_div_values[i]; + /* Calculate lowest possible value for n1 */ + n1 = div_u64(div_u64(FDCO_MIN, hs_div), frequency); + if (!n1 || (n1 & 1)) + n1++; + while (n1 <= 128) { + fdco = (u64)frequency * (u64)hs_div * (u64)n1; + if (fdco > FDCO_MAX) + break; + if (fdco >= FDCO_MIN && fdco < best_fdco) { + *out_n1 = n1; + *out_hs_div = hs_div; + *out_rfreq = div64_u64(fdco << 28, data->fxtal); + best_fdco = fdco; + } + n1 += (n1 == 1 ? 1 : 2); + } + } + + if (best_fdco == ULLONG_MAX) + return -EINVAL; + + return 0; +} + +static unsigned long si570_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + int err; + u64 rfreq, rate; + unsigned int n1, hs_div; + struct clk_si570 *data = to_clk_si570(hw); + + err = si570_get_divs(data, &rfreq, &n1, &hs_div); + if (err) { + dev_err(&data->i2c_client->dev, "unable to recalc rate\n"); + return data->frequency; + } + + rfreq = div_u64(rfreq, hs_div * n1); + rate = (data->fxtal * rfreq) >> 28; + + return rate; +} + +static long si570_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + int err; + u64 rfreq; + unsigned int n1, hs_div; + struct clk_si570 *data = to_clk_si570(hw); + + if (!rate) + return 0; + + if (div64_u64(abs(rate - data->frequency) * 10000LL, + data->frequency) < 35) { + rfreq = div64_u64((data->rfreq * rate) + + div64_u64(data->frequency, 2), data->frequency); + n1 = data->n1; + hs_div = data->hs_div; + + } else { + err = si570_calc_divs(rate, data, &rfreq, &n1, &hs_div); + if (err) { + dev_err(&data->i2c_client->dev, + "unable to round rate\n"); + return 0; + } + } + + return rate; +} + +/** + * si570_set_frequency() - Adjust output frequency + * @data: Driver data structure + * @frequency: Target frequency + * Returns 0 on success. + * + * Update output frequency for big frequency changes (> 3,500 ppm). + */ +static int si570_set_frequency(struct clk_si570 *data, unsigned long frequency) +{ + int err; + + err = si570_calc_divs(frequency, data, &data->rfreq, &data->n1, + &data->hs_div); + if (err) + return err; + + /* + * The DCO reg should be accessed with a read-modify-write operation + * per AN334 + */ + regmap_write(data->regmap, SI570_REG_FREEZE_DCO, SI570_FREEZE_DCO); + regmap_write(data->regmap, SI570_REG_HS_N1 + data->div_offset, + ((data->hs_div - HS_DIV_OFFSET) << HS_DIV_SHIFT) | + (((data->n1 - 1) >> 2) & N1_6_2_MASK)); + si570_update_rfreq(data); + regmap_write(data->regmap, SI570_REG_FREEZE_DCO, 0); + regmap_write(data->regmap, SI570_REG_CONTROL, SI570_CNTRL_NEWFREQ); + + /* Applying a new frequency can take up to 10ms */ + usleep_range(10000, 12000); + + return 0; +} + +/** + * si570_set_frequency_small() - Adjust output frequency + * @data: Driver data structure + * @frequency: Target frequency + * Returns 0 on success. + * + * Update output frequency for small frequency changes (< 3,500 ppm). + */ +static int si570_set_frequency_small(struct clk_si570 *data, + unsigned long frequency) +{ + /* + * This is a re-implementation of DIV_ROUND_CLOSEST + * using the div64_u64 function lieu of letting the compiler + * insert EABI calls + */ + data->rfreq = div64_u64((data->rfreq * frequency) + + div_u64(data->frequency, 2), data->frequency); + regmap_write(data->regmap, SI570_REG_CONTROL, SI570_CNTRL_FREEZE_M); + si570_update_rfreq(data); + regmap_write(data->regmap, SI570_REG_CONTROL, 0); + + /* Applying a new frequency (small change) can take up to 100us */ + usleep_range(100, 200); + + return 0; +} + +static int si570_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_si570 *data = to_clk_si570(hw); + struct i2c_client *client = data->i2c_client; + int err; + + if (rate < SI570_MIN_FREQ || rate > data->max_freq) { + dev_err(&client->dev, + "requested frequency %lu Hz is out of range\n", rate); + return -EINVAL; + } + + if (div64_u64(abs(rate - data->frequency) * 10000LL, + data->frequency) < 35) + err = si570_set_frequency_small(data, rate); + else + err = si570_set_frequency(data, rate); + + if (err) + return err; + + data->frequency = rate; + + return 0; +} + +static const struct clk_ops si570_clk_ops = { + .recalc_rate = si570_recalc_rate, + .round_rate = si570_round_rate, + .set_rate = si570_set_rate, +}; + +static bool si570_regmap_is_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SI570_REG_CONTROL: + return true; + default: + return false; + } +} + +static bool si570_regmap_is_writeable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SI570_REG_HS_N1 ... (SI570_REG_RFREQ4 + SI570_DIV_OFFSET_7PPM): + case SI570_REG_CONTROL: + case SI570_REG_FREEZE_DCO: + return true; + default: + return false; + } +} + +static struct regmap_config si570_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .max_register = 137, + .writeable_reg = si570_regmap_is_writeable, + .volatile_reg = si570_regmap_is_volatile, +}; + +static int si570_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct clk_si570 *data; + struct clk_init_data init; + struct clk *clk; + u32 initial_fout, factory_fout, stability; + int err; + enum clk_si570_variant variant = id->driver_data; + + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + init.ops = &si570_clk_ops; + init.flags = CLK_IS_ROOT; + init.num_parents = 0; + data->hw.init = &init; + data->i2c_client = client; + + if (variant == si57x) { + err = of_property_read_u32(client->dev.of_node, + "temperature-stability", &stability); + if (err) { + dev_err(&client->dev, + "'temperature-stability' property missing\n"); + return err; + } + /* adjust register offsets for 7ppm devices */ + if (stability == 7) + data->div_offset = SI570_DIV_OFFSET_7PPM; + + data->max_freq = SI570_MAX_FREQ; + } else { + data->max_freq = SI598_MAX_FREQ; + } + + if (of_property_read_string(client->dev.of_node, "clock-output-names", + &init.name)) + init.name = client->dev.of_node->name; + + err = of_property_read_u32(client->dev.of_node, "factory-fout", + &factory_fout); + if (err) { + dev_err(&client->dev, "'factory-fout' property missing\n"); + return err; + } + + data->regmap = devm_regmap_init_i2c(client, &si570_regmap_config); + if (IS_ERR(data->regmap)) { + dev_err(&client->dev, "failed to allocate register map\n"); + return PTR_ERR(data->regmap); + } + + i2c_set_clientdata(client, data); + err = si570_get_defaults(data, factory_fout); + if (err) + return err; + + clk = devm_clk_register(&client->dev, &data->hw); + if (IS_ERR(clk)) { + dev_err(&client->dev, "clock registration failed\n"); + return PTR_ERR(clk); + } + err = of_clk_add_provider(client->dev.of_node, of_clk_src_simple_get, + clk); + if (err) { + dev_err(&client->dev, "unable to add clk provider\n"); + return err; + } + + /* Read the requested initial output frequency from device tree */ + if (!of_property_read_u32(client->dev.of_node, "clock-frequency", + &initial_fout)) { + err = clk_set_rate(clk, initial_fout); + if (err) { + of_clk_del_provider(client->dev.of_node); + return err; + } + } + + /* Display a message indicating that we've successfully registered */ + dev_info(&client->dev, "registered, current frequency %llu Hz\n", + data->frequency); + + return 0; +} + +static int si570_remove(struct i2c_client *client) +{ + of_clk_del_provider(client->dev.of_node); + return 0; +} + +static const struct i2c_device_id si570_id[] = { + { "si570", si57x }, + { "si571", si57x }, + { "si598", si59x }, + { "si599", si59x }, + { } +}; +MODULE_DEVICE_TABLE(i2c, si570_id); + +static const struct of_device_id clk_si570_of_match[] = { + { .compatible = "silabs,si570" }, + { .compatible = "silabs,si571" }, + { .compatible = "silabs,si598" }, + { .compatible = "silabs,si599" }, + { }, +}; +MODULE_DEVICE_TABLE(of, clk_si570_of_match); + +static struct i2c_driver si570_driver = { + .driver = { + .name = "si570", + .of_match_table = of_match_ptr(clk_si570_of_match), + }, + .probe = si570_probe, + .remove = si570_remove, + .id_table = si570_id, +}; +module_i2c_driver(si570_driver); + +MODULE_AUTHOR("Guenter Roeck "); +MODULE_AUTHOR("Soeren Brinkmann Date: Mon, 21 Oct 2013 05:57:00 +0900 Subject: ARM: dts: Add dwmmc DT nodes for exynos5420 SOC This patch adds the mmc device tree node entries for exynos5420 SOC. Exynos5420 has a different version of DWMMC controller,so a new compatible string is used to distinguish it from the prior SOC's. Signed-off-by: Yuvaraj Kumar C D Signed-off-by: Kukjin Kim --- .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 2 ++ arch/arm/boot/dts/exynos5420-smdk5420.dts | 33 ++++++++++++++++++ arch/arm/boot/dts/exynos5420.dtsi | 39 ++++++++++++++++++++++ 3 files changed, 74 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt index c67b975c8906..532b1d440abc 100644 --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt @@ -16,6 +16,8 @@ Required Properties: specific extensions. - "samsung,exynos5250-dw-mshc": for controllers with Samsung Exynos5250 specific extensions. + - "samsung,exynos5420-dw-mshc": for controllers with Samsung Exynos5420 + specific extensions. * samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface unit (ciu) clock. This property is applicable only for Exynos5 SoC's and diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts index 79524c74c603..fb5a1e25c632 100644 --- a/arch/arm/boot/dts/exynos5420-smdk5420.dts +++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts @@ -31,6 +31,39 @@ }; }; + mmc@12200000 { + status = "okay"; + broken-cd; + supports-highspeed; + card-detect-delay = <200>; + samsung,dw-mshc-ciu-div = <3>; + samsung,dw-mshc-sdr-timing = <0 4>; + samsung,dw-mshc-ddr-timing = <0 2>; + pinctrl-names = "default"; + pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>; + + slot@0 { + reg = <0>; + bus-width = <8>; + }; + }; + + mmc@12220000 { + status = "okay"; + supports-highspeed; + card-detect-delay = <200>; + samsung,dw-mshc-ciu-div = <3>; + samsung,dw-mshc-sdr-timing = <2 3>; + samsung,dw-mshc-ddr-timing = <1 2>; + pinctrl-names = "default"; + pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>; + + slot@0 { + reg = <0>; + bus-width = <4>; + }; + }; + dp-controller@145B0000 { pinctrl-names = "default"; pinctrl-0 = <&dp_hpd>; diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index 09aa06cb3d3a..3ac3afe0c609 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi @@ -22,6 +22,9 @@ compatible = "samsung,exynos5420"; aliases { + mshc0 = &mmc_0; + mshc1 = &mmc_1; + mshc2 = &mmc_2; pinctrl0 = &pinctrl_0; pinctrl1 = &pinctrl_1; pinctrl2 = &pinctrl_2; @@ -88,6 +91,42 @@ clock-names = "mfc"; }; + mmc_0: mmc@12200000 { + compatible = "samsung,exynos5420-dw-mshc-smu"; + interrupts = <0 75 0>; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x12200000 0x2000>; + clocks = <&clock 351>, <&clock 132>; + clock-names = "biu", "ciu"; + fifo-depth = <0x40>; + status = "disabled"; + }; + + mmc_1: mmc@12210000 { + compatible = "samsung,exynos5420-dw-mshc-smu"; + interrupts = <0 76 0>; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x12210000 0x2000>; + clocks = <&clock 352>, <&clock 133>; + clock-names = "biu", "ciu"; + fifo-depth = <0x40>; + status = "disabled"; + }; + + mmc_2: mmc@12220000 { + compatible = "samsung,exynos5420-dw-mshc"; + interrupts = <0 77 0>; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x12220000 0x1000>; + clocks = <&clock 353>, <&clock 134>; + clock-names = "biu", "ciu"; + fifo-depth = <0x40>; + status = "disabled"; + }; + mct@101C0000 { compatible = "samsung,exynos4210-mct"; reg = <0x101C0000 0x800>; -- cgit v1.2.3 From e0b51c2eae8ebf10d80530b7a306818252206325 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 12 Dec 2013 07:39:27 +0900 Subject: ARM: dts: Update Samsung sysreg binding document Added a binding example for reference and updated the node name. While at it also removed the name description as it is not necessary. Signed-off-by: Sachin Kamat Reviewed-by: Sylwester Nawrocki Signed-off-by: Kukjin Kim --- Documentation/devicetree/bindings/arm/samsung/sysreg.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/samsung/sysreg.txt b/Documentation/devicetree/bindings/arm/samsung/sysreg.txt index 5039c0a12f55..0ab3251a6ec2 100644 --- a/Documentation/devicetree/bindings/arm/samsung/sysreg.txt +++ b/Documentation/devicetree/bindings/arm/samsung/sysreg.txt @@ -1,7 +1,12 @@ SAMSUNG S5P/Exynos SoC series System Registers (SYSREG) Properties: - - name : should be 'sysreg'; - compatible : should contain "samsung,-sysreg", "syscon"; For Exynos4 SoC series it should be "samsung,exynos4-sysreg", "syscon"; - reg : offset and length of the register set. + +Example: + syscon@10010000 { + compatible = "samsung,exynos4-sysreg", "syscon"; + reg = <0x10010000 0x400>; + }; -- cgit v1.2.3 From 1a895578d4e50577bb6aa79bd194b502f09dd768 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Wed, 13 Nov 2013 22:55:25 +0800 Subject: dma: imx-sdma: Add new dma type for ssi dual fifo script This patch adds a new DMA_TYPE for SSI dual FIFO script, included in SDMA firmware version 2. This script would allow SSI use dual fifo mode to transimit/receive data without occasional hardware underrun/overrun. Signed-off-by: Nicolin Chen Acked-by: Kumar Gala Acked-by: Sascha Hauer Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt | 1 + drivers/dma/imx-sdma.c | 4 ++++ include/linux/platform_data/dma-imx.h | 1 + 3 files changed, 6 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt index 4fa814d38321..68b83ecc3850 100644 --- a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt +++ b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt @@ -42,6 +42,7 @@ The full ID of peripheral types can be found below. 19 IPU Memory 20 ASRC 21 ESAI + 22 SSI Dual FIFO (needs firmware ver >= 2) The third cell specifies the transfer priority as below. diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index f769c7383536..152247675feb 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -725,6 +725,10 @@ static void sdma_get_pc(struct sdma_channel *sdmac, per_2_emi = sdma->script_addrs->app_2_mcu_addr; emi_2_per = sdma->script_addrs->mcu_2_app_addr; break; + case IMX_DMATYPE_SSI_DUAL: + per_2_emi = sdma->script_addrs->ssish_2_mcu_addr; + emi_2_per = sdma->script_addrs->mcu_2_ssish_addr; + break; case IMX_DMATYPE_SSI_SP: case IMX_DMATYPE_MMC: case IMX_DMATYPE_SDHC: diff --git a/include/linux/platform_data/dma-imx.h b/include/linux/platform_data/dma-imx.h index beac6b8b6a7b..bcbc6c3c14c0 100644 --- a/include/linux/platform_data/dma-imx.h +++ b/include/linux/platform_data/dma-imx.h @@ -39,6 +39,7 @@ enum sdma_peripheral_type { IMX_DMATYPE_IPU_MEMORY, /* IPU Memory */ IMX_DMATYPE_ASRC, /* ASRC */ IMX_DMATYPE_ESAI, /* ESAI */ + IMX_DMATYPE_SSI_DUAL, /* SSI Dual FIFO */ }; enum imx_dma_prio { -- cgit v1.2.3 From b31d100e9225d013b7b9b4162a2bd3c6724954bd Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Sat, 14 Dec 2013 23:01:54 -0800 Subject: pinctrl-msm: Rename compatible to be more specific Use the more specific form 8974 for the compatible to reduce the risk of future mishaps. Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- .../bindings/pinctrl/qcom,msm8974-pinctrl.txt | 92 ++++++++++++++++++++++ .../bindings/pinctrl/qcom,msm8x74-pinctrl.txt | 92 ---------------------- drivers/pinctrl/pinctrl-msm8x74.c | 2 +- 3 files changed, 93 insertions(+), 93 deletions(-) create mode 100644 Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt delete mode 100644 Documentation/devicetree/bindings/pinctrl/qcom,msm8x74-pinctrl.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt new file mode 100644 index 000000000000..4c352be5dd61 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.txt @@ -0,0 +1,92 @@ +Qualcomm MSM8974 TLMM block + +Required properties: +- compatible: "qcom,msm8x74-pinctrl" +- reg: Should be the base address and length of the TLMM block. +- interrupts: Should be the parent IRQ of the TLMM block. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be two. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells : Should be two. + The first cell is the gpio pin number and the + second cell is used for optional parameters. + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Qualcomm's pin configuration nodes act as a container for an abitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + pins, function, bias-disable, bias-pull-down, bias-pull,up, drive-strength. + +Non-empty subnodes must specify the 'pins' property. +Note that not all properties are valid for all pins. + + +Valid values for qcom,pins are: + gpio0-gpio145 + Supports mux, bias and drive-strength + + sdc1_clk, sdc1_cmd, sdc1_data, sdc2_clk, sdc2_cmd, sdc2_data + Supports bias and drive-strength + +Valid values for qcom,function are: + blsp_i2c2, blsp_i2c6, blsp_i2c11, blsp_spi1, blsp_uart2, blsp_uart8, slimbus + + (Note that this is not yet the complete list of functions) + + + +Example: + + msmgpio: pinctrl@fd510000 { + compatible = "qcom,msm8974-pinctrl"; + reg = <0xfd510000 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 208 0>; + + pinctrl-names = "default"; + pinctrl-0 = <&uart2_default>; + + uart2_default: uart2_default { + mux { + qcom,pins = "gpio4", "gpio5"; + qcom,function = "blsp_uart2"; + }; + + tx { + qcom,pins = "gpio4"; + drive-strength = <4>; + bias-disable; + }; + + rx { + qcom,pins = "gpio5"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8x74-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8x74-pinctrl.txt deleted file mode 100644 index 70ab78fe93c8..000000000000 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8x74-pinctrl.txt +++ /dev/null @@ -1,92 +0,0 @@ -Qualcomm MSM8x74 TLMM block - -Required properties: -- compatible: "qcom,msm8x74-pinctrl" -- reg: Should be the base address and length of the TLMM block. -- interrupts: Should be the parent IRQ of the TLMM block. -- interrupt-controller: Marks the device node as an interrupt controller. -- #interrupt-cells: Should be two. -- gpio-controller: Marks the device node as a GPIO controller. -- #gpio-cells : Should be two. - The first cell is the gpio pin number and the - second cell is used for optional parameters. - -Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for -a general description of GPIO and interrupt bindings. - -Please refer to pinctrl-bindings.txt in this directory for details of the -common pinctrl bindings used by client devices, including the meaning of the -phrase "pin configuration node". - -Qualcomm's pin configuration nodes act as a container for an abitrary number of -subnodes. Each of these subnodes represents some desired configuration for a -pin, a group, or a list of pins or groups. This configuration can include the -mux function to select on those pin(s)/group(s), and various pin configuration -parameters, such as pull-up, drive strength, etc. - -The name of each subnode is not important; all subnodes should be enumerated -and processed purely based on their content. - -Each subnode only affects those parameters that are explicitly listed. In -other words, a subnode that lists a mux function but no pin configuration -parameters implies no information about any pin configuration parameters. -Similarly, a pin subnode that describes a pullup parameter implies no -information about e.g. the mux function. - - -The following generic properties as defined in pinctrl-bindings.txt are valid -to specify in a pin configuration subnode: - pins, function, bias-disable, bias-pull-down, bias-pull,up, drive-strength. - -Non-empty subnodes must specify the 'pins' property. -Note that not all properties are valid for all pins. - - -Valid values for qcom,pins are: - gpio0-gpio145 - Supports mux, bias and drive-strength - - sdc1_clk, sdc1_cmd, sdc1_data, sdc2_clk, sdc2_cmd, sdc2_data - Supports bias and drive-strength - -Valid values for qcom,function are: - blsp_i2c2, blsp_i2c6, blsp_i2c11, blsp_spi1, blsp_uart2, blsp_uart8, slimbus - - (Note that this is not yet the complete list of functions) - - - -Example: - - msmgpio: pinctrl@fd510000 { - compatible = "qcom,msm8x74-pinctrl"; - reg = <0xfd510000 0x4000>; - - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - interrupts = <0 208 0>; - - pinctrl-names = "default"; - pinctrl-0 = <&uart2_default>; - - uart2_default: uart2_default { - mux { - qcom,pins = "gpio4", "gpio5"; - qcom,function = "blsp_uart2"; - }; - - tx { - qcom,pins = "gpio4"; - drive-strength = <4>; - bias-disable; - }; - - rx { - qcom,pins = "gpio5"; - drive-strength = <2>; - bias-pull-up; - }; - }; - }; diff --git a/drivers/pinctrl/pinctrl-msm8x74.c b/drivers/pinctrl/pinctrl-msm8x74.c index c702e775bf24..f944bf2172ef 100644 --- a/drivers/pinctrl/pinctrl-msm8x74.c +++ b/drivers/pinctrl/pinctrl-msm8x74.c @@ -603,7 +603,7 @@ static int msm8x74_pinctrl_probe(struct platform_device *pdev) } static const struct of_device_id msm8x74_pinctrl_of_match[] = { - { .compatible = "qcom,msm8x74-pinctrl", }, + { .compatible = "qcom,msm8974-pinctrl", }, { }, }; -- cgit v1.2.3 From 8ba3f4d00078e7a49c60c0bd6298f29402c3a0a0 Mon Sep 17 00:00:00 2001 From: Sherman Yin Date: Wed, 11 Dec 2013 10:37:17 -0800 Subject: pinctrl: Adds slew-rate, input-enable/disable This commit adds slew-rate and input-enable/disable support for pinconf -generic. Signed-off-by: Sherman Yin Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt | 3 +++ drivers/pinctrl/pinconf-generic.c | 4 ++++ include/linux/pinctrl/pinconf-generic.h | 4 ++++ 3 files changed, 11 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt index 1958ca9f9e5c..4414163e76d2 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt @@ -151,6 +151,8 @@ drive-push-pull - drive actively high and low drive-open-drain - drive with open drain drive-open-source - drive with open source drive-strength - sink or source at most X mA +input-enable - enable input on pin (no effect on output) +input-disable - disable input on pin (no effect on output) input-schmitt-enable - enable schmitt-trigger mode input-schmitt-disable - disable schmitt-trigger mode input-debounce - debounce mode with debound time X @@ -158,6 +160,7 @@ low-power-enable - enable low power mode low-power-disable - disable low power mode output-low - set the pin to output mode with low level output-high - set the pin to output mode with high level +slew-rate - set the slew rate Some of the generic properties take arguments. For those that do, the arguments are described below. diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 55a0ebe830ac..3d9a999fb699 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -48,6 +48,7 @@ static struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA"), + PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL), PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL), PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL), PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec"), @@ -160,6 +161,8 @@ static struct pinconf_generic_dt_params dt_params[] = { { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 }, { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 }, { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, + { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, + { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 }, @@ -167,6 +170,7 @@ static struct pinconf_generic_dt_params dt_params[] = { { "low-power-disable", PIN_CONFIG_LOW_POWER_MODE, 0 }, { "output-low", PIN_CONFIG_OUTPUT, 0, }, { "output-high", PIN_CONFIG_OUTPUT, 1, }, + { "slew-rate", PIN_CONFIG_SLEW_RATE, 0}, }; /** diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index 282309d7c4dc..a15f10727eb8 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -61,6 +61,9 @@ * argument is ignored. * @PIN_CONFIG_DRIVE_STRENGTH: the pin will sink or source at most the current * passed as argument. The argument is in mA. + * @PIN_CONFIG_INPUT_ENABLE: enable the pin's input. Note that this does not + * affect the pin's ability to drive output. 1 enables input, 0 disables + * input. * @PIN_CONFIG_INPUT_SCHMITT_ENABLE: control schmitt-trigger mode on the pin. * If the argument != 0, schmitt-trigger mode is enabled. If it's 0, * schmitt-trigger mode is disabled. @@ -101,6 +104,7 @@ enum pin_config_param { PIN_CONFIG_DRIVE_OPEN_DRAIN, PIN_CONFIG_DRIVE_OPEN_SOURCE, PIN_CONFIG_DRIVE_STRENGTH, + PIN_CONFIG_INPUT_ENABLE, PIN_CONFIG_INPUT_SCHMITT_ENABLE, PIN_CONFIG_INPUT_SCHMITT, PIN_CONFIG_INPUT_DEBOUNCE, -- cgit v1.2.3 From 7d0e6192c2f36139e4aa5e4107f4d7fb56d9f290 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Mon, 16 Dec 2013 01:51:47 -0800 Subject: Input: joystick - refer to /dev/input/js0 in documentation Nowadays the joystick device nodes are created under /dev/input, reflect this in the documentation in order to make copy and paste easier for users. Signed-off-by: Antonio Ospite Signed-off-by: Dmitry Torokhov --- Documentation/input/joystick-api.txt | 2 +- Documentation/input/joystick.txt | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/input/joystick-api.txt b/Documentation/input/joystick-api.txt index c507330740cd..f95f64838788 100644 --- a/Documentation/input/joystick-api.txt +++ b/Documentation/input/joystick-api.txt @@ -16,7 +16,7 @@ joystick. By default, the device is opened in blocking mode. - int fd = open ("/dev/js0", O_RDONLY); + int fd = open ("/dev/input/js0", O_RDONLY); 2. Event Reading diff --git a/Documentation/input/joystick.txt b/Documentation/input/joystick.txt index 304262bb661a..8d027dc86c1f 100644 --- a/Documentation/input/joystick.txt +++ b/Documentation/input/joystick.txt @@ -116,7 +116,7 @@ your needs: For testing the joystick driver functionality, there is the jstest program in the utilities package. You run it by typing: - jstest /dev/js0 + jstest /dev/input/js0 And it should show a line with the joystick values, which update as you move the stick, and press its buttons. The axes should all be zero when the @@ -136,7 +136,7 @@ joystick should be autocalibrated by the driver automagically. However, with some analog joysticks, that either do not use linear resistors, or if you want better precision, you can use the jscal program - jscal -c /dev/js0 + jscal -c /dev/input/js0 included in the joystick package to set better correction coefficients than what the driver would choose itself. @@ -145,7 +145,7 @@ what the driver would choose itself. calibration using the jstest command, and if you do, you then can save the correction coefficients into a file - jscal -p /dev/js0 > /etc/joystick.cal + jscal -p /dev/input/js0 > /etc/joystick.cal And add a line to your rc script executing that file @@ -556,7 +556,7 @@ interface, and "old" for the "0.x" interface. You run it by typing: 5. FAQ ~~~~~~ -Q: Running 'jstest /dev/js0' results in "File not found" error. What's the +Q: Running 'jstest /dev/input/js0' results in "File not found" error. What's the cause? A: The device files don't exist. Create them (see section 2.2). -- cgit v1.2.3 From c2729850985934a3124319f8ff1d46d8c72bb012 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Mon, 16 Dec 2013 01:52:17 -0800 Subject: Input: joystick - use sizeof(VARIABLE) in documentation Use the preferred style sizeof(VARIABLE) instead of sizeof(TYPE) in the joystick API documentation, Documentation/CodingStyle states that this is the preferred style for allocations but using it elsewhere is good too. Also fix some errors like "sizeof(struct mybuffer)" which didn't mean anything. Signed-off-by: Antonio Ospite Signed-off-by: Dmitry Torokhov --- Documentation/input/joystick-api.txt | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'Documentation') diff --git a/Documentation/input/joystick-api.txt b/Documentation/input/joystick-api.txt index f95f64838788..943b18eac918 100644 --- a/Documentation/input/joystick-api.txt +++ b/Documentation/input/joystick-api.txt @@ -23,7 +23,7 @@ By default, the device is opened in blocking mode. ~~~~~~~~~~~~~~~~ struct js_event e; - read (fd, &e, sizeof(struct js_event)); + read (fd, &e, sizeof(e)); where js_event is defined as @@ -34,8 +34,8 @@ where js_event is defined as __u8 number; /* axis/button number */ }; -If the read is successful, it will return sizeof(struct js_event), unless -you wanted to read more than one event per read as described in section 3.1. +If the read is successful, it will return sizeof(e), unless you wanted to read +more than one event per read as described in section 3.1. 2.1 js_event.type @@ -99,9 +99,9 @@ may work well if you handle JS_EVENT_INIT events separately, if ((js_event.type & ~JS_EVENT_INIT) == JS_EVENT_BUTTON) { if (js_event.value) - buttons_state |= (1 << js_event.number); - else - buttons_state &= ~(1 << js_event.number); + buttons_state |= (1 << js_event.number); + else + buttons_state &= ~(1 << js_event.number); } is much safer since it can't lose sync with the driver. As you would @@ -144,14 +144,14 @@ all events on the queue (that is, until you get a -1). For example, while (1) { - while (read (fd, &e, sizeof(struct js_event)) > 0) { - process_event (e); - } - /* EAGAIN is returned when the queue is empty */ - if (errno != EAGAIN) { - /* error */ - } - /* do something interesting with processed events */ + while (read (fd, &e, sizeof(e)) > 0) { + process_event (e); + } + /* EAGAIN is returned when the queue is empty */ + if (errno != EAGAIN) { + /* error */ + } + /* do something interesting with processed events */ } One reason for emptying the queue is that if it gets full you'll start @@ -181,7 +181,7 @@ at a time using the typical read(2) functionality. For that, you would replace the read above with something like struct js_event mybuffer[0xff]; - int i = read (fd, mybuffer, sizeof(struct mybuffer)); + int i = read (fd, mybuffer, sizeof(mybuffer)); In this case, read would return -1 if the queue was empty, or some other value in which the number of events read would be i / @@ -269,9 +269,9 @@ The driver offers backward compatibility, though. Here's a quick summary: struct JS_DATA_TYPE js; while (1) { if (read (fd, &js, JS_RETURN) != JS_RETURN) { - /* error */ - } - usleep (1000); + /* error */ + } + usleep (1000); } As you can figure out from the example, the read returns immediately, -- cgit v1.2.3 From b3c6efbc36e2c5ac820b1a800ac17cc3e040de0c Mon Sep 17 00:00:00 2001 From: Fan Du Date: Mon, 16 Dec 2013 18:47:50 +0800 Subject: xfrm: Add file to document IPsec corner case Create Documentation/networking/ipsec.txt to document IPsec corner issues and other info, which will be useful when user deploying IPsec. Signed-off-by: Fan Du Signed-off-by: Steffen Klassert --- Documentation/networking/ipsec.txt | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Documentation/networking/ipsec.txt (limited to 'Documentation') diff --git a/Documentation/networking/ipsec.txt b/Documentation/networking/ipsec.txt new file mode 100644 index 000000000000..8dbc08b7e431 --- /dev/null +++ b/Documentation/networking/ipsec.txt @@ -0,0 +1,38 @@ + +Here documents known IPsec corner cases which need to be keep in mind when +deploy various IPsec configuration in real world production environment. + +1. IPcomp: Small IP packet won't get compressed at sender, and failed on + policy check on receiver. + +Quote from RFC3173: +2.2. Non-Expansion Policy + + If the total size of a compressed payload and the IPComp header, as + defined in section 3, is not smaller than the size of the original + payload, the IP datagram MUST be sent in the original non-compressed + form. To clarify: If an IP datagram is sent non-compressed, no + + IPComp header is added to the datagram. This policy ensures saving + the decompression processing cycles and avoiding incurring IP + datagram fragmentation when the expanded datagram is larger than the + MTU. + + Small IP datagrams are likely to expand as a result of compression. + Therefore, a numeric threshold should be applied before compression, + where IP datagrams of size smaller than the threshold are sent in the + original form without attempting compression. The numeric threshold + is implementation dependent. + +Current IPComp implementation is indeed by the book, while as in practice +when sending non-compressed packet to the peer(whether or not packet len +is smaller than the threshold or the compressed len is large than original +packet len), the packet is dropped when checking the policy as this packet +matches the selector but not coming from any XFRM layer, i.e., with no +security path. Such naked packet will not eventually make it to upper layer. +The result is much more wired to the user when ping peer with different +payload length. + +One workaround is try to set "level use" for each policy if user observed +above scenario. The consequence of doing so is small packet(uncompressed) +will skip policy checking on receiver side. -- cgit v1.2.3 From 3f958fe7d3e37d26d321fe4761a6787bf22446b3 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Fri, 13 Dec 2013 14:41:50 +0800 Subject: of: Add Atmel PWM controller device tree binding The Atmel PWM controller uses the standard device tree bindings for PWM controllers. Signed-off-by: Bo Shen Acked-by: Alexandre Belloni Acked-by: Jean-Christophe PLAGNIOL-VILLARD Acked-by: Kumar Gala Signed-off-by: Thierry Reding --- .../devicetree/bindings/pwm/atmel-pwm.txt | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/atmel-pwm.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pwm/atmel-pwm.txt b/Documentation/devicetree/bindings/pwm/atmel-pwm.txt new file mode 100644 index 000000000000..02331b904d4e --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/atmel-pwm.txt @@ -0,0 +1,33 @@ +Atmel PWM controller + +Required properties: + - compatible: should be one of: + - "atmel,at91sam9rl-pwm" + - "atmel,sama5d3-pwm" + - reg: physical base address and length of the controller's registers + - #pwm-cells: Should be 3. See pwm.txt in this directory for a + description of the cells format. + +Example: + + pwm0: pwm@f8034000 { + compatible = "atmel,at91sam9rl-pwm"; + reg = <0xf8034000 0x400>; + #pwm-cells = <3>; + }; + + pwmleds { + compatible = "pwm-leds"; + + d1 { + label = "d1"; + pwms = <&pwm0 3 5000 0> + max-brightness = <255>; + }; + + d2 { + label = "d2"; + pwms = <&pwm0 1 5000 1> + max-brightness = <255>; + }; + }; -- cgit v1.2.3 From f35f6c8f74a085c1ed810d642a0c27b38d54e890 Mon Sep 17 00:00:00 2001 From: John Whitmore Date: Fri, 6 Dec 2013 12:49:08 +0000 Subject: can: update MAINTAINERS and Documentation Changed MAINTAINERS file to add Documentation/networking/can.txt to the list of maintained files. can.txt: - Globally changed Socket CAN to SocketCAN - Removed section 3.3 from the document - Updated Section 7 - Corrected a few simple typos Acked-by: Oliver Hartkopp Signed-off-by: John Whitmore Signed-off-by: Marc Kleine-Budde --- Documentation/networking/can.txt | 94 ++++++++++++++++------------------------ MAINTAINERS | 1 + 2 files changed, 38 insertions(+), 57 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt index 4c072414eadb..f3089d423515 100644 --- a/Documentation/networking/can.txt +++ b/Documentation/networking/can.txt @@ -2,21 +2,20 @@ can.txt -Readme file for the Controller Area Network Protocol Family (aka Socket CAN) +Readme file for the Controller Area Network Protocol Family (aka SocketCAN) This file contains - 1 Overview / What is Socket CAN + 1 Overview / What is SocketCAN 2 Motivation / Why using the socket API - 3 Socket CAN concept + 3 SocketCAN concept 3.1 receive lists 3.2 local loopback of sent frames - 3.3 network security issues (capabilities) - 3.4 network problem notifications + 3.3 network problem notifications - 4 How to use Socket CAN + 4 How to use SocketCAN 4.1 RAW protocol sockets with can_filters (SOCK_RAW) 4.1.1 RAW socket option CAN_RAW_FILTER 4.1.2 RAW socket option CAN_RAW_ERR_FILTER @@ -34,7 +33,7 @@ This file contains 4.3 connected transport protocols (SOCK_SEQPACKET) 4.4 unconnected transport protocols (SOCK_DGRAM) - 5 Socket CAN core module + 5 SocketCAN core module 5.1 can.ko module params 5.2 procfs content 5.3 writing own CAN protocol modules @@ -51,20 +50,20 @@ This file contains 6.6 CAN FD (flexible data rate) driver support 6.7 supported CAN hardware - 7 Socket CAN resources + 7 SocketCAN resources 8 Credits ============================================================================ -1. Overview / What is Socket CAN +1. Overview / What is SocketCAN -------------------------------- The socketcan package is an implementation of CAN protocols (Controller Area Network) for Linux. CAN is a networking technology which has widespread use in automation, embedded devices, and automotive fields. While there have been other CAN implementations -for Linux based on character devices, Socket CAN uses the Berkeley +for Linux based on character devices, SocketCAN uses the Berkeley socket API, the Linux network stack and implements the CAN device drivers as network interfaces. The CAN socket API has been designed as similar as possible to the TCP/IP protocols to allow programmers, @@ -74,7 +73,7 @@ sockets. 2. Motivation / Why using the socket API ---------------------------------------- -There have been CAN implementations for Linux before Socket CAN so the +There have been CAN implementations for Linux before SocketCAN so the question arises, why we have started another project. Most existing implementations come as a device driver for some CAN hardware, they are based on character devices and provide comparatively little @@ -89,10 +88,10 @@ the CAN controller requires employment of another device driver and often the need for adaption of large parts of the application to the new driver's API. -Socket CAN was designed to overcome all of these limitations. A new +SocketCAN was designed to overcome all of these limitations. A new protocol family has been implemented which provides a socket interface to user space applications and which builds upon the Linux network -layer, so to use all of the provided queueing functionality. A device +layer, enabling use all of the provided queueing functionality. A device driver for CAN controller hardware registers itself with the Linux network layer as a network device, so that CAN frames from the controller can be passed up to the network layer and on to the CAN @@ -146,15 +145,15 @@ solution for a couple of reasons: providing an API for device drivers to register with. However, then it would be no more difficult, or may be even easier, to use the networking framework provided by the Linux kernel, and this is what - Socket CAN does. + SocketCAN does. The use of the networking framework of the Linux kernel is just the natural and most appropriate way to implement CAN for Linux. -3. Socket CAN concept +3. SocketCAN concept --------------------- - As described in chapter 2 it is the main goal of Socket CAN to + As described in chapter 2 it is the main goal of SocketCAN to provide a socket interface to user space applications which builds upon the Linux network layer. In contrast to the commonly known TCP/IP and ethernet networking, the CAN bus is a broadcast-only(!) @@ -168,11 +167,11 @@ solution for a couple of reasons: The network transparent access of multiple applications leads to the problem that different applications may be interested in the same - CAN-IDs from the same CAN network interface. The Socket CAN core + CAN-IDs from the same CAN network interface. The SocketCAN core module - which implements the protocol family CAN - provides several high efficient receive lists for this reason. If e.g. a user space application opens a CAN RAW socket, the raw protocol module itself - requests the (range of) CAN-IDs from the Socket CAN core that are + requests the (range of) CAN-IDs from the SocketCAN core that are requested by the user. The subscription and unsubscription of CAN-IDs can be done for specific CAN interfaces or for all(!) known CAN interfaces with the can_rx_(un)register() functions provided to @@ -217,21 +216,7 @@ solution for a couple of reasons: * = you really like to have this when you're running analyser tools like 'candump' or 'cansniffer' on the (same) node. - 3.3 network security issues (capabilities) - - The Controller Area Network is a local field bus transmitting only - broadcast messages without any routing and security concepts. - In the majority of cases the user application has to deal with - raw CAN frames. Therefore it might be reasonable NOT to restrict - the CAN access only to the user root, as known from other networks. - Since the currently implemented CAN_RAW and CAN_BCM sockets can only - send and receive frames to/from CAN interfaces it does not affect - security of others networks to allow all users to access the CAN. - To enable non-root users to access CAN_RAW and CAN_BCM protocol - sockets the Kconfig options CAN_RAW_USER and/or CAN_BCM_USER may be - selected at kernel compile time. - - 3.4 network problem notifications + 3.3 network problem notifications The use of the CAN bus may lead to several problems on the physical and media access control layer. Detecting and logging of these lower @@ -251,11 +236,11 @@ solution for a couple of reasons: by default. The format of the CAN error message frame is briefly described in the Linux header file "include/linux/can/error.h". -4. How to use Socket CAN +4. How to use SocketCAN ------------------------ Like TCP/IP, you first need to open a socket for communicating over a - CAN network. Since Socket CAN implements a new protocol family, you + CAN network. Since SocketCAN implements a new protocol family, you need to pass PF_CAN as the first argument to the socket(2) system call. Currently, there are two CAN protocols to choose from, the raw socket protocol and the broadcast manager (BCM). So to open a socket, @@ -286,8 +271,8 @@ solution for a couple of reasons: }; The alignment of the (linear) payload data[] to a 64bit boundary - allows the user to define own structs and unions to easily access the - CAN payload. There is no given byteorder on the CAN bus by + allows the user to define their own structs and unions to easily access + the CAN payload. There is no given byteorder on the CAN bus by default. A read(2) system call on a CAN_RAW socket transfers a struct can_frame to the user space. @@ -479,7 +464,7 @@ solution for a couple of reasons: setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); - To set the filters to zero filters is quite obsolete as not read + To set the filters to zero filters is quite obsolete as to not read data causes the raw socket to discard the received CAN frames. But having this 'send only' use-case we may remove the receive list in the Kernel to save a little (really a very little!) CPU usage. @@ -814,17 +799,17 @@ solution for a couple of reasons: 4.4 unconnected transport protocols (SOCK_DGRAM) -5. Socket CAN core module +5. SocketCAN core module ------------------------- - The Socket CAN core module implements the protocol family + The SocketCAN core module implements the protocol family PF_CAN. CAN protocol modules are loaded by the core module at runtime. The core module provides an interface for CAN protocol modules to subscribe needed CAN IDs (see chapter 3.1). 5.1 can.ko module params - - stats_timer: To calculate the Socket CAN core statistics + - stats_timer: To calculate the SocketCAN core statistics (e.g. current/maximum frames per second) this 1 second timer is invoked at can.ko module start time by default. This timer can be disabled by using stattimer=0 on the module commandline. @@ -833,7 +818,7 @@ solution for a couple of reasons: 5.2 procfs content - As described in chapter 3.1 the Socket CAN core uses several filter + As described in chapter 3.1 the SocketCAN core uses several filter lists to deliver received CAN frames to CAN protocol modules. These receive lists, their filters and the count of filter matches can be checked in the appropriate receive list. All entries contain the @@ -860,15 +845,15 @@ solution for a couple of reasons: Additional procfs files in /proc/net/can - stats - Socket CAN core statistics (rx/tx frames, match ratios, ...) + stats - SocketCAN core statistics (rx/tx frames, match ratios, ...) reset_stats - manual statistic reset - version - prints the Socket CAN core version and the ABI version + version - prints the SocketCAN core version and the ABI version 5.3 writing own CAN protocol modules To implement a new protocol in the protocol family PF_CAN a new protocol has to be defined in include/linux/can.h . - The prototypes and definitions to use the Socket CAN core can be + The prototypes and definitions to use the SocketCAN core can be accessed by including include/linux/can/core.h . In addition to functions that register the CAN protocol and the CAN device notifier chain there are functions to subscribe CAN @@ -1105,7 +1090,7 @@ solution for a couple of reasons: $ ip link set canX up type can bitrate 125000 - A device may enter the "bus-off" state if too much errors occurred on + A device may enter the "bus-off" state if too many errors occurred on the CAN bus. Then no more messages are received or sent. An automatic bus-off recovery can be enabled by setting the "restart-ms" to a non-zero value, e.g.: @@ -1125,7 +1110,7 @@ solution for a couple of reasons: CAN FD capable CAN controllers support two different bitrates for the arbitration phase and the payload phase of the CAN FD frame. Therefore a - second bittiming has to be specified in order to enable the CAN FD bitrate. + second bit timing has to be specified in order to enable the CAN FD bitrate. Additionally CAN FD capable CAN controllers support up to 64 bytes of payload. The representation of this length in can_frame.can_dlc and @@ -1150,21 +1135,16 @@ solution for a couple of reasons: 6.7 Supported CAN hardware Please check the "Kconfig" file in "drivers/net/can" to get an actual - list of the support CAN hardware. On the Socket CAN project website + list of the support CAN hardware. On the SocketCAN project website (see chapter 7) there might be further drivers available, also for older kernel versions. -7. Socket CAN resources +7. SocketCAN resources ----------------------- - You can find further resources for Socket CAN like user space tools, - support for old kernel versions, more drivers, mailing lists, etc. - at the BerliOS OSS project website for Socket CAN: - - http://developer.berlios.de/projects/socketcan - - If you have questions, bug fixes, etc., don't hesitate to post them to - the Socketcan-Users mailing list. But please search the archives first. + The Linux CAN / SocketCAN project ressources (project site / mailing list) + are referenced in the MAINTAINERS file in the Linux source tree. + Search for CAN NETWORK [LAYERS|DRIVERS]. 8. Credits ---------- diff --git a/MAINTAINERS b/MAINTAINERS index 63ae89617fc5..3d2ac86b0115 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2012,6 +2012,7 @@ L: linux-can@vger.kernel.org W: http://gitorious.org/linux-can T: git git://gitorious.org/linux-can/linux-can-next.git S: Maintained +F: Documentation/networking/can.txt F: net/can/ F: include/linux/can/core.h F: include/uapi/linux/can.h -- cgit v1.2.3 From 43394d2fc8f6776c8971ab09544a93359acbe88b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 2 Dec 2013 16:22:49 +0100 Subject: of: Add MIPI DSI bus device tree bindings Document the device tree bindings for the MIPI DSI bus. The MIPI Display Serial Interface specifies a serial bus and a protocol for communication between a host and up to four peripherals. Signed-off-by: Thierry Reding --- .../devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt | 98 ++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt b/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt new file mode 100644 index 000000000000..973c27273772 --- /dev/null +++ b/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt @@ -0,0 +1,98 @@ +MIPI DSI (Display Serial Interface) busses +========================================== + +The MIPI Display Serial Interface specifies a serial bus and a protocol for +communication between a host and up to four peripherals. This document will +define the syntax used to represent a DSI bus in a device tree. + +This document describes DSI bus-specific properties only or defines existing +standard properties in the context of the DSI bus. + +Each DSI host provides a DSI bus. The DSI host controller's node contains a +set of properties that characterize the bus. Child nodes describe individual +peripherals on that bus. + +The following assumes that only a single peripheral is connected to a DSI +host. Experience shows that this is true for the large majority of setups. + +DSI host +-------- + +In addition to the standard properties and those defined by the parent bus of +a DSI host, the following properties apply to a node representing a DSI host. + +Required properties: +- #address-cells: The number of cells required to represent an address on the + bus. DSI peripherals are addressed using a 2-bit virtual channel number, so + a maximum of 4 devices can be addressed on a single bus. Hence the value of + this property should be 1. +- #size-cells: Should be 0. There are cases where it makes sense to use a + different value here. See below. + +DSI peripheral +-------------- + +Peripherals are represented as child nodes of the DSI host's node. Properties +described here apply to all DSI peripherals, but individual bindings may want +to define additional, device-specific properties. + +Required properties: +- reg: The virtual channel number of a DSI peripheral. Must be in the range + from 0 to 3. + +Some DSI peripherals respond to more than a single virtual channel. In that +case two alternative representations can be chosen: +- The reg property can take multiple entries, one for each virtual channel + that the peripheral responds to. +- If the virtual channels that a peripheral responds to are consecutive, the + #size-cells can be set to 1. The first cell of each entry in the reg + property is the number of the first virtual channel and the second cell is + the number of consecutive virtual channels. + +Example +------- + + dsi-host { + ... + + #address-cells = <1>; + #size-cells = <0>; + + /* peripheral responds to virtual channel 0 */ + peripheral@0 { + compatible = "..."; + reg = <0>; + }; + + ... + }; + + dsi-host { + ... + + #address-cells = <1>; + #size-cells = <0>; + + /* peripheral responds to virtual channels 0 and 2 */ + peripheral@0 { + compatible = "..."; + reg = <0, 2>; + }; + + ... + }; + + dsi-host { + ... + + #address-cells = <1>; + #size-cells = <1>; + + /* peripheral responds to virtual channels 1, 2 and 3 */ + peripheral@1 { + compatible = "..."; + reg = <1 3>; + }; + + ... + }; -- cgit v1.2.3 From d95f95eb96c511b39bf9c854217d7dddb6d06755 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 22 Nov 2013 19:19:55 +0100 Subject: of: Add simple panel device tree binding This binding specifies a set of common properties for display panels. It can be used as a basis by bindings for specific panels. Bindings for three specific panels are provided to show how the simple panel binding can be used. Acked-by: Rob Herring Signed-off-by: Thierry Reding --- .../devicetree/bindings/panel/auo,b101aw03.txt | 7 +++++++ .../bindings/panel/chunghwa,claa101wb03.txt | 7 +++++++ .../bindings/panel/panasonic,vvx10f004b00.txt | 7 +++++++ .../devicetree/bindings/panel/simple-panel.txt | 21 +++++++++++++++++++++ 4 files changed, 42 insertions(+) create mode 100644 Documentation/devicetree/bindings/panel/auo,b101aw03.txt create mode 100644 Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt create mode 100644 Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt create mode 100644 Documentation/devicetree/bindings/panel/simple-panel.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/panel/auo,b101aw03.txt b/Documentation/devicetree/bindings/panel/auo,b101aw03.txt new file mode 100644 index 000000000000..72e088a4fb3a --- /dev/null +++ b/Documentation/devicetree/bindings/panel/auo,b101aw03.txt @@ -0,0 +1,7 @@ +AU Optronics Corporation 10.1" WSVGA TFT LCD panel + +Required properties: +- compatible: should be "auo,b101aw03" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt b/Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt new file mode 100644 index 000000000000..0ab2c05a4c22 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt @@ -0,0 +1,7 @@ +Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel + +Required properties: +- compatible: should be "chunghwa,claa101wb03" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt b/Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt new file mode 100644 index 000000000000..d328b0341bf4 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt @@ -0,0 +1,7 @@ +Panasonic Corporation 10.1" WUXGA TFT LCD panel + +Required properties: +- compatible: should be "panasonic,vvx10f004b00" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/panel/simple-panel.txt b/Documentation/devicetree/bindings/panel/simple-panel.txt new file mode 100644 index 000000000000..1341bbf4aa3d --- /dev/null +++ b/Documentation/devicetree/bindings/panel/simple-panel.txt @@ -0,0 +1,21 @@ +Simple display panel + +Required properties: +- power-supply: regulator to provide the supply voltage + +Optional properties: +- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing +- enable-gpios: GPIO pin to enable or disable the panel +- backlight: phandle of the backlight device attached to the panel + +Example: + + panel: panel { + compatible = "cptt,claa101wb01"; + ddc-i2c-bus = <&panelddc>; + + power-supply = <&vdd_pnl_reg>; + enable-gpios = <&gpio 90 0>; + + backlight = <&backlight>; + }; -- cgit v1.2.3 From 9be7d864cf0763dd24e07bac7f0a94180bd5e257 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 30 Aug 2013 15:22:36 +0200 Subject: drm/tegra: Implement panel support Use the DRM panel framework to attach a panel to an output. If the panel attached to a connector supports supports the backlight brightness accessors, a property will be available to allow the brightness to be modified from userspace. Signed-off-by: Thierry Reding --- .../bindings/gpu/nvidia,tegra20-host1x.txt | 2 ++ drivers/gpu/drm/tegra/Kconfig | 1 + drivers/gpu/drm/tegra/drm.h | 1 + drivers/gpu/drm/tegra/output.c | 38 +++++++++++++++++++--- 4 files changed, 38 insertions(+), 4 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt index ab45c02aa658..31314bd40da9 100644 --- a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt @@ -125,6 +125,7 @@ of the following host1x client modules: - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection - nvidia,edid: supplies a binary EDID blob + - nvidia,panel: phandle of a display panel - hdmi: High Definition Multimedia Interface @@ -149,6 +150,7 @@ of the following host1x client modules: - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection - nvidia,edid: supplies a binary EDID blob + - nvidia,panel: phandle of a display panel - tvo: TV encoder output diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig index 8db9b3bce001..1b5448cd6829 100644 --- a/drivers/gpu/drm/tegra/Kconfig +++ b/drivers/gpu/drm/tegra/Kconfig @@ -6,6 +6,7 @@ config DRM_TEGRA select TEGRA_HOST1X select DRM_KMS_HELPER select DRM_KMS_FB_HELPER + select DRM_PANEL select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 266aae08a3bd..bb8b1305606e 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -186,6 +186,7 @@ struct tegra_output { const struct tegra_output_ops *ops; enum tegra_output_type type; + struct drm_panel *panel; struct i2c_adapter *ddc; const struct edid *edid; unsigned int hpd_irq; diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index 2cb0065e0578..5dc4d1a9cad8 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -9,6 +9,7 @@ #include +#include #include "drm.h" static int tegra_connector_get_modes(struct drm_connector *connector) @@ -17,6 +18,12 @@ static int tegra_connector_get_modes(struct drm_connector *connector) struct edid *edid = NULL; int err = 0; + if (output->panel) { + err = output->panel->funcs->get_modes(output->panel); + if (err > 0) + return err; + } + if (output->edid) edid = kmemdup(output->edid, sizeof(*edid), GFP_KERNEL); else if (output->ddc) @@ -72,6 +79,11 @@ tegra_connector_detect(struct drm_connector *connector, bool force) else status = connector_status_connected; } else { + if (!output->panel) + status = connector_status_disconnected; + else + status = connector_status_connected; + if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) status = connector_status_connected; } @@ -115,6 +127,15 @@ static const struct drm_encoder_funcs encoder_funcs = { static void tegra_encoder_dpms(struct drm_encoder *encoder, int mode) { + struct tegra_output *output = encoder_to_output(encoder); + struct drm_panel *panel = output->panel; + + if (panel && panel->funcs) { + if (mode != DRM_MODE_DPMS_ON) + drm_panel_disable(panel); + else + drm_panel_enable(panel); + } } static bool tegra_encoder_mode_fixup(struct drm_encoder *encoder, @@ -163,14 +184,23 @@ static irqreturn_t hpd_irq(int irq, void *data) int tegra_output_probe(struct tegra_output *output) { + struct device_node *ddc, *panel; enum of_gpio_flags flags; - struct device_node *ddc; size_t size; int err; if (!output->of_node) output->of_node = output->dev->of_node; + panel = of_parse_phandle(output->of_node, "nvidia,panel", 0); + if (panel) { + output->panel = of_drm_find_panel(panel); + if (!output->panel) + return -EPROBE_DEFER; + + of_node_put(panel); + } + output->edid = of_get_property(output->of_node, "nvidia,edid", &size); ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0); @@ -185,9 +215,6 @@ int tegra_output_probe(struct tegra_output *output) of_node_put(ddc); } - if (!output->edid && !output->ddc) - return -ENODEV; - output->hpd_gpio = of_get_named_gpio_flags(output->of_node, "nvidia,hpd-gpio", 0, &flags); @@ -267,6 +294,9 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output) drm_connector_helper_add(&output->connector, &connector_helper_funcs); output->connector.dpms = DRM_MODE_DPMS_OFF; + if (output->panel) + drm_panel_attach(output->panel, &output->connector); + drm_encoder_init(drm, &output->encoder, &encoder_funcs, encoder); drm_encoder_helper_add(&output->encoder, &encoder_helper_funcs); -- cgit v1.2.3 From 5d30be283f30bac34dae26a1014795b061f10c49 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 13 Dec 2013 15:27:42 +0100 Subject: gpu: host1x: Update host1x device tree example The display controller primary clock was recently renamed to "dc", so update the example to reflect that. Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt index 31314bd40da9..53045fe32d20 100644 --- a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt @@ -255,7 +255,7 @@ Example: interrupts = <0 73 0x04>; clocks = <&tegra_car TEGRA20_CLK_DISP1>, <&tegra_car TEGRA20_CLK_PLL_P>; - clock-names = "disp1", "parent"; + clock-names = "dc", "parent"; resets = <&tegra_car 27>; reset-names = "dc"; @@ -270,7 +270,7 @@ Example: interrupts = <0 74 0x04>; clocks = <&tegra_car TEGRA20_CLK_DISP2>, <&tegra_car TEGRA20_CLK_PLL_P>; - clock-names = "disp2", "parent"; + clock-names = "dc", "parent"; resets = <&tegra_car 26>; reset-names = "dc"; -- cgit v1.2.3 From 4c48140aaa38e4da44a2fcfe50c476208904fdd3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 2 Dec 2013 14:22:58 +0100 Subject: gpu: host1x: Add MIPI pad calibration DT bindings Introduce device tree bindings for the MIPI pad calibration controller found on Tegra SoCs. The controller can be used to perform calibration of pads used for DSI and CSI peripherals. Signed-off-by: Thierry Reding --- .../bindings/mipi/nvidia,tegra114-mipi.txt | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt b/Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt new file mode 100644 index 000000000000..e4a25cedc5cf --- /dev/null +++ b/Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt @@ -0,0 +1,41 @@ +NVIDIA Tegra MIPI pad calibration controller + +Required properties: +- compatible: "nvidia,tegra-mipi" +- reg: Physical base address and length of the controller's registers. +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - mipi-cal +- #nvidia,mipi-calibrate-cells: Should be 1. The cell is a bitmask of the pads + that need to be calibrated for a given device. + +User nodes need to contain an nvidia,mipi-calibrate property that has a +phandle to refer to the calibration controller node and a bitmask of the pads +that need to be calibrated. + +Example: + + mipi: mipi@700e3000 { + compatible = "nvidia,tegra114-mipi"; + reg = <0x700e3000 0x100>; + clocks = <&tegra_car TEGRA114_CLK_MIPI_CAL>; + clock-names = "mipi-cal"; + #nvidia,mipi-calibrate-cells = <1>; + }; + + ... + + host1x@50000000 { + ... + + dsi@54300000 { + ... + + nvidia,mipi-calibrate = <&mipi 0x060>; + + ... + }; + + ... + }; -- cgit v1.2.3 From 3c0f0f9f7d9b558089ce6701f72a932b63192384 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 11 Dec 2013 19:52:35 +0400 Subject: serial: clps711x: dts: Add bindings documentation for the CLPS711X UART This patch adds the devicetree documentation for the Cirrus Logic CLPS711X UART. Signed-off-by: Alexander Shiyan Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- .../bindings/serial/cirrus,clps711x-uart.txt | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Documentation/devicetree/bindings/serial/cirrus,clps711x-uart.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/cirrus,clps711x-uart.txt b/Documentation/devicetree/bindings/serial/cirrus,clps711x-uart.txt new file mode 100644 index 000000000000..8bbdd21ed6ac --- /dev/null +++ b/Documentation/devicetree/bindings/serial/cirrus,clps711x-uart.txt @@ -0,0 +1,29 @@ +* Cirrus Logic CLPS711X Universal Asynchronous Receiver/Transmitter (UART) + +Required properties: +- compatible: Should be "cirrus,clps711x-uart". +- reg: Address and length of the register set for the device. +- interrupts: Should contain UART TX and RX interrupt. +- clocks: Should contain UART core clock number. +- syscon: Phandle to SYSCON node, which contain UART control bits. + +Optional properties: +- uart-use-ms: Indicate the UART has modem signal (DCD, DSR, CTS). +- uart-use-irda: Indicate the UART use IRDA mode. + +Note: Each UART port should have an alias correctly numbered +in "aliases" node. + +Example: + aliases { + serial0 = &uart1; + }; + + uart1: uart@80000480 { + compatible = "cirrus,clps711x-uart"; + reg = <0x80000480 0x80>; + interrupts = <12 13>; + clocks = <&clks 11>; + syscon = <&syscon1>; + uart-use-ms; + }; -- cgit v1.2.3 From 8be3da65d9222e1e63b7f9d001e872947588946f Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Tue, 17 Dec 2013 17:22:20 +0100 Subject: tty/serial: at91: document clock properties Document the clock properties required by the at91 usart driver. Signed-off-by: Boris BREZILLON Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/atmel-usart.txt | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/serial/atmel-usart.txt b/Documentation/devicetree/bindings/serial/atmel-usart.txt index 2191dcb9f1da..9c5d19ac935c 100644 --- a/Documentation/devicetree/bindings/serial/atmel-usart.txt +++ b/Documentation/devicetree/bindings/serial/atmel-usart.txt @@ -6,6 +6,9 @@ Required properties: additional mode or an USART new feature. - reg: Should contain registers location and length - interrupts: Should contain interrupt +- clock-names: tuple listing input clock names. + Required elements: "usart" +- clocks: phandles to input clocks. Optional properties: - atmel,use-dma-rx: use of PDC or DMA for receiving data @@ -26,6 +29,8 @@ Example: compatible = "atmel,at91sam9260-usart"; reg = <0xfff8c000 0x4000>; interrupts = <7>; + clocks = <&usart0_clk>; + clock-names = "usart"; atmel,use-dma-rx; atmel,use-dma-tx; }; @@ -35,6 +40,8 @@ Example: compatible = "atmel,at91sam9260-usart"; reg = <0xf001c000 0x100>; interrupts = <12 4 5>; + clocks = <&usart0_clk>; + clock-names = "usart"; atmel,use-dma-rx; atmel,use-dma-tx; dmas = <&dma0 2 0x3>, -- cgit v1.2.3 From beb11fc71370bb49c58d7454d5d9c5a00a7cdb4b Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Thu, 12 Dec 2013 21:42:24 +0530 Subject: KVM: Documentation: Fix typo for KVM_ARM_VCPU_INIT ioctl Fix minor typo in "Parameters:" of KVM_ARM_VCPU_INIT documentation. Signed-off-by: Anup Patel Signed-off-by: Pranavkumar Sawargaonkar Signed-off-by: Christoffer Dall --- Documentation/virtual/kvm/api.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index a30035dd4c26..aad3244a579e 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2327,7 +2327,7 @@ current state. "addr" is ignored. Capability: basic Architectures: arm, arm64 Type: vcpu ioctl -Parameters: struct struct kvm_vcpu_init (in) +Parameters: struct kvm_vcpu_init (in) Returns: 0 on success; -1 on error Errors:  EINVAL:    the target is unknown, or the combination of features is invalid. -- cgit v1.2.3 From 2c7268c70fc1099ce4aac83c194675efd927e90f Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 11 Dec 2013 15:54:50 +0800 Subject: ARM: hi3xxx: add board support with device tree Add board support with device tree for Hisilicon Hi3620 SoC platform. Signed-off-by: Haojian Zhuang [khilman: fix checkpatch errors] [khilman: fold in patch which selects GPIO in Kconfig] Signed-off-by: Kevin Hilman --- .../bindings/arm/hisilicon/hisilicon.txt | 6 +++ arch/arm/Kconfig | 2 + arch/arm/Makefile | 1 + arch/arm/mach-hi3xxx/Kconfig | 13 +++++ arch/arm/mach-hi3xxx/Makefile | 5 ++ arch/arm/mach-hi3xxx/hi3xxx.c | 60 ++++++++++++++++++++++ 6 files changed, 87 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt create mode 100644 arch/arm/mach-hi3xxx/Kconfig create mode 100644 arch/arm/mach-hi3xxx/Makefile create mode 100644 arch/arm/mach-hi3xxx/hi3xxx.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt new file mode 100644 index 000000000000..21a73363e019 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt @@ -0,0 +1,6 @@ +Hisilicon Platforms Device Tree Bindings +---------------------------------------------------- + +Hi4511 Board +Required root node properties: + - compatible = "hisilicon,hi3620-hi4511"; diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c1f1a7eee953..75eb5323fedd 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -925,6 +925,8 @@ source "arch/arm/mach-footbridge/Kconfig" source "arch/arm/mach-gemini/Kconfig" +source "arch/arm/mach-hi3xxx/Kconfig" + source "arch/arm/mach-highbank/Kconfig" source "arch/arm/mach-integrator/Kconfig" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index c99b1086d83d..dfbafa38b4cd 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -156,6 +156,7 @@ machine-$(CONFIG_ARCH_EBSA110) += ebsa110 machine-$(CONFIG_ARCH_EP93XX) += ep93xx machine-$(CONFIG_ARCH_EXYNOS) += exynos machine-$(CONFIG_ARCH_GEMINI) += gemini +machine-$(CONFIG_ARCH_HI3xxx) += hi3xxx machine-$(CONFIG_ARCH_HIGHBANK) += highbank machine-$(CONFIG_ARCH_INTEGRATOR) += integrator machine-$(CONFIG_ARCH_IOP13XX) += iop13xx diff --git a/arch/arm/mach-hi3xxx/Kconfig b/arch/arm/mach-hi3xxx/Kconfig new file mode 100644 index 000000000000..8a502d1e9542 --- /dev/null +++ b/arch/arm/mach-hi3xxx/Kconfig @@ -0,0 +1,13 @@ +config ARCH_HI3xxx + bool "Hisilicon Hi36xx/Hi37xx family" if ARCH_MULTI_V7 + select ARM_AMBA + select ARM_GIC + select ARM_TIMER_SP804 + select ARCH_WANT_OPTIONAL_GPIOLIB + select CACHE_L2X0 + select CLKSRC_OF + select GENERIC_CLOCKEVENTS + select PINCTRL + select PINCTRL_SINGLE + help + Support for Hisilicon Hi36xx/Hi37xx processor family diff --git a/arch/arm/mach-hi3xxx/Makefile b/arch/arm/mach-hi3xxx/Makefile new file mode 100644 index 000000000000..d68ebb3d10bb --- /dev/null +++ b/arch/arm/mach-hi3xxx/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for Hisilicon Hi36xx/Hi37xx processors line +# + +obj-y += hi3xxx.o diff --git a/arch/arm/mach-hi3xxx/hi3xxx.c b/arch/arm/mach-hi3xxx/hi3xxx.c new file mode 100644 index 000000000000..fe56daf84b1a --- /dev/null +++ b/arch/arm/mach-hi3xxx/hi3xxx.c @@ -0,0 +1,60 @@ +5/* + * (Hisilicon's Hi36xx/Hi37xx SoC based) flattened device tree enabled machine + * + * Copyright (c) 2012-2013 Hisilicon Ltd. + * Copyright (c) 2012-2013 Linaro Ltd. + * + * Author: Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include +#include + +#include +#include + +/* + * This table is only for optimization. Since ioremap() could always share + * the same mapping if it's defined as static IO mapping. + * + * Without this table, system could also work. The cost is some virtual address + * spaces wasted since ioremap() may be called multi times for the same + * IO space. + */ +static struct map_desc hi3620_io_desc[] __initdata = { + { + .pfn = __phys_to_pfn(0xfc802000), + .virtual = 0xfe802000, + .length = 0x1000, + .type = MT_DEVICE, + }, +}; + +static void __init hi3620_map_io(void) +{ + debug_ll_io_init(); + iotable_init(hi3620_io_desc, ARRAY_SIZE(hi3620_io_desc)); +} + +static void __init hi3xxx_timer_init(void) +{ + of_clk_init(NULL); + clocksource_of_init(); +} + +static const char *hi3xxx_compat[] __initconst = { + "hisilicon,hi3620-hi4511", + NULL, +}; + +DT_MACHINE_START(HI3620, "Hisilicon Hi3620 (Flattened Device Tree)") + .map_io = hi3620_map_io, + .init_time = hi3xxx_timer_init, + .dt_compat = hi3xxx_compat, +MACHINE_END -- cgit v1.2.3 From a9434e96d9f089e778b440217f815c8e85daf317 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Tue, 17 Dec 2013 16:23:49 -0800 Subject: ARM: hi3xxx: add smp support Enable SMP support on hi3xxx platform Signed-off-by: Zhangfei Gao Tested-by: Zhang Mingjun Tested-by: Li Xin Signed-off-by: Haojian Zhuang [khilman: fix checkpatch errors] Signed-off-by: Kevin Hilman --- .../bindings/arm/hisilicon/hisilicon.txt | 26 +++++++ arch/arm/boot/dts/hi3620.dtsi | 38 ++++++++++ arch/arm/mach-hi3xxx/Kconfig | 4 ++ arch/arm/mach-hi3xxx/Makefile | 1 + arch/arm/mach-hi3xxx/core.h | 11 +++ arch/arm/mach-hi3xxx/hi3xxx.c | 43 ++++++++++- arch/arm/mach-hi3xxx/platsmp.c | 84 ++++++++++++++++++++++ 7 files changed, 204 insertions(+), 3 deletions(-) create mode 100644 arch/arm/mach-hi3xxx/core.h create mode 100644 arch/arm/mach-hi3xxx/platsmp.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt index 21a73363e019..8c7a4653508d 100644 --- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt +++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt @@ -4,3 +4,29 @@ Hisilicon Platforms Device Tree Bindings Hi4511 Board Required root node properties: - compatible = "hisilicon,hi3620-hi4511"; + +Hisilicon system controller + +Required properties: +- compatible : "hisilicon,sysctrl" +- reg : Register address and size + +Optional properties: +- smp-offset : offset in sysctrl for notifying slave cpu booting + cpu 1, reg; + cpu 2, reg + 0x4; + cpu 3, reg + 0x8; + If reg value is not zero, cpun exit wfi and go +- resume-offset : offset in sysctrl for notifying cpu0 when resume +- reboot-offset : offset in sysctrl for system reboot + +Example: + + /* for Hi3620 */ + sysctrl: system-controller@fc802000 { + compatible = "hisilicon,sysctrl"; + reg = <0xfc802000 0x1000>; + smp-offset = <0x31c>; + resume-offset = <0x308>; + reboot-offset = <0x4>; + }; diff --git a/arch/arm/boot/dts/hi3620.dtsi b/arch/arm/boot/dts/hi3620.dtsi index b9d86795ed5a..e311937a1e2c 100644 --- a/arch/arm/boot/dts/hi3620.dtsi +++ b/arch/arm/boot/dts/hi3620.dtsi @@ -39,6 +39,27 @@ reg = <0x0>; next-level-cache = <&L2>; }; + + cpu@1 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + reg = <1>; + next-level-cache = <&L2>; + }; + + cpu@2 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + reg = <2>; + next-level-cache = <&L2>; + }; + + cpu@3 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + reg = <3>; + next-level-cache = <&L2>; + }; }; amba { @@ -65,6 +86,17 @@ reg = <0x1000 0x1000>, <0x100 0x100>; }; + sysctrl: system-controller@802000 { + compatible = "hisilicon,sysctrl"; + reg = <0x802000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + smp-offset = <0x31c>; + resume-offset = <0x308>; + reboot-offset = <0x4>; + }; + dual_timer0: dual_timer@800000 { compatible = "arm,sp804", "arm,primecell"; reg = <0x800000 0x1000>; @@ -115,6 +147,12 @@ status = "disabled"; }; + timer5: timer@600 { + compatible = "arm,cortex-a9-twd-timer"; + reg = <0x600 0x20>; + interrupts = <1 13 0xf01>; + }; + uart0: uart@b00000 { compatible = "arm,pl011", "arm,primecell"; reg = <0xb00000 0x1000>; diff --git a/arch/arm/mach-hi3xxx/Kconfig b/arch/arm/mach-hi3xxx/Kconfig index 8a502d1e9542..018ad67f1b38 100644 --- a/arch/arm/mach-hi3xxx/Kconfig +++ b/arch/arm/mach-hi3xxx/Kconfig @@ -7,7 +7,11 @@ config ARCH_HI3xxx select CACHE_L2X0 select CLKSRC_OF select GENERIC_CLOCKEVENTS + select HAVE_ARM_SCU + select HAVE_ARM_TWD + select HAVE_SMP select PINCTRL select PINCTRL_SINGLE + select SMP help Support for Hisilicon Hi36xx/Hi37xx processor family diff --git a/arch/arm/mach-hi3xxx/Makefile b/arch/arm/mach-hi3xxx/Makefile index d68ebb3d10bb..7a869a7b2a95 100644 --- a/arch/arm/mach-hi3xxx/Makefile +++ b/arch/arm/mach-hi3xxx/Makefile @@ -3,3 +3,4 @@ # obj-y += hi3xxx.o +obj-$(CONFIG_SMP) += platsmp.o diff --git a/arch/arm/mach-hi3xxx/core.h b/arch/arm/mach-hi3xxx/core.h new file mode 100644 index 000000000000..226f02050597 --- /dev/null +++ b/arch/arm/mach-hi3xxx/core.h @@ -0,0 +1,11 @@ +#ifndef __HISILICON_CORE_H +#define __HISILICON_CORE_H + +#include + +extern void hi3xxx_set_cpu_jump(int cpu, void *jump_addr); +extern int hi3xxx_get_cpu_jump(int cpu); +extern void secondary_startup(void); +extern struct smp_operations hi3xxx_smp_ops; + +#endif diff --git a/arch/arm/mach-hi3xxx/hi3xxx.c b/arch/arm/mach-hi3xxx/hi3xxx.c index fe56daf84b1a..661a912f1527 100644 --- a/arch/arm/mach-hi3xxx/hi3xxx.c +++ b/arch/arm/mach-hi3xxx/hi3xxx.c @@ -1,4 +1,4 @@ -5/* +/* * (Hisilicon's Hi36xx/Hi37xx SoC based) flattened device tree enabled machine * * Copyright (c) 2012-2013 Hisilicon Ltd. @@ -14,11 +14,19 @@ #include #include #include +#include #include +#include + #include #include +#include "core.h" + +#define HI3620_SYSCTRL_PHYS_BASE 0xfc802000 +#define HI3620_SYSCTRL_VIRT_BASE 0xfe802000 + /* * This table is only for optimization. Since ioremap() could always share * the same mapping if it's defined as static IO mapping. @@ -29,8 +37,9 @@ */ static struct map_desc hi3620_io_desc[] __initdata = { { - .pfn = __phys_to_pfn(0xfc802000), - .virtual = 0xfe802000, + /* sysctrl */ + .pfn = __phys_to_pfn(HI3620_SYSCTRL_PHYS_BASE), + .virtual = HI3620_SYSCTRL_VIRT_BASE, .length = 0x1000, .type = MT_DEVICE, }, @@ -48,6 +57,32 @@ static void __init hi3xxx_timer_init(void) clocksource_of_init(); } +static void hi3xxx_restart(enum reboot_mode mode, const char *cmd) +{ + struct device_node *np; + void __iomem *base; + int offset; + + np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); + if (!np) { + pr_err("failed to find hisilicon,sysctrl node\n"); + return; + } + base = of_iomap(np, 0); + if (!base) { + pr_err("failed to map address in hisilicon,sysctrl node\n"); + return; + } + if (of_property_read_u32(np, "reboot-offset", &offset) < 0) { + pr_err("failed to find reboot-offset property\n"); + return; + } + writel_relaxed(0xdeadbeef, base + offset); + + while (1) + cpu_do_idle(); +} + static const char *hi3xxx_compat[] __initconst = { "hisilicon,hi3620-hi4511", NULL, @@ -57,4 +92,6 @@ DT_MACHINE_START(HI3620, "Hisilicon Hi3620 (Flattened Device Tree)") .map_io = hi3620_map_io, .init_time = hi3xxx_timer_init, .dt_compat = hi3xxx_compat, + .smp = smp_ops(hi3xxx_smp_ops), + .restart = hi3xxx_restart, MACHINE_END diff --git a/arch/arm/mach-hi3xxx/platsmp.c b/arch/arm/mach-hi3xxx/platsmp.c new file mode 100644 index 000000000000..8ebfbe7c8fae --- /dev/null +++ b/arch/arm/mach-hi3xxx/platsmp.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2013 Linaro Ltd. + * Copyright (c) 2013 Hisilicon Limited. + * Based on arch/arm/mach-vexpress/platsmp.c, Copyright (C) 2002 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ +#include +#include +#include + +#include +#include +#include + +#include "core.h" + +static void __iomem *ctrl_base; + +void hi3xxx_set_cpu_jump(int cpu, void *jump_addr) +{ + cpu = cpu_logical_map(cpu); + if (!cpu || !ctrl_base) + return; + writel_relaxed(virt_to_phys(jump_addr), ctrl_base + ((cpu - 1) << 2)); +} + +int hi3xxx_get_cpu_jump(int cpu) +{ + cpu = cpu_logical_map(cpu); + if (!cpu || !ctrl_base) + return 0; + return readl_relaxed(ctrl_base + ((cpu - 1) << 2)); +} + +static void __init hi3xxx_smp_prepare_cpus(unsigned int max_cpus) +{ + struct device_node *np = NULL; + unsigned long base = 0; + u32 offset = 0; + void __iomem *scu_base = NULL; + + if (scu_a9_has_base()) { + base = scu_a9_get_base(); + scu_base = ioremap(base, SZ_4K); + if (!scu_base) { + pr_err("ioremap(scu_base) failed\n"); + return; + } + scu_enable(scu_base); + iounmap(scu_base); + } + if (!ctrl_base) { + np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); + if (!np) { + pr_err("failed to find hisilicon,sysctrl node\n"); + return; + } + ctrl_base = of_iomap(np, 0); + if (!ctrl_base) { + pr_err("failed to map address\n"); + return; + } + if (of_property_read_u32(np, "smp-offset", &offset) < 0) { + pr_err("failed to find smp-offset property\n"); + return; + } + ctrl_base += offset; + } +} + +static int hi3xxx_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + hi3xxx_set_cpu_jump(cpu, secondary_startup); + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + return 0; +} + +struct smp_operations hi3xxx_smp_ops __initdata = { + .smp_prepare_cpus = hi3xxx_smp_prepare_cpus, + .smp_boot_secondary = hi3xxx_boot_secondary, +}; -- cgit v1.2.3 From f7074ab348e29c8068a2daaaf89920aebc903a98 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Sun, 18 Aug 2013 16:14:27 -0300 Subject: [media] s5p-jpeg: Add initial device tree support for S5PV210/Exynos4210 SoCs This patch enables the JPEG codec on S5PV210 and Exynos4210 SoCs. There are some differences in newer versions of the JPEG codec IP on SoCs like Exynos4x12 and Exynos5 series and support for them will be added in subsequent patches. Signed-off-by: Sylwester Nawrocki Acked-by: Stephen Warren Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/exynos-jpeg-codec.txt | 11 +++++++++++ drivers/media/platform/s5p-jpeg/jpeg-core.c | 12 +++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt b/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt new file mode 100644 index 000000000000..937b755baf8f --- /dev/null +++ b/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt @@ -0,0 +1,11 @@ +Samsung S5P/EXYNOS SoC series JPEG codec + +Required properties: + +- compatible : should be one of: + "samsung,s5pv210-jpeg", "samsung,exynos4210-jpeg"; +- reg : address and length of the JPEG codec IP register set; +- interrupts : specifies the JPEG codec IP interrupt; +- clocks : should contain the JPEG codec IP gate clock specifier, from the + common clock bindings; +- clock-names : should contain "jpeg" entry. diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 091b06af84ea..a4bff8ec982e 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1428,10 +1429,20 @@ static const struct dev_pm_ops s5p_jpeg_pm_ops = { .runtime_resume = s5p_jpeg_runtime_resume, }; +#ifdef CONFIG_OF +static const struct of_device_id s5p_jpeg_of_match[] = { + { .compatible = "samsung,s5pv210-jpeg" }, + { .compatible = "samsung,exynos4210-jpeg" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, s5p_jpeg_of_match); +#endif + static struct platform_driver s5p_jpeg_driver = { .probe = s5p_jpeg_probe, .remove = s5p_jpeg_remove, .driver = { + .of_match_table = of_match_ptr(s5p_jpeg_of_match), .owner = THIS_MODULE, .name = S5P_JPEG_M2M_NAME, .pm = &s5p_jpeg_pm_ops, @@ -1443,4 +1454,3 @@ module_platform_driver(s5p_jpeg_driver); MODULE_AUTHOR("Andrzej Pietrasiewicz "); MODULE_DESCRIPTION("Samsung JPEG codec driver"); MODULE_LICENSE("GPL"); - -- cgit v1.2.3 From 01d08185850c2eb5ce80722df3fdb5d7a291fb79 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Wed, 18 Dec 2013 08:39:10 -0800 Subject: Input: fix typos in Documentation/input/gamepad.txt Fix some typos and while at it also use "PS" as the name for the central "HOME" button on Sony controllers, this is how Sony itself calls it. Reviewed-by: David Herrmann Signed-off-by: Antonio Ospite Signed-off-by: Dmitry Torokhov --- Documentation/input/gamepad.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/input/gamepad.txt b/Documentation/input/gamepad.txt index 31bb6a4029ef..3f6d8a5e9cdc 100644 --- a/Documentation/input/gamepad.txt +++ b/Documentation/input/gamepad.txt @@ -68,7 +68,7 @@ features that you need, first. How each feature is mapped is described below. Legacy drivers often don't comply to these rules. As we cannot change them for backwards-compatibility reasons, you need to provide fixup mappings in user-space yourself. Some of them might also provide module-options that -change the mappings so you can adivce users to set these. +change the mappings so you can advise users to set these. All new gamepads are supposed to comply with this mapping. Please report any bugs, if they don't. @@ -150,10 +150,10 @@ Menu-Pad: BTN_START Many pads also have a third button which is branded or has a special symbol and meaning. Such buttons are mapped as BTN_MODE. Examples are the Nintendo - "HOME" button, the XBox "X"-button or Sony "P" button. + "HOME" button, the XBox "X"-button or Sony "PS" button. Rumble: - Rumble is adverticed as FF_RUMBLE. + Rumble is advertised as FF_RUMBLE. ---------------------------------------------------------------------------- Written 2013 by David Herrmann -- cgit v1.2.3 From b6344859b911990152e5ee411e62b82eb968004f Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Tue, 17 Dec 2013 11:24:41 +0800 Subject: ASoC: fsl-sai: Add device tree bindings for Freescale SAI. This adds the Document for Freescale SAI driver under Documentation/devicetree/bindings/sound/. Signed-off-by: Xiubo Li Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/fsl-sai.txt | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/fsl-sai.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt new file mode 100644 index 000000000000..98611a6761c0 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt @@ -0,0 +1,40 @@ +Freescale Synchronous Audio Interface (SAI). + +The SAI is based on I2S module that used communicating with audio codecs, +which provides a synchronous audio interface that supports fullduplex +serial interfaces with frame synchronization such as I2S, AC97, TDM, and +codec/DSP interfaces. + + +Required properties: +- compatible: Compatible list, contains "fsl,vf610-sai". +- reg: Offset and length of the register set for the device. +- clocks: Must contain an entry for each entry in clock-names. +- clock-names : Must include the "sai" entry. +- dmas : Generic dma devicetree binding as described in + Documentation/devicetree/bindings/dma/dma.txt. +- dma-names : Two dmas have to be defined, "tx" and "rx". +- pinctrl-names: Must contain a "default" entry. +- pinctrl-NNN: One property must exist for each entry in pinctrl-names. + See ../pinctrl/pinctrl-bindings.txt for details of the property values. +- big-endian-regs: If this property is absent, the little endian mode will + be in use as default, or the big endian mode will be in use for all the + device registers. +- big-endian-data: If this property is absent, the little endian mode will + be in use as default, or the big endian mode will be in use for all the + fifo data. + +Example: +sai2: sai@40031000 { + compatible = "fsl,vf610-sai"; + reg = <0x40031000 0x1000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai2_1>; + clocks = <&clks VF610_CLK_SAI2>; + clock-names = "sai"; + dma-names = "tx", "rx"; + dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>, + <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>; + big-endian-regs; + big-endian-data; +}; -- cgit v1.2.3 From cd174e67a6b312fce9bab502ba2b0583e11f537f Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Sat, 14 Dec 2013 05:13:45 +0100 Subject: ipv4: new ip_no_pmtu_disc mode to always discard incoming frag needed msgs This new mode discards all incoming fragmentation-needed notifications as I guess was originally intended with this knob. To not break backward compatibility too much, I only added a special case for mode 2 in the receiving path. Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 10 ++++++++-- net/ipv4/icmp.c | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index f76d177895d9..d71afa8bd828 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -15,12 +15,18 @@ ip_default_ttl - INTEGER forwarded) IP packets. Should be between 1 and 255 inclusive. Default: 64 (as recommended by RFC1700) -ip_no_pmtu_disc - BOOLEAN - Disable Path MTU Discovery. If enabled and a +ip_no_pmtu_disc - INTEGER + Disable Path MTU Discovery. If enabled in mode 1 and a fragmentation-required ICMP is received, the PMTU to this destination will be set to min_pmtu (see below). You will need to raise min_pmtu to the smallest interface MTU on your system manually if you want to avoid locally generated fragments. + + In mode 2 incoming Path MTU Discovery messages will be + discarded. Outgoing frames are handled the same as in mode 1, + implicitly setting IP_PMTUDISC_DONT on every created socket. + + Possible values: 0-2 Default: FALSE min_pmtu - INTEGER diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 1a4ee84ca3f3..fb3c5637199d 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -705,7 +705,9 @@ static void icmp_unreach(struct sk_buff *skb) case ICMP_PORT_UNREACH: break; case ICMP_FRAG_NEEDED: - if (net->ipv4.sysctl_ip_no_pmtu_disc) { + if (net->ipv4.sysctl_ip_no_pmtu_disc == 2) { + goto out; + } else if (net->ipv4.sysctl_ip_no_pmtu_disc) { LIMIT_NETDEBUG(KERN_INFO pr_fmt("%pI4: fragmentation needed and DF set\n"), &iph->daddr); } else { -- cgit v1.2.3 From 864382dcc10f0fdae35cc1b713ba12f059752d78 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Tue, 17 Dec 2013 16:47:14 +0100 Subject: drivers/misc: atmel_tclib: document clock properties Document the clock properties required by the atmel_tclib driver. Signed-off-by: Boris BREZILLON Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/arm/atmel-at91.txt | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 1196290082d1..78530e621a1e 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -20,6 +20,10 @@ TC/TCLIB Timer required properties: - interrupts: Should contain all interrupts for the TC block Note that you can specify several interrupt cells if the TC block has one interrupt per channel. +- clock-names: tuple listing input clock names. + Required elements: "t0_clk" + Optional elements: "t1_clk", "t2_clk" +- clocks: phandles to input clocks. Examples: @@ -28,6 +32,8 @@ One interrupt per TC block: compatible = "atmel,at91rm9200-tcb"; reg = <0xfff7c000 0x100>; interrupts = <18 4>; + clocks = <&tcb0_clk>; + clock-names = "t0_clk"; }; One interrupt per TC channel in a TC block: @@ -35,6 +41,8 @@ One interrupt per TC channel in a TC block: compatible = "atmel,at91rm9200-tcb"; reg = <0xfffdc000 0x100>; interrupts = <26 4 27 4 28 4>; + clocks = <&tcb1_clk>; + clock-names = "t0_clk"; }; RSTC Reset Controller required properties: -- cgit v1.2.3 From 725fc136432552231f7076fd09e6b57a100de1f8 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Tue, 17 Dec 2013 16:01:47 +0100 Subject: drivers/misc: atmel-ssc: document clock properties Document the clock properties required by the atmel-ssc driver. Signed-off-by: Boris BREZILLON Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/misc/atmel-ssc.txt | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/misc/atmel-ssc.txt b/Documentation/devicetree/bindings/misc/atmel-ssc.txt index a45ae08c8ed1..60960b2755f4 100644 --- a/Documentation/devicetree/bindings/misc/atmel-ssc.txt +++ b/Documentation/devicetree/bindings/misc/atmel-ssc.txt @@ -6,6 +6,9 @@ Required properties: - atmel,at91sam9g45-ssc: support dma transfer - reg: Should contain SSC registers location and length - interrupts: Should contain SSC interrupt +- clock-names: tuple listing input clock names. + Required elements: "pclk" +- clocks: phandles to input clocks. Required properties for devices compatible with "atmel,at91sam9g45-ssc": @@ -20,6 +23,8 @@ ssc0: ssc@fffbc000 { compatible = "atmel,at91rm9200-ssc"; reg = <0xfffbc000 0x4000>; interrupts = <14 4 5>; + clocks = <&ssc0_clk>; + clock-names = "pclk"; }; - DMA transfer: -- cgit v1.2.3 From c59330cd7c15d550c4edbb8cd49d48e6d65ed47f Mon Sep 17 00:00:00 2001 From: Frank Haverkamp Date: Mon, 9 Dec 2013 13:30:42 +0100 Subject: GenWQE Debugfs interfaces Debugfs interfaces for the GenWQE card. Help to debug potential problems. Dump internal chip state for debugging and failure determination. Signed-off-by: Frank Haverkamp Co-authors: Joerg-Stephan Vogt , Michael Jung , Michael Ruettger Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/debugfs-driver-genwqe | 91 +++++ drivers/misc/genwqe/card_debugfs.c | 500 ++++++++++++++++++++++++ 2 files changed, 591 insertions(+) create mode 100644 Documentation/ABI/testing/debugfs-driver-genwqe create mode 100644 drivers/misc/genwqe/card_debugfs.c (limited to 'Documentation') diff --git a/Documentation/ABI/testing/debugfs-driver-genwqe b/Documentation/ABI/testing/debugfs-driver-genwqe new file mode 100644 index 000000000000..1c2f25674e8c --- /dev/null +++ b/Documentation/ABI/testing/debugfs-driver-genwqe @@ -0,0 +1,91 @@ +What: /sys/kernel/debug/genwqe/genwqe_card/ddcb_info +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: DDCB queue dump used for debugging queueing problems. + +What: /sys/kernel/debug/genwqe/genwqe_card/curr_regs +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Dump of the current error registers. + Only available for PF. + +What: /sys/kernel/debug/genwqe/genwqe_card/curr_dbg_uid0 +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Internal chip state of UID0 (unit id 0). + Only available for PF. + +What: /sys/kernel/debug/genwqe/genwqe_card/curr_dbg_uid1 +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Internal chip state of UID1. + Only available for PF. + +What: /sys/kernel/debug/genwqe/genwqe_card/curr_dbg_uid2 +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Internal chip state of UID2. + Only available for PF. + +What: /sys/kernel/debug/genwqe/genwqe_card/prev_regs +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Dump of the error registers before the last reset of + the card occured. + Only available for PF. + +What: /sys/kernel/debug/genwqe/genwqe_card/prev_dbg_uid0 +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Internal chip state of UID0 before card was reset. + Only available for PF. + +What: /sys/kernel/debug/genwqe/genwqe_card/prev_dbg_uid1 +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Internal chip state of UID1 before card was reset. + Only available for PF. + +What: /sys/kernel/debug/genwqe/genwqe_card/prev_dbg_uid2 +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Internal chip state of UID2 before card was reset. + Only available for PF. + +What: /sys/kernel/debug/genwqe/genwqe_card/info +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Comprehensive summary of bitstream version and software + version. Used bitstream and bitstream clocking information. + +What: /sys/kernel/debug/genwqe/genwqe_card/err_inject +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Possibility to inject error cases to ensure that the drivers + error handling code works well. + +What: /sys/kernel/debug/genwqe/genwqe_card/vf<0..14>_jobtimeout_msec +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Default VF timeout 250ms. Testing might require 1000ms. + Using 0 will use the cards default value (whatever that is). + + The timeout depends on the max number of available cards + in the system and the maximum allowed queue size. + + The driver ensures that the settings are done just before + the VFs get enabled. Changing the timeouts in flight is not + possible. + Only available for PF. + +What: /sys/kernel/debug/genwqe/genwqe_card/jobtimer +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Dump job timeout register values for PF and VFs. + Only available for PF. + +What: /sys/kernel/debug/genwqe/genwqe_card/queue_working_time +Date: Dec 2013 +Contact: haver@linux.vnet.ibm.com +Description: Dump queue working time register values for PF and VFs. + Only available for PF. diff --git a/drivers/misc/genwqe/card_debugfs.c b/drivers/misc/genwqe/card_debugfs.c new file mode 100644 index 000000000000..3bfdc07a7248 --- /dev/null +++ b/drivers/misc/genwqe/card_debugfs.c @@ -0,0 +1,500 @@ +/** + * IBM Accelerator Family 'GenWQE' + * + * (C) Copyright IBM Corp. 2013 + * + * Author: Frank Haverkamp + * Author: Joerg-Stephan Vogt + * Author: Michael Jung + * Author: Michael Ruettger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * 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. + */ + +/* + * Debugfs interfaces for the GenWQE card. Help to debug potential + * problems. Dump internal chip state for debugging and failure + * determination. + */ + +#include +#include +#include +#include +#include +#include + +#include "card_base.h" +#include "card_ddcb.h" + +#define GENWQE_DEBUGFS_RO(_name, _showfn) \ + static int genwqe_debugfs_##_name##_open(struct inode *inode, \ + struct file *file) \ + { \ + return single_open(file, _showfn, inode->i_private); \ + } \ + static const struct file_operations genwqe_##_name##_fops = { \ + .open = genwqe_debugfs_##_name##_open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ + } + +static void dbg_uidn_show(struct seq_file *s, struct genwqe_reg *regs, + int entries) +{ + unsigned int i; + u32 v_hi, v_lo; + + for (i = 0; i < entries; i++) { + v_hi = (regs[i].val >> 32) & 0xffffffff; + v_lo = (regs[i].val) & 0xffffffff; + + seq_printf(s, " 0x%08x 0x%08x 0x%08x 0x%08x EXT_ERR_REC\n", + regs[i].addr, regs[i].idx, v_hi, v_lo); + } +} + +static int curr_dbg_uidn_show(struct seq_file *s, void *unused, int uid) +{ + struct genwqe_dev *cd = s->private; + int entries; + struct genwqe_reg *regs; + + entries = genwqe_ffdc_buff_size(cd, uid); + if (entries < 0) + return -EINVAL; + + if (entries == 0) + return 0; + + regs = kcalloc(entries, sizeof(*regs), GFP_KERNEL); + if (regs == NULL) + return -ENOMEM; + + genwqe_stop_traps(cd); /* halt the traps while dumping data */ + genwqe_ffdc_buff_read(cd, uid, regs, entries); + genwqe_start_traps(cd); + + dbg_uidn_show(s, regs, entries); + kfree(regs); + return 0; +} + +static int genwqe_curr_dbg_uid0_show(struct seq_file *s, void *unused) +{ + return curr_dbg_uidn_show(s, unused, 0); +} + +GENWQE_DEBUGFS_RO(curr_dbg_uid0, genwqe_curr_dbg_uid0_show); + +static int genwqe_curr_dbg_uid1_show(struct seq_file *s, void *unused) +{ + return curr_dbg_uidn_show(s, unused, 1); +} + +GENWQE_DEBUGFS_RO(curr_dbg_uid1, genwqe_curr_dbg_uid1_show); + +static int genwqe_curr_dbg_uid2_show(struct seq_file *s, void *unused) +{ + return curr_dbg_uidn_show(s, unused, 2); +} + +GENWQE_DEBUGFS_RO(curr_dbg_uid2, genwqe_curr_dbg_uid2_show); + +static int prev_dbg_uidn_show(struct seq_file *s, void *unused, int uid) +{ + struct genwqe_dev *cd = s->private; + + dbg_uidn_show(s, cd->ffdc[uid].regs, cd->ffdc[uid].entries); + return 0; +} + +static int genwqe_prev_dbg_uid0_show(struct seq_file *s, void *unused) +{ + return prev_dbg_uidn_show(s, unused, 0); +} + +GENWQE_DEBUGFS_RO(prev_dbg_uid0, genwqe_prev_dbg_uid0_show); + +static int genwqe_prev_dbg_uid1_show(struct seq_file *s, void *unused) +{ + return prev_dbg_uidn_show(s, unused, 1); +} + +GENWQE_DEBUGFS_RO(prev_dbg_uid1, genwqe_prev_dbg_uid1_show); + +static int genwqe_prev_dbg_uid2_show(struct seq_file *s, void *unused) +{ + return prev_dbg_uidn_show(s, unused, 2); +} + +GENWQE_DEBUGFS_RO(prev_dbg_uid2, genwqe_prev_dbg_uid2_show); + +static int genwqe_curr_regs_show(struct seq_file *s, void *unused) +{ + struct genwqe_dev *cd = s->private; + unsigned int i; + struct genwqe_reg *regs; + + regs = kcalloc(GENWQE_FFDC_REGS, sizeof(*regs), GFP_KERNEL); + if (regs == NULL) + return -ENOMEM; + + genwqe_stop_traps(cd); + genwqe_read_ffdc_regs(cd, regs, GENWQE_FFDC_REGS, 1); + genwqe_start_traps(cd); + + for (i = 0; i < GENWQE_FFDC_REGS; i++) { + if (regs[i].addr == 0xffffffff) + break; /* invalid entries */ + + if (regs[i].val == 0x0ull) + continue; /* do not print 0x0 FIRs */ + + seq_printf(s, " 0x%08x 0x%016llx\n", + regs[i].addr, regs[i].val); + } + return 0; +} + +GENWQE_DEBUGFS_RO(curr_regs, genwqe_curr_regs_show); + +static int genwqe_prev_regs_show(struct seq_file *s, void *unused) +{ + struct genwqe_dev *cd = s->private; + unsigned int i; + struct genwqe_reg *regs = cd->ffdc[GENWQE_DBG_REGS].regs; + + if (regs == NULL) + return -EINVAL; + + for (i = 0; i < GENWQE_FFDC_REGS; i++) { + if (regs[i].addr == 0xffffffff) + break; /* invalid entries */ + + if (regs[i].val == 0x0ull) + continue; /* do not print 0x0 FIRs */ + + seq_printf(s, " 0x%08x 0x%016llx\n", + regs[i].addr, regs[i].val); + } + return 0; +} + +GENWQE_DEBUGFS_RO(prev_regs, genwqe_prev_regs_show); + +static int genwqe_jtimer_show(struct seq_file *s, void *unused) +{ + struct genwqe_dev *cd = s->private; + unsigned int vf_num; + u64 jtimer; + + jtimer = genwqe_read_vreg(cd, IO_SLC_VF_APPJOB_TIMEOUT, 0); + seq_printf(s, " PF 0x%016llx %d msec\n", jtimer, + genwqe_pf_jobtimeout_msec); + + for (vf_num = 0; vf_num < cd->num_vfs; vf_num++) { + jtimer = genwqe_read_vreg(cd, IO_SLC_VF_APPJOB_TIMEOUT, + vf_num + 1); + seq_printf(s, " VF%-2d 0x%016llx %d msec\n", vf_num, jtimer, + cd->vf_jobtimeout_msec[vf_num]); + } + return 0; +} + +GENWQE_DEBUGFS_RO(jtimer, genwqe_jtimer_show); + +static int genwqe_queue_working_time_show(struct seq_file *s, void *unused) +{ + struct genwqe_dev *cd = s->private; + unsigned int vf_num; + u64 t; + + t = genwqe_read_vreg(cd, IO_SLC_VF_QUEUE_WTIME, 0); + seq_printf(s, " PF 0x%016llx\n", t); + + for (vf_num = 0; vf_num < cd->num_vfs; vf_num++) { + t = genwqe_read_vreg(cd, IO_SLC_VF_QUEUE_WTIME, vf_num + 1); + seq_printf(s, " VF%-2d 0x%016llx\n", vf_num, t); + } + return 0; +} + +GENWQE_DEBUGFS_RO(queue_working_time, genwqe_queue_working_time_show); + +static int genwqe_ddcb_info_show(struct seq_file *s, void *unused) +{ + struct genwqe_dev *cd = s->private; + unsigned int i; + struct ddcb_queue *queue; + struct ddcb *pddcb; + + queue = &cd->queue; + seq_puts(s, "DDCB QUEUE:\n"); + seq_printf(s, " ddcb_max: %d\n" + " ddcb_daddr: %016llx - %016llx\n" + " ddcb_vaddr: %016llx\n" + " ddcbs_in_flight: %u\n" + " ddcbs_max_in_flight: %u\n" + " ddcbs_completed: %u\n" + " busy: %u\n" + " irqs_processed: %u\n", + queue->ddcb_max, (long long)queue->ddcb_daddr, + (long long)queue->ddcb_daddr + + (queue->ddcb_max * DDCB_LENGTH), + (long long)queue->ddcb_vaddr, queue->ddcbs_in_flight, + queue->ddcbs_max_in_flight, queue->ddcbs_completed, + queue->busy, cd->irqs_processed); + + /* Hardware State */ + seq_printf(s, " 0x%08x 0x%016llx IO_QUEUE_CONFIG\n" + " 0x%08x 0x%016llx IO_QUEUE_STATUS\n" + " 0x%08x 0x%016llx IO_QUEUE_SEGMENT\n" + " 0x%08x 0x%016llx IO_QUEUE_INITSQN\n" + " 0x%08x 0x%016llx IO_QUEUE_WRAP\n" + " 0x%08x 0x%016llx IO_QUEUE_OFFSET\n" + " 0x%08x 0x%016llx IO_QUEUE_WTIME\n" + " 0x%08x 0x%016llx IO_QUEUE_ERRCNTS\n" + " 0x%08x 0x%016llx IO_QUEUE_LRW\n", + queue->IO_QUEUE_CONFIG, + __genwqe_readq(cd, queue->IO_QUEUE_CONFIG), + queue->IO_QUEUE_STATUS, + __genwqe_readq(cd, queue->IO_QUEUE_STATUS), + queue->IO_QUEUE_SEGMENT, + __genwqe_readq(cd, queue->IO_QUEUE_SEGMENT), + queue->IO_QUEUE_INITSQN, + __genwqe_readq(cd, queue->IO_QUEUE_INITSQN), + queue->IO_QUEUE_WRAP, + __genwqe_readq(cd, queue->IO_QUEUE_WRAP), + queue->IO_QUEUE_OFFSET, + __genwqe_readq(cd, queue->IO_QUEUE_OFFSET), + queue->IO_QUEUE_WTIME, + __genwqe_readq(cd, queue->IO_QUEUE_WTIME), + queue->IO_QUEUE_ERRCNTS, + __genwqe_readq(cd, queue->IO_QUEUE_ERRCNTS), + queue->IO_QUEUE_LRW, + __genwqe_readq(cd, queue->IO_QUEUE_LRW)); + + seq_printf(s, "DDCB list (ddcb_act=%d/ddcb_next=%d):\n", + queue->ddcb_act, queue->ddcb_next); + + pddcb = queue->ddcb_vaddr; + for (i = 0; i < queue->ddcb_max; i++) { + seq_printf(s, " %-3d: RETC=%03x SEQ=%04x HSI/SHI=%02x/%02x ", + i, be16_to_cpu(pddcb->retc_16), + be16_to_cpu(pddcb->seqnum_16), + pddcb->hsi, pddcb->shi); + seq_printf(s, "PRIV=%06llx CMD=%02x\n", + be64_to_cpu(pddcb->priv_64), pddcb->cmd); + pddcb++; + } + return 0; +} + +GENWQE_DEBUGFS_RO(ddcb_info, genwqe_ddcb_info_show); + +static int genwqe_info_show(struct seq_file *s, void *unused) +{ + struct genwqe_dev *cd = s->private; + u16 val16, type; + u64 app_id, slu_id, bitstream = -1; + struct pci_dev *pci_dev = cd->pci_dev; + + slu_id = __genwqe_readq(cd, IO_SLU_UNITCFG); + app_id = __genwqe_readq(cd, IO_APP_UNITCFG); + + if (genwqe_is_privileged(cd)) + bitstream = __genwqe_readq(cd, IO_SLU_BITSTREAM); + + val16 = (u16)(slu_id & 0x0fLLU); + type = (u16)((slu_id >> 20) & 0xffLLU); + + seq_printf(s, "%s driver version: %s\n" + " Device Name/Type: %s %s CardIdx: %d\n" + " SLU/APP Config : 0x%016llx/0x%016llx\n" + " Build Date : %u/%x/%u\n" + " Base Clock : %u MHz\n" + " Arch/SVN Release: %u/%llx\n" + " Bitstream : %llx\n", + GENWQE_DEVNAME, DRV_VERS_STRING, dev_name(&pci_dev->dev), + genwqe_is_privileged(cd) ? + "Physical" : "Virtual or no SR-IOV", + cd->card_idx, slu_id, app_id, + (u16)((slu_id >> 12) & 0x0fLLU), /* month */ + (u16)((slu_id >> 4) & 0xffLLU), /* day */ + (u16)((slu_id >> 16) & 0x0fLLU) + 2010, /* year */ + genwqe_base_clock_frequency(cd), + (u16)((slu_id >> 32) & 0xffLLU), slu_id >> 40, + bitstream); + + return 0; +} + +GENWQE_DEBUGFS_RO(info, genwqe_info_show); + +int genwqe_init_debugfs(struct genwqe_dev *cd) +{ + struct dentry *root; + struct dentry *file; + int ret; + char card_name[64]; + char name[64]; + unsigned int i; + + sprintf(card_name, "%s%u_card", GENWQE_DEVNAME, cd->card_idx); + + root = debugfs_create_dir(card_name, cd->debugfs_genwqe); + if (!root) { + ret = -ENOMEM; + goto err0; + } + + /* non privileged interfaces are done here */ + file = debugfs_create_file("ddcb_info", S_IRUGO, root, cd, + &genwqe_ddcb_info_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_file("info", S_IRUGO, root, cd, + &genwqe_info_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_x64("err_inject", 0666, root, &cd->err_inject); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_u32("ddcb_software_timeout", 0666, root, + &cd->ddcb_software_timeout); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_u32("kill_timeout", 0666, root, + &cd->kill_timeout); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + /* privileged interfaces follow here */ + if (!genwqe_is_privileged(cd)) { + cd->debugfs_root = root; + return 0; + } + + file = debugfs_create_file("curr_regs", S_IRUGO, root, cd, + &genwqe_curr_regs_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_file("curr_dbg_uid0", S_IRUGO, root, cd, + &genwqe_curr_dbg_uid0_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_file("curr_dbg_uid1", S_IRUGO, root, cd, + &genwqe_curr_dbg_uid1_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_file("curr_dbg_uid2", S_IRUGO, root, cd, + &genwqe_curr_dbg_uid2_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_file("prev_regs", S_IRUGO, root, cd, + &genwqe_prev_regs_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_file("prev_dbg_uid0", S_IRUGO, root, cd, + &genwqe_prev_dbg_uid0_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_file("prev_dbg_uid1", S_IRUGO, root, cd, + &genwqe_prev_dbg_uid1_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_file("prev_dbg_uid2", S_IRUGO, root, cd, + &genwqe_prev_dbg_uid2_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + for (i = 0; i < GENWQE_MAX_VFS; i++) { + sprintf(name, "vf%d_jobtimeout_msec", i); + + file = debugfs_create_u32(name, 0666, root, + &cd->vf_jobtimeout_msec[i]); + if (!file) { + ret = -ENOMEM; + goto err1; + } + } + + file = debugfs_create_file("jobtimer", S_IRUGO, root, cd, + &genwqe_jtimer_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_file("queue_working_time", S_IRUGO, root, cd, + &genwqe_queue_working_time_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_u32("skip_recovery", 0666, root, + &cd->skip_recovery); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + cd->debugfs_root = root; + return 0; +err1: + debugfs_remove_recursive(root); +err0: + return ret; +} + +void genqwe_exit_debugfs(struct genwqe_dev *cd) +{ + debugfs_remove_recursive(cd->debugfs_root); +} -- cgit v1.2.3 From b2a65138b51bd7b36a47da3691aee039cd50010c Mon Sep 17 00:00:00 2001 From: Frank Haverkamp Date: Mon, 9 Dec 2013 13:30:43 +0100 Subject: GenWQE Sysfs interfaces Sysfs interfaces for the GenWQE card. There are attributes to query the version of the bitstream as well as some for the driver. For debugging, please also see the debugfs interfaces of this driver. Signed-off-by: Frank Haverkamp Co-authors: Joerg-Stephan Vogt , Michael Jung , Michael Ruettger Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-driver-genwqe | 62 ++++++ drivers/misc/genwqe/card_sysfs.c | 288 ++++++++++++++++++++++++++ 2 files changed, 350 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-driver-genwqe create mode 100644 drivers/misc/genwqe/card_sysfs.c (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-driver-genwqe b/Documentation/ABI/testing/sysfs-driver-genwqe new file mode 100644 index 000000000000..1870737a1f5e --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-genwqe @@ -0,0 +1,62 @@ +What: /sys/class/genwqe/genwqe_card/version +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Unique bitstream identification e.g. + '0000000330336283.00000000475a4950'. + +What: /sys/class/genwqe/genwqe_card/appid +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Identifies the currently active card application e.g. 'GZIP' + for compression/decompression. + +What: /sys/class/genwqe/genwqe_card/type +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Type of the card e.g. 'GenWQE5-A7'. + +What: /sys/class/genwqe/genwqe_card/curr_bitstream +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Currently active bitstream. 1 is default, 0 is backup. + +What: /sys/class/genwqe/genwqe_card/next_bitstream +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Interface to set the next bitstream to be used. + +What: /sys/class/genwqe/genwqe_card/tempsens +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Interface to read the cards temperature sense register. + +What: /sys/class/genwqe/genwqe_card/freerunning_timer +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Interface to read the cards free running timer. + Used for performance and utilization measurements. + +What: /sys/class/genwqe/genwqe_card/queue_working_time +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Interface to read queue working time. + Used for performance and utilization measurements. + +What: /sys/class/genwqe/genwqe_card/state +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: State of the card: "unused", "used", "error". + +What: /sys/class/genwqe/genwqe_card/base_clock +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Base clock frequency of the card. + +What: /sys/class/genwqe/genwqe_card/device/sriov_numvfs +Date: Oct 2013 +Contact: haver@linux.vnet.ibm.com +Description: Enable VFs (1..15): + sudo sh -c 'echo 15 > \ + /sys/bus/pci/devices/0000\:1b\:00.0/sriov_numvfs' + Disable VFs: + Write a 0 into the same sysfs entry. diff --git a/drivers/misc/genwqe/card_sysfs.c b/drivers/misc/genwqe/card_sysfs.c new file mode 100644 index 000000000000..a72a99266c3c --- /dev/null +++ b/drivers/misc/genwqe/card_sysfs.c @@ -0,0 +1,288 @@ +/** + * IBM Accelerator Family 'GenWQE' + * + * (C) Copyright IBM Corp. 2013 + * + * Author: Frank Haverkamp + * Author: Joerg-Stephan Vogt + * Author: Michael Jung + * Author: Michael Ruettger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2 only) + * 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. + */ + +/* + * Sysfs interfaces for the GenWQE card. There are attributes to query + * the version of the bitstream as well as some for the driver. For + * debugging, please also see the debugfs interfaces of this driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "card_base.h" +#include "card_ddcb.h" + +static const char * const genwqe_types[] = { + [GENWQE_TYPE_ALTERA_230] = "GenWQE4-230", + [GENWQE_TYPE_ALTERA_530] = "GenWQE4-530", + [GENWQE_TYPE_ALTERA_A4] = "GenWQE5-A4", + [GENWQE_TYPE_ALTERA_A7] = "GenWQE5-A7", +}; + +static ssize_t status_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct genwqe_dev *cd = dev_get_drvdata(dev); + const char *cs[GENWQE_CARD_STATE_MAX] = { "unused", "used", "error" }; + + return sprintf(buf, "%s\n", cs[cd->card_state]); +} +static DEVICE_ATTR_RO(status); + +static ssize_t appid_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + char app_name[5]; + struct genwqe_dev *cd = dev_get_drvdata(dev); + + genwqe_read_app_id(cd, app_name, sizeof(app_name)); + return sprintf(buf, "%s\n", app_name); +} +static DEVICE_ATTR_RO(appid); + +static ssize_t version_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + u64 slu_id, app_id; + struct genwqe_dev *cd = dev_get_drvdata(dev); + + slu_id = __genwqe_readq(cd, IO_SLU_UNITCFG); + app_id = __genwqe_readq(cd, IO_APP_UNITCFG); + + return sprintf(buf, "%016llx.%016llx\n", slu_id, app_id); +} +static DEVICE_ATTR_RO(version); + +static ssize_t type_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + u8 card_type; + struct genwqe_dev *cd = dev_get_drvdata(dev); + + card_type = genwqe_card_type(cd); + return sprintf(buf, "%s\n", (card_type >= ARRAY_SIZE(genwqe_types)) ? + "invalid" : genwqe_types[card_type]); +} +static DEVICE_ATTR_RO(type); + +static ssize_t driver_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", DRV_VERS_STRING); +} +static DEVICE_ATTR_RO(driver); + +static ssize_t tempsens_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + u64 tempsens; + struct genwqe_dev *cd = dev_get_drvdata(dev); + + tempsens = __genwqe_readq(cd, IO_SLU_TEMPERATURE_SENSOR); + return sprintf(buf, "%016llx\n", tempsens); +} +static DEVICE_ATTR_RO(tempsens); + +static ssize_t freerunning_timer_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u64 t; + struct genwqe_dev *cd = dev_get_drvdata(dev); + + t = __genwqe_readq(cd, IO_SLC_FREE_RUNNING_TIMER); + return sprintf(buf, "%016llx\n", t); +} +static DEVICE_ATTR_RO(freerunning_timer); + +static ssize_t queue_working_time_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u64 t; + struct genwqe_dev *cd = dev_get_drvdata(dev); + + t = __genwqe_readq(cd, IO_SLC_QUEUE_WTIME); + return sprintf(buf, "%016llx\n", t); +} +static DEVICE_ATTR_RO(queue_working_time); + +static ssize_t base_clock_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u64 base_clock; + struct genwqe_dev *cd = dev_get_drvdata(dev); + + base_clock = genwqe_base_clock_frequency(cd); + return sprintf(buf, "%lld\n", base_clock); +} +static DEVICE_ATTR_RO(base_clock); + +/** + * curr_bitstream_show() - Show the current bitstream id + * + * There is a bug in some old versions of the CPLD which selects the + * bitstream, which causes the IO_SLU_BITSTREAM register to report + * unreliable data in very rare cases. This makes this sysfs + * unreliable up to the point were a new CPLD version is being used. + * + * Unfortunately there is no automatic way yet to query the CPLD + * version, such that you need to manually ensure via programming + * tools that you have a recent version of the CPLD software. + * + * The proposed circumvention is to use a special recovery bitstream + * on the backup partition (0) to identify problems while loading the + * image. + */ +static ssize_t curr_bitstream_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int curr_bitstream; + struct genwqe_dev *cd = dev_get_drvdata(dev); + + curr_bitstream = __genwqe_readq(cd, IO_SLU_BITSTREAM) & 0x1; + return sprintf(buf, "%d\n", curr_bitstream); +} +static DEVICE_ATTR_RO(curr_bitstream); + +/** + * next_bitstream_show() - Show the next activated bitstream + * + * IO_SLC_CFGREG_SOFTRESET: This register can only be accessed by the PF. + */ +static ssize_t next_bitstream_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int next_bitstream; + struct genwqe_dev *cd = dev_get_drvdata(dev); + + switch ((cd->softreset & 0xc) >> 2) { + case 0x2: + next_bitstream = 0; + break; + case 0x3: + next_bitstream = 1; + break; + default: + next_bitstream = -1; + break; /* error */ + } + return sprintf(buf, "%d\n", next_bitstream); +} + +static ssize_t next_bitstream_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int partition; + struct genwqe_dev *cd = dev_get_drvdata(dev); + + if (kstrtoint(buf, 0, &partition) < 0) + return -EINVAL; + + switch (partition) { + case 0x0: + cd->softreset = 0x78; + break; + case 0x1: + cd->softreset = 0x7c; + break; + default: + return -EINVAL; + } + + __genwqe_writeq(cd, IO_SLC_CFGREG_SOFTRESET, cd->softreset); + return count; +} +static DEVICE_ATTR_RW(next_bitstream); + +/* + * Create device_attribute structures / params: name, mode, show, store + * additional flag if valid in VF + */ +static struct attribute *genwqe_attributes[] = { + &dev_attr_tempsens.attr, + &dev_attr_next_bitstream.attr, + &dev_attr_curr_bitstream.attr, + &dev_attr_base_clock.attr, + &dev_attr_driver.attr, + &dev_attr_type.attr, + &dev_attr_version.attr, + &dev_attr_appid.attr, + &dev_attr_status.attr, + &dev_attr_freerunning_timer.attr, + &dev_attr_queue_working_time.attr, + NULL, +}; + +static struct attribute *genwqe_normal_attributes[] = { + &dev_attr_driver.attr, + &dev_attr_type.attr, + &dev_attr_version.attr, + &dev_attr_appid.attr, + &dev_attr_status.attr, + &dev_attr_freerunning_timer.attr, + &dev_attr_queue_working_time.attr, + NULL, +}; + +/** + * genwqe_is_visible() - Determine if sysfs attribute should be visible or not + * + * VFs have restricted mmio capabilities, so not all sysfs entries + * are allowed in VFs. + */ +static umode_t genwqe_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + unsigned int j; + struct device *dev = container_of(kobj, struct device, kobj); + struct genwqe_dev *cd = dev_get_drvdata(dev); + umode_t mode = attr->mode; + + if (genwqe_is_privileged(cd)) + return mode; + + for (j = 0; genwqe_normal_attributes[j] != NULL; j++) + if (genwqe_normal_attributes[j] == attr) + return mode; + + return 0; +} + +static struct attribute_group genwqe_attribute_group = { + .is_visible = genwqe_is_visible, + .attrs = genwqe_attributes, +}; + +const struct attribute_group *genwqe_attribute_groups[] = { + &genwqe_attribute_group, + NULL, +}; -- cgit v1.2.3 From 52690a6a868719d1d2f9e12b039c05d966600d41 Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Fri, 6 Dec 2013 19:54:49 +0530 Subject: spi/qspi: update binding information These update binding information for ti qspi controller. Signed-off-by: Sourav Poddar Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/ti_qspi.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/spi/ti_qspi.txt b/Documentation/devicetree/bindings/spi/ti_qspi.txt index 1f9641ade0b5..601a360531a5 100644 --- a/Documentation/devicetree/bindings/spi/ti_qspi.txt +++ b/Documentation/devicetree/bindings/spi/ti_qspi.txt @@ -3,6 +3,11 @@ TI QSPI controller. Required properties: - compatible : should be "ti,dra7xxx-qspi" or "ti,am4372-qspi". - reg: Should contain QSPI registers location and length. +- reg-names: Should contain the resource reg names. + - qspi_base: Qspi configuration register Address space + - qspi_mmap: Memory mapped Address space + - (optional) qspi_ctrlmod: Control module Address space +- interrupts: should contain the qspi interrupt number. - #address-cells, #size-cells : Must be present if the device has sub-nodes - ti,hwmods: Name of the hwmod associated to the QSPI @@ -14,7 +19,8 @@ Example: qspi: qspi@4b300000 { compatible = "ti,dra7xxx-qspi"; - reg = <0x4b300000 0x100>; + reg = <0x47900000 0x100>, <0x30000000 0x3ffffff>; + reg-names = "qspi_base", "qspi_mmap"; #address-cells = <1>; #size-cells = <0>; spi-max-frequency = <25000000>; -- cgit v1.2.3 From bf65188352f91de5b443346ac9b08af480b1b6d9 Mon Sep 17 00:00:00 2001 From: Silvan Jegen Date: Wed, 18 Dec 2013 20:16:31 +0100 Subject: doc: Fix trivial spelling mistake in efi-stub.txt Signed-off-by: Silvan Jegen Signed-off-by: Jiri Kosina --- Documentation/efi-stub.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/efi-stub.txt b/Documentation/efi-stub.txt index 44e6bb6ead10..c628788d5b47 100644 --- a/Documentation/efi-stub.txt +++ b/Documentation/efi-stub.txt @@ -20,7 +20,7 @@ The EFI boot stub is enabled with the CONFIG_EFI_STUB kernel option. **** How to install bzImage.efi The bzImage located in arch/x86/boot/bzImage must be copied to the EFI -System Partiion (ESP) and renamed with the extension ".efi". Without +System Partition (ESP) and renamed with the extension ".efi". Without the extension the EFI firmware loader will refuse to execute it. It's not possible to execute bzImage.efi from the usual Linux file systems because EFI firmware doesn't have support for them. -- cgit v1.2.3 From 507da6a1f386676b5b085972555b3a3e46190e3d Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Thu, 5 Dec 2013 20:34:05 +0100 Subject: doc: Fix typo (acces_process_vm -> access_process_vm) Signed-off-by: Stefan Weil Signed-off-by: Jiri Kosina --- Documentation/filesystems/Locking | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index fe7afe225381..5b0c083d7c0e 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -544,7 +544,7 @@ like the ->fault() handler, but simply return with VM_FAULT_NOPAGE, which will cause the VM to retry the fault. ->access() is called when get_user_pages() fails in -acces_process_vm(), typically used to debug a process through +access_process_vm(), typically used to debug a process through /proc/pid/mem or ptrace. This function is needed only for VM_IO | VM_PFNMAP VMAs. -- cgit v1.2.3 From c4b34a3b7a505dd63268cf6dcf57d10068b47cb6 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Tue, 15 Oct 2013 15:32:14 +0530 Subject: usb: phy: omap: Add omap-control Support for AM437x This adds omap control module support for USBSS in AM437x SoC. Update DT binding information to reflect these changes. Acked-by: Roger Quadros Signed-off-by: George Cherian Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/omap-usb.txt | 2 ++ drivers/usb/phy/phy-omap-control.c | 19 +++++++++++++++++++ include/linux/usb/omap_control_usb.h | 6 ++++++ 3 files changed, 27 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt index 090e5e22bd2b..c495135115cb 100644 --- a/Documentation/devicetree/bindings/usb/omap-usb.txt +++ b/Documentation/devicetree/bindings/usb/omap-usb.txt @@ -87,6 +87,8 @@ Required properties: e.g. USB3 PHY and SATA PHY on OMAP5. "ti,control-phy-dra7usb2" - if it has power down register like USB2 PHY on DRA7 platform. + "ti,control-phy-am437usb2" - if it has power down register like USB2 PHY on + AM437 platform. - reg : Address and length of the register set for the device. It contains the address of "otghs_control" for control-phy-otghs or "power" register for other types. diff --git a/drivers/usb/phy/phy-omap-control.c b/drivers/usb/phy/phy-omap-control.c index 09c5ace1edd8..e7253182e47d 100644 --- a/drivers/usb/phy/phy-omap-control.c +++ b/drivers/usb/phy/phy-omap-control.c @@ -84,6 +84,20 @@ void omap_control_usb_phy_power(struct device *dev, int on) else val |= OMAP_CTRL_USB2_PHY_PD; break; + + case OMAP_CTRL_TYPE_AM437USB2: + if (on) { + val &= ~(AM437X_CTRL_USB2_PHY_PD | + AM437X_CTRL_USB2_OTG_PD); + val |= (AM437X_CTRL_USB2_OTGVDET_EN | + AM437X_CTRL_USB2_OTGSESSEND_EN); + } else { + val &= ~(AM437X_CTRL_USB2_OTGVDET_EN | + AM437X_CTRL_USB2_OTGSESSEND_EN); + val |= (AM437X_CTRL_USB2_PHY_PD | + AM437X_CTRL_USB2_OTG_PD); + } + break; default: dev_err(dev, "%s: type %d not recognized\n", __func__, control_usb->type); @@ -197,6 +211,7 @@ static const enum omap_control_usb_type otghs_data = OMAP_CTRL_TYPE_OTGHS; static const enum omap_control_usb_type usb2_data = OMAP_CTRL_TYPE_USB2; static const enum omap_control_usb_type pipe3_data = OMAP_CTRL_TYPE_PIPE3; static const enum omap_control_usb_type dra7usb2_data = OMAP_CTRL_TYPE_DRA7USB2; +static const enum omap_control_usb_type am437usb2_data = OMAP_CTRL_TYPE_AM437USB2; static const struct of_device_id omap_control_usb_id_table[] = { { @@ -215,6 +230,10 @@ static const struct of_device_id omap_control_usb_id_table[] = { .compatible = "ti,control-phy-dra7usb2", .data = &dra7usb2_data, }, + { + .compatible = "ti,control-phy-am437usb2", + .data = &am437usb2_data, + }, {}, }; MODULE_DEVICE_TABLE(of, omap_control_usb_id_table); diff --git a/include/linux/usb/omap_control_usb.h b/include/linux/usb/omap_control_usb.h index 596b01918813..69ae383ee3cc 100644 --- a/include/linux/usb/omap_control_usb.h +++ b/include/linux/usb/omap_control_usb.h @@ -24,6 +24,7 @@ enum omap_control_usb_type { OMAP_CTRL_TYPE_USB2, /* USB2_PHY, power down in CONTROL_DEV_CONF */ OMAP_CTRL_TYPE_PIPE3, /* PIPE3 PHY, DPLL & seperate Rx/Tx power */ OMAP_CTRL_TYPE_DRA7USB2, /* USB2 PHY, power and power_aux e.g. DRA7 */ + OMAP_CTRL_TYPE_AM437USB2, /* USB2 PHY, power e.g. AM437x */ }; struct omap_control_usb { @@ -64,6 +65,11 @@ enum omap_control_usb_mode { #define OMAP_CTRL_USB2_PHY_PD BIT(28) +#define AM437X_CTRL_USB2_PHY_PD BIT(0) +#define AM437X_CTRL_USB2_OTG_PD BIT(1) +#define AM437X_CTRL_USB2_OTGVDET_EN BIT(19) +#define AM437X_CTRL_USB2_OTGSESSEND_EN BIT(20) + #if IS_ENABLED(CONFIG_OMAP_CONTROL_USB) extern void omap_control_usb_phy_power(struct device *dev, int on); extern void omap_control_usb_set_mode(struct device *dev, -- cgit v1.2.3 From 5e4fcf9d5e4c2518d6e575d045f01f8834721c6c Mon Sep 17 00:00:00 2001 From: Laszlo Papp Date: Tue, 17 Dec 2013 18:42:24 +0000 Subject: doc: driver-model/platform.txt: fix a typo The sentence is not proper English, so the use of "general" is now replaced with "in general". "generally" was also considered, but "in general" is probably the correct in this case. Signed-off-by: Laszlo Papp Signed-off-by: Jiri Kosina --- Documentation/driver-model/platform.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/driver-model/platform.txt b/Documentation/driver-model/platform.txt index 41f41632ee55..07795ec51cde 100644 --- a/Documentation/driver-model/platform.txt +++ b/Documentation/driver-model/platform.txt @@ -48,7 +48,7 @@ struct platform_driver { struct device_driver driver; }; -Note that probe() should general verify that the specified device hardware +Note that probe() should in general verify that the specified device hardware actually exists; sometimes platform setup code can't be sure. The probing can use device resources, including clocks, and device platform_data. -- cgit v1.2.3 From 1a4049ddfdaa75db7c9927dbc4d991bd73f923a0 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 12 Sep 2013 10:18:00 -0400 Subject: [SCSI] aci7xxx_old: delete decade+ obsolete driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After getting warnings in an allyesconfig build[1] from this driver, I decided to remind myself just how old it was, and whether it warranted fixing. In the Kconfig help text, I found: "This driver will eventually be phased out entirely" Going back to the history archive, I see the line was added[2] in Feb 2002, when we moved from v2.4.2.1 ---> v2.4.2.2 So, with over a decade of notification, and multiple major releases since then, I think we can justify removing this. Currently we have people wasting time building it during routine testing, and then wasting more time re-researching the known reported warnings, only to find that nobody really is willing to integrate the fixes[3] for it. A quick search didn't seem to indicate any active user base for it. If someone happens to have a quirky _old_ card that the eleven year old "new" driver doesn't work with, then it is entirely reasonable that they stick with a kernel version that predates this removal. [1] drivers/scsi/aic7xxx_old.c: In function ‘aic7xxx_register’: drivers/scsi/aic7xxx_old.c:7901:5: warning: case value ‘257’ not in enumerated type ‘ahc_chip’ [-Wswitch] drivers/scsi/aic7xxx_old.c:7898:5: warning: case value ‘513’ not in enumerated type ‘ahc_chip’ [-Wswitch] drivers/scsi/aic7xxx_old.c: In function ‘aic7xxx_load_seeprom’: drivers/scsi/aic7xxx_old.c:8517:5: warning: case value ‘257’ not in enumerated type ‘ahc_chip’ [-Wswitch] drivers/scsi/aic7xxx_old.c:8510:5: warning: case value ‘513’ not in enumerated type ‘ahc_chip’ [-Wswitch] [2] http://git.kernel.org/cgit/linux/kernel/git/tglx/history.git commit 44e8778c [3] https://lkml.org/lkml/2012/10/29/215 Signed-off-by: Paul Gortmaker Acked-by: Hannes Reinecke Acked-by: Doug Ledford Signed-off-by: James Bottomley --- Documentation/scsi/00-INDEX | 2 - Documentation/scsi/aic7xxx_old.txt | 511 -- MAINTAINERS | 1 - drivers/scsi/Kconfig | 41 - drivers/scsi/Makefile | 1 - drivers/scsi/aic7xxx_old.c | 11149 ------------------------------ drivers/scsi/aic7xxx_old/aic7xxx.h | 28 - drivers/scsi/aic7xxx_old/aic7xxx.reg | 1401 ---- drivers/scsi/aic7xxx_old/aic7xxx.seq | 1539 ----- drivers/scsi/aic7xxx_old/aic7xxx_proc.c | 270 - drivers/scsi/aic7xxx_old/aic7xxx_reg.h | 629 -- drivers/scsi/aic7xxx_old/aic7xxx_seq.c | 817 --- drivers/scsi/aic7xxx_old/scsi_message.h | 49 - drivers/scsi/aic7xxx_old/sequencer.h | 135 - 14 files changed, 16573 deletions(-) delete mode 100644 Documentation/scsi/aic7xxx_old.txt delete mode 100644 drivers/scsi/aic7xxx_old.c delete mode 100644 drivers/scsi/aic7xxx_old/aic7xxx.h delete mode 100644 drivers/scsi/aic7xxx_old/aic7xxx.reg delete mode 100644 drivers/scsi/aic7xxx_old/aic7xxx.seq delete mode 100644 drivers/scsi/aic7xxx_old/aic7xxx_proc.c delete mode 100644 drivers/scsi/aic7xxx_old/aic7xxx_reg.h delete mode 100644 drivers/scsi/aic7xxx_old/aic7xxx_seq.c delete mode 100644 drivers/scsi/aic7xxx_old/scsi_message.h delete mode 100644 drivers/scsi/aic7xxx_old/sequencer.h (limited to 'Documentation') diff --git a/Documentation/scsi/00-INDEX b/Documentation/scsi/00-INDEX index 9b0787f965e9..2044be565d93 100644 --- a/Documentation/scsi/00-INDEX +++ b/Documentation/scsi/00-INDEX @@ -42,8 +42,6 @@ aic79xx.txt - Adaptec Ultra320 SCSI host adapters aic7xxx.txt - info on driver for Adaptec controllers -aic7xxx_old.txt - - info on driver for Adaptec controllers, old generation arcmsr_spec.txt - ARECA FIRMWARE SPEC (for IOP331 adapter) dc395x.txt diff --git a/Documentation/scsi/aic7xxx_old.txt b/Documentation/scsi/aic7xxx_old.txt deleted file mode 100644 index ecfc474f36a8..000000000000 --- a/Documentation/scsi/aic7xxx_old.txt +++ /dev/null @@ -1,511 +0,0 @@ - AIC7xxx Driver for Linux - -Introduction ----------------------------- -The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com) -SCSI controllers and chipsets. Major portions of the driver and driver -development are shared between both Linux and FreeBSD. Support for the -AIC-7xxx chipsets have been in the default Linux kernel since approximately -linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD -2.1.0 or later. - - Supported cards/chipsets - ---------------------------- - Adaptec Cards - ---------------------------- - AHA-274x - AHA-274xT - AHA-2842 - AHA-2910B - AHA-2920C - AHA-2930 - AHA-2930U - AHA-2930CU - AHA-2930U2 - AHA-2940 - AHA-2940W - AHA-2940U - AHA-2940UW - AHA-2940UW-PRO - AHA-2940AU - AHA-2940U2W - AHA-2940U2 - AHA-2940U2B - AHA-2940U2BOEM - AHA-2944D - AHA-2944WD - AHA-2944UD - AHA-2944UWD - AHA-2950U2 - AHA-2950U2W - AHA-2950U2B - AHA-29160M - AHA-3940 - AHA-3940U - AHA-3940W - AHA-3940UW - AHA-3940AUW - AHA-3940U2W - AHA-3950U2B - AHA-3950U2D - AHA-3960D - AHA-39160M - AHA-3985 - AHA-3985U - AHA-3985W - AHA-3985UW - - Motherboard Chipsets - ---------------------------- - AIC-777x - AIC-785x - AIC-786x - AIC-787x - AIC-788x - AIC-789x - AIC-3860 - - Bus Types - ---------------------------- - W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support - SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s. - U - Ultra SCSI, transfer rates up to 40MB/s. - U2- Ultra 2 SCSI, transfer rates up to 80MB/s. - D - Differential SCSI. - T - Twin Channel SCSI. Up to 14 SCSI devices. - - AHA-274x - EISA SCSI controller - AHA-284x - VLB SCSI controller - AHA-29xx - PCI SCSI controller - AHA-394x - PCI controllers with two separate SCSI controllers on-board. - AHA-398x - PCI RAID controllers with three separate SCSI controllers - on-board. - - Not Supported Devices - ------------------------------ - Adaptec Cards - ---------------------------- - AHA-2920 (Only the cards that use the Future Domain chipset are not - supported, any 2920 cards based on Adaptec AIC chipsets, - such as the 2920C, are supported) - AAA-13x Raid Adapters - AAA-113x Raid Port Card - - Motherboard Chipsets - ---------------------------- - AIC-7810 - - Bus Types - ---------------------------- - R - Raid Port busses are not supported. - - The hardware RAID devices sold by Adaptec are *NOT* supported by this - driver (and will people please stop emailing me about them, they are - a totally separate beast from the bare SCSI controllers and this driver - cannot be retrofitted in any sane manner to support the hardware RAID - features on those cards - Doug Ledford). - - - People - ------------------------------ - Justin T Gibbs gibbs@plutotech.com - (BSD Driver Author) - Dan Eischen deischen@iworks.InterWorks.org - (Original Linux Driver Co-maintainer) - Dean Gehnert deang@teleport.com - (Original Linux FTP/patch maintainer) - Jess Johnson jester@frenzy.com - (AIC7xxx FAQ author) - Doug Ledford dledford@redhat.com - (Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer) - - Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original - author of the driver. John has since retired from the project. Thanks - again for all his work! - - Mailing list - ------------------------------ - There is a mailing list available for users who want to track development - and converse with other users and developers. This list is for both - FreeBSD and Linux support of the AIC7xxx chipsets. - - To subscribe to the AIC7xxx mailing list send mail to the list server, - with "subscribe AIC7xxx" in the body (no Subject: required): - To: majordomo@FreeBSD.ORG - --- - subscribe AIC7xxx - - To unsubscribe from the list, send mail to the list server with: - To: majordomo@FreeBSD.ORG - --- - unsubscribe AIC7xxx - - Send regular messages and replies to: AIC7xxx@FreeBSD.ORG - - Boot Command line options - ------------------------------ - "aic7xxx=no_reset" - Eliminate the SCSI bus reset during startup. - Some SCSI devices need the initial reset that this option disables - in order to work. If you have problems at bootup, please make sure - you aren't using this option. - - "aic7xxx=reverse_scan" - Certain PCI motherboards scan for devices at - bootup by scanning from the highest numbered PCI device to the - lowest numbered PCI device, others do just the opposite and scan - from lowest to highest numbered PCI device. There is no reliable - way to autodetect this ordering. So, we default to the most common - order, which is lowest to highest. Then, in case your motherboard - scans from highest to lowest, we have this option. If your BIOS - finds the drives on controller A before controller B but the linux - kernel finds your drives on controller B before A, then you should - use this option. - - "aic7xxx=extended" - Force the driver to detect extended drive translation - on your controller. This helps those people who have cards without - a SEEPROM make sure that linux and all other operating systems think - the same way about your hard drives. - - "aic7xxx=scbram" - Some cards have external SCB RAM that can be used to - give the card more hardware SCB slots. This allows the driver to use - that SCB RAM. Without this option, the driver won't touch the SCB - RAM because it is known to cause problems on a few cards out there - (such as 3985 class cards). - - "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel - to use the correct IRQ type for your card. This only applies to EISA - based controllers. On these controllers, 0 is for Edge triggered - interrupts, and 1 is for Level triggered interrupts. If you aren't - sure or don't know which IRQ trigger type your EISA card uses, then - let the kernel autodetect the trigger type. - - "aic7xxx=verbose" - This option can be used in one of two ways. If you - simply specify aic7xxx=verbose, then the kernel will automatically - pick the default set of verbose messages for you to see. - Alternatively, you can specify the command as - "aic7xxx=verbose:0xXXXX" where the X entries are replaced with - hexadecimal digits. This option is a bit field type option. For - a full listing of the available options, search for the - #define VERBOSE_xxxxxx lines in the aic7xxx.c file. If you want - verbose messages, then it is recommended that you simply use the - aic7xxx=verbose variant of this command. - - "aic7xxx=pci_parity:x" - This option controls whether or not the driver - enables PCI parity error checking on the PCI bus. By default, this - checking is disabled. To enable the checks, simply specify pci_parity - with no value afterwords. To reverse the parity from even to odd, - supply any number other than 0 or 255. In short: - pci_parity - Even parity checking (even is the normal PCI parity) - pci_parity:x - Where x > 0, Odd parity checking - pci_parity:0 - No check (default) - NOTE: In order to get Even PCI parity checking, you must use the - version of the option that does not include the : and a number at - the end (unless you want to enter exactly 2^32 - 1 as the number). - - "aic7xxx=no_probe" - This option will disable the probing for any VLB - based 2842 controllers and any EISA based controllers. This is - needed on certain newer motherboards where the normal EISA I/O ranges - have been claimed by other PCI devices. Probing on those machines - will often result in the machine crashing or spontaneously rebooting - during startup. Examples of machines that need this are the - Dell PowerEdge 6300 machines. - - "aic7xxx=seltime:2" - This option controls how long the card waits - during a device selection sequence for the device to respond. - The original SCSI spec says that this "should be" 256ms. This - is generally not required with modern devices. However, some - very old SCSI I devices need the full 256ms. Most modern devices - can run fine with only 64ms. The default for this option is - 64ms. If you need to change this option, then use the following - table to set the proper value in the example above: - 0 - 256ms - 1 - 128ms - 2 - 64ms - 3 - 32ms - - "aic7xxx=panic_on_abort" - This option is for debugging and will cause - the driver to panic the linux kernel and freeze the system the first - time the drivers abort or reset routines are called. This is most - helpful when some problem causes infinite reset loops that scroll too - fast to see. By using this option, you can write down what the errors - actually are and send that information to me so it can be fixed. - - "aic7xxx=dump_card" - This option will print out the *entire* set of - configuration registers on the card during the init sequence. This - is a debugging aid used to see exactly what state the card is in - when we finally finish our initialization routines. If you don't - have documentation on the chipsets, this will do you absolutely - no good unless you are simply trying to write all the information - down in order to send it to me. - - "aic7xxx=dump_sequencer" - This is the same as the above options except - that instead of dumping the register contents on the card, this - option dumps the contents of the sequencer program RAM. This gives - the ability to verify that the instructions downloaded to the - card's sequencer are indeed what they are supposed to be. Again, - unless you have documentation to tell you how to interpret these - numbers, then it is totally useless. - - "aic7xxx=override_term:0xffffffff" - This option is used to force the - termination on your SCSI controllers to a particular setting. This - is a bit mask variable that applies for up to 8 aic7xxx SCSI channels. - Each channel gets 4 bits, divided as follows: - bit 3 2 1 0 - | | | Enable/Disable Single Ended Low Byte Termination - | | En/Disable Single Ended High Byte Termination - | En/Disable Low Byte LVD Termination - En/Disable High Byte LVD Termination - - The upper 2 bits that deal with LVD termination only apply to Ultra2 - controllers. Furthermore, due to the current Ultra2 controller - designs, these bits are tied together such that setting either bit - enables both low and high byte LVD termination. It is not possible - to only set high or low byte LVD termination in this manner. This is - an artifact of the BIOS definition on Ultra2 controllers. For other - controllers, the only important bits are the two lowest bits. Setting - the higher bits on non-Ultra2 controllers has no effect. A few - examples of how to use this option: - - Enable low and high byte termination on a non-ultra2 controller that - is the first aic7xxx controller (the correct bits are 0011), - aic7xxx=override_term:0x3 - - Enable all termination on the third aic7xxx controller, high byte - termination on the second aic7xxx controller, and low and high byte - SE termination on the first aic7xxx controller - (bits are 1111 0010 0011), - aic7xxx=override_term:0xf23 - - No attempt has been made to make this option non-cryptic. It really - shouldn't be used except in dire circumstances, and if that happens, - I'm probably going to be telling you what to set this to anyway :) - - "aic7xxx=stpwlev:0xffffffff" - This option is used to control the STPWLEV - bit in the DEVCONFIG PCI register. Currently, this is one of the - very few registers that we have absolutely *no* way of detecting - what the variable should be. It depends entirely on how the chipset - and external terminators were coupled by the card/motherboard maker. - Further, a chip reset (at power up) always sets this bit to 0. If - there is no BIOS to run on the chipset/card (such as with a 2910C - or a motherboard controller with the BIOS totally disabled) then - the variable may not get set properly. Of course, if the proper - setting was 0, then that's what it would be after the reset, but if - the proper setting is actually 1.....you get the picture. Now, since - we can't detect this at all, I've added this option to force the - setting. If you have a BIOS on your controller then you should never - need to use this option. However, if you are having lots of SCSI - reset problems and can't seem to get them knocked out, this may help. - - Here's a test to know for certain if you need this option. Make - a boot floppy that you can use to boot your computer up and that - will detect the aic7xxx controller. Next, power down your computer. - While it's down, unplug all SCSI cables from your Adaptec SCSI - controller. Boot the system back up to the Adaptec EZ-SCSI BIOS - and then make sure that termination is enabled on your adapter (if - you have an Adaptec BIOS of course). Next, boot up the floppy you - made and wait for it to detect the aic7xxx controller. If the kernel - finds the controller fine, says scsi : x hosts and then tries to - detect your devices like normal, up to the point where it fails to - mount your root file system and panics, then you're fine. If, on - the other hand, the system goes into an infinite reset loop, then - you need to use this option and/or the previous option to force the - proper termination settings on your controller. If this happens, - then you next need to figure out what your settings should be. - - To find the correct settings, power your machine back down, connect - back up the SCSI cables, and boot back into your machine like normal. - However, boot with the aic7xxx=verbose:0x39 option. Record the - initial DEVCONFIG values for each of your aic7xxx controllers as - they are listed, and also record what the machine is detecting as - the proper termination on your controllers. NOTE: the order in - which the initial DEVCONFIG values are printed out is not guaranteed - to be the same order as the SCSI controllers are registered. The - above option and this option both work on the order of the SCSI - controllers as they are registered, so make sure you match the right - DEVCONFIG values with the right controllers if you have more than - one aic7xxx controller. - - Once you have the detected termination settings and the initial - DEVCONFIG values for each controller, then figure out what the - termination on each of the controllers *should* be. Hopefully, that - part is correct, but it could possibly be wrong if there is - bogus cable detection logic on your controller or something similar. - If all the controllers have the correct termination settings, then - don't set the aic7xxx=override_term variable at all, leave it alone. - Next, on any controllers that go into an infinite reset loop when - you unplug all the SCSI cables, get the starting DEVCONFIG value. - If the initial DEVCONFIG value is divisible by 2, then the correct - setting for that controller is 0. If it's an odd number, then - the correct setting for that controller is 1. For any other - controllers that didn't have an infinite reset problem, then reverse - the above options. If DEVCONFIG was even, then the correct setting - is 1, if not then the correct setting is 0. - - Now that you know what the correct setting was for each controller, - we need to encode that into the aic7xxx=stpwlev:0x... variable. - This variable is a bit field encoded variable. Bit 0 is for the first - aic7xxx controller, bit 1 for the next, etc. Put all these bits - together and you get a number. For example, if the third aic7xxx - needed a 1, but the second and first both needed a 0, then the bits - would be 100 in binary. This then translates to 0x04. You would - therefore set aic7xxx=stpwlev:0x04. This is fairly standard binary - to hexadecimal conversions here. If you aren't up to speed on the - binary->hex conversion then send an email to the aic7xxx mailing - list and someone can help you out. - - "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to disable - or enable Tagged Command Queueing (TCQ) on specific devices. As of - driver version 5.1.11, TCQ is now either on or off by default - according to the setting you choose during the make config process. - In order to en/disable TCQ for certain devices at boot time, a user - may use this boot param. The driver will then parse this message out - and en/disable the specific device entries that are present based upon - the value given. The param line is parsed in the following manner: - - { - first instance indicates the start of this parameter values - second instance is the start of entries for a particular - device entry - } - end the entries for a particular host adapter, or end the entire - set of parameter entries - , - move to next entry. Inside of a set of device entries, this - moves us to the next device on the list. Outside of device - entries, this moves us to the next host adapter - . - Same effect as , but is safe to use with insmod. - x - the number to enter into the array at this position. - 0 = Enable tagged queueing on this device and use the default - queue depth - 1-254 = Enable tagged queueing on this device and use this - number as the queue depth - 255 = Disable tagged queueing on this device. - Note: anything above 32 for an actual queue depth is wasteful - and not recommended. - - A few examples of how this can be used: - - tag_info:{{8,12,,0,,255,4}} - This line will only effect the first aic7xxx card registered. It - will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2 - at the default, set id 3 to tagged queueing enabled and use the - default queue depth, id 4 default, id 5 disabled, and id 6 to 4. - Any not specified entries stay at the default value, repeated - commas with no value specified will simply increment to the next id - without changing anything for the missing values. - - tag_info:{,,,{,,,255}} - First, second, and third adapters at default values. Fourth - adapter, id 3 is disabled. Notice that leading commas simply - increment what the first number effects, and there are no need - for trailing commas. When you close out an adapter, or the - entire entry, anything not explicitly set stays at the default - value. - - A final note on this option. The scanner I used for this isn't - perfect or highly robust. If you mess the line up, the worst that - should happen is that the line will get ignored. If you don't - close out the entire entry with the final bracket, then any other - aic7xxx options after this will get ignored. So, in general, be - sure of what you are entering, and after you have it right, just - add it to the lilo.conf file so there won't be any mistakes. As - a means of checking this parser, the entire tag_info array for - each card is now printed out in the /proc/scsi/aic7xxx/x file. You - can use that to verify that your options were parsed correctly. - - Boot command line options may be combined to form the proper set of options - a user might need. For example, the following is valid: - - aic7xxx=verbose,extended,irq_trigger:1 - - The only requirement is that individual options be separated by a comma or - a period on the command line. - - Module Loading command options - ------------------------------ - When loading the aic7xxx driver as a module, the exact same options are - available to the user. However, the syntax to specify the options changes - slightly. For insmod, you need to wrap the aic7xxx= argument in quotes - and replace all ',' with '.'. So, for example, a valid insmod line - would be: - - insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended' - - This line should result in the *exact* same behaviour as if you typed - it in at the lilo prompt and the driver was compiled into the kernel - instead of being a module. The reason for the single quote is so that - the shell won't try to interpret anything in the line, such as {. - Insmod assumes any options starting with a letter instead of a number - is a character string (which is what we want) and by switching all of - the commas to periods, insmod won't interpret this as more than one - string and write junk into our binary image. I consider it a bug in - the insmod program that even if you wrap your string in quotes (quotes - that pass the shell mind you and that insmod sees) it still treats - a comma inside of those quotes as starting a new variable, resulting - in memory scribbles if you don't switch the commas to periods. - - - Kernel Compile options - ------------------------------ - The various kernel compile time options for this driver are now fairly - well documented in the file drivers/scsi/Kconfig. In order to - see this documentation, you need to use one of the advanced configuration - programs (menuconfig and xconfig). If you are using the "make menuconfig" - method of configuring your kernel, then you would simply highlight the - option in question and hit the ? key. If you are using the "make xconfig" - method of configuring your kernel, then simply click on the help button - next to the option you have questions about. The help information from - the Configure.help file will then get automatically displayed. - - /proc support - ------------------------------ - The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/ - directory. That directory contains a file for each SCSI controller in - the system. Each file presents the current configuration and transfer - statistics (enabled with #define in aic7xxx.c) for each controller. - - Thanks to Michael Neuffer for his upper-level SCSI help, and - Matthew Jacob for statistics support. - - Debugging the driver - ------------------------------ - Should you have problems with this driver, and would like some help in - getting them solved, there are a couple debugging items built into - the driver to facilitate getting the needed information from the system. - In general, I need a complete description of the problem, with as many - logs as possible concerning what happens. To help with this, there is - a command option aic7xxx=panic_on_abort. This option, when set, forces - the driver to panic the kernel on the first SCSI abort issued by the - mid level SCSI code. If your system is going to reset loops and you - can't read the screen, then this is what you need. Not only will it - stop the system, but it also prints out a large amount of state - information in the process. Second, if you specify the option - "aic7xxx=verbose:0x1ffff", the system will print out *SOOOO* much - information as it runs that you won't be able to see anything. - However, this can actually be very useful if your machine simply - locks up when trying to boot, since it will pin-point what was last - happening (in regards to the aic7xxx driver) immediately prior to - the lockup. This is really only useful if your machine simply can - not boot up successfully. If you can get your machine to run, then - this will produce far too much information. - - FTP sites - ------------------------------ - ftp://ftp.redhat.com/pub/aic/ - - Out of date. I used to keep stuff here, but too many people - complained about having a hard time getting into Red Hat's ftp - server. So use the web site below instead. - ftp://ftp.pcnet.com/users/eischen/Linux/ - - Dan Eischen's driver distribution area - ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/ - - European Linux mirror of Teleport site - - Web sites - ------------------------------ - http://people.redhat.com/dledford/ - - My web site, also the primary aic7xxx site with several related - pages. - -Dean W. Gehnert -deang@teleport.com - -$Revision: 3.0 $ - -Modified by Doug Ledford 1998-2000 - diff --git a/MAINTAINERS b/MAINTAINERS index ac3284fe741c..82492de5919f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -484,7 +484,6 @@ M: Hannes Reinecke L: linux-scsi@vger.kernel.org S: Maintained F: drivers/scsi/aic7xxx/ -F: drivers/scsi/aic7xxx_old/ AIMSLAB FM RADIO RECEIVER DRIVER M: Hans Verkuil diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index fe25677a5511..1f02003ea08d 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -499,47 +499,6 @@ config SCSI_AACRAID source "drivers/scsi/aic7xxx/Kconfig.aic7xxx" - -config SCSI_AIC7XXX_OLD - tristate "Adaptec AIC7xxx support (old driver)" - depends on (ISA || EISA || PCI ) && SCSI - help - WARNING This driver is an older aic7xxx driver and is no longer - under active development. Adaptec, Inc. is writing a new driver to - take the place of this one, and it is recommended that whenever - possible, people should use the new Adaptec written driver instead - of this one. This driver will eventually be phased out entirely. - - This is support for the various aic7xxx based Adaptec SCSI - controllers. These include the 274x EISA cards; 284x VLB cards; - 2902, 2910, 293x, 294x, 394x, 3985 and several other PCI and - motherboard based SCSI controllers from Adaptec. It does not support - the AAA-13x RAID controllers from Adaptec, nor will it likely ever - support them. It does not support the 2920 cards from Adaptec that - use the Future Domain SCSI controller chip. For those cards, you - need the "Future Domain 16xx SCSI support" driver. - - In general, if the controller is based on an Adaptec SCSI controller - chip from the aic777x series or the aic78xx series, this driver - should work. The only exception is the 7810 which is specifically - not supported (that's the RAID controller chip on the AAA-13x - cards). - - Note that the AHA2920 SCSI host adapter is *not* supported by this - driver; choose "Future Domain 16xx SCSI support" instead if you have - one of those. - - Information on the configuration options for this controller can be - found by checking the help file for each of the available - configuration options. You should read - at a minimum before - contacting the maintainer with any questions. The SCSI-HOWTO, - available from , can also - be of great help. - - To compile this driver as a module, choose M here: the - module will be called aic7xxx_old. - source "drivers/scsi/aic7xxx/Kconfig.aic79xx" source "drivers/scsi/aic94xx/Kconfig" source "drivers/scsi/mvsas/Kconfig" diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 149bb6bf1849..e172d4f8e02f 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -70,7 +70,6 @@ obj-$(CONFIG_SCSI_AHA1740) += aha1740.o obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/ obj-$(CONFIG_SCSI_AIC79XX) += aic7xxx/ obj-$(CONFIG_SCSI_AACRAID) += aacraid/ -obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/ obj-$(CONFIG_SCSI_PM8001) += pm8001/ obj-$(CONFIG_SCSI_ISCI) += isci/ diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c deleted file mode 100644 index 33ec9c643400..000000000000 --- a/drivers/scsi/aic7xxx_old.c +++ /dev/null @@ -1,11149 +0,0 @@ -/*+M************************************************************************* - * Adaptec AIC7xxx device driver for Linux. - * - * Copyright (c) 1994 John Aycock - * The University of Calgary Department of Computer Science. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F - * driver (ultrastor.c), various Linux kernel source, the Adaptec EISA - * config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide, - * the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux, - * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file - * (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual, - * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the - * ANSI SCSI-2 specification (draft 10c), ... - * - * -------------------------------------------------------------------------- - * - * Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org): - * - * Substantially modified to include support for wide and twin bus - * adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes, - * SCB paging, and other rework of the code. - * - * Parts of this driver were also based on the FreeBSD driver by - * Justin T. Gibbs. His copyright follows: - * - * -------------------------------------------------------------------------- - * Copyright (c) 1994-1997 Justin Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU General Public License ("GPL") and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: aic7xxx.c,v 1.119 1997/06/27 19:39:18 gibbs Exp $ - *--------------------------------------------------------------------------- - * - * Thanks also go to (in alphabetical order) the following: - * - * Rory Bolt - Sequencer bug fixes - * Jay Estabrook - Initial DEC Alpha support - * Doug Ledford - Much needed abort/reset bug fixes - * Kai Makisara - DMAing of SCBs - * - * A Boot time option was also added for not resetting the scsi bus. - * - * Form: aic7xxx=extended - * aic7xxx=no_reset - * aic7xxx=ultra - * aic7xxx=irq_trigger:[0,1] # 0 edge, 1 level - * aic7xxx=verbose - * - * Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97 - * - * $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $ - *-M*************************************************************************/ - -/*+M************************************************************************** - * - * Further driver modifications made by Doug Ledford - * - * Copyright (c) 1997-1999 Doug Ledford - * - * These changes are released under the same licensing terms as the FreeBSD - * driver written by Justin Gibbs. Please see his Copyright notice above - * for the exact terms and conditions covering my changes as well as the - * warranty statement. - * - * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include - * but are not limited to: - * - * 1: Import of the latest FreeBSD sequencer code for this driver - * 2: Modification of kernel code to accommodate different sequencer semantics - * 3: Extensive changes throughout kernel portion of driver to improve - * abort/reset processing and error hanndling - * 4: Other work contributed by various people on the Internet - * 5: Changes to printk information and verbosity selection code - * 6: General reliability related changes, especially in IRQ management - * 7: Modifications to the default probe/attach order for supported cards - * 8: SMP friendliness has been improved - * - * Overall, this driver represents a significant departure from the official - * aic7xxx driver released by Dan Eischen in two ways. First, in the code - * itself. A diff between the two version of the driver is now a several - * thousand line diff. Second, in approach to solving the same problem. The - * problem is importing the FreeBSD aic7xxx driver code to linux can be a - * difficult and time consuming process, that also can be error prone. Dan - * Eischen's official driver uses the approach that the linux and FreeBSD - * drivers should be as identical as possible. To that end, his next version - * of this driver will be using a mid-layer code library that he is developing - * to moderate communications between the linux mid-level SCSI code and the - * low level FreeBSD driver. He intends to be able to essentially drop the - * FreeBSD driver into the linux kernel with only a few minor tweaks to some - * include files and the like and get things working, making for fast easy - * imports of the FreeBSD code into linux. - * - * I disagree with Dan's approach. Not that I don't think his way of doing - * things would be nice, easy to maintain, and create a more uniform driver - * between FreeBSD and Linux. I have no objection to those issues. My - * disagreement is on the needed functionality. There simply are certain - * things that are done differently in FreeBSD than linux that will cause - * problems for this driver regardless of any middle ware Dan implements. - * The biggest example of this at the moment is interrupt semantics. Linux - * doesn't provide the same protection techniques as FreeBSD does, nor can - * they be easily implemented in any middle ware code since they would truly - * belong in the kernel proper and would effect all drivers. For the time - * being, I see issues such as these as major stumbling blocks to the - * reliability of code based upon such middle ware. Therefore, I choose to - * use a different approach to importing the FreeBSD code that doesn't - * involve any middle ware type code. My approach is to import the sequencer - * code from FreeBSD wholesale. Then, to only make changes in the kernel - * portion of the driver as they are needed for the new sequencer semantics. - * In this way, the portion of the driver that speaks to the rest of the - * linux kernel is fairly static and can be changed/modified to solve - * any problems one might encounter without concern for the FreeBSD driver. - * - * Note: If time and experience should prove me wrong that the middle ware - * code Dan writes is reliable in its operation, then I'll retract my above - * statements. But, for those that don't know, I'm from Missouri (in the US) - * and our state motto is "The Show-Me State". Well, before I will put - * faith into it, you'll have to show me that it works :) - * - *_M*************************************************************************/ - -/* - * The next three defines are user configurable. These should be the only - * defines a user might need to get in here and change. There are other - * defines buried deeper in the code, but those really shouldn't need touched - * under normal conditions. - */ - -/* - * AIC7XXX_STRICT_PCI_SETUP - * Should we assume the PCI config options on our controllers are set with - * sane and proper values, or should we be anal about our PCI config - * registers and force them to what we want? The main advantage to - * defining this option is on non-Intel hardware where the BIOS may not - * have been run to set things up, or if you have one of the BIOSless - * Adaptec controllers, such as a 2910, that don't get set up by the - * BIOS. However, keep in mind that we really do set the most important - * items in the driver regardless of this setting, this only controls some - * of the more esoteric PCI options on these cards. In that sense, I - * would default to leaving this off. However, if people wish to try - * things both ways, that would also help me to know if there are some - * machines where it works one way but not another. - * - * -- July 7, 17:09 - * OK...I need this on my machine for testing, so the default is to - * leave it defined. - * - * -- July 7, 18:49 - * I needed it for testing, but it didn't make any difference, so back - * off she goes. - * - * -- July 16, 23:04 - * I turned it back on to try and compensate for the 2.1.x PCI code - * which no longer relies solely on the BIOS and now tries to set - * things itself. - */ - -#define AIC7XXX_STRICT_PCI_SETUP - -/* - * AIC7XXX_VERBOSE_DEBUGGING - * This option enables a lot of extra printk();s in the code, surrounded - * by if (aic7xxx_verbose ...) statements. Executing all of those if - * statements and the extra checks can get to where it actually does have - * an impact on CPU usage and such, as well as code size. Disabling this - * define will keep some of those from becoming part of the code. - * - * NOTE: Currently, this option has no real effect, I will be adding the - * various #ifdef's in the code later when I've decided a section is - * complete and no longer needs debugging. OK...a lot of things are now - * surrounded by this define, so turning this off does have an impact. - */ - -/* - * #define AIC7XXX_VERBOSE_DEBUGGING - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "scsi.h" -#include -#include "aic7xxx_old/aic7xxx.h" - -#include "aic7xxx_old/sequencer.h" -#include "aic7xxx_old/scsi_message.h" -#include "aic7xxx_old/aic7xxx_reg.h" -#include - -#include -#include /* for kmalloc() */ - -#define AIC7XXX_C_VERSION "5.2.6" - -#define ALL_TARGETS -1 -#define ALL_CHANNELS -1 -#define ALL_LUNS -1 -#define MAX_TARGETS 16 -#define MAX_LUNS 8 -#ifndef TRUE -# define TRUE 1 -#endif -#ifndef FALSE -# define FALSE 0 -#endif - -#if defined(__powerpc__) || defined(__i386__) || defined(__x86_64__) -# define MMAPIO -#endif - -/* - * You can try raising me for better performance or lowering me if you have - * flaky devices that go off the scsi bus when hit with too many tagged - * commands (like some IBM SCSI-3 LVD drives). - */ -#define AIC7XXX_CMDS_PER_DEVICE 32 - -typedef struct -{ - unsigned char tag_commands[16]; /* Allow for wide/twin adapters. */ -} adapter_tag_info_t; - -/* - * Make a define that will tell the driver not to the default tag depth - * everywhere. - */ -#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\ - 0, 0, 0, 0, 0, 0, 0, 0} - -/* - * Modify this as you see fit for your system. By setting tag_commands - * to 0, the driver will use it's own algorithm for determining the - * number of commands to use (see above). When 255, the driver will - * not enable tagged queueing for that particular device. When positive - * (> 0) and (< 255) the values in the array are used for the queue_depth. - * Note that the maximum value for an entry is 254, but you're insane if - * you try to use that many commands on one device. - * - * In this example, the first line will disable tagged queueing for all - * the devices on the first probed aic7xxx adapter. - * - * The second line enables tagged queueing with 4 commands/LUN for IDs - * (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the - * driver to use its own algorithm for ID 1. - * - * The third line is the same as the first line. - * - * The fourth line disables tagged queueing for devices 0 and 3. It - * enables tagged queueing for the other IDs, with 16 commands/LUN - * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for - * IDs 2, 5-7, and 9-15. - */ - -/* - * NOTE: The below structure is for reference only, the actual structure - * to modify in order to change things is found after this fake one. - * -adapter_tag_info_t aic7xxx_tag_info[] = -{ - {DEFAULT_TAG_COMMANDS}, - {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 255, 4, 4, 4}}, - {DEFAULT_TAG_COMMANDS}, - {{255, 16, 4, 255, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}} -}; -*/ - -static adapter_tag_info_t aic7xxx_tag_info[] = -{ - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS} -}; - - -/* - * Define an array of board names that can be indexed by aha_type. - * Don't forget to change this when changing the types! - */ -static const char *board_names[] = { - "AIC-7xxx Unknown", /* AIC_NONE */ - "Adaptec AIC-7810 Hardware RAID Controller", /* AIC_7810 */ - "Adaptec AIC-7770 SCSI host adapter", /* AIC_7770 */ - "Adaptec AHA-274X SCSI host adapter", /* AIC_7771 */ - "Adaptec AHA-284X SCSI host adapter", /* AIC_284x */ - "Adaptec AIC-7850 SCSI host adapter", /* AIC_7850 */ - "Adaptec AIC-7855 SCSI host adapter", /* AIC_7855 */ - "Adaptec AIC-7860 Ultra SCSI host adapter", /* AIC_7860 */ - "Adaptec AHA-2940A Ultra SCSI host adapter", /* AIC_7861 */ - "Adaptec AIC-7870 SCSI host adapter", /* AIC_7870 */ - "Adaptec AHA-294X SCSI host adapter", /* AIC_7871 */ - "Adaptec AHA-394X SCSI host adapter", /* AIC_7872 */ - "Adaptec AHA-398X SCSI host adapter", /* AIC_7873 */ - "Adaptec AHA-2944 SCSI host adapter", /* AIC_7874 */ - "Adaptec AIC-7880 Ultra SCSI host adapter", /* AIC_7880 */ - "Adaptec AHA-294X Ultra SCSI host adapter", /* AIC_7881 */ - "Adaptec AHA-394X Ultra SCSI host adapter", /* AIC_7882 */ - "Adaptec AHA-398X Ultra SCSI host adapter", /* AIC_7883 */ - "Adaptec AHA-2944 Ultra SCSI host adapter", /* AIC_7884 */ - "Adaptec AHA-2940UW Pro Ultra SCSI host adapter", /* AIC_7887 */ - "Adaptec AIC-7895 Ultra SCSI host adapter", /* AIC_7895 */ - "Adaptec AIC-7890/1 Ultra2 SCSI host adapter", /* AIC_7890 */ - "Adaptec AHA-293X Ultra2 SCSI host adapter", /* AIC_7890 */ - "Adaptec AHA-294X Ultra2 SCSI host adapter", /* AIC_7890 */ - "Adaptec AIC-7896/7 Ultra2 SCSI host adapter", /* AIC_7896 */ - "Adaptec AHA-394X Ultra2 SCSI host adapter", /* AIC_7897 */ - "Adaptec AHA-395X Ultra2 SCSI host adapter", /* AIC_7897 */ - "Adaptec PCMCIA SCSI controller", /* card bus stuff */ - "Adaptec AIC-7892 Ultra 160/m SCSI host adapter", /* AIC_7892 */ - "Adaptec AIC-7899 Ultra 160/m SCSI host adapter", /* AIC_7899 */ -}; - -/* - * There should be a specific return value for this in scsi.h, but - * it seems that most drivers ignore it. - */ -#define DID_UNDERFLOW DID_ERROR - -/* - * What we want to do is have the higher level scsi driver requeue - * the command to us. There is no specific driver status for this - * condition, but the higher level scsi driver will requeue the - * command on a DID_BUS_BUSY error. - * - * Upon further inspection and testing, it seems that DID_BUS_BUSY - * will *always* retry the command. We can get into an infinite loop - * if this happens when we really want some sort of counter that - * will automatically abort/reset the command after so many retries. - * Using DID_ERROR will do just that. (Made by a suggestion by - * Doug Ledford 8/1/96) - */ -#define DID_RETRY_COMMAND DID_ERROR - -#define HSCSIID 0x07 -#define SCSI_RESET 0x040 - -/* - * EISA/VL-bus stuff - */ -#define MINSLOT 1 -#define MAXSLOT 15 -#define SLOTBASE(x) ((x) << 12) -#define BASE_TO_SLOT(x) ((x) >> 12) - -/* - * Standard EISA Host ID regs (Offset from slot base) - */ -#define AHC_HID0 0x80 /* 0,1: msb of ID2, 2-7: ID1 */ -#define AHC_HID1 0x81 /* 0-4: ID3, 5-7: LSB ID2 */ -#define AHC_HID2 0x82 /* product */ -#define AHC_HID3 0x83 /* firmware revision */ - -/* - * AIC-7770 I/O range to reserve for a card - */ -#define MINREG 0xC00 -#define MAXREG 0xCFF - -#define INTDEF 0x5C /* Interrupt Definition Register */ - -/* - * AIC-78X0 PCI registers - */ -#define CLASS_PROGIF_REVID 0x08 -#define DEVREVID 0x000000FFul -#define PROGINFC 0x0000FF00ul -#define SUBCLASS 0x00FF0000ul -#define BASECLASS 0xFF000000ul - -#define CSIZE_LATTIME 0x0C -#define CACHESIZE 0x0000003Ful /* only 5 bits */ -#define LATTIME 0x0000FF00ul - -#define DEVCONFIG 0x40 -#define SCBSIZE32 0x00010000ul /* aic789X only */ -#define MPORTMODE 0x00000400ul /* aic7870 only */ -#define RAMPSM 0x00000200ul /* aic7870 only */ -#define RAMPSM_ULTRA2 0x00000004 -#define VOLSENSE 0x00000100ul -#define SCBRAMSEL 0x00000080ul -#define SCBRAMSEL_ULTRA2 0x00000008 -#define MRDCEN 0x00000040ul -#define EXTSCBTIME 0x00000020ul /* aic7870 only */ -#define EXTSCBPEN 0x00000010ul /* aic7870 only */ -#define BERREN 0x00000008ul -#define DACEN 0x00000004ul -#define STPWLEVEL 0x00000002ul -#define DIFACTNEGEN 0x00000001ul /* aic7870 only */ - -#define SCAMCTL 0x1a /* Ultra2 only */ -#define CCSCBBADDR 0xf0 /* aic7895/6/7 */ - -/* - * Define the different types of SEEPROMs on aic7xxx adapters - * and make it also represent the address size used in accessing - * its registers. The 93C46 chips have 1024 bits organized into - * 64 16-bit words, while the 93C56 chips have 2048 bits organized - * into 128 16-bit words. The C46 chips use 6 bits to address - * each word, while the C56 and C66 (4096 bits) use 8 bits to - * address each word. - */ -typedef enum {C46 = 6, C56_66 = 8} seeprom_chip_type; - -/* - * - * Define the format of the SEEPROM registers (16 bits). - * - */ -struct seeprom_config { - -/* - * SCSI ID Configuration Flags - */ -#define CFXFER 0x0007 /* synchronous transfer rate */ -#define CFSYNCH 0x0008 /* enable synchronous transfer */ -#define CFDISC 0x0010 /* enable disconnection */ -#define CFWIDEB 0x0020 /* wide bus device (wide card) */ -#define CFSYNCHISULTRA 0x0040 /* CFSYNC is an ultra offset */ -#define CFNEWULTRAFORMAT 0x0080 /* Use the Ultra2 SEEPROM format */ -#define CFSTART 0x0100 /* send start unit SCSI command */ -#define CFINCBIOS 0x0200 /* include in BIOS scan */ -#define CFRNFOUND 0x0400 /* report even if not found */ -#define CFMULTILUN 0x0800 /* probe mult luns in BIOS scan */ -#define CFWBCACHEYES 0x4000 /* Enable W-Behind Cache on drive */ -#define CFWBCACHENC 0xc000 /* Don't change W-Behind Cache */ -/* UNUSED 0x3000 */ - unsigned short device_flags[16]; /* words 0-15 */ - -/* - * BIOS Control Bits - */ -#define CFSUPREM 0x0001 /* support all removable drives */ -#define CFSUPREMB 0x0002 /* support removable drives for boot only */ -#define CFBIOSEN 0x0004 /* BIOS enabled */ -/* UNUSED 0x0008 */ -#define CFSM2DRV 0x0010 /* support more than two drives */ -#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ -/* UNUSED 0x0040 */ -#define CFEXTEND 0x0080 /* extended translation enabled */ -/* UNUSED 0xFF00 */ - unsigned short bios_control; /* word 16 */ - -/* - * Host Adapter Control Bits - */ -#define CFAUTOTERM 0x0001 /* Perform Auto termination */ -#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable (Ultra cards) */ -#define CF284XSELTO 0x0003 /* Selection timeout (284x cards) */ -#define CF284XFIFO 0x000C /* FIFO Threshold (284x cards) */ -#define CFSTERM 0x0004 /* SCSI low byte termination */ -#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */ -#define CFSPARITY 0x0010 /* SCSI parity */ -#define CF284XSTERM 0x0020 /* SCSI low byte termination (284x cards) */ -#define CFRESETB 0x0040 /* reset SCSI bus at boot */ -#define CFBPRIMARY 0x0100 /* Channel B primary on 7895 chipsets */ -#define CFSEAUTOTERM 0x0400 /* aic7890 Perform SE Auto Term */ -#define CFLVDSTERM 0x0800 /* aic7890 LVD Termination */ -/* UNUSED 0xF280 */ - unsigned short adapter_control; /* word 17 */ - -/* - * Bus Release, Host Adapter ID - */ -#define CFSCSIID 0x000F /* host adapter SCSI ID */ -/* UNUSED 0x00F0 */ -#define CFBRTIME 0xFF00 /* bus release time */ - unsigned short brtime_id; /* word 18 */ - -/* - * Maximum targets - */ -#define CFMAXTARG 0x00FF /* maximum targets */ -/* UNUSED 0xFF00 */ - unsigned short max_targets; /* word 19 */ - - unsigned short res_1[11]; /* words 20-30 */ - unsigned short checksum; /* word 31 */ -}; - -#define SELBUS_MASK 0x0a -#define SELNARROW 0x00 -#define SELBUSB 0x08 -#define SINGLE_BUS 0x00 - -#define SCB_TARGET(scb) \ - (((scb)->hscb->target_channel_lun & TID) >> 4) -#define SCB_LUN(scb) \ - ((scb)->hscb->target_channel_lun & LID) -#define SCB_IS_SCSIBUS_B(scb) \ - (((scb)->hscb->target_channel_lun & SELBUSB) != 0) - -/* - * If an error occurs during a data transfer phase, run the command - * to completion - it's easier that way - making a note of the error - * condition in this location. This then will modify a DID_OK status - * into an appropriate error for the higher-level SCSI code. - */ -#define aic7xxx_error(cmd) ((cmd)->SCp.Status) - -/* - * Keep track of the targets returned status. - */ -#define aic7xxx_status(cmd) ((cmd)->SCp.sent_command) - -/* - * The position of the SCSI commands scb within the scb array. - */ -#define aic7xxx_position(cmd) ((cmd)->SCp.have_data_in) - -/* - * The stored DMA mapping for single-buffer data transfers. - */ -#define aic7xxx_mapping(cmd) ((cmd)->SCp.phase) - -/* - * Get out private data area from a scsi cmd pointer - */ -#define AIC_DEV(cmd) ((struct aic_dev_data *)(cmd)->device->hostdata) - -/* - * So we can keep track of our host structs - */ -static struct aic7xxx_host *first_aic7xxx = NULL; - -/* - * As of Linux 2.1, the mid-level SCSI code uses virtual addresses - * in the scatter-gather lists. We need to convert the virtual - * addresses to physical addresses. - */ -struct hw_scatterlist { - unsigned int address; - unsigned int length; -}; - -/* - * Maximum number of SG segments these cards can support. - */ -#define AIC7XXX_MAX_SG 128 - -/* - * The maximum number of SCBs we could have for ANY type - * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE - * SEQUENCER CODE IF THIS IS MODIFIED! - */ -#define AIC7XXX_MAXSCB 255 - - -struct aic7xxx_hwscb { -/* ------------ Begin hardware supported fields ---------------- */ -/* 0*/ unsigned char control; -/* 1*/ unsigned char target_channel_lun; /* 4/1/3 bits */ -/* 2*/ unsigned char target_status; -/* 3*/ unsigned char SG_segment_count; -/* 4*/ unsigned int SG_list_pointer; -/* 8*/ unsigned char residual_SG_segment_count; -/* 9*/ unsigned char residual_data_count[3]; -/*12*/ unsigned int data_pointer; -/*16*/ unsigned int data_count; -/*20*/ unsigned int SCSI_cmd_pointer; -/*24*/ unsigned char SCSI_cmd_length; -/*25*/ unsigned char tag; /* Index into our kernel SCB array. - * Also used as the tag for tagged I/O - */ -#define SCB_PIO_TRANSFER_SIZE 26 /* amount we need to upload/download - * via PIO to initialize a transaction. - */ -/*26*/ unsigned char next; /* Used to thread SCBs awaiting selection - * or disconnected down in the sequencer. - */ -/*27*/ unsigned char prev; -/*28*/ unsigned int pad; /* - * Unused by the kernel, but we require - * the padding so that the array of - * hardware SCBs is aligned on 32 byte - * boundaries so the sequencer can index - */ -}; - -typedef enum { - SCB_FREE = 0x0000, - SCB_DTR_SCB = 0x0001, - SCB_WAITINGQ = 0x0002, - SCB_ACTIVE = 0x0004, - SCB_SENSE = 0x0008, - SCB_ABORT = 0x0010, - SCB_DEVICE_RESET = 0x0020, - SCB_RESET = 0x0040, - SCB_RECOVERY_SCB = 0x0080, - SCB_MSGOUT_PPR = 0x0100, - SCB_MSGOUT_SENT = 0x0200, - SCB_MSGOUT_SDTR = 0x0400, - SCB_MSGOUT_WDTR = 0x0800, - SCB_MSGOUT_BITS = SCB_MSGOUT_PPR | - SCB_MSGOUT_SENT | - SCB_MSGOUT_SDTR | - SCB_MSGOUT_WDTR, - SCB_QUEUED_ABORT = 0x1000, - SCB_QUEUED_FOR_DONE = 0x2000, - SCB_WAS_BUSY = 0x4000, - SCB_QUEUE_FULL = 0x8000 -} scb_flag_type; - -typedef enum { - AHC_FNONE = 0x00000000, - AHC_PAGESCBS = 0x00000001, - AHC_CHANNEL_B_PRIMARY = 0x00000002, - AHC_USEDEFAULTS = 0x00000004, - AHC_INDIRECT_PAGING = 0x00000008, - AHC_CHNLB = 0x00000020, - AHC_CHNLC = 0x00000040, - AHC_EXTEND_TRANS_A = 0x00000100, - AHC_EXTEND_TRANS_B = 0x00000200, - AHC_TERM_ENB_A = 0x00000400, - AHC_TERM_ENB_SE_LOW = 0x00000400, - AHC_TERM_ENB_B = 0x00000800, - AHC_TERM_ENB_SE_HIGH = 0x00000800, - AHC_HANDLING_REQINITS = 0x00001000, - AHC_TARGETMODE = 0x00002000, - AHC_NEWEEPROM_FMT = 0x00004000, - /* - * Here ends the FreeBSD defined flags and here begins the linux defined - * flags. NOTE: I did not preserve the old flag name during this change - * specifically to force me to evaluate what flags were being used properly - * and what flags weren't. This way, I could clean up the flag usage on - * a use by use basis. Doug Ledford - */ - AHC_MOTHERBOARD = 0x00020000, - AHC_NO_STPWEN = 0x00040000, - AHC_RESET_DELAY = 0x00080000, - AHC_A_SCANNED = 0x00100000, - AHC_B_SCANNED = 0x00200000, - AHC_MULTI_CHANNEL = 0x00400000, - AHC_BIOS_ENABLED = 0x00800000, - AHC_SEEPROM_FOUND = 0x01000000, - AHC_TERM_ENB_LVD = 0x02000000, - AHC_ABORT_PENDING = 0x04000000, - AHC_RESET_PENDING = 0x08000000, -#define AHC_IN_ISR_BIT 28 - AHC_IN_ISR = 0x10000000, - AHC_IN_ABORT = 0x20000000, - AHC_IN_RESET = 0x40000000, - AHC_EXTERNAL_SRAM = 0x80000000 -} ahc_flag_type; - -typedef enum { - AHC_NONE = 0x0000, - AHC_CHIPID_MASK = 0x00ff, - AHC_AIC7770 = 0x0001, - AHC_AIC7850 = 0x0002, - AHC_AIC7860 = 0x0003, - AHC_AIC7870 = 0x0004, - AHC_AIC7880 = 0x0005, - AHC_AIC7890 = 0x0006, - AHC_AIC7895 = 0x0007, - AHC_AIC7896 = 0x0008, - AHC_AIC7892 = 0x0009, - AHC_AIC7899 = 0x000a, - AHC_VL = 0x0100, - AHC_EISA = 0x0200, - AHC_PCI = 0x0400, -} ahc_chip; - -typedef enum { - AHC_FENONE = 0x0000, - AHC_ULTRA = 0x0001, - AHC_ULTRA2 = 0x0002, - AHC_WIDE = 0x0004, - AHC_TWIN = 0x0008, - AHC_MORE_SRAM = 0x0010, - AHC_CMD_CHAN = 0x0020, - AHC_QUEUE_REGS = 0x0040, - AHC_SG_PRELOAD = 0x0080, - AHC_SPIOCAP = 0x0100, - AHC_ULTRA3 = 0x0200, - AHC_NEW_AUTOTERM = 0x0400, - AHC_AIC7770_FE = AHC_FENONE, - AHC_AIC7850_FE = AHC_SPIOCAP, - AHC_AIC7860_FE = AHC_ULTRA|AHC_SPIOCAP, - AHC_AIC7870_FE = AHC_FENONE, - AHC_AIC7880_FE = AHC_ULTRA, - AHC_AIC7890_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2| - AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_NEW_AUTOTERM, - AHC_AIC7895_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA, - AHC_AIC7896_FE = AHC_AIC7890_FE, - AHC_AIC7892_FE = AHC_AIC7890_FE|AHC_ULTRA3, - AHC_AIC7899_FE = AHC_AIC7890_FE|AHC_ULTRA3, -} ahc_feature; - -#define SCB_DMA_ADDR(scb, addr) ((unsigned long)(addr) + (scb)->scb_dma->dma_offset) - -struct aic7xxx_scb_dma { - unsigned long dma_offset; /* Correction you have to add - * to virtual address to get - * dma handle in this region */ - dma_addr_t dma_address; /* DMA handle of the start, - * for unmap */ - unsigned int dma_len; /* DMA length */ -}; - -typedef enum { - AHC_BUG_NONE = 0x0000, - AHC_BUG_TMODE_WIDEODD = 0x0001, - AHC_BUG_AUTOFLUSH = 0x0002, - AHC_BUG_CACHETHEN = 0x0004, - AHC_BUG_CACHETHEN_DIS = 0x0008, - AHC_BUG_PCI_2_1_RETRY = 0x0010, - AHC_BUG_PCI_MWI = 0x0020, - AHC_BUG_SCBCHAN_UPLOAD = 0x0040, -} ahc_bugs; - -struct aic7xxx_scb { - struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */ - struct scsi_cmnd *cmd; /* scsi_cmnd for this scb */ - struct aic7xxx_scb *q_next; /* next scb in queue */ - volatile scb_flag_type flags; /* current state of scb */ - struct hw_scatterlist *sg_list; /* SG list in adapter format */ - unsigned char tag_action; - unsigned char sg_count; - unsigned char *sense_cmd; /* - * Allocate 6 characters for - * sense command. - */ - unsigned char *cmnd; - unsigned int sg_length; /* - * We init this during - * buildscb so we don't have - * to calculate anything during - * underflow/overflow/stat code - */ - void *kmalloc_ptr; - struct aic7xxx_scb_dma *scb_dma; -}; - -/* - * Define a linked list of SCBs. - */ -typedef struct { - struct aic7xxx_scb *head; - struct aic7xxx_scb *tail; -} scb_queue_type; - -static struct { - unsigned char errno; - const char *errmesg; -} hard_error[] = { - { ILLHADDR, "Illegal Host Access" }, - { ILLSADDR, "Illegal Sequencer Address referenced" }, - { ILLOPCODE, "Illegal Opcode in sequencer program" }, - { SQPARERR, "Sequencer Ram Parity Error" }, - { DPARERR, "Data-Path Ram Parity Error" }, - { MPARERR, "Scratch Ram/SCB Array Ram Parity Error" }, - { PCIERRSTAT,"PCI Error detected" }, - { CIOPARERR, "CIOBUS Parity Error" } -}; - -static unsigned char -generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 }; - -typedef struct { - scb_queue_type free_scbs; /* - * SCBs assigned to free slot on - * card (no paging required) - */ - struct aic7xxx_scb *scb_array[AIC7XXX_MAXSCB]; - struct aic7xxx_hwscb *hscbs; - unsigned char numscbs; /* current number of scbs */ - unsigned char maxhscbs; /* hardware scbs */ - unsigned char maxscbs; /* max scbs including pageable scbs */ - dma_addr_t hscbs_dma; /* DMA handle to hscbs */ - unsigned int hscbs_dma_len; /* length of the above DMA area */ - void *hscb_kmalloc_ptr; -} scb_data_type; - -struct target_cmd { - unsigned char mesg_bytes[4]; - unsigned char command[28]; -}; - -#define AHC_TRANS_CUR 0x0001 -#define AHC_TRANS_ACTIVE 0x0002 -#define AHC_TRANS_GOAL 0x0004 -#define AHC_TRANS_USER 0x0008 -#define AHC_TRANS_QUITE 0x0010 -typedef struct { - unsigned char width; - unsigned char period; - unsigned char offset; - unsigned char options; -} transinfo_type; - -struct aic_dev_data { - volatile scb_queue_type delayed_scbs; - volatile unsigned short temp_q_depth; - unsigned short max_q_depth; - volatile unsigned char active_cmds; - /* - * Statistics Kept: - * - * Total Xfers (count for each command that has a data xfer), - * broken down by reads && writes. - * - * Further sorted into a few bins for keeping tabs on how many commands - * we get of various sizes. - * - */ - long w_total; /* total writes */ - long r_total; /* total reads */ - long barrier_total; /* total num of REQ_BARRIER commands */ - long ordered_total; /* How many REQ_BARRIER commands we - used ordered tags to satisfy */ - long w_bins[6]; /* binned write */ - long r_bins[6]; /* binned reads */ - transinfo_type cur; - transinfo_type goal; -#define BUS_DEVICE_RESET_PENDING 0x01 -#define DEVICE_RESET_DELAY 0x02 -#define DEVICE_PRINT_DTR 0x04 -#define DEVICE_WAS_BUSY 0x08 -#define DEVICE_DTR_SCANNED 0x10 -#define DEVICE_SCSI_3 0x20 - volatile unsigned char flags; - unsigned needppr:1; - unsigned needppr_copy:1; - unsigned needsdtr:1; - unsigned needsdtr_copy:1; - unsigned needwdtr:1; - unsigned needwdtr_copy:1; - unsigned dtr_pending:1; - struct scsi_device *SDptr; - struct list_head list; -}; - -/* - * Define a structure used for each host adapter. Note, in order to avoid - * problems with architectures I can't test on (because I don't have one, - * such as the Alpha based systems) which happen to give faults for - * non-aligned memory accesses, care was taken to align this structure - * in a way that guaranteed all accesses larger than 8 bits were aligned - * on the appropriate boundary. It's also organized to try and be more - * cache line efficient. Be careful when changing this lest you might hurt - * overall performance and bring down the wrath of the masses. - */ -struct aic7xxx_host { - /* - * This is the first 64 bytes in the host struct - */ - - /* - * We are grouping things here....first, items that get either read or - * written with nearly every interrupt - */ - volatile long flags; - ahc_feature features; /* chip features */ - unsigned long base; /* card base address */ - volatile unsigned char __iomem *maddr; /* memory mapped address */ - unsigned long isr_count; /* Interrupt count */ - unsigned long spurious_int; - scb_data_type *scb_data; - struct aic7xxx_cmd_queue { - struct scsi_cmnd *head; - struct scsi_cmnd *tail; - } completeq; - - /* - * Things read/written on nearly every entry into aic7xxx_queue() - */ - volatile scb_queue_type waiting_scbs; - unsigned char unpause; /* unpause value for HCNTRL */ - unsigned char pause; /* pause value for HCNTRL */ - volatile unsigned char qoutfifonext; - volatile unsigned char activescbs; /* active scbs */ - volatile unsigned char max_activescbs; - volatile unsigned char qinfifonext; - volatile unsigned char *untagged_scbs; - volatile unsigned char *qoutfifo; - volatile unsigned char *qinfifo; - - unsigned char dev_last_queue_full[MAX_TARGETS]; - unsigned char dev_last_queue_full_count[MAX_TARGETS]; - unsigned short ultraenb; /* Gets downloaded to card as a bitmap */ - unsigned short discenable; /* Gets downloaded to card as a bitmap */ - transinfo_type user[MAX_TARGETS]; - - unsigned char msg_buf[13]; /* The message for the target */ - unsigned char msg_type; -#define MSG_TYPE_NONE 0x00 -#define MSG_TYPE_INITIATOR_MSGOUT 0x01 -#define MSG_TYPE_INITIATOR_MSGIN 0x02 - unsigned char msg_len; /* Length of message */ - unsigned char msg_index; /* Index into msg_buf array */ - - - /* - * We put the less frequently used host structure items - * after the more frequently used items to try and ease - * the burden on the cache subsystem. - * These entries are not *commonly* accessed, whereas - * the preceding entries are accessed very often. - */ - - unsigned int irq; /* IRQ for this adapter */ - int instance; /* aic7xxx instance number */ - int scsi_id; /* host adapter SCSI ID */ - int scsi_id_b; /* channel B for twin adapters */ - unsigned int bios_address; - int board_name_index; - unsigned short bios_control; /* bios control - SEEPROM */ - unsigned short adapter_control; /* adapter control - SEEPROM */ - struct pci_dev *pdev; - unsigned char pci_bus; - unsigned char pci_device_fn; - struct seeprom_config sc; - unsigned short sc_type; - unsigned short sc_size; - struct aic7xxx_host *next; /* allow for multiple IRQs */ - struct Scsi_Host *host; /* pointer to scsi host */ - struct list_head aic_devs; /* all aic_dev structs on host */ - int host_no; /* SCSI host number */ - unsigned long mbase; /* I/O memory address */ - ahc_chip chip; /* chip type */ - ahc_bugs bugs; - dma_addr_t fifo_dma; /* DMA handle for fifo arrays */ -}; - -/* - * Valid SCSIRATE values. (p. 3-17) - * Provides a mapping of transfer periods in ns/4 to the proper value to - * stick in the SCSIRATE reg to use that transfer rate. - */ -#define AHC_SYNCRATE_ULTRA3 0 -#define AHC_SYNCRATE_ULTRA2 1 -#define AHC_SYNCRATE_ULTRA 3 -#define AHC_SYNCRATE_FAST 6 -#define AHC_SYNCRATE_CRC 0x40 -#define AHC_SYNCRATE_SE 0x10 -static struct aic7xxx_syncrate { - /* Rates in Ultra mode have bit 8 of sxfr set */ -#define ULTRA_SXFR 0x100 - int sxfr_ultra2; - int sxfr; - unsigned char period; - const char *rate[2]; -} aic7xxx_syncrates[] = { - { 0x42, 0x000, 9, {"80.0", "160.0"} }, - { 0x13, 0x000, 10, {"40.0", "80.0"} }, - { 0x14, 0x000, 11, {"33.0", "66.6"} }, - { 0x15, 0x100, 12, {"20.0", "40.0"} }, - { 0x16, 0x110, 15, {"16.0", "32.0"} }, - { 0x17, 0x120, 18, {"13.4", "26.8"} }, - { 0x18, 0x000, 25, {"10.0", "20.0"} }, - { 0x19, 0x010, 31, {"8.0", "16.0"} }, - { 0x1a, 0x020, 37, {"6.67", "13.3"} }, - { 0x1b, 0x030, 43, {"5.7", "11.4"} }, - { 0x10, 0x040, 50, {"5.0", "10.0"} }, - { 0x00, 0x050, 56, {"4.4", "8.8" } }, - { 0x00, 0x060, 62, {"4.0", "8.0" } }, - { 0x00, 0x070, 68, {"3.6", "7.2" } }, - { 0x00, 0x000, 0, {NULL, NULL} }, -}; - -#define CTL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 3) & 0x1), \ - (((scb->hscb)->target_channel_lun >> 4) & 0xf), \ - ((scb->hscb)->target_channel_lun & 0x07) - -#define CTL_OF_CMD(cmd) ((cmd->device->channel) & 0x01), \ - ((cmd->device->id) & 0x0f), \ - ((cmd->device->lun) & 0x07) - -#define TARGET_INDEX(cmd) ((cmd)->device->id | ((cmd)->device->channel << 3)) - -/* - * A nice little define to make doing our printks a little easier - */ - -#define WARN_LEAD KERN_WARNING "(scsi%d:%d:%d:%d) " -#define INFO_LEAD KERN_INFO "(scsi%d:%d:%d:%d) " - -/* - * XXX - these options apply unilaterally to _all_ 274x/284x/294x - * cards in the system. This should be fixed. Exceptions to this - * rule are noted in the comments. - */ - -/* - * Use this as the default queue depth when setting tagged queueing on. - */ -static unsigned int aic7xxx_default_queue_depth = AIC7XXX_CMDS_PER_DEVICE; - -/* - * Skip the scsi bus reset. Non 0 make us skip the reset at startup. This - * has no effect on any later resets that might occur due to things like - * SCSI bus timeouts. - */ -static unsigned int aic7xxx_no_reset = 0; -/* - * Certain PCI motherboards will scan PCI devices from highest to lowest, - * others scan from lowest to highest, and they tend to do all kinds of - * strange things when they come into contact with PCI bridge chips. The - * net result of all this is that the PCI card that is actually used to boot - * the machine is very hard to detect. Most motherboards go from lowest - * PCI slot number to highest, and the first SCSI controller found is the - * one you boot from. The only exceptions to this are when a controller - * has its BIOS disabled. So, we by default sort all of our SCSI controllers - * from lowest PCI slot number to highest PCI slot number. We also force - * all controllers with their BIOS disabled to the end of the list. This - * works on *almost* all computers. Where it doesn't work, we have this - * option. Setting this option to non-0 will reverse the order of the sort - * to highest first, then lowest, but will still leave cards with their BIOS - * disabled at the very end. That should fix everyone up unless there are - * really strange cirumstances. - */ -static int aic7xxx_reverse_scan = 0; -/* - * Should we force EXTENDED translation on a controller. - * 0 == Use whatever is in the SEEPROM or default to off - * 1 == Use whatever is in the SEEPROM or default to on - */ -static unsigned int aic7xxx_extended = 0; -/* - * The IRQ trigger method used on EISA controllers. Does not effect PCI cards. - * -1 = Use detected settings. - * 0 = Force Edge triggered mode. - * 1 = Force Level triggered mode. - */ -static int aic7xxx_irq_trigger = -1; -/* - * This variable is used to override the termination settings on a controller. - * This should not be used under normal conditions. However, in the case - * that a controller does not have a readable SEEPROM (so that we can't - * read the SEEPROM settings directly) and that a controller has a buggered - * version of the cable detection logic, this can be used to force the - * correct termination. It is preferable to use the manual termination - * settings in the BIOS if possible, but some motherboard controllers store - * those settings in a format we can't read. In other cases, auto term - * should also work, but the chipset was put together with no auto term - * logic (common on motherboard controllers). In those cases, we have - * 32 bits here to work with. That's good for 8 controllers/channels. The - * bits are organized as 4 bits per channel, with scsi0 getting the lowest - * 4 bits in the int. A 1 in a bit position indicates the termination setting - * that corresponds to that bit should be enabled, a 0 is disabled. - * It looks something like this: - * - * 0x0f = 1111-Single Ended Low Byte Termination on/off - * ||\-Single Ended High Byte Termination on/off - * |\-LVD Low Byte Termination on/off - * \-LVD High Byte Termination on/off - * - * For non-Ultra2 controllers, the upper 2 bits are not important. So, to - * enable both high byte and low byte termination on scsi0, I would need to - * make sure that the override_term variable was set to 0x03 (bits 0011). - * To make sure that all termination is enabled on an Ultra2 controller at - * scsi2 and only high byte termination on scsi1 and high and low byte - * termination on scsi0, I would set override_term=0xf23 (bits 1111 0010 0011) - * - * For the most part, users should never have to use this, that's why I - * left it fairly cryptic instead of easy to understand. If you need it, - * most likely someone will be telling you what your's needs to be set to. - */ -static int aic7xxx_override_term = -1; -/* - * Certain motherboard chipset controllers tend to screw - * up the polarity of the term enable output pin. Use this variable - * to force the correct polarity for your system. This is a bitfield variable - * similar to the previous one, but this one has one bit per channel instead - * of four. - * 0 = Force the setting to active low. - * 1 = Force setting to active high. - * Most Adaptec cards are active high, several motherboards are active low. - * To force a 2940 card at SCSI 0 to active high and a motherboard 7895 - * controller at scsi1 and scsi2 to active low, and a 2910 card at scsi3 - * to active high, you would need to set stpwlev=0x9 (bits 1001). - * - * People shouldn't need to use this, but if you are experiencing lots of - * SCSI timeout problems, this may help. There is one sure way to test what - * this option needs to be. Using a boot floppy to boot the system, configure - * your system to enable all SCSI termination (in the Adaptec SCSI BIOS) and - * if needed then also pass a value to override_term to make sure that the - * driver is enabling SCSI termination, then set this variable to either 0 - * or 1. When the driver boots, make sure there are *NO* SCSI cables - * connected to your controller. If it finds and inits the controller - * without problem, then the setting you passed to stpwlev was correct. If - * the driver goes into a reset loop and hangs the system, then you need the - * other setting for this variable. If neither setting lets the machine - * boot then you have definite termination problems that may not be fixable. - */ -static int aic7xxx_stpwlev = -1; -/* - * Set this to non-0 in order to force the driver to panic the kernel - * and print out debugging info on a SCSI abort or reset cycle. - */ -static int aic7xxx_panic_on_abort = 0; -/* - * PCI bus parity checking of the Adaptec controllers. This is somewhat - * dubious at best. To my knowledge, this option has never actually - * solved a PCI parity problem, but on certain machines with broken PCI - * chipset configurations, it can generate tons of false error messages. - * It's included in the driver for completeness. - * 0 = Shut off PCI parity check - * -1 = Normal polarity pci parity checking - * 1 = reverse polarity pci parity checking - * - * NOTE: you can't actually pass -1 on the lilo prompt. So, to set this - * variable to -1 you would actually want to simply pass the variable - * name without a number. That will invert the 0 which will result in - * -1. - */ -static int aic7xxx_pci_parity = 0; -/* - * Set this to any non-0 value to cause us to dump the contents of all - * the card's registers in a hex dump format tailored to each model of - * controller. - * - * NOTE: THE CONTROLLER IS LEFT IN AN UNUSABLE STATE BY THIS OPTION. - * YOU CANNOT BOOT UP WITH THIS OPTION, IT IS FOR DEBUGGING PURPOSES - * ONLY - */ -static int aic7xxx_dump_card = 0; -/* - * Set this to a non-0 value to make us dump out the 32 bit instruction - * registers on the card after completing the sequencer download. This - * allows the actual sequencer download to be verified. It is possible - * to use this option and still boot up and run your system. This is - * only intended for debugging purposes. - */ -static int aic7xxx_dump_sequencer = 0; -/* - * Certain newer motherboards have put new PCI based devices into the - * IO spaces that used to typically be occupied by VLB or EISA cards. - * This overlap can cause these newer motherboards to lock up when scanned - * for older EISA and VLB devices. Setting this option to non-0 will - * cause the driver to skip scanning for any VLB or EISA controllers and - * only support the PCI controllers. NOTE: this means that if the kernel - * os compiled with PCI support disabled, then setting this to non-0 - * would result in never finding any devices :) - */ -static int aic7xxx_no_probe = 0; -/* - * On some machines, enabling the external SCB RAM isn't reliable yet. I - * haven't had time to make test patches for things like changing the - * timing mode on that external RAM either. Some of those changes may - * fix the problem. Until then though, we default to external SCB RAM - * off and give a command line option to enable it. - */ -static int aic7xxx_scbram = 0; -/* - * So that we can set how long each device is given as a selection timeout. - * The table of values goes like this: - * 0 - 256ms - * 1 - 128ms - * 2 - 64ms - * 3 - 32ms - * We default to 64ms because it's fast. Some old SCSI-I devices need a - * longer time. The final value has to be left shifted by 3, hence 0x10 - * is the final value. - */ -static int aic7xxx_seltime = 0x10; -/* - * So that insmod can find the variable and make it point to something - */ -#ifdef MODULE -static char * aic7xxx = NULL; -module_param(aic7xxx, charp, 0); -#endif - -#define VERBOSE_NORMAL 0x0000 -#define VERBOSE_NEGOTIATION 0x0001 -#define VERBOSE_SEQINT 0x0002 -#define VERBOSE_SCSIINT 0x0004 -#define VERBOSE_PROBE 0x0008 -#define VERBOSE_PROBE2 0x0010 -#define VERBOSE_NEGOTIATION2 0x0020 -#define VERBOSE_MINOR_ERROR 0x0040 -#define VERBOSE_TRACING 0x0080 -#define VERBOSE_ABORT 0x0f00 -#define VERBOSE_ABORT_MID 0x0100 -#define VERBOSE_ABORT_FIND 0x0200 -#define VERBOSE_ABORT_PROCESS 0x0400 -#define VERBOSE_ABORT_RETURN 0x0800 -#define VERBOSE_RESET 0xf000 -#define VERBOSE_RESET_MID 0x1000 -#define VERBOSE_RESET_FIND 0x2000 -#define VERBOSE_RESET_PROCESS 0x4000 -#define VERBOSE_RESET_RETURN 0x8000 -static int aic7xxx_verbose = VERBOSE_NORMAL | VERBOSE_NEGOTIATION | - VERBOSE_PROBE; /* verbose messages */ - - -/**************************************************************************** - * - * We're going to start putting in function declarations so that order of - * functions is no longer important. As needed, they are added here. - * - ***************************************************************************/ - -static int aic7xxx_release(struct Scsi_Host *host); -static void aic7xxx_set_syncrate(struct aic7xxx_host *p, - struct aic7xxx_syncrate *syncrate, int target, int channel, - unsigned int period, unsigned int offset, unsigned char options, - unsigned int type, struct aic_dev_data *aic_dev); -static void aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel, - int lun, unsigned int width, unsigned int type, - struct aic_dev_data *aic_dev); -static void aic7xxx_panic_abort(struct aic7xxx_host *p, struct scsi_cmnd *cmd); -static void aic7xxx_print_card(struct aic7xxx_host *p); -static void aic7xxx_print_scratch_ram(struct aic7xxx_host *p); -static void aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded); -#ifdef AIC7XXX_VERBOSE_DEBUGGING -static void aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer); -#endif - -/**************************************************************************** - * - * These functions are now used. They happen to be wrapped in useless - * inb/outb port read/writes around the real reads and writes because it - * seems that certain very fast CPUs have a problem dealing with us when - * going at full speed. - * - ***************************************************************************/ - -static unsigned char -aic_inb(struct aic7xxx_host *p, long port) -{ -#ifdef MMAPIO - unsigned char x; - if(p->maddr) - { - x = readb(p->maddr + port); - } - else - { - x = inb(p->base + port); - } - return(x); -#else - return(inb(p->base + port)); -#endif -} - -static void -aic_outb(struct aic7xxx_host *p, unsigned char val, long port) -{ -#ifdef MMAPIO - if(p->maddr) - { - writeb(val, p->maddr + port); - mb(); /* locked operation in order to force CPU ordering */ - readb(p->maddr + HCNTRL); /* dummy read to flush the PCI write */ - } - else - { - outb(val, p->base + port); - mb(); /* locked operation in order to force CPU ordering */ - } -#else - outb(val, p->base + port); - mb(); /* locked operation in order to force CPU ordering */ -#endif -} - -/*+F************************************************************************* - * Function: - * aic7xxx_setup - * - * Description: - * Handle Linux boot parameters. This routine allows for assigning a value - * to a parameter with a ':' between the parameter and the value. - * ie. aic7xxx=unpause:0x0A,extended - *-F*************************************************************************/ -static int -aic7xxx_setup(char *s) -{ - int i, n; - char *p; - char *end; - - static struct { - const char *name; - unsigned int *flag; - } options[] = { - { "extended", &aic7xxx_extended }, - { "no_reset", &aic7xxx_no_reset }, - { "irq_trigger", &aic7xxx_irq_trigger }, - { "verbose", &aic7xxx_verbose }, - { "reverse_scan",&aic7xxx_reverse_scan }, - { "override_term", &aic7xxx_override_term }, - { "stpwlev", &aic7xxx_stpwlev }, - { "no_probe", &aic7xxx_no_probe }, - { "panic_on_abort", &aic7xxx_panic_on_abort }, - { "pci_parity", &aic7xxx_pci_parity }, - { "dump_card", &aic7xxx_dump_card }, - { "dump_sequencer", &aic7xxx_dump_sequencer }, - { "default_queue_depth", &aic7xxx_default_queue_depth }, - { "scbram", &aic7xxx_scbram }, - { "seltime", &aic7xxx_seltime }, - { "tag_info", NULL } - }; - - end = strchr(s, '\0'); - - while ((p = strsep(&s, ",.")) != NULL) - { - for (i = 0; i < ARRAY_SIZE(options); i++) - { - n = strlen(options[i].name); - if (!strncmp(options[i].name, p, n)) - { - if (!strncmp(p, "tag_info", n)) - { - if (p[n] == ':') - { - char *base; - char *tok, *tok_end, *tok_end2; - char tok_list[] = { '.', ',', '{', '}', '\0' }; - int i, instance = -1, device = -1; - unsigned char done = FALSE; - - base = p; - tok = base + n + 1; /* Forward us just past the ':' */ - tok_end = strchr(tok, '\0'); - if (tok_end < end) - *tok_end = ','; - while(!done) - { - switch(*tok) - { - case '{': - if (instance == -1) - instance = 0; - else if (device == -1) - device = 0; - tok++; - break; - case '}': - if (device != -1) - device = -1; - else if (instance != -1) - instance = -1; - tok++; - break; - case ',': - case '.': - if (instance == -1) - done = TRUE; - else if (device >= 0) - device++; - else if (instance >= 0) - instance++; - if ( (device >= MAX_TARGETS) || - (instance >= ARRAY_SIZE(aic7xxx_tag_info)) ) - done = TRUE; - tok++; - if (!done) - { - base = tok; - } - break; - case '\0': - done = TRUE; - break; - default: - done = TRUE; - tok_end = strchr(tok, '\0'); - for(i=0; tok_list[i]; i++) - { - tok_end2 = strchr(tok, tok_list[i]); - if ( (tok_end2) && (tok_end2 < tok_end) ) - { - tok_end = tok_end2; - done = FALSE; - } - } - if ( (instance >= 0) && (device >= 0) && - (instance < ARRAY_SIZE(aic7xxx_tag_info)) && - (device < MAX_TARGETS) ) - aic7xxx_tag_info[instance].tag_commands[device] = - simple_strtoul(tok, NULL, 0) & 0xff; - tok = tok_end; - break; - } - } - while((p != base) && (p != NULL)) - p = strsep(&s, ",."); - } - } - else if (p[n] == ':') - { - *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); - if(!strncmp(p, "seltime", n)) - { - *(options[i].flag) = (*(options[i].flag) % 4) << 3; - } - } - else if (!strncmp(p, "verbose", n)) - { - *(options[i].flag) = 0xff29; - } - else - { - *(options[i].flag) = ~(*(options[i].flag)); - if(!strncmp(p, "seltime", n)) - { - *(options[i].flag) = (*(options[i].flag) % 4) << 3; - } - } - } - } - } - return 1; -} - -__setup("aic7xxx=", aic7xxx_setup); - -/*+F************************************************************************* - * Function: - * pause_sequencer - * - * Description: - * Pause the sequencer and wait for it to actually stop - this - * is important since the sequencer can disable pausing for critical - * sections. - *-F*************************************************************************/ -static void -pause_sequencer(struct aic7xxx_host *p) -{ - aic_outb(p, p->pause, HCNTRL); - while ((aic_inb(p, HCNTRL) & PAUSE) == 0) - { - ; - } - if(p->features & AHC_ULTRA2) - { - aic_inb(p, CCSCBCTL); - } -} - -/*+F************************************************************************* - * Function: - * unpause_sequencer - * - * Description: - * Unpause the sequencer. Unremarkable, yet done often enough to - * warrant an easy way to do it. - *-F*************************************************************************/ -static void -unpause_sequencer(struct aic7xxx_host *p, int unpause_always) -{ - if (unpause_always || - ( !(aic_inb(p, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) && - !(p->flags & AHC_HANDLING_REQINITS) ) ) - { - aic_outb(p, p->unpause, HCNTRL); - } -} - -/*+F************************************************************************* - * Function: - * restart_sequencer - * - * Description: - * Restart the sequencer program from address zero. This assumes - * that the sequencer is already paused. - *-F*************************************************************************/ -static void -restart_sequencer(struct aic7xxx_host *p) -{ - aic_outb(p, 0, SEQADDR0); - aic_outb(p, 0, SEQADDR1); - aic_outb(p, FASTMODE, SEQCTL); -} - -/* - * We include the aic7xxx_seq.c file here so that the other defines have - * already been made, and so that it comes before the code that actually - * downloads the instructions (since we don't typically use function - * prototype, our code has to be ordered that way, it's a left-over from - * the original driver days.....I should fix it some time DL). - */ -#include "aic7xxx_old/aic7xxx_seq.c" - -/*+F************************************************************************* - * Function: - * aic7xxx_check_patch - * - * Description: - * See if the next patch to download should be downloaded. - *-F*************************************************************************/ -static int -aic7xxx_check_patch(struct aic7xxx_host *p, - struct sequencer_patch **start_patch, int start_instr, int *skip_addr) -{ - struct sequencer_patch *cur_patch; - struct sequencer_patch *last_patch; - int num_patches; - - num_patches = ARRAY_SIZE(sequencer_patches); - last_patch = &sequencer_patches[num_patches]; - cur_patch = *start_patch; - - while ((cur_patch < last_patch) && (start_instr == cur_patch->begin)) - { - if (cur_patch->patch_func(p) == 0) - { - /* - * Start rejecting code. - */ - *skip_addr = start_instr + cur_patch->skip_instr; - cur_patch += cur_patch->skip_patch; - } - else - { - /* - * Found an OK patch. Advance the patch pointer to the next patch - * and wait for our instruction pointer to get here. - */ - cur_patch++; - } - } - - *start_patch = cur_patch; - if (start_instr < *skip_addr) - /* - * Still skipping - */ - return (0); - return(1); -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_download_instr - * - * Description: - * Find the next patch to download. - *-F*************************************************************************/ -static void -aic7xxx_download_instr(struct aic7xxx_host *p, int instrptr, - unsigned char *dconsts) -{ - union ins_formats instr; - struct ins_format1 *fmt1_ins; - struct ins_format3 *fmt3_ins; - unsigned char opcode; - - instr = *(union ins_formats*) &seqprog[instrptr * 4]; - - instr.integer = le32_to_cpu(instr.integer); - - fmt1_ins = &instr.format1; - fmt3_ins = NULL; - - /* Pull the opcode */ - opcode = instr.format1.opcode; - switch (opcode) - { - case AIC_OP_JMP: - case AIC_OP_JC: - case AIC_OP_JNC: - case AIC_OP_CALL: - case AIC_OP_JNE: - case AIC_OP_JNZ: - case AIC_OP_JE: - case AIC_OP_JZ: - { - struct sequencer_patch *cur_patch; - int address_offset; - unsigned int address; - int skip_addr; - int i; - - fmt3_ins = &instr.format3; - address_offset = 0; - address = fmt3_ins->address; - cur_patch = sequencer_patches; - skip_addr = 0; - - for (i = 0; i < address;) - { - aic7xxx_check_patch(p, &cur_patch, i, &skip_addr); - if (skip_addr > i) - { - int end_addr; - - end_addr = min_t(int, address, skip_addr); - address_offset += end_addr - i; - i = skip_addr; - } - else - { - i++; - } - } - address -= address_offset; - fmt3_ins->address = address; - /* Fall Through to the next code section */ - } - case AIC_OP_OR: - case AIC_OP_AND: - case AIC_OP_XOR: - case AIC_OP_ADD: - case AIC_OP_ADC: - case AIC_OP_BMOV: - if (fmt1_ins->parity != 0) - { - fmt1_ins->immediate = dconsts[fmt1_ins->immediate]; - } - fmt1_ins->parity = 0; - /* Fall Through to the next code section */ - case AIC_OP_ROL: - if ((p->features & AHC_ULTRA2) != 0) - { - int i, count; - - /* Calculate odd parity for the instruction */ - for ( i=0, count=0; i < 31; i++) - { - unsigned int mask; - - mask = 0x01 << i; - if ((instr.integer & mask) != 0) - count++; - } - if (!(count & 0x01)) - instr.format1.parity = 1; - } - else - { - if (fmt3_ins != NULL) - { - instr.integer = fmt3_ins->immediate | - (fmt3_ins->source << 8) | - (fmt3_ins->address << 16) | - (fmt3_ins->opcode << 25); - } - else - { - instr.integer = fmt1_ins->immediate | - (fmt1_ins->source << 8) | - (fmt1_ins->destination << 16) | - (fmt1_ins->ret << 24) | - (fmt1_ins->opcode << 25); - } - } - aic_outb(p, (instr.integer & 0xff), SEQRAM); - aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM); - aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM); - aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM); - udelay(10); - break; - - default: - panic("aic7xxx: Unknown opcode encountered in sequencer program."); - break; - } -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_loadseq - * - * Description: - * Load the sequencer code into the controller memory. - *-F*************************************************************************/ -static void -aic7xxx_loadseq(struct aic7xxx_host *p) -{ - struct sequencer_patch *cur_patch; - int i; - int downloaded; - int skip_addr; - unsigned char download_consts[4] = {0, 0, 0, 0}; - - if (aic7xxx_verbose & VERBOSE_PROBE) - { - printk(KERN_INFO "(scsi%d) Downloading sequencer code...", p->host_no); - } -#if 0 - download_consts[TMODE_NUMCMDS] = p->num_targetcmds; -#endif - download_consts[TMODE_NUMCMDS] = 0; - cur_patch = &sequencer_patches[0]; - downloaded = 0; - skip_addr = 0; - - aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|FASTMODE, SEQCTL); - aic_outb(p, 0, SEQADDR0); - aic_outb(p, 0, SEQADDR1); - - for (i = 0; i < sizeof(seqprog) / 4; i++) - { - if (aic7xxx_check_patch(p, &cur_patch, i, &skip_addr) == 0) - { - /* Skip this instruction for this configuration. */ - continue; - } - aic7xxx_download_instr(p, i, &download_consts[0]); - downloaded++; - } - - aic_outb(p, 0, SEQADDR0); - aic_outb(p, 0, SEQADDR1); - aic_outb(p, FASTMODE | FAILDIS, SEQCTL); - unpause_sequencer(p, TRUE); - mdelay(1); - pause_sequencer(p); - aic_outb(p, FASTMODE, SEQCTL); - if (aic7xxx_verbose & VERBOSE_PROBE) - { - printk(" %d instructions downloaded\n", downloaded); - } - if (aic7xxx_dump_sequencer) - aic7xxx_print_sequencer(p, downloaded); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_print_sequencer - * - * Description: - * Print the contents of the sequencer memory to the screen. - *-F*************************************************************************/ -static void -aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded) -{ - int i, k, temp; - - aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|FASTMODE, SEQCTL); - aic_outb(p, 0, SEQADDR0); - aic_outb(p, 0, SEQADDR1); - - k = 0; - for (i=0; i < downloaded; i++) - { - if ( k == 0 ) - printk("%03x: ", i); - temp = aic_inb(p, SEQRAM); - temp |= (aic_inb(p, SEQRAM) << 8); - temp |= (aic_inb(p, SEQRAM) << 16); - temp |= (aic_inb(p, SEQRAM) << 24); - printk("%08x", temp); - if ( ++k == 8 ) - { - printk("\n"); - k = 0; - } - else - printk(" "); - } - aic_outb(p, 0, SEQADDR0); - aic_outb(p, 0, SEQADDR1); - aic_outb(p, FASTMODE | FAILDIS, SEQCTL); - unpause_sequencer(p, TRUE); - mdelay(1); - pause_sequencer(p); - aic_outb(p, FASTMODE, SEQCTL); - printk("\n"); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_info - * - * Description: - * Return a string describing the driver. - *-F*************************************************************************/ -static const char * -aic7xxx_info(struct Scsi_Host *dooh) -{ - static char buffer[256]; - char *bp; - struct aic7xxx_host *p; - - bp = &buffer[0]; - p = (struct aic7xxx_host *)dooh->hostdata; - memset(bp, 0, sizeof(buffer)); - strcpy(bp, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) "); - strcat(bp, AIC7XXX_C_VERSION); - strcat(bp, "/"); - strcat(bp, AIC7XXX_H_VERSION); - strcat(bp, "\n"); - strcat(bp, " <"); - strcat(bp, board_names[p->board_name_index]); - strcat(bp, ">"); - - return(bp); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_find_syncrate - * - * Description: - * Look up the valid period to SCSIRATE conversion in our table - *-F*************************************************************************/ -static struct aic7xxx_syncrate * -aic7xxx_find_syncrate(struct aic7xxx_host *p, unsigned int *period, - unsigned int maxsync, unsigned char *options) -{ - struct aic7xxx_syncrate *syncrate; - int done = FALSE; - - switch(*options) - { - case MSG_EXT_PPR_OPTION_DT_CRC: - case MSG_EXT_PPR_OPTION_DT_UNITS: - if(!(p->features & AHC_ULTRA3)) - { - *options = 0; - maxsync = max_t(unsigned int, maxsync, AHC_SYNCRATE_ULTRA2); - } - break; - case MSG_EXT_PPR_OPTION_DT_CRC_QUICK: - case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK: - if(!(p->features & AHC_ULTRA3)) - { - *options = 0; - maxsync = max_t(unsigned int, maxsync, AHC_SYNCRATE_ULTRA2); - } - else - { - /* - * we don't support the Quick Arbitration variants of dual edge - * clocking. As it turns out, we want to send back the - * same basic option, but without the QA attribute. - * We know that we are responding because we would never set - * these options ourself, we would only respond to them. - */ - switch(*options) - { - case MSG_EXT_PPR_OPTION_DT_CRC_QUICK: - *options = MSG_EXT_PPR_OPTION_DT_CRC; - break; - case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK: - *options = MSG_EXT_PPR_OPTION_DT_UNITS; - break; - } - } - break; - default: - *options = 0; - maxsync = max_t(unsigned int, maxsync, AHC_SYNCRATE_ULTRA2); - break; - } - syncrate = &aic7xxx_syncrates[maxsync]; - while ( (syncrate->rate[0] != NULL) && - (!(p->features & AHC_ULTRA2) || syncrate->sxfr_ultra2) ) - { - if (*period <= syncrate->period) - { - switch(*options) - { - case MSG_EXT_PPR_OPTION_DT_CRC: - case MSG_EXT_PPR_OPTION_DT_UNITS: - if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC)) - { - done = TRUE; - /* - * oops, we went too low for the CRC/DualEdge signalling, so - * clear the options byte - */ - *options = 0; - /* - * We'll be sending a reply to this packet to set the options - * properly, so unilaterally set the period as well. - */ - *period = syncrate->period; - } - else - { - done = TRUE; - if(syncrate == &aic7xxx_syncrates[maxsync]) - { - *period = syncrate->period; - } - } - break; - default: - if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC)) - { - done = TRUE; - if(syncrate == &aic7xxx_syncrates[maxsync]) - { - *period = syncrate->period; - } - } - break; - } - if(done) - { - break; - } - } - syncrate++; - } - if ( (*period == 0) || (syncrate->rate[0] == NULL) || - ((p->features & AHC_ULTRA2) && (syncrate->sxfr_ultra2 == 0)) ) - { - /* - * Use async transfers for this target - */ - *options = 0; - *period = 255; - syncrate = NULL; - } - return (syncrate); -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_find_period - * - * Description: - * Look up the valid SCSIRATE to period conversion in our table - *-F*************************************************************************/ -static unsigned int -aic7xxx_find_period(struct aic7xxx_host *p, unsigned int scsirate, - unsigned int maxsync) -{ - struct aic7xxx_syncrate *syncrate; - - if (p->features & AHC_ULTRA2) - { - scsirate &= SXFR_ULTRA2; - } - else - { - scsirate &= SXFR; - } - - syncrate = &aic7xxx_syncrates[maxsync]; - while (syncrate->rate[0] != NULL) - { - if (p->features & AHC_ULTRA2) - { - if (syncrate->sxfr_ultra2 == 0) - break; - else if (scsirate == syncrate->sxfr_ultra2) - return (syncrate->period); - else if (scsirate == (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC)) - return (syncrate->period); - } - else if (scsirate == (syncrate->sxfr & ~ULTRA_SXFR)) - { - return (syncrate->period); - } - syncrate++; - } - return (0); /* async */ -} - -/*+F************************************************************************* - * Function: - * aic7xxx_validate_offset - * - * Description: - * Set a valid offset value for a particular card in use and transfer - * settings in use. - *-F*************************************************************************/ -static void -aic7xxx_validate_offset(struct aic7xxx_host *p, - struct aic7xxx_syncrate *syncrate, unsigned int *offset, int wide) -{ - unsigned int maxoffset; - - /* Limit offset to what the card (and device) can do */ - if (syncrate == NULL) - { - maxoffset = 0; - } - else if (p->features & AHC_ULTRA2) - { - maxoffset = MAX_OFFSET_ULTRA2; - } - else - { - if (wide) - maxoffset = MAX_OFFSET_16BIT; - else - maxoffset = MAX_OFFSET_8BIT; - } - *offset = min(*offset, maxoffset); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_set_syncrate - * - * Description: - * Set the actual syncrate down in the card and in our host structs - *-F*************************************************************************/ -static void -aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate, - int target, int channel, unsigned int period, unsigned int offset, - unsigned char options, unsigned int type, struct aic_dev_data *aic_dev) -{ - unsigned char tindex; - unsigned short target_mask; - unsigned char lun, old_options; - unsigned int old_period, old_offset; - - tindex = target | (channel << 3); - target_mask = 0x01 << tindex; - lun = aic_inb(p, SCB_TCL) & 0x07; - - if (syncrate == NULL) - { - period = 0; - offset = 0; - } - - old_period = aic_dev->cur.period; - old_offset = aic_dev->cur.offset; - old_options = aic_dev->cur.options; - - - if (type & AHC_TRANS_CUR) - { - unsigned int scsirate; - - scsirate = aic_inb(p, TARG_SCSIRATE + tindex); - if (p->features & AHC_ULTRA2) - { - scsirate &= ~SXFR_ULTRA2; - if (syncrate != NULL) - { - switch(options) - { - case MSG_EXT_PPR_OPTION_DT_UNITS: - /* - * mask off the CRC bit in the xfer settings - */ - scsirate |= (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC); - break; - default: - scsirate |= syncrate->sxfr_ultra2; - break; - } - } - if (type & AHC_TRANS_ACTIVE) - { - aic_outb(p, offset, SCSIOFFSET); - } - aic_outb(p, offset, TARG_OFFSET + tindex); - } - else /* Not an Ultra2 controller */ - { - scsirate &= ~(SXFR|SOFS); - p->ultraenb &= ~target_mask; - if (syncrate != NULL) - { - if (syncrate->sxfr & ULTRA_SXFR) - { - p->ultraenb |= target_mask; - } - scsirate |= (syncrate->sxfr & SXFR); - scsirate |= (offset & SOFS); - } - if (type & AHC_TRANS_ACTIVE) - { - unsigned char sxfrctl0; - - sxfrctl0 = aic_inb(p, SXFRCTL0); - sxfrctl0 &= ~FAST20; - if (p->ultraenb & target_mask) - sxfrctl0 |= FAST20; - aic_outb(p, sxfrctl0, SXFRCTL0); - } - aic_outb(p, p->ultraenb & 0xff, ULTRA_ENB); - aic_outb(p, (p->ultraenb >> 8) & 0xff, ULTRA_ENB + 1 ); - } - if (type & AHC_TRANS_ACTIVE) - { - aic_outb(p, scsirate, SCSIRATE); - } - aic_outb(p, scsirate, TARG_SCSIRATE + tindex); - aic_dev->cur.period = period; - aic_dev->cur.offset = offset; - aic_dev->cur.options = options; - if ( !(type & AHC_TRANS_QUITE) && - (aic7xxx_verbose & VERBOSE_NEGOTIATION) && - (aic_dev->flags & DEVICE_PRINT_DTR) ) - { - if (offset) - { - int rate_mod = (scsirate & WIDEXFER) ? 1 : 0; - - printk(INFO_LEAD "Synchronous at %s Mbyte/sec, " - "offset %d.\n", p->host_no, channel, target, lun, - syncrate->rate[rate_mod], offset); - } - else - { - printk(INFO_LEAD "Using asynchronous transfers.\n", - p->host_no, channel, target, lun); - } - aic_dev->flags &= ~DEVICE_PRINT_DTR; - } - } - - if (type & AHC_TRANS_GOAL) - { - aic_dev->goal.period = period; - aic_dev->goal.offset = offset; - aic_dev->goal.options = options; - } - - if (type & AHC_TRANS_USER) - { - p->user[tindex].period = period; - p->user[tindex].offset = offset; - p->user[tindex].options = options; - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_set_width - * - * Description: - * Set the actual width down in the card and in our host structs - *-F*************************************************************************/ -static void -aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel, int lun, - unsigned int width, unsigned int type, struct aic_dev_data *aic_dev) -{ - unsigned char tindex; - unsigned short target_mask; - unsigned int old_width; - - tindex = target | (channel << 3); - target_mask = 1 << tindex; - - old_width = aic_dev->cur.width; - - if (type & AHC_TRANS_CUR) - { - unsigned char scsirate; - - scsirate = aic_inb(p, TARG_SCSIRATE + tindex); - - scsirate &= ~WIDEXFER; - if (width == MSG_EXT_WDTR_BUS_16_BIT) - scsirate |= WIDEXFER; - - aic_outb(p, scsirate, TARG_SCSIRATE + tindex); - - if (type & AHC_TRANS_ACTIVE) - aic_outb(p, scsirate, SCSIRATE); - - aic_dev->cur.width = width; - - if ( !(type & AHC_TRANS_QUITE) && - (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - (aic_dev->flags & DEVICE_PRINT_DTR) ) - { - printk(INFO_LEAD "Using %s transfers\n", p->host_no, channel, target, - lun, (scsirate & WIDEXFER) ? "Wide(16bit)" : "Narrow(8bit)" ); - } - } - - if (type & AHC_TRANS_GOAL) - aic_dev->goal.width = width; - if (type & AHC_TRANS_USER) - p->user[tindex].width = width; - - if (aic_dev->goal.offset) - { - if (p->features & AHC_ULTRA2) - { - aic_dev->goal.offset = MAX_OFFSET_ULTRA2; - } - else if (width == MSG_EXT_WDTR_BUS_16_BIT) - { - aic_dev->goal.offset = MAX_OFFSET_16BIT; - } - else - { - aic_dev->goal.offset = MAX_OFFSET_8BIT; - } - } -} - -/*+F************************************************************************* - * Function: - * scbq_init - * - * Description: - * SCB queue initialization. - * - *-F*************************************************************************/ -static void -scbq_init(volatile scb_queue_type *queue) -{ - queue->head = NULL; - queue->tail = NULL; -} - -/*+F************************************************************************* - * Function: - * scbq_insert_head - * - * Description: - * Add an SCB to the head of the list. - * - *-F*************************************************************************/ -static inline void -scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) -{ - scb->q_next = queue->head; - queue->head = scb; - if (queue->tail == NULL) /* If list was empty, update tail. */ - queue->tail = queue->head; -} - -/*+F************************************************************************* - * Function: - * scbq_remove_head - * - * Description: - * Remove an SCB from the head of the list. - * - *-F*************************************************************************/ -static inline struct aic7xxx_scb * -scbq_remove_head(volatile scb_queue_type *queue) -{ - struct aic7xxx_scb * scbp; - - scbp = queue->head; - if (queue->head != NULL) - queue->head = queue->head->q_next; - if (queue->head == NULL) /* If list is now empty, update tail. */ - queue->tail = NULL; - return(scbp); -} - -/*+F************************************************************************* - * Function: - * scbq_remove - * - * Description: - * Removes an SCB from the list. - * - *-F*************************************************************************/ -static inline void -scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) -{ - if (queue->head == scb) - { - /* At beginning of queue, remove from head. */ - scbq_remove_head(queue); - } - else - { - struct aic7xxx_scb *curscb = queue->head; - - /* - * Search until the next scb is the one we're looking for, or - * we run out of queue. - */ - while ((curscb != NULL) && (curscb->q_next != scb)) - { - curscb = curscb->q_next; - } - if (curscb != NULL) - { - /* Found it. */ - curscb->q_next = scb->q_next; - if (scb->q_next == NULL) - { - /* Update the tail when removing the tail. */ - queue->tail = curscb; - } - } - } -} - -/*+F************************************************************************* - * Function: - * scbq_insert_tail - * - * Description: - * Add an SCB at the tail of the list. - * - *-F*************************************************************************/ -static inline void -scbq_insert_tail(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) -{ - scb->q_next = NULL; - if (queue->tail != NULL) /* Add the scb at the end of the list. */ - queue->tail->q_next = scb; - queue->tail = scb; /* Update the tail. */ - if (queue->head == NULL) /* If list was empty, update head. */ - queue->head = queue->tail; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_match_scb - * - * Description: - * Checks to see if an scb matches the target/channel as specified. - * If target is ALL_TARGETS (-1), then we're looking for any device - * on the specified channel; this happens when a channel is going - * to be reset and all devices on that channel must be aborted. - *-F*************************************************************************/ -static int -aic7xxx_match_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb, - int target, int channel, int lun, unsigned char tag) -{ - int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F; - int chan = (scb->hscb->target_channel_lun >> 3) & 0x01; - int slun = scb->hscb->target_channel_lun & 0x07; - int match; - - match = ((chan == channel) || (channel == ALL_CHANNELS)); - if (match != 0) - match = ((targ == target) || (target == ALL_TARGETS)); - if (match != 0) - match = ((lun == slun) || (lun == ALL_LUNS)); - if (match != 0) - match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL)); - - return (match); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_add_curscb_to_free_list - * - * Description: - * Adds the current scb (in SCBPTR) to the list of free SCBs. - *-F*************************************************************************/ -static void -aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p) -{ - /* - * Invalidate the tag so that aic7xxx_find_scb doesn't think - * it's active - */ - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic_outb(p, 0, SCB_CONTROL); - - aic_outb(p, aic_inb(p, FREE_SCBH), SCB_NEXT); - aic_outb(p, aic_inb(p, SCBPTR), FREE_SCBH); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_rem_scb_from_disc_list - * - * Description: - * Removes the current SCB from the disconnected list and adds it - * to the free list. - *-F*************************************************************************/ -static unsigned char -aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr, - unsigned char prev) -{ - unsigned char next; - - aic_outb(p, scbptr, SCBPTR); - next = aic_inb(p, SCB_NEXT); - aic7xxx_add_curscb_to_free_list(p); - - if (prev != SCB_LIST_NULL) - { - aic_outb(p, prev, SCBPTR); - aic_outb(p, next, SCB_NEXT); - } - else - { - aic_outb(p, next, DISCONNECTED_SCBH); - } - - return next; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_busy_target - * - * Description: - * Set the specified target busy. - *-F*************************************************************************/ -static inline void -aic7xxx_busy_target(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - p->untagged_scbs[scb->hscb->target_channel_lun] = scb->hscb->tag; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_index_busy_target - * - * Description: - * Returns the index of the busy target, and optionally sets the - * target inactive. - *-F*************************************************************************/ -static inline unsigned char -aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char tcl, - int unbusy) -{ - unsigned char busy_scbid; - - busy_scbid = p->untagged_scbs[tcl]; - if (unbusy) - { - p->untagged_scbs[tcl] = SCB_LIST_NULL; - } - return (busy_scbid); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_find_scb - * - * Description: - * Look through the SCB array of the card and attempt to find the - * hardware SCB that corresponds to the passed in SCB. Return - * SCB_LIST_NULL if unsuccessful. This routine assumes that the - * card is already paused. - *-F*************************************************************************/ -static unsigned char -aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - unsigned char saved_scbptr; - unsigned char curindex; - - saved_scbptr = aic_inb(p, SCBPTR); - curindex = 0; - for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++) - { - aic_outb(p, curindex, SCBPTR); - if (aic_inb(p, SCB_TAG) == scb->hscb->tag) - { - break; - } - } - aic_outb(p, saved_scbptr, SCBPTR); - if (curindex >= p->scb_data->maxhscbs) - { - curindex = SCB_LIST_NULL; - } - - return (curindex); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_allocate_scb - * - * Description: - * Get an SCB from the free list or by allocating a new one. - *-F*************************************************************************/ -static int -aic7xxx_allocate_scb(struct aic7xxx_host *p) -{ - struct aic7xxx_scb *scbp = NULL; - int scb_size = (sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG) + 12 + 6; - int i; - int step = PAGE_SIZE / 1024; - unsigned long scb_count = 0; - struct hw_scatterlist *hsgp; - struct aic7xxx_scb *scb_ap; - struct aic7xxx_scb_dma *scb_dma; - unsigned char *bufs; - - if (p->scb_data->numscbs < p->scb_data->maxscbs) - { - /* - * Calculate the optimal number of SCBs to allocate. - * - * NOTE: This formula works because the sizeof(sg_array) is always - * 1024. Therefore, scb_size * i would always be > PAGE_SIZE * - * (i/step). The (i-1) allows the left hand side of the equation - * to grow into the right hand side to a point of near perfect - * efficiency since scb_size * (i -1) is growing slightly faster - * than the right hand side. If the number of SG array elements - * is changed, this function may not be near so efficient any more. - * - * Since the DMA'able buffers are now allocated in a separate - * chunk this algorithm has been modified to match. The '12' - * and '6' factors in scb_size are for the DMA'able command byte - * and sensebuffers respectively. -DaveM - */ - for ( i=step;; i *= 2 ) - { - if ( (scb_size * (i-1)) >= ( (PAGE_SIZE * (i/step)) - 64 ) ) - { - i /= 2; - break; - } - } - scb_count = min( (i-1), p->scb_data->maxscbs - p->scb_data->numscbs); - scb_ap = kmalloc(sizeof (struct aic7xxx_scb) * scb_count - + sizeof(struct aic7xxx_scb_dma), GFP_ATOMIC); - if (scb_ap == NULL) - return(0); - scb_dma = (struct aic7xxx_scb_dma *)&scb_ap[scb_count]; - hsgp = (struct hw_scatterlist *) - pci_alloc_consistent(p->pdev, scb_size * scb_count, - &scb_dma->dma_address); - if (hsgp == NULL) - { - kfree(scb_ap); - return(0); - } - bufs = (unsigned char *)&hsgp[scb_count * AIC7XXX_MAX_SG]; -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - { - if (p->scb_data->numscbs == 0) - printk(INFO_LEAD "Allocating initial %ld SCB structures.\n", - p->host_no, -1, -1, -1, scb_count); - else - printk(INFO_LEAD "Allocating %ld additional SCB structures.\n", - p->host_no, -1, -1, -1, scb_count); - } -#endif - memset(scb_ap, 0, sizeof (struct aic7xxx_scb) * scb_count); - scb_dma->dma_offset = (unsigned long)scb_dma->dma_address - - (unsigned long)hsgp; - scb_dma->dma_len = scb_size * scb_count; - for (i=0; i < scb_count; i++) - { - scbp = &scb_ap[i]; - scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs]; - scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG]; - scbp->sense_cmd = bufs; - scbp->cmnd = bufs + 6; - bufs += 12 + 6; - scbp->scb_dma = scb_dma; - memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb)); - scbp->hscb->tag = p->scb_data->numscbs; - /* - * Place in the scb array; never is removed - */ - p->scb_data->scb_array[p->scb_data->numscbs++] = scbp; - scbq_insert_tail(&p->scb_data->free_scbs, scbp); - } - scbp->kmalloc_ptr = scb_ap; - } - return(scb_count); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_queue_cmd_complete - * - * Description: - * Due to race conditions present in the SCSI subsystem, it is easier - * to queue completed commands, then call scsi_done() on them when - * we're finished. This function queues the completed commands. - *-F*************************************************************************/ -static void -aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, struct scsi_cmnd *cmd) -{ - aic7xxx_position(cmd) = SCB_LIST_NULL; - cmd->host_scribble = (char *)p->completeq.head; - p->completeq.head = cmd; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_done_cmds_complete - * - * Description: - * Process the completed command queue. - *-F*************************************************************************/ -static void aic7xxx_done_cmds_complete(struct aic7xxx_host *p) -{ - struct scsi_cmnd *cmd; - - while (p->completeq.head != NULL) { - cmd = p->completeq.head; - p->completeq.head = (struct scsi_cmnd *) cmd->host_scribble; - cmd->host_scribble = NULL; - cmd->scsi_done(cmd); - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_free_scb - * - * Description: - * Free the scb and insert into the free scb list. - *-F*************************************************************************/ -static void -aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - - scb->flags = SCB_FREE; - scb->cmd = NULL; - scb->sg_count = 0; - scb->sg_length = 0; - scb->tag_action = 0; - scb->hscb->control = 0; - scb->hscb->target_status = 0; - scb->hscb->target_channel_lun = SCB_LIST_NULL; - - scbq_insert_head(&p->scb_data->free_scbs, scb); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_done - * - * Description: - * Calls the higher level scsi done function and frees the scb. - *-F*************************************************************************/ -static void -aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - struct scsi_cmnd *cmd = scb->cmd; - struct aic_dev_data *aic_dev = cmd->device->hostdata; - int tindex = TARGET_INDEX(cmd); - struct aic7xxx_scb *scbp; - unsigned char queue_depth; - - scsi_dma_unmap(cmd); - - if (scb->flags & SCB_SENSE) - { - pci_unmap_single(p->pdev, - le32_to_cpu(scb->sg_list[0].address), - SCSI_SENSE_BUFFERSIZE, - PCI_DMA_FROMDEVICE); - } - if (scb->flags & SCB_RECOVERY_SCB) - { - p->flags &= ~AHC_ABORT_PENDING; - } - if (scb->flags & (SCB_RESET|SCB_ABORT)) - { - cmd->result |= (DID_RESET << 16); - } - - if ((scb->flags & SCB_MSGOUT_BITS) != 0) - { - unsigned short mask; - int message_error = FALSE; - - mask = 0x01 << tindex; - - /* - * Check to see if we get an invalid message or a message error - * after failing to negotiate a wide or sync transfer message. - */ - if ((scb->flags & SCB_SENSE) && - ((scb->cmd->sense_buffer[12] == 0x43) || /* INVALID_MESSAGE */ - (scb->cmd->sense_buffer[12] == 0x49))) /* MESSAGE_ERROR */ - { - message_error = TRUE; - } - - if (scb->flags & SCB_MSGOUT_WDTR) - { - if (message_error) - { - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - (aic_dev->flags & DEVICE_PRINT_DTR) ) - { - printk(INFO_LEAD "Device failed to complete Wide Negotiation " - "processing and\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "returned a sense error code for invalid message, " - "disabling future\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no, - CTL_OF_SCB(scb)); - } - aic_dev->needwdtr = aic_dev->needwdtr_copy = 0; - } - } - if (scb->flags & SCB_MSGOUT_SDTR) - { - if (message_error) - { - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - (aic_dev->flags & DEVICE_PRINT_DTR) ) - { - printk(INFO_LEAD "Device failed to complete Sync Negotiation " - "processing and\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "returned a sense error code for invalid message, " - "disabling future\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no, - CTL_OF_SCB(scb)); - aic_dev->flags &= ~DEVICE_PRINT_DTR; - } - aic_dev->needsdtr = aic_dev->needsdtr_copy = 0; - } - } - if (scb->flags & SCB_MSGOUT_PPR) - { - if(message_error) - { - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - (aic_dev->flags & DEVICE_PRINT_DTR) ) - { - printk(INFO_LEAD "Device failed to complete Parallel Protocol " - "Request processing and\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "returned a sense error code for invalid message, " - "disabling future\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "Parallel Protocol Request negotiation to this " - "device.\n", p->host_no, CTL_OF_SCB(scb)); - } - /* - * Disable PPR negotiation and revert back to WDTR and SDTR setup - */ - aic_dev->needppr = aic_dev->needppr_copy = 0; - aic_dev->needsdtr = aic_dev->needsdtr_copy = 1; - aic_dev->needwdtr = aic_dev->needwdtr_copy = 1; - } - } - } - - queue_depth = aic_dev->temp_q_depth; - if (queue_depth >= aic_dev->active_cmds) - { - scbp = scbq_remove_head(&aic_dev->delayed_scbs); - if (scbp) - { - if (queue_depth == 1) - { - /* - * Give extra preference to untagged devices, such as CD-R devices - * This makes it more likely that a drive *won't* stuff up while - * waiting on data at a critical time, such as CD-R writing and - * audio CD ripping operations. Should also benefit tape drives. - */ - scbq_insert_head(&p->waiting_scbs, scbp); - } - else - { - scbq_insert_tail(&p->waiting_scbs, scbp); - } -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "Moving SCB from delayed to waiting queue.\n", - p->host_no, CTL_OF_SCB(scbp)); -#endif - if (queue_depth > aic_dev->active_cmds) - { - scbp = scbq_remove_head(&aic_dev->delayed_scbs); - if (scbp) - scbq_insert_tail(&p->waiting_scbs, scbp); - } - } - } - if (!(scb->tag_action)) - { - aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, - /* unbusy */ TRUE); - if (cmd->device->simple_tags) - { - aic_dev->temp_q_depth = aic_dev->max_q_depth; - } - } - if(scb->flags & SCB_DTR_SCB) - { - aic_dev->dtr_pending = 0; - } - aic_dev->active_cmds--; - p->activescbs--; - - if ((scb->sg_length >= 512) && (((cmd->result >> 16) & 0xf) == DID_OK)) - { - long *ptr; - int x, i; - - - if (rq_data_dir(cmd->request) == WRITE) - { - aic_dev->w_total++; - ptr = aic_dev->w_bins; - } - else - { - aic_dev->r_total++; - ptr = aic_dev->r_bins; - } - x = scb->sg_length; - x >>= 10; - for(i=0; i<6; i++) - { - x >>= 2; - if(!x) { - ptr[i]++; - break; - } - } - if(i == 6 && x) - ptr[5]++; - } - aic7xxx_free_scb(p, scb); - aic7xxx_queue_cmd_complete(p, cmd); - -} - -/*+F************************************************************************* - * Function: - * aic7xxx_run_done_queue - * - * Description: - * Calls the aic7xxx_done() for the scsi_cmnd of each scb in the - * aborted list, and adds each scb to the free list. If complete - * is TRUE, we also process the commands complete list. - *-F*************************************************************************/ -static void -aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete) -{ - struct aic7xxx_scb *scb; - int i, found = 0; - - for (i = 0; i < p->scb_data->numscbs; i++) - { - scb = p->scb_data->scb_array[i]; - if (scb->flags & SCB_QUEUED_FOR_DONE) - { - if (scb->flags & SCB_QUEUE_FULL) - { - scb->cmd->result = QUEUE_FULL << 1; - } - else - { - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Aborting scb %d\n", - p->host_no, CTL_OF_SCB(scb), scb->hscb->tag); - /* - * Clear any residual information since the normal aic7xxx_done() path - * doesn't touch the residuals. - */ - scb->hscb->residual_SG_segment_count = 0; - scb->hscb->residual_data_count[0] = 0; - scb->hscb->residual_data_count[1] = 0; - scb->hscb->residual_data_count[2] = 0; - } - found++; - aic7xxx_done(p, scb); - } - } - if (aic7xxx_verbose & (VERBOSE_ABORT_RETURN | VERBOSE_RESET_RETURN)) - { - printk(INFO_LEAD "%d commands found and queued for " - "completion.\n", p->host_no, -1, -1, -1, found); - } - if (complete) - { - aic7xxx_done_cmds_complete(p); - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_abort_waiting_scb - * - * Description: - * Manipulate the waiting for selection list and return the - * scb that follows the one that we remove. - *-F*************************************************************************/ -static unsigned char -aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb, - unsigned char scbpos, unsigned char prev) -{ - unsigned char curscb, next; - - /* - * Select the SCB we want to abort and pull the next pointer out of it. - */ - curscb = aic_inb(p, SCBPTR); - aic_outb(p, scbpos, SCBPTR); - next = aic_inb(p, SCB_NEXT); - - aic7xxx_add_curscb_to_free_list(p); - - /* - * Update the waiting list - */ - if (prev == SCB_LIST_NULL) - { - /* - * First in the list - */ - aic_outb(p, next, WAITING_SCBH); - } - else - { - /* - * Select the scb that pointed to us and update its next pointer. - */ - aic_outb(p, prev, SCBPTR); - aic_outb(p, next, SCB_NEXT); - } - /* - * Point us back at the original scb position and inform the SCSI - * system that the command has been aborted. - */ - aic_outb(p, curscb, SCBPTR); - return (next); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_search_qinfifo - * - * Description: - * Search the queue-in FIFO for matching SCBs and conditionally - * requeue. Returns the number of matching SCBs. - *-F*************************************************************************/ -static int -aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, int channel, - int lun, unsigned char tag, int flags, int requeue, - volatile scb_queue_type *queue) -{ - int found; - unsigned char qinpos, qintail; - struct aic7xxx_scb *scbp; - - found = 0; - qinpos = aic_inb(p, QINPOS); - qintail = p->qinfifonext; - - p->qinfifonext = qinpos; - - while (qinpos != qintail) - { - scbp = p->scb_data->scb_array[p->qinfifo[qinpos++]]; - if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) - { - /* - * We found an scb that needs to be removed. - */ - if (requeue && (queue != NULL)) - { - if (scbp->flags & SCB_WAITINGQ) - { - scbq_remove(queue, scbp); - scbq_remove(&p->waiting_scbs, scbp); - scbq_remove(&AIC_DEV(scbp->cmd)->delayed_scbs, scbp); - AIC_DEV(scbp->cmd)->active_cmds++; - p->activescbs++; - } - scbq_insert_tail(queue, scbp); - AIC_DEV(scbp->cmd)->active_cmds--; - p->activescbs--; - scbp->flags |= SCB_WAITINGQ; - if ( !(scbp->tag_action & TAG_ENB) ) - { - aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun, - TRUE); - } - } - else if (requeue) - { - p->qinfifo[p->qinfifonext++] = scbp->hscb->tag; - } - else - { - /* - * Preserve any SCB_RECOVERY_SCB flags on this scb then set the - * flags we were called with, presumeably so aic7xxx_run_done_queue - * can find this scb - */ - scbp->flags = flags | (scbp->flags & SCB_RECOVERY_SCB); - if (aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun, - FALSE) == scbp->hscb->tag) - { - aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun, - TRUE); - } - } - found++; - } - else - { - p->qinfifo[p->qinfifonext++] = scbp->hscb->tag; - } - } - /* - * Now that we've done the work, clear out any left over commands in the - * qinfifo and update the KERNEL_QINPOS down on the card. - * - * NOTE: This routine expect the sequencer to already be paused when - * it is run....make sure it's that way! - */ - qinpos = p->qinfifonext; - while(qinpos != qintail) - { - p->qinfifo[qinpos++] = SCB_LIST_NULL; - } - if (p->features & AHC_QUEUE_REGS) - aic_outb(p, p->qinfifonext, HNSCB_QOFF); - else - aic_outb(p, p->qinfifonext, KERNEL_QINPOS); - - return (found); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_scb_on_qoutfifo - * - * Description: - * Is the scb that was passed to us currently on the qoutfifo? - *-F*************************************************************************/ -static int -aic7xxx_scb_on_qoutfifo(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - int i=0; - - while(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] != SCB_LIST_NULL) - { - if(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] == scb->hscb->tag) - return TRUE; - else - i++; - } - return FALSE; -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_reset_device - * - * Description: - * The device at the given target/channel has been reset. Abort - * all active and queued scbs for that target/channel. This function - * need not worry about linked next pointers because if was a MSG_ABORT_TAG - * then we had a tagged command (no linked next), if it was MSG_ABORT or - * MSG_BUS_DEV_RESET then the device won't know about any commands any more - * and no busy commands will exist, and if it was a bus reset, then nothing - * knows about any linked next commands any more. In all cases, we don't - * need to worry about the linked next or busy scb, we just need to clear - * them. - *-F*************************************************************************/ -static void -aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel, - int lun, unsigned char tag) -{ - struct aic7xxx_scb *scbp, *prev_scbp; - struct scsi_device *sd; - unsigned char active_scb, tcl, scb_tag; - int i = 0, init_lists = FALSE; - struct aic_dev_data *aic_dev; - - /* - * Restore this when we're done - */ - active_scb = aic_inb(p, SCBPTR); - scb_tag = aic_inb(p, SCB_TAG); - - if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS)) - { - printk(INFO_LEAD "Reset device, hardware_scb %d,\n", - p->host_no, channel, target, lun, active_scb); - printk(INFO_LEAD "Current scb %d, SEQADDR 0x%x, LASTPHASE " - "0x%x\n", - p->host_no, channel, target, lun, scb_tag, - aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), - aic_inb(p, LASTPHASE)); - printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n", - p->host_no, channel, target, lun, - (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0, - aic_inb(p, SG_COUNT), aic_inb(p, SCSISIGI)); - printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n", - p->host_no, channel, target, lun, aic_inb(p, SSTAT0), - aic_inb(p, SSTAT1), aic_inb(p, SSTAT2)); - } - - /* - * Deal with the busy target and linked next issues. - */ - list_for_each_entry(aic_dev, &p->aic_devs, list) - { - if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS)) - printk(INFO_LEAD "processing aic_dev %p\n", p->host_no, channel, target, - lun, aic_dev); - sd = aic_dev->SDptr; - - if((target != ALL_TARGETS && target != sd->id) || - (channel != ALL_CHANNELS && channel != sd->channel)) - continue; - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Cleaning up status information " - "and delayed_scbs.\n", p->host_no, sd->channel, sd->id, sd->lun); - aic_dev->flags &= ~BUS_DEVICE_RESET_PENDING; - if ( tag == SCB_LIST_NULL ) - { - aic_dev->dtr_pending = 0; - aic_dev->needppr = aic_dev->needppr_copy; - aic_dev->needsdtr = aic_dev->needsdtr_copy; - aic_dev->needwdtr = aic_dev->needwdtr_copy; - aic_dev->flags = DEVICE_PRINT_DTR; - aic_dev->temp_q_depth = aic_dev->max_q_depth; - } - tcl = (sd->id << 4) | (sd->channel << 3) | sd->lun; - if ( (aic7xxx_index_busy_target(p, tcl, FALSE) == tag) || - (tag == SCB_LIST_NULL) ) - aic7xxx_index_busy_target(p, tcl, /* unbusy */ TRUE); - prev_scbp = NULL; - scbp = aic_dev->delayed_scbs.head; - while (scbp != NULL) - { - prev_scbp = scbp; - scbp = scbp->q_next; - if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag)) - { - scbq_remove(&aic_dev->delayed_scbs, prev_scbp); - if (prev_scbp->flags & SCB_WAITINGQ) - { - aic_dev->active_cmds++; - p->activescbs++; - } - prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); - prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; - } - } - } - - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Cleaning QINFIFO.\n", p->host_no, channel, target, lun ); - aic7xxx_search_qinfifo(p, target, channel, lun, tag, - SCB_RESET | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE, NULL); - -/* - * Search the waiting_scbs queue for matches, this catches any SCB_QUEUED - * ABORT/RESET commands. - */ - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Cleaning waiting_scbs.\n", p->host_no, channel, - target, lun ); - { - struct aic7xxx_scb *scbp, *prev_scbp; - - prev_scbp = NULL; - scbp = p->waiting_scbs.head; - while (scbp != NULL) - { - prev_scbp = scbp; - scbp = scbp->q_next; - if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag)) - { - scbq_remove(&p->waiting_scbs, prev_scbp); - if (prev_scbp->flags & SCB_WAITINGQ) - { - AIC_DEV(prev_scbp->cmd)->active_cmds++; - p->activescbs++; - } - prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); - prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; - } - } - } - - - /* - * Search waiting for selection list. - */ - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Cleaning waiting for selection " - "list.\n", p->host_no, channel, target, lun); - { - unsigned char next, prev, scb_index; - - next = aic_inb(p, WAITING_SCBH); /* Start at head of list. */ - prev = SCB_LIST_NULL; - while (next != SCB_LIST_NULL) - { - aic_outb(p, next, SCBPTR); - scb_index = aic_inb(p, SCB_TAG); - if (scb_index >= p->scb_data->numscbs) - { - /* - * No aic7xxx_verbose check here.....we want to see this since it - * means either the kernel driver or the sequencer screwed things up - */ - printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, " - "numscbs=%d\n", p->host_no, channel, target, lun, scb_index, - p->scb_data->numscbs); - next = aic_inb(p, SCB_NEXT); - aic7xxx_add_curscb_to_free_list(p); - } - else - { - scbp = p->scb_data->scb_array[scb_index]; - if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) - { - next = aic7xxx_abort_waiting_scb(p, scbp, next, prev); - if (scbp->flags & SCB_WAITINGQ) - { - AIC_DEV(scbp->cmd)->active_cmds++; - p->activescbs++; - } - scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); - scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; - if (prev == SCB_LIST_NULL) - { - /* - * This is either the first scb on the waiting list, or we - * have already yanked the first and haven't left any behind. - * Either way, we need to turn off the selection hardware if - * it isn't already off. - */ - aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); - aic_outb(p, CLRSELTIMEO, CLRSINT1); - } - } - else - { - prev = next; - next = aic_inb(p, SCB_NEXT); - } - } - } - } - - /* - * Go through disconnected list and remove any entries we have queued - * for completion, zeroing their control byte too. - */ - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Cleaning disconnected scbs " - "list.\n", p->host_no, channel, target, lun); - if (p->flags & AHC_PAGESCBS) - { - unsigned char next, prev, scb_index; - - next = aic_inb(p, DISCONNECTED_SCBH); - prev = SCB_LIST_NULL; - while (next != SCB_LIST_NULL) - { - aic_outb(p, next, SCBPTR); - scb_index = aic_inb(p, SCB_TAG); - if (scb_index > p->scb_data->numscbs) - { - printk(WARN_LEAD "Disconnected List inconsistency; SCB index=%d, " - "numscbs=%d\n", p->host_no, channel, target, lun, scb_index, - p->scb_data->numscbs); - next = aic7xxx_rem_scb_from_disc_list(p, next, prev); - } - else - { - scbp = p->scb_data->scb_array[scb_index]; - if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) - { - next = aic7xxx_rem_scb_from_disc_list(p, next, prev); - if (scbp->flags & SCB_WAITINGQ) - { - AIC_DEV(scbp->cmd)->active_cmds++; - p->activescbs++; - } - scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); - scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; - scbp->hscb->control = 0; - } - else - { - prev = next; - next = aic_inb(p, SCB_NEXT); - } - } - } - } - - /* - * Walk the free list making sure no entries on the free list have - * a valid SCB_TAG value or SCB_CONTROL byte. - */ - if (p->flags & AHC_PAGESCBS) - { - unsigned char next; - - next = aic_inb(p, FREE_SCBH); - while (next != SCB_LIST_NULL) - { - aic_outb(p, next, SCBPTR); - if (aic_inb(p, SCB_TAG) < p->scb_data->numscbs) - { - printk(WARN_LEAD "Free list inconsistency!.\n", p->host_no, channel, - target, lun); - init_lists = TRUE; - next = SCB_LIST_NULL; - } - else - { - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic_outb(p, 0, SCB_CONTROL); - next = aic_inb(p, SCB_NEXT); - } - } - } - - /* - * Go through the hardware SCB array looking for commands that - * were active but not on any list. - */ - if (init_lists) - { - aic_outb(p, SCB_LIST_NULL, FREE_SCBH); - aic_outb(p, SCB_LIST_NULL, WAITING_SCBH); - aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH); - } - for (i = p->scb_data->maxhscbs - 1; i >= 0; i--) - { - unsigned char scbid; - - aic_outb(p, i, SCBPTR); - if (init_lists) - { - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic_outb(p, SCB_LIST_NULL, SCB_NEXT); - aic_outb(p, 0, SCB_CONTROL); - aic7xxx_add_curscb_to_free_list(p); - } - else - { - scbid = aic_inb(p, SCB_TAG); - if (scbid < p->scb_data->numscbs) - { - scbp = p->scb_data->scb_array[scbid]; - if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) - { - aic_outb(p, 0, SCB_CONTROL); - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic7xxx_add_curscb_to_free_list(p); - } - } - } - } - - /* - * Go through the entire SCB array now and look for commands for - * for this target that are stillactive. These are other (most likely - * tagged) commands that were disconnected when the reset occurred. - * Any commands we find here we know this about, it wasn't on any queue, - * it wasn't in the qinfifo, it wasn't in the disconnected or waiting - * lists, so it really must have been a paged out SCB. In that case, - * we shouldn't need to bother with updating any counters, just mark - * the correct flags and go on. - */ - for (i = 0; i < p->scb_data->numscbs; i++) - { - scbp = p->scb_data->scb_array[i]; - if ((scbp->flags & SCB_ACTIVE) && - aic7xxx_match_scb(p, scbp, target, channel, lun, tag) && - !aic7xxx_scb_on_qoutfifo(p, scbp)) - { - if (scbp->flags & SCB_WAITINGQ) - { - scbq_remove(&p->waiting_scbs, scbp); - scbq_remove(&AIC_DEV(scbp->cmd)->delayed_scbs, scbp); - AIC_DEV(scbp->cmd)->active_cmds++; - p->activescbs++; - } - scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; - scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); - } - } - - aic_outb(p, active_scb, SCBPTR); -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_clear_intstat - * - * Description: - * Clears the interrupt status. - *-F*************************************************************************/ -static void -aic7xxx_clear_intstat(struct aic7xxx_host *p) -{ - /* Clear any interrupt conditions this may have caused. */ - aic_outb(p, CLRSELDO | CLRSELDI | CLRSELINGO, CLRSINT0); - aic_outb(p, CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR | - CLRPHASECHG | CLRREQINIT, CLRSINT1); - aic_outb(p, CLRSCSIINT | CLRSEQINT | CLRBRKADRINT | CLRPARERR, CLRINT); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_reset_current_bus - * - * Description: - * Reset the current SCSI bus. - *-F*************************************************************************/ -static void -aic7xxx_reset_current_bus(struct aic7xxx_host *p) -{ - - /* Disable reset interrupts. */ - aic_outb(p, aic_inb(p, SIMODE1) & ~ENSCSIRST, SIMODE1); - - /* Turn off the bus' current operations, after all, we shouldn't have any - * valid commands left to cause a RSELI and SELO once we've tossed the - * bus away with this reset, so we might as well shut down the sequencer - * until the bus is restarted as opposed to saving the current settings - * and restoring them (which makes no sense to me). */ - - /* Turn on the bus reset. */ - aic_outb(p, aic_inb(p, SCSISEQ) | SCSIRSTO, SCSISEQ); - while ( (aic_inb(p, SCSISEQ) & SCSIRSTO) == 0) - mdelay(5); - - /* - * Some of the new Ultra2 chipsets need a longer delay after a chip - * reset than just the init setup creates, so we have to delay here - * before we go into a reset in order to make the chips happy. - */ - if (p->features & AHC_ULTRA2) - mdelay(250); - else - mdelay(50); - - /* Turn off the bus reset. */ - aic_outb(p, 0, SCSISEQ); - mdelay(10); - - aic7xxx_clear_intstat(p); - /* Re-enable reset interrupts. */ - aic_outb(p, aic_inb(p, SIMODE1) | ENSCSIRST, SIMODE1); - -} - -/*+F************************************************************************* - * Function: - * aic7xxx_reset_channel - * - * Description: - * Reset the channel. - *-F*************************************************************************/ -static void -aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset) -{ - unsigned long offset_min, offset_max; - unsigned char sblkctl; - int cur_channel; - - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Reset channel called, %s initiate reset.\n", - p->host_no, channel, -1, -1, (initiate_reset==TRUE) ? "will" : "won't" ); - - - if (channel == 1) - { - offset_min = 8; - offset_max = 16; - } - else - { - if (p->features & AHC_TWIN) - { - /* Channel A */ - offset_min = 0; - offset_max = 8; - } - else - { - offset_min = 0; - if (p->features & AHC_WIDE) - { - offset_max = 16; - } - else - { - offset_max = 8; - } - } - } - - while (offset_min < offset_max) - { - /* - * Revert to async/narrow transfers until we renegotiate. - */ - aic_outb(p, 0, TARG_SCSIRATE + offset_min); - if (p->features & AHC_ULTRA2) - { - aic_outb(p, 0, TARG_OFFSET + offset_min); - } - offset_min++; - } - - /* - * Reset the bus and unpause/restart the controller - */ - sblkctl = aic_inb(p, SBLKCTL); - if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) - cur_channel = (sblkctl & SELBUSB) >> 3; - else - cur_channel = 0; - if ( (cur_channel != channel) && (p->features & AHC_TWIN) ) - { - /* - * Case 1: Command for another bus is active - */ - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Stealthily resetting idle channel.\n", p->host_no, - channel, -1, -1); - /* - * Stealthily reset the other bus without upsetting the current bus. - */ - aic_outb(p, sblkctl ^ SELBUSB, SBLKCTL); - aic_outb(p, aic_inb(p, SIMODE1) & ~ENBUSFREE, SIMODE1); - if (initiate_reset) - { - aic7xxx_reset_current_bus(p); - } - aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ); - aic7xxx_clear_intstat(p); - aic_outb(p, sblkctl, SBLKCTL); - } - else - { - /* - * Case 2: A command from this bus is active or we're idle. - */ - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Resetting currently active channel.\n", p->host_no, - channel, -1, -1); - aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT), - SIMODE1); - p->flags &= ~AHC_HANDLING_REQINITS; - p->msg_type = MSG_TYPE_NONE; - p->msg_len = 0; - if (initiate_reset) - { - aic7xxx_reset_current_bus(p); - } - aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ); - aic7xxx_clear_intstat(p); - } - if (aic7xxx_verbose & VERBOSE_RESET_RETURN) - printk(INFO_LEAD "Channel reset\n", p->host_no, channel, -1, -1); - /* - * Clean up all the state information for the pending transactions - * on this bus. - */ - aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL); - - if ( !(p->features & AHC_TWIN) ) - { - restart_sequencer(p); - } - - return; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_run_waiting_queues - * - * Description: - * Scan the awaiting_scbs queue downloading and starting as many - * scbs as we can. - *-F*************************************************************************/ -static void -aic7xxx_run_waiting_queues(struct aic7xxx_host *p) -{ - struct aic7xxx_scb *scb; - struct aic_dev_data *aic_dev; - int sent; - - - if (p->waiting_scbs.head == NULL) - return; - - sent = 0; - - /* - * First handle SCBs that are waiting but have been assigned a slot. - */ - while ((scb = scbq_remove_head(&p->waiting_scbs)) != NULL) - { - aic_dev = scb->cmd->device->hostdata; - if ( !scb->tag_action ) - { - aic_dev->temp_q_depth = 1; - } - if ( aic_dev->active_cmds >= aic_dev->temp_q_depth) - { - scbq_insert_tail(&aic_dev->delayed_scbs, scb); - } - else - { - scb->flags &= ~SCB_WAITINGQ; - aic_dev->active_cmds++; - p->activescbs++; - if ( !(scb->tag_action) ) - { - aic7xxx_busy_target(p, scb); - } - p->qinfifo[p->qinfifonext++] = scb->hscb->tag; - sent++; - } - } - if (sent) - { - if (p->features & AHC_QUEUE_REGS) - aic_outb(p, p->qinfifonext, HNSCB_QOFF); - else - { - pause_sequencer(p); - aic_outb(p, p->qinfifonext, KERNEL_QINPOS); - unpause_sequencer(p, FALSE); - } - if (p->activescbs > p->max_activescbs) - p->max_activescbs = p->activescbs; - } -} - -#ifdef CONFIG_PCI - -#define DPE 0x80 -#define SSE 0x40 -#define RMA 0x20 -#define RTA 0x10 -#define STA 0x08 -#define DPR 0x01 - -/*+F************************************************************************* - * Function: - * aic7xxx_pci_intr - * - * Description: - * Check the scsi card for PCI errors and clear the interrupt - * - * NOTE: If you don't have this function and a 2940 card encounters - * a PCI error condition, the machine will end up locked as the - * interrupt handler gets slammed with non-stop PCI error interrupts - *-F*************************************************************************/ -static void -aic7xxx_pci_intr(struct aic7xxx_host *p) -{ - unsigned char status1; - - pci_read_config_byte(p->pdev, PCI_STATUS + 1, &status1); - - if ( (status1 & DPE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Data Parity Error during PCI address or PCI write" - "phase.\n", p->host_no, -1, -1, -1); - if ( (status1 & SSE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Signal System Error Detected\n", p->host_no, - -1, -1, -1); - if ( (status1 & RMA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Received a PCI Master Abort\n", p->host_no, - -1, -1, -1); - if ( (status1 & RTA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Received a PCI Target Abort\n", p->host_no, - -1, -1, -1); - if ( (status1 & STA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Signaled a PCI Target Abort\n", p->host_no, - -1, -1, -1); - if ( (status1 & DPR) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Data Parity Error has been reported via PCI pin " - "PERR#\n", p->host_no, -1, -1, -1); - - pci_write_config_byte(p->pdev, PCI_STATUS + 1, status1); - if (status1 & (DPR|RMA|RTA)) - aic_outb(p, CLRPARERR, CLRINT); - - if ( (aic7xxx_panic_on_abort) && (p->spurious_int > 500) ) - aic7xxx_panic_abort(p, NULL); - -} -#endif /* CONFIG_PCI */ - -/*+F************************************************************************* - * Function: - * aic7xxx_construct_ppr - * - * Description: - * Build up a Parallel Protocol Request message for use with SCSI-3 - * devices. - *-F*************************************************************************/ -static void -aic7xxx_construct_ppr(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - p->msg_buf[p->msg_index++] = MSG_EXTENDED; - p->msg_buf[p->msg_index++] = MSG_EXT_PPR_LEN; - p->msg_buf[p->msg_index++] = MSG_EXT_PPR; - p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.period; - p->msg_buf[p->msg_index++] = 0; - p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.offset; - p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.width; - p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.options; - p->msg_len += 8; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_construct_sdtr - * - * Description: - * Constucts a synchronous data transfer message in the message - * buffer on the sequencer. - *-F*************************************************************************/ -static void -aic7xxx_construct_sdtr(struct aic7xxx_host *p, unsigned char period, - unsigned char offset) -{ - p->msg_buf[p->msg_index++] = MSG_EXTENDED; - p->msg_buf[p->msg_index++] = MSG_EXT_SDTR_LEN; - p->msg_buf[p->msg_index++] = MSG_EXT_SDTR; - p->msg_buf[p->msg_index++] = period; - p->msg_buf[p->msg_index++] = offset; - p->msg_len += 5; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_construct_wdtr - * - * Description: - * Constucts a wide data transfer message in the message buffer - * on the sequencer. - *-F*************************************************************************/ -static void -aic7xxx_construct_wdtr(struct aic7xxx_host *p, unsigned char bus_width) -{ - p->msg_buf[p->msg_index++] = MSG_EXTENDED; - p->msg_buf[p->msg_index++] = MSG_EXT_WDTR_LEN; - p->msg_buf[p->msg_index++] = MSG_EXT_WDTR; - p->msg_buf[p->msg_index++] = bus_width; - p->msg_len += 4; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_calc_residual - * - * Description: - * Calculate the residual data not yet transferred. - *-F*************************************************************************/ -static void -aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - struct aic7xxx_hwscb *hscb; - struct scsi_cmnd *cmd; - int actual, i; - - cmd = scb->cmd; - hscb = scb->hscb; - - /* - * Don't destroy valid residual information with - * residual coming from a check sense operation. - */ - if (((scb->hscb->control & DISCONNECTED) == 0) && - (scb->flags & SCB_SENSE) == 0) - { - /* - * We had an underflow. At this time, there's only - * one other driver that bothers to check for this, - * and cmd->underflow seems to be set rather half- - * heartedly in the higher-level SCSI code. - */ - actual = scb->sg_length; - for (i=1; i < hscb->residual_SG_segment_count; i++) - { - actual -= scb->sg_list[scb->sg_count - i].length; - } - actual -= (hscb->residual_data_count[2] << 16) | - (hscb->residual_data_count[1] << 8) | - hscb->residual_data_count[0]; - - if (actual < cmd->underflow) - { - if (aic7xxx_verbose & VERBOSE_MINOR_ERROR) - { - printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG " - "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow, - (rq_data_dir(cmd->request) == WRITE) ? "wrote" : "read", actual, - hscb->residual_SG_segment_count); - printk(INFO_LEAD "status 0x%x.\n", p->host_no, CTL_OF_SCB(scb), - hscb->target_status); - } - /* - * In 2.4, only send back the residual information, don't flag this - * as an error. Before 2.4 we had to flag this as an error because - * the mid layer didn't check residual data counts to see if the - * command needs retried. - */ - scsi_set_resid(cmd, scb->sg_length - actual); - aic7xxx_status(cmd) = hscb->target_status; - } - } - - /* - * Clean out the residual information in the SCB for the - * next consumer. - */ - hscb->residual_data_count[2] = 0; - hscb->residual_data_count[1] = 0; - hscb->residual_data_count[0] = 0; - hscb->residual_SG_segment_count = 0; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_handle_device_reset - * - * Description: - * Interrupt handler for sequencer interrupts (SEQINT). - *-F*************************************************************************/ -static void -aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel) -{ - unsigned char tindex = target; - - tindex |= ((channel & 0x01) << 3); - - /* - * Go back to async/narrow transfers and renegotiate. - */ - aic_outb(p, 0, TARG_SCSIRATE + tindex); - if (p->features & AHC_ULTRA2) - aic_outb(p, 0, TARG_OFFSET + tindex); - aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL); - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel, - target, -1); - aic7xxx_run_done_queue(p, /*complete*/ TRUE); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_handle_seqint - * - * Description: - * Interrupt handler for sequencer interrupts (SEQINT). - *-F*************************************************************************/ -static void -aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) -{ - struct aic7xxx_scb *scb; - struct aic_dev_data *aic_dev; - unsigned short target_mask; - unsigned char target, lun, tindex; - unsigned char queue_flag = FALSE; - char channel; - int result; - - target = ((aic_inb(p, SAVED_TCL) >> 4) & 0x0f); - if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) - channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3; - else - channel = 0; - tindex = target + (channel << 3); - lun = aic_inb(p, SAVED_TCL) & 0x07; - target_mask = (0x01 << tindex); - - /* - * Go ahead and clear the SEQINT now, that avoids any interrupt race - * conditions later on in case we enable some other interrupt. - */ - aic_outb(p, CLRSEQINT, CLRINT); - switch (intstat & SEQINT_MASK) - { - case NO_MATCH: - { - aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), - SCSISEQ); - printk(WARN_LEAD "No active SCB for reconnecting target - Issuing " - "BUS DEVICE RESET.\n", p->host_no, channel, target, lun); - printk(WARN_LEAD " SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n", - p->host_no, channel, target, lun, - aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1), - (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0)); - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, NULL); - } - break; - - case SEND_REJECT: - { - if (aic7xxx_verbose & VERBOSE_MINOR_ERROR) - printk(INFO_LEAD "Rejecting unknown message (0x%x) received from " - "target, SEQ_FLAGS=0x%x\n", p->host_no, channel, target, lun, - aic_inb(p, ACCUM), aic_inb(p, SEQ_FLAGS)); - } - break; - - case NO_IDENT: - { - /* - * The reconnecting target either did not send an identify - * message, or did, but we didn't find an SCB to match and - * before it could respond to our ATN/abort, it hit a dataphase. - * The only safe thing to do is to blow it away with a bus - * reset. - */ - if (aic7xxx_verbose & (VERBOSE_SEQINT | VERBOSE_RESET_MID)) - printk(INFO_LEAD "Target did not send an IDENTIFY message; " - "LASTPHASE 0x%x, SAVED_TCL 0x%x\n", p->host_no, channel, target, - lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL)); - - aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE); - aic7xxx_run_done_queue(p, TRUE); - - } - break; - - case BAD_PHASE: - if (aic_inb(p, LASTPHASE) == P_BUSFREE) - { - if (aic7xxx_verbose & VERBOSE_SEQINT) - printk(INFO_LEAD "Missed busfree.\n", p->host_no, channel, - target, lun); - restart_sequencer(p); - } - else - { - if (aic7xxx_verbose & VERBOSE_SEQINT) - printk(INFO_LEAD "Unknown scsi bus phase, continuing\n", p->host_no, - channel, target, lun); - } - break; - - case EXTENDED_MSG: - { - p->msg_type = MSG_TYPE_INITIATOR_MSGIN; - p->msg_len = 0; - p->msg_index = 0; - -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "Enabling REQINITs for MSG_IN\n", p->host_no, - channel, target, lun); -#endif - - /* - * To actually receive the message, simply turn on - * REQINIT interrupts and let our interrupt handler - * do the rest (REQINIT should already be true). - */ - p->flags |= AHC_HANDLING_REQINITS; - aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1); - - /* - * We don't want the sequencer unpaused yet so we return early - */ - return; - } - - case REJECT_MSG: - { - /* - * What we care about here is if we had an outstanding SDTR - * or WDTR message for this target. If we did, this is a - * signal that the target is refusing negotiation. - */ - unsigned char scb_index; - unsigned char last_msg; - - scb_index = aic_inb(p, SCB_TAG); - scb = p->scb_data->scb_array[scb_index]; - aic_dev = AIC_DEV(scb->cmd); - last_msg = aic_inb(p, LAST_MSG); - - if ( (last_msg == MSG_IDENTIFYFLAG) && - (scb->tag_action) && - !(scb->flags & SCB_MSGOUT_BITS) ) - { - if (scb->tag_action == MSG_ORDERED_Q_TAG) - { - /* - * OK...the device seems able to accept tagged commands, but - * not ordered tag commands, only simple tag commands. So, we - * disable ordered tag commands and go on with life just like - * normal. - */ - scsi_adjust_queue_depth(scb->cmd->device, MSG_SIMPLE_TAG, - scb->cmd->device->queue_depth); - scb->tag_action = MSG_SIMPLE_Q_TAG; - scb->hscb->control &= ~SCB_TAG_TYPE; - scb->hscb->control |= MSG_SIMPLE_Q_TAG; - aic_outb(p, scb->hscb->control, SCB_CONTROL); - /* - * OK..we set the tag type to simple tag command, now we re-assert - * ATNO and hope this will take us into the identify phase again - * so we can resend the tag type and info to the device. - */ - aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); - } - else if (scb->tag_action == MSG_SIMPLE_Q_TAG) - { - unsigned char i; - struct aic7xxx_scb *scbp; - int old_verbose; - /* - * Hmmmm....the device is flaking out on tagged commands. - */ - scsi_adjust_queue_depth(scb->cmd->device, 0 /* untagged */, - p->host->cmd_per_lun); - aic_dev->max_q_depth = aic_dev->temp_q_depth = 1; - /* - * We set this command up as a bus device reset. However, we have - * to clear the tag type as it's causing us problems. We shouldn't - * have to worry about any other commands being active, since if - * the device is refusing tagged commands, this should be the - * first tagged command sent to the device, however, we do have - * to worry about any other tagged commands that may already be - * in the qinfifo. The easiest way to do this, is to issue a BDR, - * send all the commands back to the mid level code, then let them - * come back and get rebuilt as untagged commands. - */ - scb->tag_action = 0; - scb->hscb->control &= ~(TAG_ENB | SCB_TAG_TYPE); - aic_outb(p, scb->hscb->control, SCB_CONTROL); - - old_verbose = aic7xxx_verbose; - aic7xxx_verbose &= ~(VERBOSE_RESET|VERBOSE_ABORT); - for (i=0; i < p->scb_data->numscbs; i++) - { - scbp = p->scb_data->scb_array[i]; - if ((scbp->flags & SCB_ACTIVE) && (scbp != scb)) - { - if (aic7xxx_match_scb(p, scbp, target, channel, lun, i)) - { - aic7xxx_reset_device(p, target, channel, lun, i); - } - } - } - aic7xxx_run_done_queue(p, TRUE); - aic7xxx_verbose = old_verbose; - /* - * Wait until after the for loop to set the busy index since - * aic7xxx_reset_device will clear the busy index during its - * operation. - */ - aic7xxx_busy_target(p, scb); - printk(INFO_LEAD "Device is refusing tagged commands, using " - "untagged I/O.\n", p->host_no, channel, target, lun); - aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); - } - } - else if (scb->flags & SCB_MSGOUT_PPR) - { - /* - * As per the draft specs, any device capable of supporting any of - * the option values other than 0 are not allowed to reject the - * PPR message. Instead, they must negotiate out what they do - * support instead of rejecting our offering or else they cause - * a parity error during msg_out phase to signal that they don't - * like our settings. - */ - aic_dev->needppr = aic_dev->needppr_copy = 0; - aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT, - (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE), aic_dev); - aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE, - aic_dev); - aic_dev->goal.options = aic_dev->dtr_pending = 0; - scb->flags &= ~SCB_MSGOUT_BITS; - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Device is rejecting PPR messages, falling " - "back.\n", p->host_no, channel, target, lun); - } - if ( aic_dev->goal.width ) - { - aic_dev->needwdtr = aic_dev->needwdtr_copy = 1; - aic_dev->dtr_pending = 1; - scb->flags |= SCB_MSGOUT_WDTR; - } - if ( aic_dev->goal.offset ) - { - aic_dev->needsdtr = aic_dev->needsdtr_copy = 1; - if( !aic_dev->dtr_pending ) - { - aic_dev->dtr_pending = 1; - scb->flags |= SCB_MSGOUT_SDTR; - } - } - if ( aic_dev->dtr_pending ) - { - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); - } - } - else if (scb->flags & SCB_MSGOUT_WDTR) - { - /* - * note 8bit xfers and clear flag - */ - aic_dev->needwdtr = aic_dev->needwdtr_copy = 0; - scb->flags &= ~SCB_MSGOUT_BITS; - aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT, - (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR), aic_dev); - aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE, - aic_dev); - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Device is rejecting WDTR messages, using " - "narrow transfers.\n", p->host_no, channel, target, lun); - } - aic_dev->needsdtr = aic_dev->needsdtr_copy; - } - else if (scb->flags & SCB_MSGOUT_SDTR) - { - /* - * note asynch xfers and clear flag - */ - aic_dev->needsdtr = aic_dev->needsdtr_copy = 0; - scb->flags &= ~SCB_MSGOUT_BITS; - aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, - (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL), aic_dev); - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Device is rejecting SDTR messages, using " - "async transfers.\n", p->host_no, channel, target, lun); - } - } - else if (aic7xxx_verbose & VERBOSE_SEQINT) - { - /* - * Otherwise, we ignore it. - */ - printk(INFO_LEAD "Received MESSAGE_REJECT for unknown cause. " - "Ignoring.\n", p->host_no, channel, target, lun); - } - } - break; - - case BAD_STATUS: - { - unsigned char scb_index; - struct aic7xxx_hwscb *hscb; - struct scsi_cmnd *cmd; - - /* The sequencer will notify us when a command has an error that - * would be of interest to the kernel. This allows us to leave - * the sequencer running in the common case of command completes - * without error. The sequencer will have DMA'd the SCB back - * up to us, so we can reference the drivers SCB array. - * - * Set the default return value to 0 indicating not to send - * sense. The sense code will change this if needed and this - * reduces code duplication. - */ - aic_outb(p, 0, RETURN_1); - scb_index = aic_inb(p, SCB_TAG); - if (scb_index > p->scb_data->numscbs) - { - printk(WARN_LEAD "Invalid SCB during SEQINT 0x%02x, SCB_TAG %d.\n", - p->host_no, channel, target, lun, intstat, scb_index); - break; - } - scb = p->scb_data->scb_array[scb_index]; - hscb = scb->hscb; - - if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) - { - printk(WARN_LEAD "Invalid SCB during SEQINT 0x%x, scb %d, flags 0x%x," - " cmd 0x%lx.\n", p->host_no, channel, target, lun, intstat, - scb_index, scb->flags, (unsigned long) scb->cmd); - } - else - { - cmd = scb->cmd; - aic_dev = AIC_DEV(scb->cmd); - hscb->target_status = aic_inb(p, SCB_TARGET_STATUS); - aic7xxx_status(cmd) = hscb->target_status; - - cmd->result = hscb->target_status; - - switch (status_byte(hscb->target_status)) - { - case GOOD: - if (aic7xxx_verbose & VERBOSE_SEQINT) - printk(INFO_LEAD "Interrupted for status of GOOD???\n", - p->host_no, CTL_OF_SCB(scb)); - break; - - case COMMAND_TERMINATED: - case CHECK_CONDITION: - if ( !(scb->flags & SCB_SENSE) ) - { - /* - * Send a sense command to the requesting target. - * XXX - revisit this and get rid of the memcopys. - */ - memcpy(scb->sense_cmd, &generic_sense[0], - sizeof(generic_sense)); - - scb->sense_cmd[1] = (cmd->device->lun << 5); - scb->sense_cmd[4] = SCSI_SENSE_BUFFERSIZE; - - scb->sg_list[0].length = - cpu_to_le32(SCSI_SENSE_BUFFERSIZE); - scb->sg_list[0].address = - cpu_to_le32(pci_map_single(p->pdev, cmd->sense_buffer, - SCSI_SENSE_BUFFERSIZE, - PCI_DMA_FROMDEVICE)); - - /* - * XXX - We should allow disconnection, but can't as it - * might allow overlapped tagged commands. - */ - /* hscb->control &= DISCENB; */ - hscb->control = 0; - hscb->target_status = 0; - hscb->SG_list_pointer = - cpu_to_le32(SCB_DMA_ADDR(scb, scb->sg_list)); - hscb->SCSI_cmd_pointer = - cpu_to_le32(SCB_DMA_ADDR(scb, scb->sense_cmd)); - hscb->data_count = scb->sg_list[0].length; - hscb->data_pointer = scb->sg_list[0].address; - hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]); - hscb->residual_SG_segment_count = 0; - hscb->residual_data_count[0] = 0; - hscb->residual_data_count[1] = 0; - hscb->residual_data_count[2] = 0; - - scb->sg_count = hscb->SG_segment_count = 1; - scb->sg_length = SCSI_SENSE_BUFFERSIZE; - scb->tag_action = 0; - scb->flags |= SCB_SENSE; - /* - * Ensure the target is busy since this will be an - * an untagged request. - */ -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - if (scb->flags & SCB_MSGOUT_BITS) - printk(INFO_LEAD "Requesting SENSE with %s\n", p->host_no, - CTL_OF_SCB(scb), (scb->flags & SCB_MSGOUT_SDTR) ? - "SDTR" : "WDTR"); - else - printk(INFO_LEAD "Requesting SENSE, no MSG\n", p->host_no, - CTL_OF_SCB(scb)); - } -#endif - aic7xxx_busy_target(p, scb); - aic_outb(p, SEND_SENSE, RETURN_1); - aic7xxx_error(cmd) = DID_OK; - break; - } /* first time sense, no errors */ - printk(INFO_LEAD "CHECK_CONDITION on REQUEST_SENSE, returning " - "an error.\n", p->host_no, CTL_OF_SCB(scb)); - aic7xxx_error(cmd) = DID_ERROR; - scb->flags &= ~SCB_SENSE; - break; - - case QUEUE_FULL: - queue_flag = TRUE; /* Mark that this is a QUEUE_FULL and */ - case BUSY: /* drop through to here */ - { - struct aic7xxx_scb *next_scbp, *prev_scbp; - unsigned char active_hscb, next_hscb, prev_hscb, scb_index; - /* - * We have to look three places for queued commands: - * 1: p->waiting_scbs queue - * 2: QINFIFO - * 3: WAITING_SCBS list on card (for commands that are started - * but haven't yet made it to the device) - * - * Of special note here is that commands on 2 or 3 above will - * have already been marked as active, while commands on 1 will - * not. The aic7xxx_done() function will want to unmark them - * from active, so any commands we pull off of 1 need to - * up the active count. - */ - next_scbp = p->waiting_scbs.head; - while ( next_scbp != NULL ) - { - prev_scbp = next_scbp; - next_scbp = next_scbp->q_next; - if ( aic7xxx_match_scb(p, prev_scbp, target, channel, lun, - SCB_LIST_NULL) ) - { - scbq_remove(&p->waiting_scbs, prev_scbp); - scb->flags = SCB_QUEUED_FOR_DONE | SCB_QUEUE_FULL; - p->activescbs++; - aic_dev->active_cmds++; - } - } - aic7xxx_search_qinfifo(p, target, channel, lun, - SCB_LIST_NULL, SCB_QUEUED_FOR_DONE | SCB_QUEUE_FULL, - FALSE, NULL); - next_scbp = NULL; - active_hscb = aic_inb(p, SCBPTR); - prev_hscb = next_hscb = scb_index = SCB_LIST_NULL; - next_hscb = aic_inb(p, WAITING_SCBH); - while (next_hscb != SCB_LIST_NULL) - { - aic_outb(p, next_hscb, SCBPTR); - scb_index = aic_inb(p, SCB_TAG); - if (scb_index < p->scb_data->numscbs) - { - next_scbp = p->scb_data->scb_array[scb_index]; - if (aic7xxx_match_scb(p, next_scbp, target, channel, lun, - SCB_LIST_NULL) ) - { - next_scbp->flags = SCB_QUEUED_FOR_DONE | SCB_QUEUE_FULL; - next_hscb = aic_inb(p, SCB_NEXT); - aic_outb(p, 0, SCB_CONTROL); - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic7xxx_add_curscb_to_free_list(p); - if (prev_hscb == SCB_LIST_NULL) - { - /* We were first on the list, - * so we kill the selection - * hardware. Let the sequencer - * re-init the hardware itself - */ - aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); - aic_outb(p, CLRSELTIMEO, CLRSINT1); - aic_outb(p, next_hscb, WAITING_SCBH); - } - else - { - aic_outb(p, prev_hscb, SCBPTR); - aic_outb(p, next_hscb, SCB_NEXT); - } - } - else - { - prev_hscb = next_hscb; - next_hscb = aic_inb(p, SCB_NEXT); - } - } /* scb_index >= p->scb_data->numscbs */ - } - aic_outb(p, active_hscb, SCBPTR); - aic7xxx_run_done_queue(p, FALSE); - -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if( (aic7xxx_verbose & VERBOSE_MINOR_ERROR) || - (aic7xxx_verbose > 0xffff) ) - { - if (queue_flag) - printk(INFO_LEAD "Queue full received; queue depth %d, " - "active %d\n", p->host_no, CTL_OF_SCB(scb), - aic_dev->max_q_depth, aic_dev->active_cmds); - else - printk(INFO_LEAD "Target busy\n", p->host_no, CTL_OF_SCB(scb)); - } -#endif - if (queue_flag) - { - int diff; - result = scsi_track_queue_full(cmd->device, - aic_dev->active_cmds); - if ( result < 0 ) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - printk(INFO_LEAD "Tagged Command Queueing disabled.\n", - p->host_no, CTL_OF_SCB(scb)); - diff = aic_dev->max_q_depth - p->host->cmd_per_lun; - aic_dev->temp_q_depth = 1; - aic_dev->max_q_depth = 1; - } - else if ( result > 0 ) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - printk(INFO_LEAD "Queue depth reduced to %d\n", p->host_no, - CTL_OF_SCB(scb), result); - diff = aic_dev->max_q_depth - result; - aic_dev->max_q_depth = result; - /* temp_q_depth could have been dropped to 1 for an untagged - * command that might be coming up */ - if(aic_dev->temp_q_depth > result) - aic_dev->temp_q_depth = result; - } - /* We should free up the no unused SCB entries. But, that's - * a difficult thing to do because we use a direct indexed - * array, so we can't just take any entries and free them, - * we *have* to free the ones at the end of the array, and - * they very well could be in use right now, which means - * in order to do this right, we have to add a delayed - * freeing mechanism tied into the scb_free() code area. - * We'll add that later. - */ - } - break; - } - - default: - if (aic7xxx_verbose & VERBOSE_SEQINT) - printk(INFO_LEAD "Unexpected target status 0x%x.\n", p->host_no, - CTL_OF_SCB(scb), scb->hscb->target_status); - if (!aic7xxx_error(cmd)) - { - aic7xxx_error(cmd) = DID_RETRY_COMMAND; - } - break; - } /* end switch */ - } /* end else of */ - } - break; - - case AWAITING_MSG: - { - unsigned char scb_index, msg_out; - - scb_index = aic_inb(p, SCB_TAG); - msg_out = aic_inb(p, MSG_OUT); - scb = p->scb_data->scb_array[scb_index]; - aic_dev = AIC_DEV(scb->cmd); - p->msg_index = p->msg_len = 0; - /* - * This SCB had a MK_MESSAGE set in its control byte informing - * the sequencer that we wanted to send a special message to - * this target. - */ - - if ( !(scb->flags & SCB_DEVICE_RESET) && - (msg_out == MSG_IDENTIFYFLAG) && - (scb->hscb->control & TAG_ENB) ) - { - p->msg_buf[p->msg_index++] = scb->tag_action; - p->msg_buf[p->msg_index++] = scb->hscb->tag; - p->msg_len += 2; - } - - if (scb->flags & SCB_DEVICE_RESET) - { - p->msg_buf[p->msg_index++] = MSG_BUS_DEV_RESET; - p->msg_len++; - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Bus device reset mailed.\n", - p->host_no, CTL_OF_SCB(scb)); - } - else if (scb->flags & SCB_ABORT) - { - if (scb->tag_action) - { - p->msg_buf[p->msg_index++] = MSG_ABORT_TAG; - } - else - { - p->msg_buf[p->msg_index++] = MSG_ABORT; - } - p->msg_len++; - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "Abort message mailed.\n", p->host_no, - CTL_OF_SCB(scb)); - } - else if (scb->flags & SCB_MSGOUT_PPR) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Sending PPR (%d/%d/%d/%d) message.\n", - p->host_no, CTL_OF_SCB(scb), - aic_dev->goal.period, - aic_dev->goal.offset, - aic_dev->goal.width, - aic_dev->goal.options); - } - aic7xxx_construct_ppr(p, scb); - } - else if (scb->flags & SCB_MSGOUT_WDTR) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Sending WDTR message.\n", p->host_no, - CTL_OF_SCB(scb)); - } - aic7xxx_construct_wdtr(p, aic_dev->goal.width); - } - else if (scb->flags & SCB_MSGOUT_SDTR) - { - unsigned int max_sync, period; - unsigned char options = 0; - /* - * Now that the device is selected, use the bits in SBLKCTL and - * SSTAT2 to determine the max sync rate for this device. - */ - if (p->features & AHC_ULTRA2) - { - if ( (aic_inb(p, SBLKCTL) & ENAB40) && - !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) - { - max_sync = AHC_SYNCRATE_ULTRA2; - } - else - { - max_sync = AHC_SYNCRATE_ULTRA; - } - } - else if (p->features & AHC_ULTRA) - { - max_sync = AHC_SYNCRATE_ULTRA; - } - else - { - max_sync = AHC_SYNCRATE_FAST; - } - period = aic_dev->goal.period; - aic7xxx_find_syncrate(p, &period, max_sync, &options); - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no, - CTL_OF_SCB(scb), period, - aic_dev->goal.offset); - } - aic7xxx_construct_sdtr(p, period, aic_dev->goal.offset); - } - else - { - panic("aic7xxx: AWAITING_MSG for an SCB that does " - "not have a waiting message.\n"); - } - /* - * We've set everything up to send our message, now to actually do - * so we need to enable reqinit interrupts and let the interrupt - * handler do the rest. We don't want to unpause the sequencer yet - * though so we'll return early. We also have to make sure that - * we clear the SEQINT *BEFORE* we set the REQINIT handler active - * or else it's possible on VLB cards to lose the first REQINIT - * interrupt. Edge triggered EISA cards could also lose this - * interrupt, although PCI and level triggered cards should not - * have this problem since they continually interrupt the kernel - * until we take care of the situation. - */ - scb->flags |= SCB_MSGOUT_SENT; - p->msg_index = 0; - p->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - p->flags |= AHC_HANDLING_REQINITS; - aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1); - return; - } - break; - - case DATA_OVERRUN: - { - unsigned char scb_index = aic_inb(p, SCB_TAG); - unsigned char lastphase = aic_inb(p, LASTPHASE); - unsigned int i; - - scb = (p->scb_data->scb_array[scb_index]); - /* - * XXX - What do we really want to do on an overrun? The - * mid-level SCSI code should handle this, but for now, - * we'll just indicate that the command should retried. - * If we retrieved sense info on this target, then the - * base SENSE info should have been saved prior to the - * overrun error. In that case, we return DID_OK and let - * the mid level code pick up on the sense info. Otherwise - * we return DID_ERROR so the command will get retried. - */ - if ( !(scb->flags & SCB_SENSE) ) - { - printk(WARN_LEAD "Data overrun detected in %s phase, tag %d;\n", - p->host_no, CTL_OF_SCB(scb), - (lastphase == P_DATAIN) ? "Data-In" : "Data-Out", scb->hscb->tag); - printk(KERN_WARNING " %s seen Data Phase. Length=%d, NumSGs=%d.\n", - (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't", - scb->sg_length, scb->sg_count); - printk(KERN_WARNING " Raw SCSI Command: 0x"); - for (i = 0; i < scb->hscb->SCSI_cmd_length; i++) - { - printk("%02x ", scb->cmd->cmnd[i]); - } - printk("\n"); - if(aic7xxx_verbose > 0xffff) - { - for (i = 0; i < scb->sg_count; i++) - { - printk(KERN_WARNING " sg[%d] - Addr 0x%x : Length %d\n", - i, - le32_to_cpu(scb->sg_list[i].address), - le32_to_cpu(scb->sg_list[i].length) ); - } - } - aic7xxx_error(scb->cmd) = DID_ERROR; - } - else - printk(INFO_LEAD "Data Overrun during SEND_SENSE operation.\n", - p->host_no, CTL_OF_SCB(scb)); - } - break; - - case WIDE_RESIDUE: - { - unsigned char resid_sgcnt, index; - unsigned char scb_index = aic_inb(p, SCB_TAG); - unsigned int cur_addr, resid_dcnt; - unsigned int native_addr, native_length, sg_addr; - int i; - - if(scb_index > p->scb_data->numscbs) - { - printk(WARN_LEAD "invalid scb_index during WIDE_RESIDUE.\n", - p->host_no, -1, -1, -1); - /* - * XXX: Add error handling here - */ - break; - } - scb = p->scb_data->scb_array[scb_index]; - if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) - { - printk(WARN_LEAD "invalid scb during WIDE_RESIDUE flags:0x%x " - "scb->cmd:0x%lx\n", p->host_no, CTL_OF_SCB(scb), - scb->flags, (unsigned long)scb->cmd); - break; - } - if(aic7xxx_verbose & VERBOSE_MINOR_ERROR) - printk(INFO_LEAD "Got WIDE_RESIDUE message, patching up data " - "pointer.\n", p->host_no, CTL_OF_SCB(scb)); - - /* - * We have a valid scb to use on this WIDE_RESIDUE message, so - * we need to walk the sg list looking for this particular sg - * segment, then see if we happen to be at the very beginning of - * the segment. If we are, then we have to back things up to - * the previous segment. If not, then we simply need to remove - * one byte from this segments address and add one to the byte - * count. - */ - cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) | - (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24); - sg_addr = aic_inb(p, SG_COUNT + 1) | (aic_inb(p, SG_COUNT + 2) << 8) | - (aic_inb(p, SG_COUNT + 3) << 16) | (aic_inb(p, SG_COUNT + 4) << 24); - resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT); - resid_dcnt = aic_inb(p, SCB_RESID_DCNT) | - (aic_inb(p, SCB_RESID_DCNT + 1) << 8) | - (aic_inb(p, SCB_RESID_DCNT + 2) << 16); - index = scb->sg_count - ((resid_sgcnt) ? resid_sgcnt : 1); - native_addr = le32_to_cpu(scb->sg_list[index].address); - native_length = le32_to_cpu(scb->sg_list[index].length); - /* - * If resid_dcnt == native_length, then we just loaded this SG - * segment and we need to back it up one... - */ - if(resid_dcnt == native_length) - { - if(index == 0) - { - /* - * Oops, this isn't right, we can't back up to before the - * beginning. This must be a bogus message, ignore it. - */ - break; - } - resid_dcnt = 1; - resid_sgcnt += 1; - native_addr = le32_to_cpu(scb->sg_list[index - 1].address); - native_length = le32_to_cpu(scb->sg_list[index - 1].length); - cur_addr = native_addr + (native_length - 1); - sg_addr -= sizeof(struct hw_scatterlist); - } - else - { - /* - * resid_dcnt != native_length, so we are in the middle of a SG - * element. Back it up one byte and leave the rest alone. - */ - resid_dcnt += 1; - cur_addr -= 1; - } - - /* - * Output the new addresses and counts to the right places on the - * card. - */ - aic_outb(p, resid_sgcnt, SG_COUNT); - aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT); - aic_outb(p, sg_addr & 0xff, SG_COUNT + 1); - aic_outb(p, (sg_addr >> 8) & 0xff, SG_COUNT + 2); - aic_outb(p, (sg_addr >> 16) & 0xff, SG_COUNT + 3); - aic_outb(p, (sg_addr >> 24) & 0xff, SG_COUNT + 4); - aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); - - /* - * The sequencer actually wants to find the new address - * in the SHADDR register set. On the Ultra2 and later controllers - * this register set is readonly. In order to get the right number - * into the register, you actually have to enter it in HADDR and then - * use the PRELOADEN bit of DFCNTRL to drop it through from the - * HADDR register to the SHADDR register. On non-Ultra2 controllers, - * we simply write it direct. - */ - if(p->features & AHC_ULTRA2) - { - /* - * We might as well be accurate and drop both the resid_dcnt and - * cur_addr into HCNT and HADDR and have both of them drop - * through to the shadow layer together. - */ - aic_outb(p, resid_dcnt & 0xff, HCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); - aic_outb(p, cur_addr & 0xff, HADDR); - aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); - aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); - aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); - aic_outb(p, aic_inb(p, DMAPARAMS) | PRELOADEN, DFCNTRL); - udelay(1); - aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL); - i=0; - while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000)) - { - udelay(1); - } - } - else - { - aic_outb(p, cur_addr & 0xff, SHADDR); - aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1); - aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2); - aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3); - } - } - break; - - case SEQ_SG_FIXUP: - { - unsigned char scb_index, tmp; - int sg_addr, sg_length; - - scb_index = aic_inb(p, SCB_TAG); - - if(scb_index > p->scb_data->numscbs) - { - printk(WARN_LEAD "invalid scb_index during SEQ_SG_FIXUP.\n", - p->host_no, -1, -1, -1); - printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " - "0x%x\n", p->host_no, -1, -1, -1, - aic_inb(p, SCSISIGI), - aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), - aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); - printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", - p->host_no, -1, -1, -1, aic_inb(p, SG_CACHEPTR), - aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 | - aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT)); - /* - * XXX: Add error handling here - */ - break; - } - scb = p->scb_data->scb_array[scb_index]; - if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) - { - printk(WARN_LEAD "invalid scb during SEQ_SG_FIXUP flags:0x%x " - "scb->cmd:0x%p\n", p->host_no, CTL_OF_SCB(scb), - scb->flags, scb->cmd); - printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " - "0x%x\n", p->host_no, CTL_OF_SCB(scb), - aic_inb(p, SCSISIGI), - aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), - aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); - printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", - p->host_no, CTL_OF_SCB(scb), aic_inb(p, SG_CACHEPTR), - aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 | - aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT)); - break; - } - if(aic7xxx_verbose & VERBOSE_MINOR_ERROR) - printk(INFO_LEAD "Fixing up SG address for sequencer.\n", p->host_no, - CTL_OF_SCB(scb)); - /* - * Advance the SG pointer to the next element in the list - */ - tmp = aic_inb(p, SG_NEXT); - tmp += SG_SIZEOF; - aic_outb(p, tmp, SG_NEXT); - if( tmp < SG_SIZEOF ) - aic_outb(p, aic_inb(p, SG_NEXT + 1) + 1, SG_NEXT + 1); - tmp = aic_inb(p, SG_COUNT) - 1; - aic_outb(p, tmp, SG_COUNT); - sg_addr = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].address); - sg_length = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].length); - /* - * Now stuff the element we just advanced past down onto the - * card so it can be stored in the residual area. - */ - aic_outb(p, sg_addr & 0xff, HADDR); - aic_outb(p, (sg_addr >> 8) & 0xff, HADDR + 1); - aic_outb(p, (sg_addr >> 16) & 0xff, HADDR + 2); - aic_outb(p, (sg_addr >> 24) & 0xff, HADDR + 3); - aic_outb(p, sg_length & 0xff, HCNT); - aic_outb(p, (sg_length >> 8) & 0xff, HCNT + 1); - aic_outb(p, (sg_length >> 16) & 0xff, HCNT + 2); - aic_outb(p, (tmp << 2) | ((tmp == 1) ? LAST_SEG : 0), SG_CACHEPTR); - aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL); - while(aic_inb(p, SSTAT0) & SDONE) udelay(1); - while(aic_inb(p, DFCNTRL) & (HDMAEN|SCSIEN)) aic_outb(p, 0, DFCNTRL); - } - break; - -#ifdef AIC7XXX_NOT_YET - case TRACEPOINT2: - { - printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, - channel, target, lun); - } - break; - - /* XXX Fill these in later */ - case MSG_BUFFER_BUSY: - printk("aic7xxx: Message buffer busy.\n"); - break; - case MSGIN_PHASEMIS: - printk("aic7xxx: Message-in phasemis.\n"); - break; -#endif - - default: /* unknown */ - printk(WARN_LEAD "Unknown SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n", - p->host_no, channel, target, lun, intstat, - aic_inb(p, SCSISIGI)); - break; - } - - /* - * Clear the sequencer interrupt and unpause the sequencer. - */ - unpause_sequencer(p, /* unpause always */ TRUE); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_parse_msg - * - * Description: - * Parses incoming messages into actions on behalf of - * aic7xxx_handle_reqinit - *_F*************************************************************************/ -static int -aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - int reject, reply, done; - unsigned char target_scsirate, tindex; - unsigned short target_mask; - unsigned char target, channel, lun; - unsigned char bus_width, new_bus_width; - unsigned char trans_options, new_trans_options; - unsigned int period, new_period, offset, new_offset, maxsync; - struct aic7xxx_syncrate *syncrate; - struct aic_dev_data *aic_dev; - - target = scb->cmd->device->id; - channel = scb->cmd->device->channel; - lun = scb->cmd->device->lun; - reply = reject = done = FALSE; - tindex = TARGET_INDEX(scb->cmd); - aic_dev = AIC_DEV(scb->cmd); - target_scsirate = aic_inb(p, TARG_SCSIRATE + tindex); - target_mask = (0x01 << tindex); - - /* - * Parse as much of the message as is available, - * rejecting it if we don't support it. When - * the entire message is available and has been - * handled, return TRUE indicating that we have - * parsed an entire message. - */ - - if (p->msg_buf[0] != MSG_EXTENDED) - { - reject = TRUE; - } - - /* - * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when - * using the SDTR messages. We need the PPR messages to enable the - * higher speeds that include things like Dual Edge clocking. - */ - if (p->features & AHC_ULTRA2) - { - if ( (aic_inb(p, SBLKCTL) & ENAB40) && - !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) - { - if (p->features & AHC_ULTRA3) - maxsync = AHC_SYNCRATE_ULTRA3; - else - maxsync = AHC_SYNCRATE_ULTRA2; - } - else - { - maxsync = AHC_SYNCRATE_ULTRA; - } - } - else if (p->features & AHC_ULTRA) - { - maxsync = AHC_SYNCRATE_ULTRA; - } - else - { - maxsync = AHC_SYNCRATE_FAST; - } - - /* - * Just accept the length byte outright and perform - * more checking once we know the message type. - */ - - if ( !reject && (p->msg_len > 2) ) - { - switch(p->msg_buf[2]) - { - case MSG_EXT_SDTR: - { - - if (p->msg_buf[1] != MSG_EXT_SDTR_LEN) - { - reject = TRUE; - break; - } - - if (p->msg_len < (MSG_EXT_SDTR_LEN + 2)) - { - break; - } - - period = new_period = p->msg_buf[3]; - offset = new_offset = p->msg_buf[4]; - trans_options = new_trans_options = 0; - bus_width = new_bus_width = target_scsirate & WIDEXFER; - - /* - * If our current max syncrate is in the Ultra3 range, bump it back - * down to Ultra2 since we can't negotiate DT transfers using SDTR - */ - if(maxsync == AHC_SYNCRATE_ULTRA3) - maxsync = AHC_SYNCRATE_ULTRA2; - - /* - * We might have a device that is starting negotiation with us - * before we can start up negotiation with it....be prepared to - * have a device ask for a higher speed then we want to give it - * in that case - */ - if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != - (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) - { - if (!(aic_dev->flags & DEVICE_DTR_SCANNED)) - { - /* - * We shouldn't get here unless this is a narrow drive, wide - * devices should trigger this same section of code in the WDTR - * handler first instead. - */ - aic_dev->goal.width = MSG_EXT_WDTR_BUS_8_BIT; - aic_dev->goal.options = 0; - if(p->user[tindex].offset) - { - aic_dev->needsdtr_copy = 1; - aic_dev->goal.period = max_t(unsigned char, 10,p->user[tindex].period); - if(p->features & AHC_ULTRA2) - { - aic_dev->goal.offset = MAX_OFFSET_ULTRA2; - } - else - { - aic_dev->goal.offset = MAX_OFFSET_8BIT; - } - } - else - { - aic_dev->needsdtr_copy = 0; - aic_dev->goal.period = 255; - aic_dev->goal.offset = 0; - } - aic_dev->flags |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR; - } - else if (aic_dev->needsdtr_copy == 0) - { - /* - * This is a preemptive message from the target, we've already - * scanned this target and set our options for it, and we - * don't need a SDTR with this target (for whatever reason), - * so reject this incoming SDTR - */ - reject = TRUE; - break; - } - - /* The device is sending this message first and we have to reply */ - reply = TRUE; - - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Received pre-emptive SDTR message from " - "target.\n", p->host_no, CTL_OF_SCB(scb)); - } - /* - * Validate the values the device passed to us against our SEEPROM - * settings. We don't have to do this if we aren't replying since - * the device isn't allowed to send values greater than the ones - * we first sent to it. - */ - new_period = max_t(unsigned int, period, aic_dev->goal.period); - new_offset = min_t(unsigned int, offset, aic_dev->goal.offset); - } - - /* - * Use our new_period, new_offset, bus_width, and card options - * to determine the actual syncrate settings - */ - syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync, - &trans_options); - aic7xxx_validate_offset(p, syncrate, &new_offset, bus_width); - - /* - * Did we drop to async? If so, send a reply regardless of whether - * or not we initiated this negotiation. - */ - if ((new_offset == 0) && (new_offset != offset)) - { - aic_dev->needsdtr_copy = 0; - reply = TRUE; - } - - /* - * Did we start this, if not, or if we went too low and had to - * go async, then send an SDTR back to the target - */ - if(reply) - { - /* when sending a reply, make sure that the goal settings are - * updated along with current and active since the code that - * will actually build the message for the sequencer uses the - * goal settings as its guidelines. - */ - aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, - new_offset, trans_options, - AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR, - aic_dev); - scb->flags &= ~SCB_MSGOUT_BITS; - scb->flags |= SCB_MSGOUT_SDTR; - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); - } - else - { - aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, - new_offset, trans_options, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev); - aic_dev->needsdtr = 0; - } - done = TRUE; - break; - } - case MSG_EXT_WDTR: - { - - if (p->msg_buf[1] != MSG_EXT_WDTR_LEN) - { - reject = TRUE; - break; - } - - if (p->msg_len < (MSG_EXT_WDTR_LEN + 2)) - { - break; - } - - bus_width = new_bus_width = p->msg_buf[3]; - - if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) == - (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) ) - { - switch(bus_width) - { - default: - { - reject = TRUE; - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - ((aic_dev->flags & DEVICE_PRINT_DTR) || - (aic7xxx_verbose > 0xffff)) ) - { - printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n", - p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width)); - } - } /* We fall through on purpose */ - case MSG_EXT_WDTR_BUS_8_BIT: - { - aic_dev->goal.width = MSG_EXT_WDTR_BUS_8_BIT; - aic_dev->needwdtr_copy &= ~target_mask; - break; - } - case MSG_EXT_WDTR_BUS_16_BIT: - { - break; - } - } - aic_dev->needwdtr = 0; - aic7xxx_set_width(p, target, channel, lun, new_bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev); - } - else - { - if ( !(aic_dev->flags & DEVICE_DTR_SCANNED) ) - { - /* - * Well, we now know the WDTR and SYNC caps of this device since - * it contacted us first, mark it as such and copy the user stuff - * over to the goal stuff. - */ - if( (p->features & AHC_WIDE) && p->user[tindex].width ) - { - aic_dev->goal.width = MSG_EXT_WDTR_BUS_16_BIT; - aic_dev->needwdtr_copy = 1; - } - - /* - * Devices that support DT transfers don't start WDTR requests - */ - aic_dev->goal.options = 0; - - if(p->user[tindex].offset) - { - aic_dev->needsdtr_copy = 1; - aic_dev->goal.period = max_t(unsigned char, 10, p->user[tindex].period); - if(p->features & AHC_ULTRA2) - { - aic_dev->goal.offset = MAX_OFFSET_ULTRA2; - } - else if( aic_dev->goal.width ) - { - aic_dev->goal.offset = MAX_OFFSET_16BIT; - } - else - { - aic_dev->goal.offset = MAX_OFFSET_8BIT; - } - } else { - aic_dev->needsdtr_copy = 0; - aic_dev->goal.period = 255; - aic_dev->goal.offset = 0; - } - - aic_dev->flags |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR; - } - else if (aic_dev->needwdtr_copy == 0) - { - /* - * This is a preemptive message from the target, we've already - * scanned this target and set our options for it, and we - * don't need a WDTR with this target (for whatever reason), - * so reject this incoming WDTR - */ - reject = TRUE; - break; - } - - /* The device is sending this message first and we have to reply */ - reply = TRUE; - - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Received pre-emptive WDTR message from " - "target.\n", p->host_no, CTL_OF_SCB(scb)); - } - switch(bus_width) - { - case MSG_EXT_WDTR_BUS_16_BIT: - { - if ( (p->features & AHC_WIDE) && - (aic_dev->goal.width == MSG_EXT_WDTR_BUS_16_BIT) ) - { - new_bus_width = MSG_EXT_WDTR_BUS_16_BIT; - break; - } - } /* Fall through if we aren't a wide card */ - default: - case MSG_EXT_WDTR_BUS_8_BIT: - { - aic_dev->needwdtr_copy = 0; - new_bus_width = MSG_EXT_WDTR_BUS_8_BIT; - break; - } - } - scb->flags &= ~SCB_MSGOUT_BITS; - scb->flags |= SCB_MSGOUT_WDTR; - aic_dev->needwdtr = 0; - if(aic_dev->dtr_pending == 0) - { - /* there is no other command with SCB_DTR_SCB already set that will - * trigger the release of the dtr_pending bit. Both set the bit - * and set scb->flags |= SCB_DTR_SCB - */ - aic_dev->dtr_pending = 1; - scb->flags |= SCB_DTR_SCB; - } - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); - /* when sending a reply, make sure that the goal settings are - * updated along with current and active since the code that - * will actually build the message for the sequencer uses the - * goal settings as its guidelines. - */ - aic7xxx_set_width(p, target, channel, lun, new_bus_width, - AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR, - aic_dev); - } - - /* - * By virtue of the SCSI spec, a WDTR message negates any existing - * SDTR negotiations. So, even if needsdtr isn't marked for this - * device, we still have to do a new SDTR message if the device - * supports SDTR at all. Therefore, we check needsdtr_copy instead - * of needstr. - */ - aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE, - aic_dev); - aic_dev->needsdtr = aic_dev->needsdtr_copy; - done = TRUE; - break; - } - case MSG_EXT_PPR: - { - - if (p->msg_buf[1] != MSG_EXT_PPR_LEN) - { - reject = TRUE; - break; - } - - if (p->msg_len < (MSG_EXT_PPR_LEN + 2)) - { - break; - } - - period = new_period = p->msg_buf[3]; - offset = new_offset = p->msg_buf[5]; - bus_width = new_bus_width = p->msg_buf[6]; - trans_options = new_trans_options = p->msg_buf[7] & 0xf; - - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Parsing PPR message (%d/%d/%d/%d)\n", - p->host_no, CTL_OF_SCB(scb), period, offset, bus_width, - trans_options); - } - - /* - * We might have a device that is starting negotiation with us - * before we can start up negotiation with it....be prepared to - * have a device ask for a higher speed then we want to give it - * in that case - */ - if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) != - (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) ) - { - /* Have we scanned the device yet? */ - if (!(aic_dev->flags & DEVICE_DTR_SCANNED)) - { - /* The device is electing to use PPR messages, so we will too until - * we know better */ - aic_dev->needppr = aic_dev->needppr_copy = 1; - aic_dev->needsdtr = aic_dev->needsdtr_copy = 0; - aic_dev->needwdtr = aic_dev->needwdtr_copy = 0; - - /* We know the device is SCSI-3 compliant due to PPR */ - aic_dev->flags |= DEVICE_SCSI_3; - - /* - * Not only is the device starting this up, but it also hasn't - * been scanned yet, so this would likely be our TUR or our - * INQUIRY command at scan time, so we need to use the - * settings from the SEEPROM if they existed. Of course, even - * if we didn't find a SEEPROM, we stuffed default values into - * the user settings anyway, so use those in all cases. - */ - aic_dev->goal.width = p->user[tindex].width; - if(p->user[tindex].offset) - { - aic_dev->goal.period = p->user[tindex].period; - aic_dev->goal.options = p->user[tindex].options; - if(p->features & AHC_ULTRA2) - { - aic_dev->goal.offset = MAX_OFFSET_ULTRA2; - } - else if( aic_dev->goal.width && - (bus_width == MSG_EXT_WDTR_BUS_16_BIT) && - p->features & AHC_WIDE ) - { - aic_dev->goal.offset = MAX_OFFSET_16BIT; - } - else - { - aic_dev->goal.offset = MAX_OFFSET_8BIT; - } - } - else - { - aic_dev->goal.period = 255; - aic_dev->goal.offset = 0; - aic_dev->goal.options = 0; - } - aic_dev->flags |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR; - } - else if (aic_dev->needppr_copy == 0) - { - /* - * This is a preemptive message from the target, we've already - * scanned this target and set our options for it, and we - * don't need a PPR with this target (for whatever reason), - * so reject this incoming PPR - */ - reject = TRUE; - break; - } - - /* The device is sending this message first and we have to reply */ - reply = TRUE; - - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Received pre-emptive PPR message from " - "target.\n", p->host_no, CTL_OF_SCB(scb)); - } - - } - - switch(bus_width) - { - case MSG_EXT_WDTR_BUS_16_BIT: - { - if ( (aic_dev->goal.width == MSG_EXT_WDTR_BUS_16_BIT) && - p->features & AHC_WIDE) - { - break; - } - } - default: - { - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - ((aic_dev->flags & DEVICE_PRINT_DTR) || - (aic7xxx_verbose > 0xffff)) ) - { - reply = TRUE; - printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n", - p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width)); - } - } /* We fall through on purpose */ - case MSG_EXT_WDTR_BUS_8_BIT: - { - /* - * According to the spec, if we aren't wide, we also can't be - * Dual Edge so clear the options byte - */ - new_trans_options = 0; - new_bus_width = MSG_EXT_WDTR_BUS_8_BIT; - break; - } - } - - if(reply) - { - /* when sending a reply, make sure that the goal settings are - * updated along with current and active since the code that - * will actually build the message for the sequencer uses the - * goal settings as its guidelines. - */ - aic7xxx_set_width(p, target, channel, lun, new_bus_width, - AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR, - aic_dev); - syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync, - &new_trans_options); - aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width); - aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, - new_offset, new_trans_options, - AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR, - aic_dev); - } - else - { - aic7xxx_set_width(p, target, channel, lun, new_bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev); - syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync, - &new_trans_options); - aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width); - aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, - new_offset, new_trans_options, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev); - } - - /* - * As it turns out, if we don't *have* to have PPR messages, then - * configure ourselves not to use them since that makes some - * external drive chassis work (those chassis can't parse PPR - * messages and they mangle the SCSI bus until you send a WDTR - * and SDTR that they can understand). - */ - if(new_trans_options == 0) - { - aic_dev->needppr = aic_dev->needppr_copy = 0; - if(new_offset) - { - aic_dev->needsdtr = aic_dev->needsdtr_copy = 1; - } - if (new_bus_width) - { - aic_dev->needwdtr = aic_dev->needwdtr_copy = 1; - } - } - - if((new_offset == 0) && (offset != 0)) - { - /* - * Oops, the syncrate went to low for this card and we fell off - * to async (should never happen with a device that uses PPR - * messages, but have to be complete) - */ - reply = TRUE; - } - - if(reply) - { - scb->flags &= ~SCB_MSGOUT_BITS; - scb->flags |= SCB_MSGOUT_PPR; - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); - } - else - { - aic_dev->needppr = 0; - } - done = TRUE; - break; - } - default: - { - reject = TRUE; - break; - } - } /* end of switch(p->msg_type) */ - } /* end of if (!reject && (p->msg_len > 2)) */ - - if (!reply && reject) - { - aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); - done = TRUE; - } - return(done); -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_handle_reqinit - * - * Description: - * Interrupt handler for REQINIT interrupts (used to transfer messages to - * and from devices). - *_F*************************************************************************/ -static void -aic7xxx_handle_reqinit(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - unsigned char lastbyte; - unsigned char phasemis; - int done = FALSE; - - switch(p->msg_type) - { - case MSG_TYPE_INITIATOR_MSGOUT: - { - if (p->msg_len == 0) - panic("aic7xxx: REQINIT with no active message!\n"); - - lastbyte = (p->msg_index == (p->msg_len - 1)); - phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK) != P_MESGOUT; - - if (lastbyte || phasemis) - { - /* Time to end the message */ - p->msg_len = 0; - p->msg_type = MSG_TYPE_NONE; - /* - * NOTE-TO-MYSELF: If you clear the REQINIT after you - * disable REQINITs, then cases of REJECT_MSG stop working - * and hang the bus - */ - aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1); - aic_outb(p, CLRSCSIINT, CLRINT); - p->flags &= ~AHC_HANDLING_REQINITS; - - if (phasemis == 0) - { - aic_outb(p, p->msg_buf[p->msg_index], SINDEX); - aic_outb(p, 0, RETURN_1); -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "Completed sending of REQINIT message.\n", - p->host_no, CTL_OF_SCB(scb)); -#endif - } - else - { - aic_outb(p, MSGOUT_PHASEMIS, RETURN_1); -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "PHASEMIS while sending REQINIT message.\n", - p->host_no, CTL_OF_SCB(scb)); -#endif - } - unpause_sequencer(p, TRUE); - } - else - { - /* - * Present the byte on the bus (clearing REQINIT) but don't - * unpause the sequencer. - */ - aic_outb(p, CLRREQINIT, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - aic_outb(p, p->msg_buf[p->msg_index++], SCSIDATL); - } - break; - } - case MSG_TYPE_INITIATOR_MSGIN: - { - phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK ) != P_MESGIN; - - if (phasemis == 0) - { - p->msg_len++; - /* Pull the byte in without acking it */ - p->msg_buf[p->msg_index] = aic_inb(p, SCSIBUSL); - done = aic7xxx_parse_msg(p, scb); - /* Ack the byte */ - aic_outb(p, CLRREQINIT, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - aic_inb(p, SCSIDATL); - p->msg_index++; - } - if (phasemis || done) - { -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - { - if (phasemis) - printk(INFO_LEAD "PHASEMIS while receiving REQINIT message.\n", - p->host_no, CTL_OF_SCB(scb)); - else - printk(INFO_LEAD "Completed receipt of REQINIT message.\n", - p->host_no, CTL_OF_SCB(scb)); - } -#endif - /* Time to end our message session */ - p->msg_len = 0; - p->msg_type = MSG_TYPE_NONE; - aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1); - aic_outb(p, CLRSCSIINT, CLRINT); - p->flags &= ~AHC_HANDLING_REQINITS; - unpause_sequencer(p, TRUE); - } - break; - } - default: - { - panic("aic7xxx: Unknown REQINIT message type.\n"); - break; - } - } /* End of switch(p->msg_type) */ -} - -/*+F************************************************************************* - * Function: - * aic7xxx_handle_scsiint - * - * Description: - * Interrupt handler for SCSI interrupts (SCSIINT). - *-F*************************************************************************/ -static void -aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat) -{ - unsigned char scb_index; - unsigned char status; - struct aic7xxx_scb *scb; - struct aic_dev_data *aic_dev; - - scb_index = aic_inb(p, SCB_TAG); - status = aic_inb(p, SSTAT1); - - if (scb_index < p->scb_data->numscbs) - { - scb = p->scb_data->scb_array[scb_index]; - if ((scb->flags & SCB_ACTIVE) == 0) - { - scb = NULL; - } - } - else - { - scb = NULL; - } - - - if ((status & SCSIRSTI) != 0) - { - int channel; - - if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) - channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3; - else - channel = 0; - - if (aic7xxx_verbose & VERBOSE_RESET) - printk(WARN_LEAD "Someone else reset the channel!!\n", - p->host_no, channel, -1, -1); - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, NULL); - /* - * Go through and abort all commands for the channel, but do not - * reset the channel again. - */ - aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE); - aic7xxx_run_done_queue(p, TRUE); - scb = NULL; - } - else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) ) - { - /* - * First look at what phase we were last in. If it's message-out, - * chances are pretty good that the bus free was in response to - * one of our abort requests. - */ - unsigned char lastphase = aic_inb(p, LASTPHASE); - unsigned char saved_tcl = aic_inb(p, SAVED_TCL); - unsigned char target = (saved_tcl >> 4) & 0x0F; - int channel; - int printerror = TRUE; - - if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) - channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3; - else - channel = 0; - - aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), - SCSISEQ); - if (lastphase == P_MESGOUT) - { - unsigned char message; - - message = aic_inb(p, SINDEX); - - if ((message == MSG_ABORT) || (message == MSG_ABORT_TAG)) - { - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "SCB %d abort delivered.\n", p->host_no, - CTL_OF_SCB(scb), scb->hscb->tag); - aic7xxx_reset_device(p, target, channel, ALL_LUNS, - (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag ); - aic7xxx_run_done_queue(p, TRUE); - scb = NULL; - printerror = 0; - } - else if (message == MSG_BUS_DEV_RESET) - { - aic7xxx_handle_device_reset(p, target, channel); - scb = NULL; - printerror = 0; - } - } - if ( (scb != NULL) && (scb->flags & SCB_DTR_SCB) ) - { - /* - * Hmmm...error during a negotiation command. Either we have a - * borken bus, or the device doesn't like our negotiation message. - * Since we check the INQUIRY data of a device before sending it - * negotiation messages, assume the bus is borken for whatever - * reason. Complete the command. - */ - printerror = 0; - aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag); - aic7xxx_run_done_queue(p, TRUE); - scb = NULL; - } - if (printerror != 0) - { - if (scb != NULL) - { - unsigned char tag; - - if ((scb->hscb->control & TAG_ENB) != 0) - { - tag = scb->hscb->tag; - } - else - { - tag = SCB_LIST_NULL; - } - aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag); - aic7xxx_run_done_queue(p, TRUE); - } - else - { - aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL); - aic7xxx_run_done_queue(p, TRUE); - } - printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, " - "SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase, - (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0)); - scb = NULL; - } - aic_outb(p, MSG_NOOP, MSG_OUT); - aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT), - SIMODE1); - p->flags &= ~AHC_HANDLING_REQINITS; - aic_outb(p, CLRBUSFREE, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - restart_sequencer(p); - unpause_sequencer(p, TRUE); - } - else if ((status & SELTO) != 0) - { - unsigned char scbptr; - unsigned char nextscb; - struct scsi_cmnd *cmd; - - scbptr = aic_inb(p, WAITING_SCBH); - if (scbptr > p->scb_data->maxhscbs) - { - /* - * I'm still trying to track down exactly how this happens, but until - * I find it, this code will make sure we aren't passing bogus values - * into the SCBPTR register, even if that register will just wrap - * things around, we still don't like having out of range variables. - * - * NOTE: Don't check the aic7xxx_verbose variable, I want this message - * to always be displayed. - */ - printk(INFO_LEAD "Invalid WAITING_SCBH value %d, improvising.\n", - p->host_no, -1, -1, -1, scbptr); - if (p->scb_data->maxhscbs > 4) - scbptr &= (p->scb_data->maxhscbs - 1); - else - scbptr &= 0x03; - } - aic_outb(p, scbptr, SCBPTR); - scb_index = aic_inb(p, SCB_TAG); - - scb = NULL; - if (scb_index < p->scb_data->numscbs) - { - scb = p->scb_data->scb_array[scb_index]; - if ((scb->flags & SCB_ACTIVE) == 0) - { - scb = NULL; - } - } - if (scb == NULL) - { - printk(WARN_LEAD "Referenced SCB %d not valid during SELTO.\n", - p->host_no, -1, -1, -1, scb_index); - printk(KERN_WARNING " SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x " - "SSTAT1 = 0x%x\n", aic_inb(p, SCSISEQ), - aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), - aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, NULL); - } - else - { - cmd = scb->cmd; - cmd->result = (DID_TIME_OUT << 16); - - /* - * Clear out this hardware SCB - */ - aic_outb(p, 0, SCB_CONTROL); - - /* - * Clear out a few values in the card that are in an undetermined - * state. - */ - aic_outb(p, MSG_NOOP, MSG_OUT); - - /* - * Shift the waiting for selection queue forward - */ - nextscb = aic_inb(p, SCB_NEXT); - aic_outb(p, nextscb, WAITING_SCBH); - - /* - * Put this SCB back on the free list. - */ - aic7xxx_add_curscb_to_free_list(p); -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "Selection Timeout.\n", p->host_no, CTL_OF_SCB(scb)); -#endif - if (scb->flags & SCB_QUEUED_ABORT) - { - /* - * We know that this particular SCB had to be the queued abort since - * the disconnected SCB would have gotten a reconnect instead. - * What we need to do then is to let the command timeout again so - * we get a reset since this abort just failed. - */ - cmd->result = 0; - scb = NULL; - } - } - /* - * Keep the sequencer from trying to restart any selections - */ - aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); - /* - * Make sure the data bits on the bus are released - * Don't do this on 7770 chipsets, it makes them give us - * a BRKADDRINT and kills the card. - */ - if( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI ) - aic_outb(p, 0, SCSIBUSL); - - /* - * Delay for the selection timeout delay period then stop the selection - */ - udelay(301); - aic_outb(p, CLRSELINGO, CLRSINT0); - /* - * Clear out all the interrupt status bits - */ - aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1); - p->flags &= ~AHC_HANDLING_REQINITS; - aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - /* - * Restarting the sequencer will stop the selection and make sure devices - * are allowed to reselect in. - */ - restart_sequencer(p); - unpause_sequencer(p, TRUE); - } - else if (scb == NULL) - { - printk(WARN_LEAD "aic7xxx_isr - referenced scb not valid " - "during scsiint 0x%x scb(%d)\n" - " SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n", - p->host_no, -1, -1, -1, status, scb_index, aic_inb(p, SIMODE0), - aic_inb(p, SIMODE1), aic_inb(p, SSTAT0), - (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0)); - /* - * Turn off the interrupt and set status to zero, so that it - * falls through the rest of the SCSIINT code. - */ - aic_outb(p, status, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - unpause_sequencer(p, /* unpause always */ TRUE); - scb = NULL; - } - else if (status & SCSIPERR) - { - /* - * Determine the bus phase and queue an appropriate message. - */ - char *phase; - struct scsi_cmnd *cmd; - unsigned char mesg_out = MSG_NOOP; - unsigned char lastphase = aic_inb(p, LASTPHASE); - unsigned char sstat2 = aic_inb(p, SSTAT2); - - cmd = scb->cmd; - switch (lastphase) - { - case P_DATAOUT: - phase = "Data-Out"; - break; - case P_DATAIN: - phase = "Data-In"; - mesg_out = MSG_INITIATOR_DET_ERR; - break; - case P_COMMAND: - phase = "Command"; - break; - case P_MESGOUT: - phase = "Message-Out"; - break; - case P_STATUS: - phase = "Status"; - mesg_out = MSG_INITIATOR_DET_ERR; - break; - case P_MESGIN: - phase = "Message-In"; - mesg_out = MSG_PARITY_ERROR; - break; - default: - phase = "unknown"; - break; - } - - /* - * A parity error has occurred during a data - * transfer phase. Flag it and continue. - */ - if( (p->features & AHC_ULTRA3) && - (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) && - (lastphase == P_DATAIN) ) - { - printk(WARN_LEAD "CRC error during %s phase.\n", - p->host_no, CTL_OF_SCB(scb), phase); - if(sstat2 & CRCVALERR) - { - printk(WARN_LEAD " CRC error in intermediate CRC packet.\n", - p->host_no, CTL_OF_SCB(scb)); - } - if(sstat2 & CRCENDERR) - { - printk(WARN_LEAD " CRC error in ending CRC packet.\n", - p->host_no, CTL_OF_SCB(scb)); - } - if(sstat2 & CRCREQERR) - { - printk(WARN_LEAD " Target incorrectly requested a CRC packet.\n", - p->host_no, CTL_OF_SCB(scb)); - } - if(sstat2 & DUAL_EDGE_ERROR) - { - printk(WARN_LEAD " Dual Edge transmission error.\n", - p->host_no, CTL_OF_SCB(scb)); - } - } - else if( (lastphase == P_MESGOUT) && - (scb->flags & SCB_MSGOUT_PPR) ) - { - /* - * As per the draft specs, any device capable of supporting any of - * the option values other than 0 are not allowed to reject the - * PPR message. Instead, they must negotiate out what they do - * support instead of rejecting our offering or else they cause - * a parity error during msg_out phase to signal that they don't - * like our settings. - */ - aic_dev = AIC_DEV(scb->cmd); - aic_dev->needppr = aic_dev->needppr_copy = 0; - aic7xxx_set_width(p, scb->cmd->device->id, scb->cmd->device->channel, scb->cmd->device->lun, - MSG_EXT_WDTR_BUS_8_BIT, - (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE), - aic_dev); - aic7xxx_set_syncrate(p, NULL, scb->cmd->device->id, scb->cmd->device->channel, 0, 0, - 0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE, - aic_dev); - aic_dev->goal.options = 0; - scb->flags &= ~SCB_MSGOUT_BITS; - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "parity error during PPR message, reverting " - "to WDTR/SDTR\n", p->host_no, CTL_OF_SCB(scb)); - } - if ( aic_dev->goal.width ) - { - aic_dev->needwdtr = aic_dev->needwdtr_copy = 1; - } - if ( aic_dev->goal.offset ) - { - if( aic_dev->goal.period <= 9 ) - { - aic_dev->goal.period = 10; - } - aic_dev->needsdtr = aic_dev->needsdtr_copy = 1; - } - scb = NULL; - } - - /* - * We've set the hardware to assert ATN if we get a parity - * error on "in" phases, so all we need to do is stuff the - * message buffer with the appropriate message. "In" phases - * have set mesg_out to something other than MSG_NOP. - */ - if (mesg_out != MSG_NOOP) - { - aic_outb(p, mesg_out, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); - scb = NULL; - } - aic_outb(p, CLRSCSIPERR, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - unpause_sequencer(p, /* unpause_always */ TRUE); - } - else if ( (status & REQINIT) && - (p->flags & AHC_HANDLING_REQINITS) ) - { -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "Handling REQINIT, SSTAT1=0x%x.\n", p->host_no, - CTL_OF_SCB(scb), aic_inb(p, SSTAT1)); -#endif - aic7xxx_handle_reqinit(p, scb); - return; - } - else - { - /* - * We don't know what's going on. Turn off the - * interrupt source and try to continue. - */ - if (aic7xxx_verbose & VERBOSE_SCSIINT) - printk(INFO_LEAD "Unknown SCSIINT status, SSTAT1(0x%x).\n", - p->host_no, -1, -1, -1, status); - aic_outb(p, status, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - unpause_sequencer(p, /* unpause always */ TRUE); - scb = NULL; - } - if (scb != NULL) - { - aic7xxx_done(p, scb); - } -} - -#ifdef AIC7XXX_VERBOSE_DEBUGGING -static void -aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer) -{ - unsigned char saved_scbptr, free_scbh, dis_scbh, wait_scbh, temp; - int i, bogus, lost; - static unsigned char scb_status[AIC7XXX_MAXSCB]; - -#define SCB_NO_LIST 0 -#define SCB_FREE_LIST 1 -#define SCB_WAITING_LIST 2 -#define SCB_DISCONNECTED_LIST 4 -#define SCB_CURRENTLY_ACTIVE 8 - - /* - * Note, these checks will fail on a regular basis once the machine moves - * beyond the bus scan phase. The problem is race conditions concerning - * the scbs and where they are linked in. When you have 30 or so commands - * outstanding on the bus, and run this twice with every interrupt, the - * chances get pretty good that you'll catch the sequencer with an SCB - * only partially linked in. Therefore, once we pass the scan phase - * of the bus, we really should disable this function. - */ - bogus = FALSE; - memset(&scb_status[0], 0, sizeof(scb_status)); - pause_sequencer(p); - saved_scbptr = aic_inb(p, SCBPTR); - if (saved_scbptr >= p->scb_data->maxhscbs) - { - printk("Bogus SCBPTR %d\n", saved_scbptr); - bogus = TRUE; - } - scb_status[saved_scbptr] = SCB_CURRENTLY_ACTIVE; - free_scbh = aic_inb(p, FREE_SCBH); - if ( (free_scbh != SCB_LIST_NULL) && - (free_scbh >= p->scb_data->maxhscbs) ) - { - printk("Bogus FREE_SCBH %d\n", free_scbh); - bogus = TRUE; - } - else - { - temp = free_scbh; - while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) ) - { - if(scb_status[temp] & 0x07) - { - printk("HSCB %d on multiple lists, status 0x%02x", temp, - scb_status[temp] | SCB_FREE_LIST); - bogus = TRUE; - } - scb_status[temp] |= SCB_FREE_LIST; - aic_outb(p, temp, SCBPTR); - temp = aic_inb(p, SCB_NEXT); - } - } - - dis_scbh = aic_inb(p, DISCONNECTED_SCBH); - if ( (dis_scbh != SCB_LIST_NULL) && - (dis_scbh >= p->scb_data->maxhscbs) ) - { - printk("Bogus DISCONNECTED_SCBH %d\n", dis_scbh); - bogus = TRUE; - } - else - { - temp = dis_scbh; - while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) ) - { - if(scb_status[temp] & 0x07) - { - printk("HSCB %d on multiple lists, status 0x%02x", temp, - scb_status[temp] | SCB_DISCONNECTED_LIST); - bogus = TRUE; - } - scb_status[temp] |= SCB_DISCONNECTED_LIST; - aic_outb(p, temp, SCBPTR); - temp = aic_inb(p, SCB_NEXT); - } - } - - wait_scbh = aic_inb(p, WAITING_SCBH); - if ( (wait_scbh != SCB_LIST_NULL) && - (wait_scbh >= p->scb_data->maxhscbs) ) - { - printk("Bogus WAITING_SCBH %d\n", wait_scbh); - bogus = TRUE; - } - else - { - temp = wait_scbh; - while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) ) - { - if(scb_status[temp] & 0x07) - { - printk("HSCB %d on multiple lists, status 0x%02x", temp, - scb_status[temp] | SCB_WAITING_LIST); - bogus = TRUE; - } - scb_status[temp] |= SCB_WAITING_LIST; - aic_outb(p, temp, SCBPTR); - temp = aic_inb(p, SCB_NEXT); - } - } - - lost=0; - for(i=0; i < p->scb_data->maxhscbs; i++) - { - aic_outb(p, i, SCBPTR); - temp = aic_inb(p, SCB_NEXT); - if ( ((temp != SCB_LIST_NULL) && - (temp >= p->scb_data->maxhscbs)) ) - { - printk("HSCB %d bad, SCB_NEXT invalid(%d).\n", i, temp); - bogus = TRUE; - } - if ( temp == i ) - { - printk("HSCB %d bad, SCB_NEXT points to self.\n", i); - bogus = TRUE; - } - if (scb_status[i] == 0) - lost++; - if (lost > 1) - { - printk("Too many lost scbs.\n"); - bogus=TRUE; - } - } - aic_outb(p, saved_scbptr, SCBPTR); - unpause_sequencer(p, FALSE); - if (bogus) - { - printk("Bogus parameters found in card SCB array structures.\n"); - printk("%s\n", buffer); - aic7xxx_panic_abort(p, NULL); - } - return; -} -#endif - - -/*+F************************************************************************* - * Function: - * aic7xxx_handle_command_completion_intr - * - * Description: - * SCSI command completion interrupt handler. - *-F*************************************************************************/ -static void -aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p) -{ - struct aic7xxx_scb *scb = NULL; - struct aic_dev_data *aic_dev; - struct scsi_cmnd *cmd; - unsigned char scb_index, tindex; - -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) ) - printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1); -#endif - - /* - * Read the INTSTAT location after clearing the CMDINT bit. This forces - * any posted PCI writes to flush to memory. Gerard Roudier suggested - * this fix to the possible race of clearing the CMDINT bit but not - * having all command bytes flushed onto the qoutfifo. - */ - aic_outb(p, CLRCMDINT, CLRINT); - aic_inb(p, INTSTAT); - /* - * The sequencer will continue running when it - * issues this interrupt. There may be >1 commands - * finished, so loop until we've processed them all. - */ - - while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL) - { - scb_index = p->qoutfifo[p->qoutfifonext]; - p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL; - if ( scb_index >= p->scb_data->numscbs ) - { - printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no, - -1, -1, -1, scb_index); - continue; - } - scb = p->scb_data->scb_array[scb_index]; - if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) - { - printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags " - "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags, - (unsigned long) scb->cmd); - continue; - } - tindex = TARGET_INDEX(scb->cmd); - aic_dev = AIC_DEV(scb->cmd); - if (scb->flags & SCB_QUEUED_ABORT) - { - pause_sequencer(p); - if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) && - (aic_inb(p, SCB_TAG) == scb->hscb->tag) ) - { - unpause_sequencer(p, FALSE); - continue; - } - aic7xxx_reset_device(p, scb->cmd->device->id, scb->cmd->device->channel, - scb->cmd->device->lun, scb->hscb->tag); - scb->flags &= ~(SCB_QUEUED_FOR_DONE | SCB_RESET | SCB_ABORT | - SCB_QUEUED_ABORT); - unpause_sequencer(p, FALSE); - } - else if (scb->flags & SCB_ABORT) - { - /* - * We started to abort this, but it completed on us, let it - * through as successful - */ - scb->flags &= ~(SCB_ABORT|SCB_RESET); - } - else if (scb->flags & SCB_SENSE) - { - char *buffer = &scb->cmd->sense_buffer[0]; - - if (buffer[12] == 0x47 || buffer[12] == 0x54) - { - /* - * Signal that we need to re-negotiate things. - */ - aic_dev->needppr = aic_dev->needppr_copy; - aic_dev->needsdtr = aic_dev->needsdtr_copy; - aic_dev->needwdtr = aic_dev->needwdtr_copy; - } - } - cmd = scb->cmd; - if (scb->hscb->residual_SG_segment_count != 0) - { - aic7xxx_calculate_residual(p, scb); - } - cmd->result |= (aic7xxx_error(cmd) << 16); - aic7xxx_done(p, scb); - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_isr - * - * Description: - * SCSI controller interrupt handler. - *-F*************************************************************************/ -static void -aic7xxx_isr(void *dev_id) -{ - struct aic7xxx_host *p; - unsigned char intstat; - - p = dev_id; - - /* - * Just a few sanity checks. Make sure that we have an int pending. - * Also, if PCI, then we are going to check for a PCI bus error status - * should we get too many spurious interrupts. - */ - if (!((intstat = aic_inb(p, INTSTAT)) & INT_PEND)) - { -#ifdef CONFIG_PCI - if ( (p->chip & AHC_PCI) && (p->spurious_int > 500) && - !(p->flags & AHC_HANDLING_REQINITS) ) - { - if ( aic_inb(p, ERROR) & PCIERRSTAT ) - { - aic7xxx_pci_intr(p); - } - p->spurious_int = 0; - } - else if ( !(p->flags & AHC_HANDLING_REQINITS) ) - { - p->spurious_int++; - } -#endif - return; - } - - p->spurious_int = 0; - - /* - * Keep track of interrupts for /proc/scsi - */ - p->isr_count++; - -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) && - (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) ) - aic7xxx_check_scbs(p, "Bogus settings at start of interrupt."); -#endif - - /* - * Handle all the interrupt sources - especially for SCSI - * interrupts, we won't get a second chance at them. - */ - if (intstat & CMDCMPLT) - { - aic7xxx_handle_command_completion_intr(p); - } - - if (intstat & BRKADRINT) - { - int i; - unsigned char errno = aic_inb(p, ERROR); - - printk(KERN_ERR "(scsi%d) BRKADRINT error(0x%x):\n", p->host_no, errno); - for (i = 0; i < ARRAY_SIZE(hard_error); i++) - { - if (errno & hard_error[i].errno) - { - printk(KERN_ERR " %s\n", hard_error[i].errmesg); - } - } - printk(KERN_ERR "(scsi%d) SEQADDR=0x%x\n", p->host_no, - (((aic_inb(p, SEQADDR1) << 8) & 0x100) | aic_inb(p, SEQADDR0))); - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, NULL); -#ifdef CONFIG_PCI - if (errno & PCIERRSTAT) - aic7xxx_pci_intr(p); -#endif - if (errno & (SQPARERR | ILLOPCODE | ILLSADDR)) - { - panic("aic7xxx: unrecoverable BRKADRINT.\n"); - } - if (errno & ILLHADDR) - { - printk(KERN_ERR "(scsi%d) BUG! Driver accessed chip without first " - "pausing controller!\n", p->host_no); - } -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (errno & DPARERR) - { - if (aic_inb(p, DMAPARAMS) & DIRECTION) - printk("(scsi%d) while DMAing SCB from host to card.\n", p->host_no); - else - printk("(scsi%d) while DMAing SCB from card to host.\n", p->host_no); - } -#endif - aic_outb(p, CLRPARERR | CLRBRKADRINT, CLRINT); - unpause_sequencer(p, FALSE); - } - - if (intstat & SEQINT) - { - /* - * Read the CCSCBCTL register to work around a bug in the Ultra2 cards - */ - if(p->features & AHC_ULTRA2) - { - aic_inb(p, CCSCBCTL); - } - aic7xxx_handle_seqint(p, intstat); - } - - if (intstat & SCSIINT) - { - aic7xxx_handle_scsiint(p, intstat); - } - -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) && - (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) ) - aic7xxx_check_scbs(p, "Bogus settings at end of interrupt."); -#endif - -} - -/*+F************************************************************************* - * Function: - * do_aic7xxx_isr - * - * Description: - * This is a gross hack to solve a problem in linux kernels 2.1.85 and - * above. Please, children, do not try this at home, and if you ever see - * anything like it, please inform the Gross Hack Police immediately - *-F*************************************************************************/ -static irqreturn_t -do_aic7xxx_isr(int irq, void *dev_id) -{ - unsigned long cpu_flags; - struct aic7xxx_host *p; - - p = dev_id; - if(!p) - return IRQ_NONE; - spin_lock_irqsave(p->host->host_lock, cpu_flags); - p->flags |= AHC_IN_ISR; - do - { - aic7xxx_isr(dev_id); - } while ( (aic_inb(p, INTSTAT) & INT_PEND) ); - aic7xxx_done_cmds_complete(p); - aic7xxx_run_waiting_queues(p); - p->flags &= ~AHC_IN_ISR; - spin_unlock_irqrestore(p->host->host_lock, cpu_flags); - - return IRQ_HANDLED; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_init_transinfo - * - * Description: - * Set up the initial aic_dev values from the BIOS settings and from - * INQUIRY results - *-F*************************************************************************/ -static void -aic7xxx_init_transinfo(struct aic7xxx_host *p, struct aic_dev_data *aic_dev) -{ - struct scsi_device *sdpnt = aic_dev->SDptr; - unsigned char tindex; - - tindex = sdpnt->id | (sdpnt->channel << 3); - if (!(aic_dev->flags & DEVICE_DTR_SCANNED)) - { - aic_dev->flags |= DEVICE_DTR_SCANNED; - - if ( sdpnt->wdtr && (p->features & AHC_WIDE) ) - { - aic_dev->needwdtr = aic_dev->needwdtr_copy = 1; - aic_dev->goal.width = p->user[tindex].width; - } - else - { - aic_dev->needwdtr = aic_dev->needwdtr_copy = 0; - pause_sequencer(p); - aic7xxx_set_width(p, sdpnt->id, sdpnt->channel, sdpnt->lun, - MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE | - AHC_TRANS_GOAL | - AHC_TRANS_CUR), aic_dev ); - unpause_sequencer(p, FALSE); - } - if ( sdpnt->sdtr && p->user[tindex].offset ) - { - aic_dev->goal.period = p->user[tindex].period; - aic_dev->goal.options = p->user[tindex].options; - if (p->features & AHC_ULTRA2) - aic_dev->goal.offset = MAX_OFFSET_ULTRA2; - else if (aic_dev->goal.width == MSG_EXT_WDTR_BUS_16_BIT) - aic_dev->goal.offset = MAX_OFFSET_16BIT; - else - aic_dev->goal.offset = MAX_OFFSET_8BIT; - if ( sdpnt->ppr && p->user[tindex].period <= 9 && - p->user[tindex].options ) - { - aic_dev->needppr = aic_dev->needppr_copy = 1; - aic_dev->needsdtr = aic_dev->needsdtr_copy = 0; - aic_dev->needwdtr = aic_dev->needwdtr_copy = 0; - aic_dev->flags |= DEVICE_SCSI_3; - } - else - { - aic_dev->needsdtr = aic_dev->needsdtr_copy = 1; - aic_dev->goal.period = max_t(unsigned char, 10, aic_dev->goal.period); - aic_dev->goal.options = 0; - } - } - else - { - aic_dev->needsdtr = aic_dev->needsdtr_copy = 0; - aic_dev->goal.period = 255; - aic_dev->goal.offset = 0; - aic_dev->goal.options = 0; - } - aic_dev->flags |= DEVICE_PRINT_DTR; - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_slave_alloc - * - * Description: - * Set up the initial aic_dev struct pointers - *-F*************************************************************************/ -static int -aic7xxx_slave_alloc(struct scsi_device *SDptr) -{ - struct aic7xxx_host *p = (struct aic7xxx_host *)SDptr->host->hostdata; - struct aic_dev_data *aic_dev; - - aic_dev = kmalloc(sizeof(struct aic_dev_data), GFP_KERNEL); - if(!aic_dev) - return 1; - /* - * Check to see if channel was scanned. - */ - - if (!(p->flags & AHC_A_SCANNED) && (SDptr->channel == 0)) - { - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(INFO_LEAD "Scanning channel for devices.\n", - p->host_no, 0, -1, -1); - p->flags |= AHC_A_SCANNED; - } - else - { - if (!(p->flags & AHC_B_SCANNED) && (SDptr->channel == 1)) - { - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(INFO_LEAD "Scanning channel for devices.\n", - p->host_no, 1, -1, -1); - p->flags |= AHC_B_SCANNED; - } - } - - memset(aic_dev, 0, sizeof(struct aic_dev_data)); - SDptr->hostdata = aic_dev; - aic_dev->SDptr = SDptr; - aic_dev->max_q_depth = 1; - aic_dev->temp_q_depth = 1; - scbq_init(&aic_dev->delayed_scbs); - INIT_LIST_HEAD(&aic_dev->list); - list_add_tail(&aic_dev->list, &p->aic_devs); - return 0; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_device_queue_depth - * - * Description: - * Determines the queue depth for a given device. There are two ways - * a queue depth can be obtained for a tagged queueing device. One - * way is the default queue depth which is determined by whether - * aic7xxx_default_queue_depth. The other is by the aic7xxx_tag_info - * array. - * - * If tagged queueing isn't supported on the device, then we set the - * depth to p->host->hostt->cmd_per_lun for internal driver queueing. - * as the default queue depth. Otherwise, we use either 4 or 8 as the - * default queue depth (dependent on the number of hardware SCBs). - * The other way we determine queue depth is through the use of the - * aic7xxx_tag_info array which is enabled by defining - * AIC7XXX_TAGGED_QUEUEING_BY_DEVICE. This array can be initialized - * with queue depths for individual devices. It also allows tagged - * queueing to be [en|dis]abled for a specific adapter. - *-F*************************************************************************/ -static void -aic7xxx_device_queue_depth(struct aic7xxx_host *p, struct scsi_device *device) -{ - int tag_enabled = FALSE; - struct aic_dev_data *aic_dev = device->hostdata; - unsigned char tindex; - - tindex = device->id | (device->channel << 3); - - if (device->simple_tags) - return; // We've already enabled this device - - if (device->tagged_supported) - { - tag_enabled = TRUE; - - if (!(p->discenable & (1 << tindex))) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - printk(INFO_LEAD "Disconnection disabled, unable to " - "enable tagged queueing.\n", - p->host_no, device->channel, device->id, device->lun); - tag_enabled = FALSE; - } - else - { - if (p->instance >= ARRAY_SIZE(aic7xxx_tag_info)) - { - static int print_warning = TRUE; - if(print_warning) - { - printk(KERN_INFO "aic7xxx: WARNING, insufficient tag_info instances for" - " installed controllers.\n"); - printk(KERN_INFO "aic7xxx: Please update the aic7xxx_tag_info array in" - " the aic7xxx.c source file.\n"); - print_warning = FALSE; - } - aic_dev->max_q_depth = aic_dev->temp_q_depth = - aic7xxx_default_queue_depth; - } - else - { - - if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 255) - { - tag_enabled = FALSE; - } - else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0) - { - aic_dev->max_q_depth = aic_dev->temp_q_depth = - aic7xxx_default_queue_depth; - } - else - { - aic_dev->max_q_depth = aic_dev->temp_q_depth = - aic7xxx_tag_info[p->instance].tag_commands[tindex]; - } - } - } - } - if (tag_enabled) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Tagged queuing enabled, queue depth %d.\n", - p->host_no, device->channel, device->id, - device->lun, aic_dev->max_q_depth); - } - scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, aic_dev->max_q_depth); - } - else - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Tagged queuing disabled, queue depth %d.\n", - p->host_no, device->channel, device->id, - device->lun, device->host->cmd_per_lun); - } - scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun); - } - return; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_slave_destroy - * - * Description: - * prepare for this device to go away - *-F*************************************************************************/ -static void -aic7xxx_slave_destroy(struct scsi_device *SDptr) -{ - struct aic_dev_data *aic_dev = SDptr->hostdata; - - list_del(&aic_dev->list); - SDptr->hostdata = NULL; - kfree(aic_dev); - return; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_slave_configure - * - * Description: - * Configure the device we are attaching to the controller. This is - * where we get to do things like scan the INQUIRY data, set queue - * depths, allocate command structs, etc. - *-F*************************************************************************/ -static int -aic7xxx_slave_configure(struct scsi_device *SDptr) -{ - struct aic7xxx_host *p = (struct aic7xxx_host *) SDptr->host->hostdata; - struct aic_dev_data *aic_dev; - int scbnum; - - aic_dev = (struct aic_dev_data *)SDptr->hostdata; - - aic7xxx_init_transinfo(p, aic_dev); - aic7xxx_device_queue_depth(p, SDptr); - if(list_empty(&aic_dev->list)) - list_add_tail(&aic_dev->list, &p->aic_devs); - - scbnum = 0; - list_for_each_entry(aic_dev, &p->aic_devs, list) { - scbnum += aic_dev->max_q_depth; - } - while (scbnum > p->scb_data->numscbs) - { - /* - * Pre-allocate the needed SCBs to get around the possibility of having - * to allocate some when memory is more or less exhausted and we need - * the SCB in order to perform a swap operation (possible deadlock) - */ - if ( aic7xxx_allocate_scb(p) == 0 ) - break; - } - - - return(0); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_probe - * - * Description: - * Probing for EISA boards: it looks like the first two bytes - * are a manufacturer code - three characters, five bits each: - * - * BYTE 0 BYTE 1 BYTE 2 BYTE 3 - * ?1111122 22233333 PPPPPPPP RRRRRRRR - * - * The characters are baselined off ASCII '@', so add that value - * to each to get the real ASCII code for it. The next two bytes - * appear to be a product and revision number, probably vendor- - * specific. This is what is being searched for at each port, - * and what should probably correspond to the ID= field in the - * ECU's .cfg file for the card - if your card is not detected, - * make sure your signature is listed in the array. - * - * The fourth byte's lowest bit seems to be an enabled/disabled - * flag (rest of the bits are reserved?). - * - * NOTE: This function is only needed on Intel and Alpha platforms, - * the other platforms we support don't have EISA/VLB busses. So, - * we #ifdef this entire function to avoid compiler warnings about - * an unused function. - *-F*************************************************************************/ -#if defined(__i386__) || defined(__alpha__) -static int -aic7xxx_probe(int slot, int base, ahc_flag_type *flags) -{ - int i; - unsigned char buf[4]; - - static struct { - int n; - unsigned char signature[sizeof(buf)]; - ahc_chip type; - int bios_disabled; - } AIC7xxx[] = { - { 4, { 0x04, 0x90, 0x77, 0x70 }, - AHC_AIC7770|AHC_EISA, FALSE }, /* mb 7770 */ - { 4, { 0x04, 0x90, 0x77, 0x71 }, - AHC_AIC7770|AHC_EISA, FALSE }, /* host adapter 274x */ - { 4, { 0x04, 0x90, 0x77, 0x56 }, - AHC_AIC7770|AHC_VL, FALSE }, /* 284x BIOS enabled */ - { 4, { 0x04, 0x90, 0x77, 0x57 }, - AHC_AIC7770|AHC_VL, TRUE } /* 284x BIOS disabled */ - }; - - /* - * The VL-bus cards need to be primed by - * writing before a signature check. - */ - for (i = 0; i < sizeof(buf); i++) - { - outb(0x80 + i, base); - buf[i] = inb(base + i); - } - - for (i = 0; i < ARRAY_SIZE(AIC7xxx); i++) - { - /* - * Signature match on enabled card? - */ - if (!memcmp(buf, AIC7xxx[i].signature, AIC7xxx[i].n)) - { - if (inb(base + 4) & 1) - { - if (AIC7xxx[i].bios_disabled) - { - *flags |= AHC_USEDEFAULTS; - } - else - { - *flags |= AHC_BIOS_ENABLED; - } - return (i); - } - - printk("aic7xxx: " - "disabled at slot %d, ignored.\n", slot); - } - } - - return (-1); -} -#endif /* (__i386__) || (__alpha__) */ - - -/*+F************************************************************************* - * Function: - * read_2840_seeprom - * - * Description: - * Reads the 2840 serial EEPROM and returns 1 if successful and 0 if - * not successful. - * - * See read_seeprom (for the 2940) for the instruction set of the 93C46 - * chip. - * - * The 2840 interface to the 93C46 serial EEPROM is through the - * STATUS_2840 and SEECTL_2840 registers. The CS_2840, CK_2840, and - * DO_2840 bits of the SEECTL_2840 register are connected to the chip - * select, clock, and data out lines respectively of the serial EEPROM. - * The DI_2840 bit of the STATUS_2840 is connected to the data in line - * of the serial EEPROM. The EEPROM_TF bit of STATUS_2840 register is - * useful in that it gives us an 800 nsec timer. After a read from the - * SEECTL_2840 register the timing flag is cleared and goes high 800 nsec - * later. - *-F*************************************************************************/ -static int -read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc) -{ - int i = 0, k = 0; - unsigned char temp; - unsigned short checksum = 0; - unsigned short *seeprom = (unsigned short *) sc; - struct seeprom_cmd { - unsigned char len; - unsigned char bits[3]; - }; - struct seeprom_cmd seeprom_read = {3, {1, 1, 0}}; - -#define CLOCK_PULSE(p) \ - while ((aic_inb(p, STATUS_2840) & EEPROM_TF) == 0) \ - { \ - ; /* Do nothing */ \ - } \ - (void) aic_inb(p, SEECTL_2840); - - /* - * Read the first 32 registers of the seeprom. For the 2840, - * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers - * but only the first 32 are used by Adaptec BIOS. The loop - * will range from 0 to 31. - */ - for (k = 0; k < (sizeof(*sc) / 2); k++) - { - /* - * Send chip select for one clock cycle. - */ - aic_outb(p, CK_2840 | CS_2840, SEECTL_2840); - CLOCK_PULSE(p); - - /* - * Now we're ready to send the read command followed by the - * address of the 16-bit register we want to read. - */ - for (i = 0; i < seeprom_read.len; i++) - { - temp = CS_2840 | seeprom_read.bits[i]; - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - temp = temp ^ CK_2840; - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - } - /* - * Send the 6 bit address (MSB first, LSB last). - */ - for (i = 5; i >= 0; i--) - { - temp = k; - temp = (temp >> i) & 1; /* Mask out all but lower bit. */ - temp = CS_2840 | temp; - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - temp = temp ^ CK_2840; - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - } - - /* - * Now read the 16 bit register. An initial 0 precedes the - * register contents which begins with bit 15 (MSB) and ends - * with bit 0 (LSB). The initial 0 will be shifted off the - * top of our word as we let the loop run from 0 to 16. - */ - for (i = 0; i <= 16; i++) - { - temp = CS_2840; - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - temp = temp ^ CK_2840; - seeprom[k] = (seeprom[k] << 1) | (aic_inb(p, STATUS_2840) & DI_2840); - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - } - /* - * The serial EEPROM has a checksum in the last word. Keep a - * running checksum for all words read except for the last - * word. We'll verify the checksum after all words have been - * read. - */ - if (k < (sizeof(*sc) / 2) - 1) - { - checksum = checksum + seeprom[k]; - } - - /* - * Reset the chip select for the next command cycle. - */ - aic_outb(p, 0, SEECTL_2840); - CLOCK_PULSE(p); - aic_outb(p, CK_2840, SEECTL_2840); - CLOCK_PULSE(p); - aic_outb(p, 0, SEECTL_2840); - CLOCK_PULSE(p); - } - -#if 0 - printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum); - printk("Serial EEPROM:"); - for (k = 0; k < (sizeof(*sc) / 2); k++) - { - if (((k % 8) == 0) && (k != 0)) - { - printk("\n "); - } - printk(" 0x%x", seeprom[k]); - } - printk("\n"); -#endif - - if (checksum != sc->checksum) - { - printk("aic7xxx: SEEPROM checksum error, ignoring SEEPROM settings.\n"); - return (0); - } - - return (1); -#undef CLOCK_PULSE -} - -#define CLOCK_PULSE(p) \ - do { \ - int limit = 0; \ - do { \ - mb(); \ - pause_sequencer(p); /* This is just to generate some PCI */ \ - /* traffic so the PCI read is flushed */ \ - /* it shouldn't be needed, but some */ \ - /* chipsets do indeed appear to need */ \ - /* something to force PCI reads to get */ \ - /* flushed */ \ - udelay(1); /* Do nothing */ \ - } while (((aic_inb(p, SEECTL) & SEERDY) == 0) && (++limit < 1000)); \ - } while(0) - -/*+F************************************************************************* - * Function: - * acquire_seeprom - * - * Description: - * Acquires access to the memory port on PCI controllers. - *-F*************************************************************************/ -static int -acquire_seeprom(struct aic7xxx_host *p) -{ - - /* - * Request access of the memory port. When access is - * granted, SEERDY will go high. We use a 1 second - * timeout which should be near 1 second more than - * is needed. Reason: after the 7870 chip reset, there - * should be no contention. - */ - aic_outb(p, SEEMS, SEECTL); - CLOCK_PULSE(p); - if ((aic_inb(p, SEECTL) & SEERDY) == 0) - { - aic_outb(p, 0, SEECTL); - return (0); - } - return (1); -} - -/*+F************************************************************************* - * Function: - * release_seeprom - * - * Description: - * Releases access to the memory port on PCI controllers. - *-F*************************************************************************/ -static void -release_seeprom(struct aic7xxx_host *p) -{ - /* - * Make sure the SEEPROM is ready before we release it. - */ - CLOCK_PULSE(p); - aic_outb(p, 0, SEECTL); -} - -/*+F************************************************************************* - * Function: - * read_seeprom - * - * Description: - * Reads the serial EEPROM and returns 1 if successful and 0 if - * not successful. - * - * The instruction set of the 93C46/56/66 chips is as follows: - * - * Start OP - * Function Bit Code Address Data Description - * ------------------------------------------------------------------- - * READ 1 10 A5 - A0 Reads data stored in memory, - * starting at specified address - * EWEN 1 00 11XXXX Write enable must precede - * all programming modes - * ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0 - * WRITE 1 01 A5 - A0 D15 - D0 Writes register - * ERAL 1 00 10XXXX Erase all registers - * WRAL 1 00 01XXXX D15 - D0 Writes to all registers - * EWDS 1 00 00XXXX Disables all programming - * instructions - * *Note: A value of X for address is a don't care condition. - * *Note: The 93C56 and 93C66 have 8 address bits. - * - * - * The 93C46 has a four wire interface: clock, chip select, data in, and - * data out. In order to perform one of the above functions, you need - * to enable the chip select for a clock period (typically a minimum of - * 1 usec, with the clock high and low a minimum of 750 and 250 nsec - * respectively. While the chip select remains high, you can clock in - * the instructions (above) starting with the start bit, followed by the - * OP code, Address, and Data (if needed). For the READ instruction, the - * requested 16-bit register contents is read from the data out line but - * is preceded by an initial zero (leading 0, followed by 16-bits, MSB - * first). The clock cycling from low to high initiates the next data - * bit to be sent from the chip. - * - * The 78xx interface to the 93C46 serial EEPROM is through the SEECTL - * register. After successful arbitration for the memory port, the - * SEECS bit of the SEECTL register is connected to the chip select. - * The SEECK, SEEDO, and SEEDI are connected to the clock, data out, - * and data in lines respectively. The SEERDY bit of SEECTL is useful - * in that it gives us an 800 nsec timer. After a write to the SEECTL - * register, the SEERDY goes high 800 nsec later. The one exception - * to this is when we first request access to the memory port. The - * SEERDY goes high to signify that access has been granted and, for - * this case, has no implied timing. - *-F*************************************************************************/ -static int -read_seeprom(struct aic7xxx_host *p, int offset, - unsigned short *scarray, unsigned int len, seeprom_chip_type chip) -{ - int i = 0, k; - unsigned char temp; - unsigned short checksum = 0; - struct seeprom_cmd { - unsigned char len; - unsigned char bits[3]; - }; - struct seeprom_cmd seeprom_read = {3, {1, 1, 0}}; - - /* - * Request access of the memory port. - */ - if (acquire_seeprom(p) == 0) - { - return (0); - } - - /* - * Read 'len' registers of the seeprom. For the 7870, the 93C46 - * SEEPROM is a 1024-bit device with 64 16-bit registers but only - * the first 32 are used by Adaptec BIOS. Some adapters use the - * 93C56 SEEPROM which is a 2048-bit device. The loop will range - * from 0 to 'len' - 1. - */ - for (k = 0; k < len; k++) - { - /* - * Send chip select for one clock cycle. - */ - aic_outb(p, SEEMS | SEECK | SEECS, SEECTL); - CLOCK_PULSE(p); - - /* - * Now we're ready to send the read command followed by the - * address of the 16-bit register we want to read. - */ - for (i = 0; i < seeprom_read.len; i++) - { - temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1); - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - temp = temp ^ SEECK; - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - } - /* - * Send the 6 or 8 bit address (MSB first, LSB last). - */ - for (i = ((int) chip - 1); i >= 0; i--) - { - temp = k + offset; - temp = (temp >> i) & 1; /* Mask out all but lower bit. */ - temp = SEEMS | SEECS | (temp << 1); - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - temp = temp ^ SEECK; - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - } - - /* - * Now read the 16 bit register. An initial 0 precedes the - * register contents which begins with bit 15 (MSB) and ends - * with bit 0 (LSB). The initial 0 will be shifted off the - * top of our word as we let the loop run from 0 to 16. - */ - for (i = 0; i <= 16; i++) - { - temp = SEEMS | SEECS; - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - temp = temp ^ SEECK; - scarray[k] = (scarray[k] << 1) | (aic_inb(p, SEECTL) & SEEDI); - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - } - - /* - * The serial EEPROM should have a checksum in the last word. - * Keep a running checksum for all words read except for the - * last word. We'll verify the checksum after all words have - * been read. - */ - if (k < (len - 1)) - { - checksum = checksum + scarray[k]; - } - - /* - * Reset the chip select for the next command cycle. - */ - aic_outb(p, SEEMS, SEECTL); - CLOCK_PULSE(p); - aic_outb(p, SEEMS | SEECK, SEECTL); - CLOCK_PULSE(p); - aic_outb(p, SEEMS, SEECTL); - CLOCK_PULSE(p); - } - - /* - * Release access to the memory port and the serial EEPROM. - */ - release_seeprom(p); - -#if 0 - printk("Computed checksum 0x%x, checksum read 0x%x\n", - checksum, scarray[len - 1]); - printk("Serial EEPROM:"); - for (k = 0; k < len; k++) - { - if (((k % 8) == 0) && (k != 0)) - { - printk("\n "); - } - printk(" 0x%x", scarray[k]); - } - printk("\n"); -#endif - if ( (checksum != scarray[len - 1]) || (checksum == 0) ) - { - return (0); - } - - return (1); -} - -/*+F************************************************************************* - * Function: - * read_brdctl - * - * Description: - * Reads the BRDCTL register. - *-F*************************************************************************/ -static unsigned char -read_brdctl(struct aic7xxx_host *p) -{ - unsigned char brdctl, value; - - /* - * Make sure the SEEPROM is ready before we access it - */ - CLOCK_PULSE(p); - if (p->features & AHC_ULTRA2) - { - brdctl = BRDRW_ULTRA2; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - value = aic_inb(p, BRDCTL); - CLOCK_PULSE(p); - return(value); - } - brdctl = BRDRW; - if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) || - (p->flags & AHC_CHNLB) ) - { - brdctl |= BRDCS; - } - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - value = aic_inb(p, BRDCTL); - CLOCK_PULSE(p); - aic_outb(p, 0, BRDCTL); - CLOCK_PULSE(p); - return (value); -} - -/*+F************************************************************************* - * Function: - * write_brdctl - * - * Description: - * Writes a value to the BRDCTL register. - *-F*************************************************************************/ -static void -write_brdctl(struct aic7xxx_host *p, unsigned char value) -{ - unsigned char brdctl; - - /* - * Make sure the SEEPROM is ready before we access it - */ - CLOCK_PULSE(p); - if (p->features & AHC_ULTRA2) - { - brdctl = value; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - brdctl |= BRDSTB_ULTRA2; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - brdctl &= ~BRDSTB_ULTRA2; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - read_brdctl(p); - CLOCK_PULSE(p); - } - else - { - brdctl = BRDSTB; - if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) || - (p->flags & AHC_CHNLB) ) - { - brdctl |= BRDCS; - } - brdctl = BRDSTB | BRDCS; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - brdctl |= value; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - brdctl &= ~BRDSTB; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - brdctl &= ~BRDCS; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - } -} - -/*+F************************************************************************* - * Function: - * aic785x_cable_detect - * - * Description: - * Detect the cables that are present on aic785x class controller chips - *-F*************************************************************************/ -static void -aic785x_cable_detect(struct aic7xxx_host *p, int *int_50, - int *ext_present, int *eeprom) -{ - unsigned char brdctl; - - aic_outb(p, BRDRW | BRDCS, BRDCTL); - CLOCK_PULSE(p); - aic_outb(p, 0, BRDCTL); - CLOCK_PULSE(p); - brdctl = aic_inb(p, BRDCTL); - CLOCK_PULSE(p); - *int_50 = !(brdctl & BRDDAT5); - *ext_present = !(brdctl & BRDDAT6); - *eeprom = (aic_inb(p, SPIOCAP) & EEPROM); -} - -#undef CLOCK_PULSE - -/*+F************************************************************************* - * Function: - * aic2940_uwpro_cable_detect - * - * Description: - * Detect the cables that are present on the 2940-UWPro cards - * - * NOTE: This function assumes the SEEPROM will have already been acquired - * prior to invocation of this function. - *-F*************************************************************************/ -static void -aic2940_uwpro_wide_cable_detect(struct aic7xxx_host *p, int *int_68, - int *ext_68, int *eeprom) -{ - unsigned char brdctl; - - /* - * First read the status of our cables. Set the rom bank to - * 0 since the bank setting serves as a multiplexor for the - * cable detection logic. BRDDAT5 controls the bank switch. - */ - write_brdctl(p, 0); - - /* - * Now we read the state of the internal 68 connector. BRDDAT6 - * is don't care, BRDDAT7 is internal 68. The cable is - * present if the bit is 0 - */ - brdctl = read_brdctl(p); - *int_68 = !(brdctl & BRDDAT7); - - /* - * Set the bank bit in brdctl and then read the external cable state - * and the EEPROM status - */ - write_brdctl(p, BRDDAT5); - brdctl = read_brdctl(p); - - *ext_68 = !(brdctl & BRDDAT6); - *eeprom = !(brdctl & BRDDAT7); - - /* - * We're done, the calling function will release the SEEPROM for us - */ -} - -/*+F************************************************************************* - * Function: - * aic787x_cable_detect - * - * Description: - * Detect the cables that are present on aic787x class controller chips - * - * NOTE: This function assumes the SEEPROM will have already been acquired - * prior to invocation of this function. - *-F*************************************************************************/ -static void -aic787x_cable_detect(struct aic7xxx_host *p, int *int_50, int *int_68, - int *ext_present, int *eeprom) -{ - unsigned char brdctl; - - /* - * First read the status of our cables. Set the rom bank to - * 0 since the bank setting serves as a multiplexor for the - * cable detection logic. BRDDAT5 controls the bank switch. - */ - write_brdctl(p, 0); - - /* - * Now we read the state of the two internal connectors. BRDDAT6 - * is internal 50, BRDDAT7 is internal 68. For each, the cable is - * present if the bit is 0 - */ - brdctl = read_brdctl(p); - *int_50 = !(brdctl & BRDDAT6); - *int_68 = !(brdctl & BRDDAT7); - - /* - * Set the bank bit in brdctl and then read the external cable state - * and the EEPROM status - */ - write_brdctl(p, BRDDAT5); - brdctl = read_brdctl(p); - - *ext_present = !(brdctl & BRDDAT6); - *eeprom = !(brdctl & BRDDAT7); - - /* - * We're done, the calling function will release the SEEPROM for us - */ -} - -/*+F************************************************************************* - * Function: - * aic787x_ultra2_term_detect - * - * Description: - * Detect the termination settings present on ultra2 class controllers - * - * NOTE: This function assumes the SEEPROM will have already been acquired - * prior to invocation of this function. - *-F*************************************************************************/ -static void -aic7xxx_ultra2_term_detect(struct aic7xxx_host *p, int *enableSE_low, - int *enableSE_high, int *enableLVD_low, - int *enableLVD_high, int *eprom_present) -{ - unsigned char brdctl; - - brdctl = read_brdctl(p); - - *eprom_present = (brdctl & BRDDAT7); - *enableSE_high = (brdctl & BRDDAT6); - *enableSE_low = (brdctl & BRDDAT5); - *enableLVD_high = (brdctl & BRDDAT4); - *enableLVD_low = (brdctl & BRDDAT3); -} - -/*+F************************************************************************* - * Function: - * configure_termination - * - * Description: - * Configures the termination settings on PCI adapters that have - * SEEPROMs available. - *-F*************************************************************************/ -static void -configure_termination(struct aic7xxx_host *p) -{ - int internal50_present = 0; - int internal68_present = 0; - int external_present = 0; - int eprom_present = 0; - int enableSE_low = 0; - int enableSE_high = 0; - int enableLVD_low = 0; - int enableLVD_high = 0; - unsigned char brddat = 0; - unsigned char max_target = 0; - unsigned char sxfrctl1 = aic_inb(p, SXFRCTL1); - - if (acquire_seeprom(p)) - { - if (p->features & (AHC_WIDE|AHC_TWIN)) - max_target = 16; - else - max_target = 8; - aic_outb(p, SEEMS | SEECS, SEECTL); - sxfrctl1 &= ~STPWEN; - /* - * The termination/cable detection logic is split into three distinct - * groups. Ultra2 and later controllers, 2940UW-Pro controllers, and - * older 7850, 7860, 7870, 7880, and 7895 controllers. Each has its - * own unique way of detecting their cables and writing the results - * back to the card. - */ - if (p->features & AHC_ULTRA2) - { - /* - * As long as user hasn't overridden term settings, always check the - * cable detection logic - */ - if (aic7xxx_override_term == -1) - { - aic7xxx_ultra2_term_detect(p, &enableSE_low, &enableSE_high, - &enableLVD_low, &enableLVD_high, - &eprom_present); - } - - /* - * If the user is overriding settings, then they have been preserved - * to here as fake adapter_control entries. Parse them and allow - * them to override the detected settings (if we even did detection). - */ - if (!(p->adapter_control & CFSEAUTOTERM)) - { - enableSE_low = (p->adapter_control & CFSTERM); - enableSE_high = (p->adapter_control & CFWSTERM); - } - if (!(p->adapter_control & CFAUTOTERM)) - { - enableLVD_low = enableLVD_high = (p->adapter_control & CFLVDSTERM); - } - - /* - * Now take those settings that we have and translate them into the - * values that must be written into the registers. - * - * Flash Enable = BRDDAT7 - * Secondary High Term Enable = BRDDAT6 - * Secondary Low Term Enable = BRDDAT5 - * LVD/Primary High Term Enable = BRDDAT4 - * LVD/Primary Low Term Enable = STPWEN bit in SXFRCTL1 - */ - if (enableLVD_low != 0) - { - sxfrctl1 |= STPWEN; - p->flags |= AHC_TERM_ENB_LVD; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) LVD/Primary Low byte termination " - "Enabled\n", p->host_no); - } - - if (enableLVD_high != 0) - { - brddat |= BRDDAT4; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) LVD/Primary High byte termination " - "Enabled\n", p->host_no); - } - - if (enableSE_low != 0) - { - brddat |= BRDDAT5; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Secondary Low byte termination " - "Enabled\n", p->host_no); - } - - if (enableSE_high != 0) - { - brddat |= BRDDAT6; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Secondary High byte termination " - "Enabled\n", p->host_no); - } - } - else if (p->features & AHC_NEW_AUTOTERM) - { - /* - * The 50 pin connector termination is controlled by STPWEN in the - * SXFRCTL1 register. Since the Adaptec docs typically say the - * controller is not allowed to be in the middle of a cable and - * this is the only connection on that stub of the bus, there is - * no need to even check for narrow termination, it's simply - * always on. - */ - sxfrctl1 |= STPWEN; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Narrow channel termination Enabled\n", - p->host_no); - - if (p->adapter_control & CFAUTOTERM) - { - aic2940_uwpro_wide_cable_detect(p, &internal68_present, - &external_present, - &eprom_present); - printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, " - "Ext-68 %s)\n", p->host_no, - "Don't Care", - internal68_present ? "YES" : "NO", - external_present ? "YES" : "NO"); - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no, - eprom_present ? "is" : "is not"); - if (internal68_present && external_present) - { - brddat = 0; - p->flags &= ~AHC_TERM_ENB_SE_HIGH; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Wide channel termination Disabled\n", - p->host_no); - } - else - { - brddat = BRDDAT6; - p->flags |= AHC_TERM_ENB_SE_HIGH; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n", - p->host_no); - } - } - else - { - /* - * The termination of the Wide channel is done more like normal - * though, and the setting of this termination is done by writing - * either a 0 or 1 to BRDDAT6 of the BRDDAT register - */ - if (p->adapter_control & CFWSTERM) - { - brddat = BRDDAT6; - p->flags |= AHC_TERM_ENB_SE_HIGH; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n", - p->host_no); - } - else - { - brddat = 0; - } - } - } - else - { - if (p->adapter_control & CFAUTOTERM) - { - if (p->flags & AHC_MOTHERBOARD) - { - printk(KERN_INFO "(scsi%d) Warning - detected auto-termination\n", - p->host_no); - printk(KERN_INFO "(scsi%d) Please verify driver detected settings " - "are correct.\n", p->host_no); - printk(KERN_INFO "(scsi%d) If not, then please properly set the " - "device termination\n", p->host_no); - printk(KERN_INFO "(scsi%d) in the Adaptec SCSI BIOS by hitting " - "CTRL-A when prompted\n", p->host_no); - printk(KERN_INFO "(scsi%d) during machine bootup.\n", p->host_no); - } - /* Configure auto termination. */ - - if ( (p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870 ) - { - aic787x_cable_detect(p, &internal50_present, &internal68_present, - &external_present, &eprom_present); - } - else - { - aic785x_cable_detect(p, &internal50_present, &external_present, - &eprom_present); - } - - if (max_target <= 8) - internal68_present = 0; - - if (max_target > 8) - { - printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, " - "Ext-68 %s)\n", p->host_no, - internal50_present ? "YES" : "NO", - internal68_present ? "YES" : "NO", - external_present ? "YES" : "NO"); - } - else - { - printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Ext-50 %s)\n", - p->host_no, - internal50_present ? "YES" : "NO", - external_present ? "YES" : "NO"); - } - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no, - eprom_present ? "is" : "is not"); - - /* - * Now set the termination based on what we found. BRDDAT6 - * controls wide termination enable. - * Flash Enable = BRDDAT7 - * SE High Term Enable = BRDDAT6 - */ - if (internal50_present && internal68_present && external_present) - { - printk(KERN_INFO "(scsi%d) Illegal cable configuration!! Only two\n", - p->host_no); - printk(KERN_INFO "(scsi%d) connectors on the SCSI controller may be " - "in use at a time!\n", p->host_no); - /* - * Force termination (low and high byte) on. This is safer than - * leaving it completely off, especially since this message comes - * most often from motherboard controllers that don't even have 3 - * connectors, but instead are failing the cable detection. - */ - internal50_present = external_present = 0; - enableSE_high = enableSE_low = 1; - } - - if ((max_target > 8) && - ((external_present == 0) || (internal68_present == 0)) ) - { - brddat |= BRDDAT6; - p->flags |= AHC_TERM_ENB_SE_HIGH; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n", - p->host_no); - } - - if ( ((internal50_present ? 1 : 0) + - (internal68_present ? 1 : 0) + - (external_present ? 1 : 0)) <= 1 ) - { - sxfrctl1 |= STPWEN; - p->flags |= AHC_TERM_ENB_SE_LOW; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n", - p->host_no); - } - } - else /* p->adapter_control & CFAUTOTERM */ - { - if (p->adapter_control & CFSTERM) - { - sxfrctl1 |= STPWEN; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n", - p->host_no); - } - - if (p->adapter_control & CFWSTERM) - { - brddat |= BRDDAT6; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n", - p->host_no); - } - } - } - - aic_outb(p, sxfrctl1, SXFRCTL1); - write_brdctl(p, brddat); - release_seeprom(p); - } -} - -/*+F************************************************************************* - * Function: - * detect_maxscb - * - * Description: - * Detects the maximum number of SCBs for the controller and returns - * the count and a mask in p (p->maxscbs, p->qcntmask). - *-F*************************************************************************/ -static void -detect_maxscb(struct aic7xxx_host *p) -{ - int i; - - /* - * It's possible that we've already done this for multichannel - * adapters. - */ - if (p->scb_data->maxhscbs == 0) - { - /* - * We haven't initialized the SCB settings yet. Walk the SCBs to - * determince how many there are. - */ - aic_outb(p, 0, FREE_SCBH); - - for (i = 0; i < AIC7XXX_MAXSCB; i++) - { - aic_outb(p, i, SCBPTR); - aic_outb(p, i, SCB_CONTROL); - if (aic_inb(p, SCB_CONTROL) != i) - break; - aic_outb(p, 0, SCBPTR); - if (aic_inb(p, SCB_CONTROL) != 0) - break; - - aic_outb(p, i, SCBPTR); - aic_outb(p, 0, SCB_CONTROL); /* Clear the control byte. */ - aic_outb(p, i + 1, SCB_NEXT); /* Set the next pointer. */ - aic_outb(p, SCB_LIST_NULL, SCB_TAG); /* Make the tag invalid. */ - aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS); /* no busy untagged */ - aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+1);/* targets active yet */ - aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+2); - aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+3); - } - - /* Make sure the last SCB terminates the free list. */ - aic_outb(p, i - 1, SCBPTR); - aic_outb(p, SCB_LIST_NULL, SCB_NEXT); - - /* Ensure we clear the first (0) SCBs control byte. */ - aic_outb(p, 0, SCBPTR); - aic_outb(p, 0, SCB_CONTROL); - - p->scb_data->maxhscbs = i; - /* - * Use direct indexing instead for speed - */ - if ( i == AIC7XXX_MAXSCB ) - p->flags &= ~AHC_PAGESCBS; - } - -} - -/*+F************************************************************************* - * Function: - * aic7xxx_register - * - * Description: - * Register a Adaptec aic7xxx chip SCSI controller with the kernel. - *-F*************************************************************************/ -static int -aic7xxx_register(struct scsi_host_template *template, struct aic7xxx_host *p, - int reset_delay) -{ - int i, result; - int max_targets; - int found = 1; - unsigned char term, scsi_conf; - struct Scsi_Host *host; - - host = p->host; - - p->scb_data->maxscbs = AIC7XXX_MAXSCB; - host->can_queue = AIC7XXX_MAXSCB; - host->cmd_per_lun = 3; - host->sg_tablesize = AIC7XXX_MAX_SG; - host->this_id = p->scsi_id; - host->io_port = p->base; - host->n_io_port = 0xFF; - host->base = p->mbase; - host->irq = p->irq; - if (p->features & AHC_WIDE) - { - host->max_id = 16; - } - if (p->features & AHC_TWIN) - { - host->max_channel = 1; - } - - p->host = host; - p->host_no = host->host_no; - host->unique_id = p->instance; - p->isr_count = 0; - p->next = NULL; - p->completeq.head = NULL; - p->completeq.tail = NULL; - scbq_init(&p->scb_data->free_scbs); - scbq_init(&p->waiting_scbs); - INIT_LIST_HEAD(&p->aic_devs); - - /* - * We currently have no commands of any type - */ - p->qinfifonext = 0; - p->qoutfifonext = 0; - - printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no, - board_names[p->board_name_index]); - switch(p->chip) - { - case (AHC_AIC7770|AHC_EISA): - printk("EISA slot %d\n", p->pci_device_fn); - break; - case (AHC_AIC7770|AHC_VL): - printk("VLB slot %d\n", p->pci_device_fn); - break; - default: - printk("PCI %d/%d/%d\n", p->pci_bus, PCI_SLOT(p->pci_device_fn), - PCI_FUNC(p->pci_device_fn)); - break; - } - if (p->features & AHC_TWIN) - { - printk(KERN_INFO "(scsi%d) Twin Channel, A SCSI ID %d, B SCSI ID %d, ", - p->host_no, p->scsi_id, p->scsi_id_b); - } - else - { - char *channel; - - channel = ""; - - if ((p->flags & AHC_MULTI_CHANNEL) != 0) - { - channel = " A"; - - if ( (p->flags & (AHC_CHNLB|AHC_CHNLC)) != 0 ) - { - channel = (p->flags & AHC_CHNLB) ? " B" : " C"; - } - } - if (p->features & AHC_WIDE) - { - printk(KERN_INFO "(scsi%d) Wide ", p->host_no); - } - else - { - printk(KERN_INFO "(scsi%d) Narrow ", p->host_no); - } - printk("Channel%s, SCSI ID=%d, ", channel, p->scsi_id); - } - aic_outb(p, 0, SEQ_FLAGS); - - detect_maxscb(p); - - printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs); - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%lx, IRQ %d\n", - p->host_no, (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis", - p->base, p->irq); - printk(KERN_INFO "(scsi%d) IO Memory at 0x%lx, MMAP Memory at %p\n", - p->host_no, p->mbase, p->maddr); - } - -#ifdef CONFIG_PCI - /* - * Now that we know our instance number, we can set the flags we need to - * force termination if need be. - */ - if (aic7xxx_stpwlev != -1) - { - /* - * This option only applies to PCI controllers. - */ - if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) - { - unsigned char devconfig; - - pci_read_config_byte(p->pdev, DEVCONFIG, &devconfig); - if ( (aic7xxx_stpwlev >> p->instance) & 0x01 ) - { - devconfig |= STPWLEVEL; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("(scsi%d) Force setting STPWLEVEL bit\n", p->host_no); - } - else - { - devconfig &= ~STPWLEVEL; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("(scsi%d) Force clearing STPWLEVEL bit\n", p->host_no); - } - pci_write_config_byte(p->pdev, DEVCONFIG, devconfig); - } - } -#endif - - /* - * That took care of devconfig and stpwlev, now for the actual termination - * settings. - */ - if (aic7xxx_override_term != -1) - { - /* - * Again, this only applies to PCI controllers. We don't have problems - * with the termination on 274x controllers to the best of my knowledge. - */ - if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) - { - unsigned char term_override; - - term_override = ( (aic7xxx_override_term >> (p->instance * 4)) & 0x0f); - p->adapter_control &= - ~(CFSTERM|CFWSTERM|CFLVDSTERM|CFAUTOTERM|CFSEAUTOTERM); - if ( (p->features & AHC_ULTRA2) && (term_override & 0x0c) ) - { - p->adapter_control |= CFLVDSTERM; - } - if (term_override & 0x02) - { - p->adapter_control |= CFWSTERM; - } - if (term_override & 0x01) - { - p->adapter_control |= CFSTERM; - } - } - } - - if ( (p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1) ) - { - if (p->features & AHC_SPIOCAP) - { - if ( aic_inb(p, SPIOCAP) & SSPIOCPS ) - /* - * Update the settings in sxfrctl1 to match the termination - * settings. - */ - configure_termination(p); - } - else if ((p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870) - { - configure_termination(p); - } - } - - /* - * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels - */ - if (p->features & AHC_TWIN) - { - /* Select channel B */ - aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL); - - if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1)) - term = (aic_inb(p, SXFRCTL1) & STPWEN); - else - term = ((p->flags & AHC_TERM_ENB_B) ? STPWEN : 0); - - aic_outb(p, p->scsi_id_b, SCSIID); - scsi_conf = aic_inb(p, SCSICONF + 1); - aic_outb(p, DFON | SPIOEN, SXFRCTL0); - aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | - ENSTIMER | ACTNEGEN, SXFRCTL1); - aic_outb(p, 0, SIMODE0); - aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1); - aic_outb(p, 0, SCSIRATE); - - /* Select channel A */ - aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL); - } - - if (p->features & AHC_ULTRA2) - { - aic_outb(p, p->scsi_id, SCSIID_ULTRA2); - } - else - { - aic_outb(p, p->scsi_id, SCSIID); - } - if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1)) - term = (aic_inb(p, SXFRCTL1) & STPWEN); - else - term = ((p->flags & (AHC_TERM_ENB_A|AHC_TERM_ENB_LVD)) ? STPWEN : 0); - scsi_conf = aic_inb(p, SCSICONF); - aic_outb(p, DFON | SPIOEN, SXFRCTL0); - aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | - ENSTIMER | ACTNEGEN, SXFRCTL1); - aic_outb(p, 0, SIMODE0); - /* - * If we are a cardbus adapter then don't enable SCSI reset detection. - * We shouldn't likely be sharing SCSI busses with someone else, and - * if we don't have a cable currently plugged into the controller then - * we won't have a power source for the SCSI termination, which means - * we'll see infinite incoming bus resets. - */ - if(p->flags & AHC_NO_STPWEN) - aic_outb(p, ENSELTIMO | ENSCSIPERR, SIMODE1); - else - aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1); - aic_outb(p, 0, SCSIRATE); - if ( p->features & AHC_ULTRA2) - aic_outb(p, 0, SCSIOFFSET); - - /* - * Look at the information that board initialization or the board - * BIOS has left us. In the lower four bits of each target's - * scratch space any value other than 0 indicates that we should - * initiate synchronous transfers. If it's zero, the user or the - * BIOS has decided to disable synchronous negotiation to that - * target so we don't activate the needsdtr flag. - */ - if ((p->features & (AHC_TWIN|AHC_WIDE)) == 0) - { - max_targets = 8; - } - else - { - max_targets = 16; - } - - if (!(aic7xxx_no_reset)) - { - /* - * If we reset the bus, then clear the transfer settings, else leave - * them be. - */ - aic_outb(p, 0, ULTRA_ENB); - aic_outb(p, 0, ULTRA_ENB + 1); - p->ultraenb = 0; - } - - /* - * Allocate enough hardware scbs to handle the maximum number of - * concurrent transactions we can have. We have to make sure that - * the allocated memory is contiguous memory. The Linux kmalloc - * routine should only allocate contiguous memory, but note that - * this could be a problem if kmalloc() is changed. - */ - { - size_t array_size; - unsigned int hscb_physaddr; - - array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb); - if (p->scb_data->hscbs == NULL) - { - /* pci_alloc_consistent enforces the alignment already and - * clears the area as well. - */ - p->scb_data->hscbs = pci_alloc_consistent(p->pdev, array_size, - &p->scb_data->hscbs_dma); - /* We have to use pci_free_consistent, not kfree */ - p->scb_data->hscb_kmalloc_ptr = NULL; - p->scb_data->hscbs_dma_len = array_size; - } - if (p->scb_data->hscbs == NULL) - { - printk("(scsi%d) Unable to allocate hardware SCB array; " - "failing detection.\n", p->host_no); - aic_outb(p, 0, SIMODE1); - p->irq = 0; - return(0); - } - - hscb_physaddr = p->scb_data->hscbs_dma; - aic_outb(p, hscb_physaddr & 0xFF, HSCB_ADDR); - aic_outb(p, (hscb_physaddr >> 8) & 0xFF, HSCB_ADDR + 1); - aic_outb(p, (hscb_physaddr >> 16) & 0xFF, HSCB_ADDR + 2); - aic_outb(p, (hscb_physaddr >> 24) & 0xFF, HSCB_ADDR + 3); - - /* Set up the fifo areas at the same time */ - p->untagged_scbs = pci_alloc_consistent(p->pdev, 3*256, &p->fifo_dma); - if (p->untagged_scbs == NULL) - { - printk("(scsi%d) Unable to allocate hardware FIFO arrays; " - "failing detection.\n", p->host_no); - p->irq = 0; - return(0); - } - - p->qoutfifo = p->untagged_scbs + 256; - p->qinfifo = p->qoutfifo + 256; - for (i = 0; i < 256; i++) - { - p->untagged_scbs[i] = SCB_LIST_NULL; - p->qinfifo[i] = SCB_LIST_NULL; - p->qoutfifo[i] = SCB_LIST_NULL; - } - - hscb_physaddr = p->fifo_dma; - aic_outb(p, hscb_physaddr & 0xFF, SCBID_ADDR); - aic_outb(p, (hscb_physaddr >> 8) & 0xFF, SCBID_ADDR + 1); - aic_outb(p, (hscb_physaddr >> 16) & 0xFF, SCBID_ADDR + 2); - aic_outb(p, (hscb_physaddr >> 24) & 0xFF, SCBID_ADDR + 3); - } - - /* The Q-FIFOs we just set up are all empty */ - aic_outb(p, 0, QINPOS); - aic_outb(p, 0, KERNEL_QINPOS); - aic_outb(p, 0, QOUTPOS); - - if(p->features & AHC_QUEUE_REGS) - { - aic_outb(p, SCB_QSIZE_256, QOFF_CTLSTA); - aic_outb(p, 0, SDSCB_QOFF); - aic_outb(p, 0, SNSCB_QOFF); - aic_outb(p, 0, HNSCB_QOFF); - } - - /* - * We don't have any waiting selections or disconnected SCBs. - */ - aic_outb(p, SCB_LIST_NULL, WAITING_SCBH); - aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH); - - /* - * Message out buffer starts empty - */ - aic_outb(p, MSG_NOOP, MSG_OUT); - aic_outb(p, MSG_NOOP, LAST_MSG); - - /* - * Set all the other asundry items that haven't been set yet. - * This includes just dumping init values to a lot of registers simply - * to make sure they've been touched and are ready for use parity wise - * speaking. - */ - aic_outb(p, 0, TMODE_CMDADDR); - aic_outb(p, 0, TMODE_CMDADDR + 1); - aic_outb(p, 0, TMODE_CMDADDR + 2); - aic_outb(p, 0, TMODE_CMDADDR + 3); - aic_outb(p, 0, TMODE_CMDADDR_NEXT); - - /* - * Link us into the list of valid hosts - */ - p->next = first_aic7xxx; - first_aic7xxx = p; - - /* - * Allocate the first set of scbs for this controller. This is to stream- - * line code elsewhere in the driver. If we have to check for the existence - * of scbs in certain code sections, it slows things down. However, as - * soon as we register the IRQ for this card, we could get an interrupt that - * includes possibly the SCSI_RSTI interrupt. If we catch that interrupt - * then we are likely to segfault if we don't have at least one chunk of - * SCBs allocated or add checks all through the reset code to make sure - * that the SCBs have been allocated which is an invalid running condition - * and therefore I think it's preferable to simply pre-allocate the first - * chunk of SCBs. - */ - aic7xxx_allocate_scb(p); - - /* - * Load the sequencer program, then re-enable the board - - * resetting the AIC-7770 disables it, leaving the lights - * on with nobody home. - */ - aic7xxx_loadseq(p); - - /* - * Make sure the AUTOFLUSHDIS bit is *not* set in the SBLKCTL register - */ - aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL); - - if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) - { - aic_outb(p, ENABLE, BCTL); /* Enable the boards BUS drivers. */ - } - - if ( !(aic7xxx_no_reset) ) - { - if (p->features & AHC_TWIN) - { - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Resetting channel B\n", p->host_no); - aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL); - aic7xxx_reset_current_bus(p); - aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL); - } - /* Reset SCSI bus A. */ - if (aic7xxx_verbose & VERBOSE_PROBE2) - { /* In case we are a 3940, 3985, or 7895, print the right channel */ - char *channel = ""; - if (p->flags & AHC_MULTI_CHANNEL) - { - channel = " A"; - if (p->flags & (AHC_CHNLB|AHC_CHNLC)) - channel = (p->flags & AHC_CHNLB) ? " B" : " C"; - } - printk(KERN_INFO "(scsi%d) Resetting channel%s\n", p->host_no, channel); - } - - aic7xxx_reset_current_bus(p); - - } - else - { - if (!reset_delay) - { - printk(KERN_INFO "(scsi%d) Not resetting SCSI bus. Note: Don't use " - "the no_reset\n", p->host_no); - printk(KERN_INFO "(scsi%d) option unless you have a verifiable need " - "for it.\n", p->host_no); - } - } - - /* - * Register IRQ with the kernel. Only allow sharing IRQs with - * PCI devices. - */ - if (!(p->chip & AHC_PCI)) - { - result = (request_irq(p->irq, do_aic7xxx_isr, 0, "aic7xxx", p)); - } - else - { - result = (request_irq(p->irq, do_aic7xxx_isr, IRQF_SHARED, - "aic7xxx", p)); - if (result < 0) - { - result = (request_irq(p->irq, do_aic7xxx_isr, IRQF_DISABLED | IRQF_SHARED, - "aic7xxx", p)); - } - } - if (result < 0) - { - printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring " - "controller.\n", p->host_no, p->irq); - aic_outb(p, 0, SIMODE1); - p->irq = 0; - return (0); - } - - if(aic_inb(p, INTSTAT) & INT_PEND) - printk(INFO_LEAD "spurious interrupt during configuration, cleared.\n", - p->host_no, -1, -1 , -1); - aic7xxx_clear_intstat(p); - - unpause_sequencer(p, /* unpause_always */ TRUE); - - return (found); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_chip_reset - * - * Description: - * Perform a chip reset on the aic7xxx SCSI controller. The controller - * is paused upon return. - *-F*************************************************************************/ -static int -aic7xxx_chip_reset(struct aic7xxx_host *p) -{ - unsigned char sblkctl; - int wait; - - /* - * For some 274x boards, we must clear the CHIPRST bit and pause - * the sequencer. For some reason, this makes the driver work. - */ - aic_outb(p, PAUSE | CHIPRST, HCNTRL); - - /* - * In the future, we may call this function as a last resort for - * error handling. Let's be nice and not do any unnecessary delays. - */ - wait = 1000; /* 1 msec (1000 * 1 msec) */ - while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK)) - { - udelay(1); /* 1 usec */ - } - - pause_sequencer(p); - - sblkctl = aic_inb(p, SBLKCTL) & (SELBUSB|SELWIDE); - if (p->chip & AHC_PCI) - sblkctl &= ~SELBUSB; - switch( sblkctl ) - { - case 0: /* normal narrow card */ - break; - case 2: /* Wide card */ - p->features |= AHC_WIDE; - break; - case 8: /* Twin card */ - p->features |= AHC_TWIN; - p->flags |= AHC_MULTI_CHANNEL; - break; - default: /* hmmm...we don't know what this is */ - printk(KERN_WARNING "aic7xxx: Unsupported adapter type %d, ignoring.\n", - aic_inb(p, SBLKCTL) & 0x0a); - return(-1); - } - return(0); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_alloc - * - * Description: - * Allocate and initialize a host structure. Returns NULL upon error - * and a pointer to a aic7xxx_host struct upon success. - *-F*************************************************************************/ -static struct aic7xxx_host * -aic7xxx_alloc(struct scsi_host_template *sht, struct aic7xxx_host *temp) -{ - struct aic7xxx_host *p = NULL; - struct Scsi_Host *host; - - /* - * Allocate a storage area by registering us with the mid-level - * SCSI layer. - */ - host = scsi_register(sht, sizeof(struct aic7xxx_host)); - - if (host != NULL) - { - p = (struct aic7xxx_host *) host->hostdata; - memset(p, 0, sizeof(struct aic7xxx_host)); - *p = *temp; - p->host = host; - - p->scb_data = kzalloc(sizeof(scb_data_type), GFP_ATOMIC); - if (p->scb_data) - { - scbq_init (&p->scb_data->free_scbs); - } - else - { - /* - * For some reason we don't have enough memory. Free the - * allocated memory for the aic7xxx_host struct, and return NULL. - */ - release_region(p->base, MAXREG - MINREG); - scsi_unregister(host); - return(NULL); - } - p->host_no = host->host_no; - } - return (p); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_free - * - * Description: - * Frees and releases all resources associated with an instance of - * the driver (struct aic7xxx_host *). - *-F*************************************************************************/ -static void -aic7xxx_free(struct aic7xxx_host *p) -{ - int i; - - /* - * Free the allocated hardware SCB space. - */ - if (p->scb_data != NULL) - { - struct aic7xxx_scb_dma *scb_dma = NULL; - if (p->scb_data->hscbs != NULL) - { - pci_free_consistent(p->pdev, p->scb_data->hscbs_dma_len, - p->scb_data->hscbs, p->scb_data->hscbs_dma); - p->scb_data->hscbs = p->scb_data->hscb_kmalloc_ptr = NULL; - } - /* - * Free the driver SCBs. These were allocated on an as-need - * basis. We allocated these in groups depending on how many - * we could fit into a given amount of RAM. The tail SCB for - * these allocations has a pointer to the alloced area. - */ - for (i = 0; i < p->scb_data->numscbs; i++) - { - if (p->scb_data->scb_array[i]->scb_dma != scb_dma) - { - scb_dma = p->scb_data->scb_array[i]->scb_dma; - pci_free_consistent(p->pdev, scb_dma->dma_len, - (void *)((unsigned long)scb_dma->dma_address - - scb_dma->dma_offset), - scb_dma->dma_address); - } - kfree(p->scb_data->scb_array[i]->kmalloc_ptr); - p->scb_data->scb_array[i] = NULL; - } - - /* - * Free the SCB data area. - */ - kfree(p->scb_data); - } - - pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_load_seeprom - * - * Description: - * Load the seeprom and configure adapter and target settings. - * Returns 1 if the load was successful and 0 otherwise. - *-F*************************************************************************/ -static void -aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1) -{ - int have_seeprom = 0; - int i, max_targets, mask; - unsigned char scsirate, scsi_conf; - unsigned short scarray[128]; - struct seeprom_config *sc = (struct seeprom_config *) scarray; - - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk(KERN_INFO "aic7xxx: Loading serial EEPROM..."); - } - switch (p->chip) - { - case (AHC_AIC7770|AHC_EISA): /* None of these adapters have seeproms. */ - if (aic_inb(p, SCSICONF) & TERM_ENB) - p->flags |= AHC_TERM_ENB_A; - if ( (p->features & AHC_TWIN) && (aic_inb(p, SCSICONF + 1) & TERM_ENB) ) - p->flags |= AHC_TERM_ENB_B; - break; - - case (AHC_AIC7770|AHC_VL): - have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray); - break; - - default: - have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, p->sc_type); - if (!have_seeprom) - { - if(p->sc_type == C46) - have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, C56_66); - else - have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, C46); - } - if (!have_seeprom) - { - p->sc_size = 128; - have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, p->sc_type); - if (!have_seeprom) - { - if(p->sc_type == C46) - have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, C56_66); - else - have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, C46); - } - } - break; - } - - if (!have_seeprom) - { - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("\naic7xxx: No SEEPROM available.\n"); - } - p->flags |= AHC_NEWEEPROM_FMT; - if (aic_inb(p, SCSISEQ) == 0) - { - p->flags |= AHC_USEDEFAULTS; - p->flags &= ~AHC_BIOS_ENABLED; - p->scsi_id = p->scsi_id_b = 7; - *sxfrctl1 |= STPWEN; - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("aic7xxx: Using default values.\n"); - } - } - else if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("aic7xxx: Using leftover BIOS values.\n"); - } - if ( ((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) && (*sxfrctl1 & STPWEN) ) - { - p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH; - sc->adapter_control &= ~CFAUTOTERM; - sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM; - } - if (aic7xxx_extended) - p->flags |= (AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B); - else - p->flags &= ~(AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B); - } - else - { - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("done\n"); - } - - /* - * Note things in our flags - */ - p->flags |= AHC_SEEPROM_FOUND; - - /* - * Update the settings in sxfrctl1 to match the termination settings. - */ - *sxfrctl1 = 0; - - /* - * Get our SCSI ID from the SEEPROM setting... - */ - p->scsi_id = (sc->brtime_id & CFSCSIID); - - /* - * First process the settings that are different between the VLB - * and PCI adapter seeproms. - */ - if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7770) - { - /* VLB adapter seeproms */ - if (sc->bios_control & CF284XEXTEND) - p->flags |= AHC_EXTEND_TRANS_A; - - if (sc->adapter_control & CF284XSTERM) - { - *sxfrctl1 |= STPWEN; - p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH; - } - } - else - { - /* PCI adapter seeproms */ - if (sc->bios_control & CFEXTEND) - p->flags |= AHC_EXTEND_TRANS_A; - if (sc->bios_control & CFBIOSEN) - p->flags |= AHC_BIOS_ENABLED; - else - p->flags &= ~AHC_BIOS_ENABLED; - - if (sc->adapter_control & CFSTERM) - { - *sxfrctl1 |= STPWEN; - p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH; - } - } - memcpy(&p->sc, sc, sizeof(struct seeprom_config)); - } - - p->discenable = 0; - - /* - * Limit to 16 targets just in case. The 2842 for one is known to - * blow the max_targets setting, future cards might also. - */ - max_targets = ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8); - - if (have_seeprom) - { - for (i = 0; i < max_targets; i++) - { - if( ((p->features & AHC_ULTRA) && - !(sc->adapter_control & CFULTRAEN) && - (sc->device_flags[i] & CFSYNCHISULTRA)) || - (sc->device_flags[i] & CFNEWULTRAFORMAT) ) - { - p->flags |= AHC_NEWEEPROM_FMT; - break; - } - } - } - - for (i = 0; i < max_targets; i++) - { - mask = (0x01 << i); - if (!have_seeprom) - { - if (aic_inb(p, SCSISEQ) != 0) - { - /* - * OK...the BIOS set things up and left behind the settings we need. - * Just make our sc->device_flags[i] entry match what the card has - * set for this device. - */ - p->discenable = - ~(aic_inb(p, DISC_DSB) | (aic_inb(p, DISC_DSB + 1) << 8) ); - p->ultraenb = - (aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8) ); - sc->device_flags[i] = (p->discenable & mask) ? CFDISC : 0; - if (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER) - sc->device_flags[i] |= CFWIDEB; - if (p->features & AHC_ULTRA2) - { - if (aic_inb(p, TARG_OFFSET + i)) - { - sc->device_flags[i] |= CFSYNCH; - sc->device_flags[i] |= (aic_inb(p, TARG_SCSIRATE + i) & 0x07); - if ( (aic_inb(p, TARG_SCSIRATE + i) & 0x18) == 0x18 ) - sc->device_flags[i] |= CFSYNCHISULTRA; - } - } - else - { - if (aic_inb(p, TARG_SCSIRATE + i) & ~WIDEXFER) - { - sc->device_flags[i] |= CFSYNCH; - if (p->features & AHC_ULTRA) - sc->device_flags[i] |= ((p->ultraenb & mask) ? - CFSYNCHISULTRA : 0); - } - } - } - else - { - /* - * Assume the BIOS has NOT been run on this card and nothing between - * the card and the devices is configured yet. - */ - sc->device_flags[i] = CFDISC; - if (p->features & AHC_WIDE) - sc->device_flags[i] |= CFWIDEB; - if (p->features & AHC_ULTRA3) - sc->device_flags[i] |= 2; - else if (p->features & AHC_ULTRA2) - sc->device_flags[i] |= 3; - else if (p->features & AHC_ULTRA) - sc->device_flags[i] |= CFSYNCHISULTRA; - sc->device_flags[i] |= CFSYNCH; - aic_outb(p, 0, TARG_SCSIRATE + i); - if (p->features & AHC_ULTRA2) - aic_outb(p, 0, TARG_OFFSET + i); - } - } - if (sc->device_flags[i] & CFDISC) - { - p->discenable |= mask; - } - if (p->flags & AHC_NEWEEPROM_FMT) - { - if ( !(p->features & AHC_ULTRA2) ) - { - /* - * I know of two different Ultra BIOSes that do this differently. - * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to - * be == to 0x03 and SYNCHISULTRA to be true to mean 40MByte/s - * while on the IBM Netfinity 5000 they want the same thing - * to be something else, while flags[i] & CFXFER == 0x03 and - * SYNCHISULTRA false should be 40MByte/s. So, we set both to - * 40MByte/s and the lower speeds be damned. People will have - * to select around the conversely mapped lower speeds in order - * to select lower speeds on these boards. - */ - if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) && - ((sc->device_flags[i] & CFXFER) == 0x03) ) - { - sc->device_flags[i] &= ~CFXFER; - sc->device_flags[i] |= CFSYNCHISULTRA; - } - if (sc->device_flags[i] & CFSYNCHISULTRA) - { - p->ultraenb |= mask; - } - } - else if ( !(sc->device_flags[i] & CFNEWULTRAFORMAT) && - (p->features & AHC_ULTRA2) && - (sc->device_flags[i] & CFSYNCHISULTRA) ) - { - p->ultraenb |= mask; - } - } - else if (sc->adapter_control & CFULTRAEN) - { - p->ultraenb |= mask; - } - if ( (sc->device_flags[i] & CFSYNCH) == 0) - { - sc->device_flags[i] &= ~CFXFER; - p->ultraenb &= ~mask; - p->user[i].offset = 0; - p->user[i].period = 0; - p->user[i].options = 0; - } - else - { - if (p->features & AHC_ULTRA3) - { - p->user[i].offset = MAX_OFFSET_ULTRA2; - if( (sc->device_flags[i] & CFXFER) < 0x03 ) - { - scsirate = (sc->device_flags[i] & CFXFER); - p->user[i].options = MSG_EXT_PPR_OPTION_DT_CRC; - } - else - { - scsirate = (sc->device_flags[i] & CFXFER) | - ((p->ultraenb & mask) ? 0x18 : 0x10); - p->user[i].options = 0; - } - p->user[i].period = aic7xxx_find_period(p, scsirate, - AHC_SYNCRATE_ULTRA3); - } - else if (p->features & AHC_ULTRA2) - { - p->user[i].offset = MAX_OFFSET_ULTRA2; - scsirate = (sc->device_flags[i] & CFXFER) | - ((p->ultraenb & mask) ? 0x18 : 0x10); - p->user[i].options = 0; - p->user[i].period = aic7xxx_find_period(p, scsirate, - AHC_SYNCRATE_ULTRA2); - } - else - { - scsirate = (sc->device_flags[i] & CFXFER) << 4; - p->user[i].options = 0; - p->user[i].offset = MAX_OFFSET_8BIT; - if (p->features & AHC_ULTRA) - { - short ultraenb; - ultraenb = aic_inb(p, ULTRA_ENB) | - (aic_inb(p, ULTRA_ENB + 1) << 8); - p->user[i].period = aic7xxx_find_period(p, scsirate, - (p->ultraenb & mask) ? - AHC_SYNCRATE_ULTRA : - AHC_SYNCRATE_FAST); - } - else - p->user[i].period = aic7xxx_find_period(p, scsirate, - AHC_SYNCRATE_FAST); - } - } - if ( (sc->device_flags[i] & CFWIDEB) && (p->features & AHC_WIDE) ) - { - p->user[i].width = MSG_EXT_WDTR_BUS_16_BIT; - } - else - { - p->user[i].width = MSG_EXT_WDTR_BUS_8_BIT; - } - } - aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB); - aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1); - - /* - * We set the p->ultraenb from the SEEPROM to begin with, but now we make - * it match what is already down in the card. If we are doing a reset - * on the card then this will get put back to a default state anyway. - * This allows us to not have to pre-emptively negotiate when using the - * no_reset option. - */ - if (p->features & AHC_ULTRA) - p->ultraenb = aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8); - - - scsi_conf = (p->scsi_id & HSCSIID); - - if(have_seeprom) - { - p->adapter_control = sc->adapter_control; - p->bios_control = sc->bios_control; - - switch (p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7895: - case AHC_AIC7896: - case AHC_AIC7899: - if (p->adapter_control & CFBPRIMARY) - p->flags |= AHC_CHANNEL_B_PRIMARY; - default: - break; - } - - if (sc->adapter_control & CFSPARITY) - scsi_conf |= ENSPCHK; - } - else - { - scsi_conf |= ENSPCHK | RESET_SCSI; - } - - /* - * Only set the SCSICONF and SCSICONF + 1 registers if we are a PCI card. - * The 2842 and 2742 cards already have these registers set and we don't - * want to muck with them since we don't set all the bits they do. - */ - if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI ) - { - /* Set the host ID */ - aic_outb(p, scsi_conf, SCSICONF); - /* In case we are a wide card */ - aic_outb(p, p->scsi_id, SCSICONF + 1); - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_configure_bugs - * - * Description: - * Take the card passed in and set the appropriate bug flags based upon - * the card model. Also make any changes needed to device registers or - * PCI registers while we are here. - *-F*************************************************************************/ -static void -aic7xxx_configure_bugs(struct aic7xxx_host *p) -{ - unsigned short tmp_word; - - switch(p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7860: - p->bugs |= AHC_BUG_PCI_2_1_RETRY; - /* fall through */ - case AHC_AIC7850: - case AHC_AIC7870: - p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI; - break; - case AHC_AIC7880: - p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY | - AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI; - break; - case AHC_AIC7890: - p->bugs |= AHC_BUG_AUTOFLUSH | AHC_BUG_CACHETHEN; - break; - case AHC_AIC7892: - p->bugs |= AHC_BUG_SCBCHAN_UPLOAD; - break; - case AHC_AIC7895: - p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY | - AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI; - break; - case AHC_AIC7896: - p->bugs |= AHC_BUG_CACHETHEN_DIS; - break; - case AHC_AIC7899: - p->bugs |= AHC_BUG_SCBCHAN_UPLOAD; - break; - default: - /* Nothing to do */ - break; - } - - /* - * Now handle the bugs that require PCI register or card register tweaks - */ - pci_read_config_word(p->pdev, PCI_COMMAND, &tmp_word); - if(p->bugs & AHC_BUG_PCI_MWI) - { - tmp_word &= ~PCI_COMMAND_INVALIDATE; - } - else - { - tmp_word |= PCI_COMMAND_INVALIDATE; - } - pci_write_config_word(p->pdev, PCI_COMMAND, tmp_word); - - if(p->bugs & AHC_BUG_CACHETHEN) - { - aic_outb(p, aic_inb(p, DSCOMMAND0) & ~CACHETHEN, DSCOMMAND0); - } - else if (p->bugs & AHC_BUG_CACHETHEN_DIS) - { - aic_outb(p, aic_inb(p, DSCOMMAND0) | CACHETHEN, DSCOMMAND0); - } - - return; -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_detect - * - * Description: - * Try to detect and register an Adaptec 7770 or 7870 SCSI controller. - * - * XXX - This should really be called aic7xxx_probe(). A sequence of - * probe(), attach()/detach(), and init() makes more sense than - * one do-it-all function. This may be useful when (and if) the - * mid-level SCSI code is overhauled. - *-F*************************************************************************/ -static int -aic7xxx_detect(struct scsi_host_template *template) -{ - struct aic7xxx_host *temp_p = NULL; - struct aic7xxx_host *current_p = NULL; - struct aic7xxx_host *list_p = NULL; - int found = 0; -#if defined(__i386__) || defined(__alpha__) - ahc_flag_type flags = 0; - int type; -#endif - unsigned char sxfrctl1; -#if defined(__i386__) || defined(__alpha__) - unsigned char hcntrl, hostconf; - unsigned int slot, base; -#endif - -#ifdef MODULE - /* - * If we are called as a module, the aic7xxx pointer may not be null - * and it would point to our bootup string, just like on the lilo - * command line. IF not NULL, then process this config string with - * aic7xxx_setup - */ - if(aic7xxx) - aic7xxx_setup(aic7xxx); -#endif - - template->proc_name = "aic7xxx"; - template->sg_tablesize = AIC7XXX_MAX_SG; - - -#ifdef CONFIG_PCI - /* - * PCI-bus probe. - */ - { - static struct - { - unsigned short vendor_id; - unsigned short device_id; - ahc_chip chip; - ahc_flag_type flags; - ahc_feature features; - int board_name_index; - unsigned short seeprom_size; - unsigned short seeprom_type; - } const aic_pdevs[] = { - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7810, AHC_NONE, - AHC_FNONE, AHC_FENONE, 1, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AHC_AIC7850, - AHC_PAGESCBS, AHC_AIC7850_FE, 5, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850, - AHC_PAGESCBS, AHC_AIC7850_FE, 6, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7821, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 7, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 7, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 7, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 7, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MOTHERBOARD, - AHC_AIC7860_FE, 7, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 8, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD, - AHC_AIC7870_FE, 9, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 10, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7870_FE, 11, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7870_FE, 12, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 13, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD, - AHC_AIC7880_FE, 14, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 15, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7880_FE, 16, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7880_FE, 17, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7885, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7886, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE | AHC_NEW_AUTOTERM, 19, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7895_FE, 20, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890, AHC_AIC7890, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 21, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 21, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 22, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 23, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 24, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 25, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 26, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWEN, - AHC_AIC7860_FE, 27, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 28, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 28, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 28, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 28, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 29, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 29, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 29, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 29, - 32, C56_66 }, - }; - - unsigned short command; - unsigned int devconfig, i, oldverbose; - struct pci_dev *pdev = NULL; - - for (i = 0; i < ARRAY_SIZE(aic_pdevs); i++) - { - pdev = NULL; - while ((pdev = pci_get_device(aic_pdevs[i].vendor_id, - aic_pdevs[i].device_id, - pdev))) { - if (pci_enable_device(pdev)) - continue; - if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */ - { - if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2)) - { - printk(KERN_INFO "aic7xxx: The 7810 RAID controller is not " - "supported by\n"); - printk(KERN_INFO " this driver, we are ignoring it.\n"); - } - } - else if ( (temp_p = kzalloc(sizeof(struct aic7xxx_host), - GFP_ATOMIC)) != NULL ) - { - temp_p->chip = aic_pdevs[i].chip | AHC_PCI; - temp_p->flags = aic_pdevs[i].flags; - temp_p->features = aic_pdevs[i].features; - temp_p->board_name_index = aic_pdevs[i].board_name_index; - temp_p->sc_size = aic_pdevs[i].seeprom_size; - temp_p->sc_type = aic_pdevs[i].seeprom_type; - - /* - * Read sundry information from PCI BIOS. - */ - temp_p->irq = pdev->irq; - temp_p->pdev = pdev; - temp_p->pci_bus = pdev->bus->number; - temp_p->pci_device_fn = pdev->devfn; - temp_p->base = pci_resource_start(pdev, 0); - temp_p->mbase = pci_resource_start(pdev, 1); - current_p = list_p; - while(current_p && temp_p) - { - if ( ((current_p->pci_bus == temp_p->pci_bus) && - (current_p->pci_device_fn == temp_p->pci_device_fn)) || - (temp_p->base && (current_p->base == temp_p->base)) || - (temp_p->mbase && (current_p->mbase == temp_p->mbase)) ) - { - /* duplicate PCI entry, skip it */ - kfree(temp_p); - temp_p = NULL; - continue; - } - current_p = current_p->next; - } - if(pci_request_regions(temp_p->pdev, "aic7xxx")) - { - printk("aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk("aic7xxx: I/O ports already in use, ignoring.\n"); - kfree(temp_p); - continue; - } - - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("aic7xxx: <%s> at PCI %d/%d\n", - board_names[aic_pdevs[i].board_name_index], - PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn)); - pci_read_config_word(pdev, PCI_COMMAND, &command); - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("aic7xxx: Initial PCI_COMMAND value was 0x%x\n", - (int)command); - } -#ifdef AIC7XXX_STRICT_PCI_SETUP - command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | - PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; -#else - command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; -#endif - command &= ~PCI_COMMAND_INVALIDATE; - if (aic7xxx_pci_parity == 0) - command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY); - pci_write_config_word(pdev, PCI_COMMAND, command); -#ifdef AIC7XXX_STRICT_PCI_SETUP - pci_read_config_dword(pdev, DEVCONFIG, &devconfig); - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig); - } - devconfig |= 0x80000040; - pci_write_config_dword(pdev, DEVCONFIG, devconfig); -#endif /* AIC7XXX_STRICT_PCI_SETUP */ - - temp_p->unpause = INTEN; - temp_p->pause = temp_p->unpause | PAUSE; - if ( ((temp_p->base == 0) && - (temp_p->mbase == 0)) || - (temp_p->irq == 0) ) - { - printk("aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk("aic7xxx: Controller disabled by BIOS, ignoring.\n"); - goto skip_pci_controller; - } - -#ifdef MMAPIO - if ( !(temp_p->base) || !(temp_p->flags & AHC_MULTI_CHANNEL) || - ((temp_p->chip != (AHC_AIC7870 | AHC_PCI)) && - (temp_p->chip != (AHC_AIC7880 | AHC_PCI))) ) - { - temp_p->maddr = ioremap_nocache(temp_p->mbase, 256); - if(temp_p->maddr) - { - /* - * We need to check the I/O with the MMAPed address. Some machines - * simply fail to work with MMAPed I/O and certain controllers. - */ - if(aic_inb(temp_p, HCNTRL) == 0xff) - { - /* - * OK.....we failed our test....go back to programmed I/O - */ - printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to " - "Programmed I/O.\n"); - iounmap(temp_p->maddr); - temp_p->maddr = NULL; - if(temp_p->base == 0) - { - printk("aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk("aic7xxx: Controller disabled by BIOS, ignoring.\n"); - goto skip_pci_controller; - } - } - } - } -#endif - - /* - * We HAVE to make sure the first pause_sequencer() and all other - * subsequent I/O that isn't PCI config space I/O takes place - * after the MMAPed I/O region is configured and tested. The - * problem is the PowerPC architecture that doesn't support - * programmed I/O at all, so we have to have the MMAP I/O set up - * for this pause to even work on those machines. - */ - pause_sequencer(temp_p); - - /* - * Clear out any pending PCI error status messages. Also set - * verbose to 0 so that we don't emit strange PCI error messages - * while cleaning out the current status bits. - */ - oldverbose = aic7xxx_verbose; - aic7xxx_verbose = 0; - aic7xxx_pci_intr(temp_p); - aic7xxx_verbose = oldverbose; - - temp_p->bios_address = 0; - - /* - * Remember how the card was setup in case there is no seeprom. - */ - if (temp_p->features & AHC_ULTRA2) - temp_p->scsi_id = aic_inb(temp_p, SCSIID_ULTRA2) & OID; - else - temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID; - /* - * Get current termination setting - */ - sxfrctl1 = aic_inb(temp_p, SXFRCTL1); - - if (aic7xxx_chip_reset(temp_p) == -1) - { - goto skip_pci_controller; - } - /* - * Very quickly put the term setting back into the register since - * the chip reset may cause odd things to happen. This is to keep - * LVD busses with lots of drives from draining the power out of - * the diffsense line before we get around to running the - * configure_termination() function. Also restore the STPWLEVEL - * bit of DEVCONFIG - */ - aic_outb(temp_p, sxfrctl1, SXFRCTL1); - pci_write_config_dword(temp_p->pdev, DEVCONFIG, devconfig); - sxfrctl1 &= STPWEN; - - /* - * We need to set the CHNL? assignments before loading the SEEPROM - * The 3940 and 3985 cards (original stuff, not any of the later - * stuff) are 7870 and 7880 class chips. The Ultra2 stuff falls - * under 7896 and 7897. The 7895 is in a class by itself :) - */ - switch (temp_p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7870: /* 3840 / 3985 */ - case AHC_AIC7880: /* 3840 UW / 3985 UW */ - if(temp_p->flags & AHC_MULTI_CHANNEL) - { - switch(PCI_SLOT(temp_p->pci_device_fn)) - { - case 5: - temp_p->flags |= AHC_CHNLB; - break; - case 8: - temp_p->flags |= AHC_CHNLB; - break; - case 12: - temp_p->flags |= AHC_CHNLC; - break; - default: - break; - } - } - break; - - case AHC_AIC7895: /* 7895 */ - case AHC_AIC7896: /* 7896/7 */ - case AHC_AIC7899: /* 7899 */ - if (PCI_FUNC(pdev->devfn) != 0) - { - temp_p->flags |= AHC_CHNLB; - } - /* - * The 7895 is the only chipset that sets the SCBSIZE32 param - * in the DEVCONFIG register. The Ultra2 chipsets use - * the DSCOMMAND0 register instead. - */ - if ((temp_p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) - { - pci_read_config_dword(pdev, DEVCONFIG, &devconfig); - devconfig |= SCBSIZE32; - pci_write_config_dword(pdev, DEVCONFIG, devconfig); - } - break; - default: - break; - } - - /* - * Loading of the SEEPROM needs to come after we've set the flags - * to indicate possible CHNLB and CHNLC assigments. Otherwise, - * on 394x and 398x cards we'll end up reading the wrong settings - * for channels B and C - */ - switch (temp_p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7892: - case AHC_AIC7899: - aic_outb(temp_p, 0, SCAMCTL); - /* - * Switch to the alt mode of the chip... - */ - aic_outb(temp_p, aic_inb(temp_p, SFUNCT) | ALT_MODE, SFUNCT); - /* - * Set our options...the last two items set our CRC after x byte - * count in target mode... - */ - aic_outb(temp_p, AUTO_MSGOUT_DE | DIS_MSGIN_DUALEDGE, OPTIONMODE); - aic_outb(temp_p, 0x00, 0x0b); - aic_outb(temp_p, 0x10, 0x0a); - /* - * switch back to normal mode... - */ - aic_outb(temp_p, aic_inb(temp_p, SFUNCT) & ~ALT_MODE, SFUNCT); - aic_outb(temp_p, CRCVALCHKEN | CRCENDCHKEN | CRCREQCHKEN | - TARGCRCENDEN | TARGCRCCNTEN, - CRCCONTROL1); - aic_outb(temp_p, ((aic_inb(temp_p, DSCOMMAND0) | USCBSIZE32 | - MPARCKEN | CIOPARCKEN | CACHETHEN) & - ~DPARCKEN), DSCOMMAND0); - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - break; - case AHC_AIC7890: - case AHC_AIC7896: - aic_outb(temp_p, 0, SCAMCTL); - aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | - CACHETHEN | MPARCKEN | USCBSIZE32 | - CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0); - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - break; - case AHC_AIC7850: - case AHC_AIC7860: - /* - * Set the DSCOMMAND0 register on these cards different from - * on the 789x cards. Also, read the SEEPROM as well. - */ - aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | - CACHETHEN | MPARCKEN) & ~DPARCKEN, - DSCOMMAND0); - /* FALLTHROUGH */ - default: - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - break; - case AHC_AIC7880: - /* - * Check the rev of the chipset before we change DSCOMMAND0 - */ - pci_read_config_dword(pdev, DEVCONFIG, &devconfig); - if ((devconfig & 0xff) >= 1) - { - aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | - CACHETHEN | MPARCKEN) & ~DPARCKEN, - DSCOMMAND0); - } - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - break; - } - - - /* - * and then we need another switch based on the type in order to - * make sure the channel B primary flag is set properly on 7895 - * controllers....Arrrgggghhh!!! We also have to catch the fact - * that when you disable the BIOS on the 7895 on the Intel DK440LX - * motherboard, and possibly others, it only sets the BIOS disabled - * bit on the A channel...I think I'm starting to lean towards - * going postal.... - */ - switch(temp_p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7895: - case AHC_AIC7896: - case AHC_AIC7899: - current_p = list_p; - while(current_p != NULL) - { - if ( (current_p->pci_bus == temp_p->pci_bus) && - (PCI_SLOT(current_p->pci_device_fn) == - PCI_SLOT(temp_p->pci_device_fn)) ) - { - if ( PCI_FUNC(current_p->pci_device_fn) == 0 ) - { - temp_p->flags |= - (current_p->flags & AHC_CHANNEL_B_PRIMARY); - temp_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS); - temp_p->flags |= - (current_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS)); - } - else - { - current_p->flags |= - (temp_p->flags & AHC_CHANNEL_B_PRIMARY); - current_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS); - current_p->flags |= - (temp_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS)); - } - } - current_p = current_p->next; - } - break; - default: - break; - } - - /* - * We only support external SCB RAM on the 7895/6/7 chipsets. - * We could support it on the 7890/1 easy enough, but I don't - * know of any 7890/1 based cards that have it. I do know - * of 7895/6/7 cards that have it and they work properly. - */ - switch(temp_p->chip & AHC_CHIPID_MASK) - { - default: - break; - case AHC_AIC7895: - case AHC_AIC7896: - case AHC_AIC7899: - pci_read_config_dword(pdev, DEVCONFIG, &devconfig); - if (temp_p->features & AHC_ULTRA2) - { - if ( (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) && - (aic7xxx_scbram) ) - { - aic_outb(temp_p, - aic_inb(temp_p, DSCOMMAND0) & ~SCBRAMSEL_ULTRA2, - DSCOMMAND0); - temp_p->flags |= AHC_EXTERNAL_SRAM; - devconfig |= EXTSCBPEN; - } - else if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) - { - printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk("aic7xxx: external SCB RAM detected, " - "but not enabled\n"); - } - } - else - { - if ((devconfig & RAMPSM) && (aic7xxx_scbram)) - { - devconfig &= ~SCBRAMSEL; - devconfig |= EXTSCBPEN; - temp_p->flags |= AHC_EXTERNAL_SRAM; - } - else if (devconfig & RAMPSM) - { - printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk("aic7xxx: external SCB RAM detected, " - "but not enabled\n"); - } - } - pci_write_config_dword(pdev, DEVCONFIG, devconfig); - if ( (temp_p->flags & AHC_EXTERNAL_SRAM) && - (temp_p->flags & AHC_CHNLB) ) - aic_outb(temp_p, 1, CCSCBBADDR); - break; - } - - /* - * Take the LED out of diagnostic mode - */ - aic_outb(temp_p, - (aic_inb(temp_p, SBLKCTL) & ~(DIAGLEDEN | DIAGLEDON)), - SBLKCTL); - - /* - * We don't know where this is set in the SEEPROM or by the - * BIOS, so we default to 100%. On Ultra2 controllers, use 75% - * instead. - */ - if (temp_p->features & AHC_ULTRA2) - { - aic_outb(temp_p, RD_DFTHRSH_MAX | WR_DFTHRSH_MAX, DFF_THRSH); - } - else - { - aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS); - } - - /* - * Call our function to fixup any bugs that exist on this chipset. - * This may muck with PCI settings and other device settings, so - * make sure it's after all the other PCI and device register - * tweaks so it can back out bad settings on specific broken cards. - */ - aic7xxx_configure_bugs(temp_p); - - /* Hold a pci device reference */ - pci_dev_get(temp_p->pdev); - - if ( list_p == NULL ) - { - list_p = current_p = temp_p; - } - else - { - current_p = list_p; - while(current_p->next != NULL) - current_p = current_p->next; - current_p->next = temp_p; - } - temp_p->next = NULL; - found++; - continue; -skip_pci_controller: -#ifdef CONFIG_PCI - pci_release_regions(temp_p->pdev); -#endif - kfree(temp_p); - } /* Found an Adaptec PCI device. */ - else /* Well, we found one, but we couldn't get any memory */ - { - printk("aic7xxx: Found <%s>\n", - board_names[aic_pdevs[i].board_name_index]); - printk(KERN_INFO "aic7xxx: Unable to allocate device memory, " - "skipping.\n"); - } - } /* while(pdev=....) */ - } /* for PCI_DEVICES */ - } -#endif /* CONFIG_PCI */ - -#if defined(__i386__) || defined(__alpha__) - /* - * EISA/VL-bus card signature probe. - */ - slot = MINSLOT; - while ( (slot <= MAXSLOT) && - !(aic7xxx_no_probe) ) - { - base = SLOTBASE(slot) + MINREG; - - if (!request_region(base, MAXREG - MINREG, "aic7xxx")) - { - /* - * Some other driver has staked a - * claim to this i/o region already. - */ - slot++; - continue; /* back to the beginning of the for loop */ - } - flags = 0; - type = aic7xxx_probe(slot, base + AHC_HID0, &flags); - if (type == -1) - { - release_region(base, MAXREG - MINREG); - slot++; - continue; - } - temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC); - if (temp_p == NULL) - { - printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n"); - release_region(base, MAXREG - MINREG); - slot++; - continue; /* back to the beginning of the while loop */ - } - - /* - * Pause the card preserving the IRQ type. Allow the operator - * to override the IRQ trigger. - */ - if (aic7xxx_irq_trigger == 1) - hcntrl = IRQMS; /* Level */ - else if (aic7xxx_irq_trigger == 0) - hcntrl = 0; /* Edge */ - else - hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */ - memset(temp_p, 0, sizeof(struct aic7xxx_host)); - temp_p->unpause = hcntrl | INTEN; - temp_p->pause = hcntrl | PAUSE | INTEN; - temp_p->base = base; - temp_p->mbase = 0; - temp_p->maddr = NULL; - temp_p->pci_bus = 0; - temp_p->pci_device_fn = slot; - aic_outb(temp_p, hcntrl | PAUSE, HCNTRL); - while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ; - if (aic7xxx_chip_reset(temp_p) == -1) - temp_p->irq = 0; - else - temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F; - temp_p->flags |= AHC_PAGESCBS; - - switch (temp_p->irq) - { - case 9: - case 10: - case 11: - case 12: - case 14: - case 15: - break; - - default: - printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ " - "level %d, ignoring.\n", temp_p->irq); - kfree(temp_p); - release_region(base, MAXREG - MINREG); - slot++; - continue; /* back to the beginning of the while loop */ - } - - /* - * We are committed now, everything has been checked and this card - * has been found, now we just set it up - */ - - /* - * Insert our new struct into the list at the end - */ - if (list_p == NULL) - { - list_p = current_p = temp_p; - } - else - { - current_p = list_p; - while (current_p->next != NULL) - current_p = current_p->next; - current_p->next = temp_p; - } - - switch (type) - { - case 0: - temp_p->board_name_index = 2; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("aic7xxx: <%s> at EISA %d\n", - board_names[2], slot); - /* FALLTHROUGH */ - case 1: - { - temp_p->chip = AHC_AIC7770 | AHC_EISA; - temp_p->features |= AHC_AIC7770_FE; - temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL); - - /* - * Get the primary channel information. Right now we don't - * do anything with this, but someday we will be able to inform - * the mid-level SCSI code which channel is primary. - */ - if (temp_p->board_name_index == 0) - { - temp_p->board_name_index = 3; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("aic7xxx: <%s> at EISA %d\n", - board_names[3], slot); - } - if (temp_p->bios_control & CHANNEL_B_PRIMARY) - { - temp_p->flags |= AHC_CHANNEL_B_PRIMARY; - } - - if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED) - { - temp_p->flags &= ~AHC_BIOS_ENABLED; - } - else - { - temp_p->flags &= ~AHC_USEDEFAULTS; - temp_p->flags |= AHC_BIOS_ENABLED; - if ( (temp_p->bios_control & 0x20) == 0 ) - { - temp_p->bios_address = 0xcc000; - temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07)); - } - else - { - temp_p->bios_address = 0xd0000; - temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06)); - } - } - temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8; - temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1); - if (temp_p->features & AHC_WIDE) - { - temp_p->scsi_id = temp_p->adapter_control & HWSCSIID; - temp_p->scsi_id_b = temp_p->scsi_id; - } - else - { - temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID; - temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID; - } - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - break; - } - - case 2: - case 3: - temp_p->chip = AHC_AIC7770 | AHC_VL; - temp_p->features |= AHC_AIC7770_FE; - if (type == 2) - temp_p->flags |= AHC_BIOS_ENABLED; - else - temp_p->flags &= ~AHC_BIOS_ENABLED; - if (aic_inb(temp_p, SCSICONF) & TERM_ENB) - sxfrctl1 = STPWEN; - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - temp_p->board_name_index = 4; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("aic7xxx: <%s> at VLB %d\n", - board_names[2], slot); - switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL ) - { - case 0x00: - temp_p->bios_address = 0xe0000; - break; - case 0x20: - temp_p->bios_address = 0xc8000; - break; - case 0x40: - temp_p->bios_address = 0xd0000; - break; - case 0x60: - temp_p->bios_address = 0xd8000; - break; - default: - break; /* can't get here */ - } - break; - - default: /* Won't get here. */ - break; - } - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n", - (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base, - temp_p->irq, - (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered"); - printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n", - (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis"); - } - - /* - * All the 7770 based chipsets have this bug - */ - temp_p->bugs |= AHC_BUG_TMODE_WIDEODD; - - /* - * Set the FIFO threshold and the bus off time. - */ - hostconf = aic_inb(temp_p, HOSTCONF); - aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD); - aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME); - slot++; - found++; - } - -#endif /* defined(__i386__) || defined(__alpha__) */ - - /* - * Now, we re-order the probed devices by BIOS address and BUS class. - * In general, we follow this algorithm to make the adapters show up - * in the same order under linux that the computer finds them. - * 1: All VLB/EISA cards with BIOS_ENABLED first, according to BIOS - * address, going from lowest to highest. - * 2: All PCI controllers with BIOS_ENABLED next, according to BIOS - * address, going from lowest to highest. - * 3: Remaining VLB/EISA controllers going in slot order. - * 4: Remaining PCI controllers, going in PCI device order (reversible) - */ - - { - struct aic7xxx_host *sort_list[4] = { NULL, NULL, NULL, NULL }; - struct aic7xxx_host *vlb, *pci; - struct aic7xxx_host *prev_p; - struct aic7xxx_host *p; - unsigned char left; - - prev_p = vlb = pci = NULL; - - temp_p = list_p; - while (temp_p != NULL) - { - switch(temp_p->chip & ~AHC_CHIPID_MASK) - { - case AHC_EISA: - case AHC_VL: - { - p = temp_p; - if (p->flags & AHC_BIOS_ENABLED) - vlb = sort_list[0]; - else - vlb = sort_list[2]; - - if (vlb == NULL) - { - vlb = temp_p; - temp_p = temp_p->next; - vlb->next = NULL; - } - else - { - current_p = vlb; - prev_p = NULL; - while ( (current_p != NULL) && - (current_p->bios_address < temp_p->bios_address)) - { - prev_p = current_p; - current_p = current_p->next; - } - if (prev_p != NULL) - { - prev_p->next = temp_p; - temp_p = temp_p->next; - prev_p->next->next = current_p; - } - else - { - vlb = temp_p; - temp_p = temp_p->next; - vlb->next = current_p; - } - } - - if (p->flags & AHC_BIOS_ENABLED) - sort_list[0] = vlb; - else - sort_list[2] = vlb; - - break; - } - default: /* All PCI controllers fall through to default */ - { - - p = temp_p; - if (p->flags & AHC_BIOS_ENABLED) - pci = sort_list[1]; - else - pci = sort_list[3]; - - if (pci == NULL) - { - pci = temp_p; - temp_p = temp_p->next; - pci->next = NULL; - } - else - { - current_p = pci; - prev_p = NULL; - if (!aic7xxx_reverse_scan) - { - while ( (current_p != NULL) && - ( (PCI_SLOT(current_p->pci_device_fn) | - (current_p->pci_bus << 8)) < - (PCI_SLOT(temp_p->pci_device_fn) | - (temp_p->pci_bus << 8)) ) ) - { - prev_p = current_p; - current_p = current_p->next; - } - } - else - { - while ( (current_p != NULL) && - ( (PCI_SLOT(current_p->pci_device_fn) | - (current_p->pci_bus << 8)) > - (PCI_SLOT(temp_p->pci_device_fn) | - (temp_p->pci_bus << 8)) ) ) - { - prev_p = current_p; - current_p = current_p->next; - } - } - /* - * Are we dealing with a 7895/6/7/9 where we need to sort the - * channels as well, if so, the bios_address values should - * be the same - */ - if ( (current_p) && (temp_p->flags & AHC_MULTI_CHANNEL) && - (temp_p->pci_bus == current_p->pci_bus) && - (PCI_SLOT(temp_p->pci_device_fn) == - PCI_SLOT(current_p->pci_device_fn)) ) - { - if (temp_p->flags & AHC_CHNLB) - { - if ( !(temp_p->flags & AHC_CHANNEL_B_PRIMARY) ) - { - prev_p = current_p; - current_p = current_p->next; - } - } - else - { - if (temp_p->flags & AHC_CHANNEL_B_PRIMARY) - { - prev_p = current_p; - current_p = current_p->next; - } - } - } - if (prev_p != NULL) - { - prev_p->next = temp_p; - temp_p = temp_p->next; - prev_p->next->next = current_p; - } - else - { - pci = temp_p; - temp_p = temp_p->next; - pci->next = current_p; - } - } - - if (p->flags & AHC_BIOS_ENABLED) - sort_list[1] = pci; - else - sort_list[3] = pci; - - break; - } - } /* End of switch(temp_p->type) */ - } /* End of while (temp_p != NULL) */ - /* - * At this point, the cards have been broken into 4 sorted lists, now - * we run through the lists in order and register each controller - */ - { - int i; - - left = found; - for (i=0; iname = board_names[temp_p->board_name_index]; - p = aic7xxx_alloc(template, temp_p); - if (p != NULL) - { - p->instance = found - left; - if (aic7xxx_register(template, p, (--left)) == 0) - { - found--; - aic7xxx_release(p->host); - scsi_unregister(p->host); - } - else if (aic7xxx_dump_card) - { - pause_sequencer(p); - aic7xxx_print_card(p); - aic7xxx_print_scratch_ram(p); - unpause_sequencer(p, TRUE); - } - } - current_p = temp_p; - temp_p = (struct aic7xxx_host *)temp_p->next; - kfree(current_p); - } - } - } - } - return (found); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_buildscb - * - * Description: - * Build a SCB. - *-F*************************************************************************/ -static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd, - struct aic7xxx_scb *scb) -{ - unsigned short mask; - struct aic7xxx_hwscb *hscb; - struct aic_dev_data *aic_dev = cmd->device->hostdata; - struct scsi_device *sdptr = cmd->device; - unsigned char tindex = TARGET_INDEX(cmd); - int use_sg; - - mask = (0x01 << tindex); - hscb = scb->hscb; - - /* - * Setup the control byte if we need negotiation and have not - * already requested it. - */ - hscb->control = 0; - scb->tag_action = 0; - - if (p->discenable & mask) - { - hscb->control |= DISCENB; - /* We always force TEST_UNIT_READY to untagged */ - if (cmd->cmnd[0] != TEST_UNIT_READY && sdptr->simple_tags) - { - hscb->control |= MSG_SIMPLE_Q_TAG; - scb->tag_action = MSG_SIMPLE_Q_TAG; - } - } - if ( !(aic_dev->dtr_pending) && - (aic_dev->needppr || aic_dev->needwdtr || aic_dev->needsdtr) && - (aic_dev->flags & DEVICE_DTR_SCANNED) ) - { - aic_dev->dtr_pending = 1; - scb->tag_action = 0; - hscb->control &= DISCENB; - hscb->control |= MK_MESSAGE; - if(aic_dev->needppr) - { - scb->flags |= SCB_MSGOUT_PPR; - } - else if(aic_dev->needwdtr) - { - scb->flags |= SCB_MSGOUT_WDTR; - } - else if(aic_dev->needsdtr) - { - scb->flags |= SCB_MSGOUT_SDTR; - } - scb->flags |= SCB_DTR_SCB; - } - hscb->target_channel_lun = ((cmd->device->id << 4) & 0xF0) | - ((cmd->device->channel & 0x01) << 3) | (cmd->device->lun & 0x07); - - /* - * The interpretation of request_buffer and request_bufflen - * changes depending on whether or not use_sg is zero; a - * non-zero use_sg indicates the number of elements in the - * scatter-gather array. - */ - - /* - * XXX - this relies on the host data being stored in a - * little-endian format. - */ - hscb->SCSI_cmd_length = cmd->cmd_len; - memcpy(scb->cmnd, cmd->cmnd, cmd->cmd_len); - hscb->SCSI_cmd_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, scb->cmnd)); - - use_sg = scsi_dma_map(cmd); - BUG_ON(use_sg < 0); - - if (use_sg) { - struct scatterlist *sg; /* Must be mid-level SCSI code scatterlist */ - - /* - * We must build an SG list in adapter format, as the kernel's SG list - * cannot be used directly because of data field size (__alpha__) - * differences and the kernel SG list uses virtual addresses where - * we need physical addresses. - */ - int i; - - scb->sg_length = 0; - - - /* - * Copy the segments into the SG array. NOTE!!! - We used to - * have the first entry both in the data_pointer area and the first - * SG element. That has changed somewhat. We still have the first - * entry in both places, but now we download the address of - * scb->sg_list[1] instead of 0 to the sg pointer in the hscb. - */ - scsi_for_each_sg(cmd, sg, use_sg, i) { - unsigned int len = sg_dma_len(sg); - scb->sg_list[i].address = cpu_to_le32(sg_dma_address(sg)); - scb->sg_list[i].length = cpu_to_le32(len); - scb->sg_length += len; - } - /* Copy the first SG into the data pointer area. */ - hscb->data_pointer = scb->sg_list[0].address; - hscb->data_count = scb->sg_list[0].length; - scb->sg_count = i; - hscb->SG_segment_count = i; - hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[1])); - } else { - scb->sg_count = 0; - scb->sg_length = 0; - hscb->SG_segment_count = 0; - hscb->SG_list_pointer = 0; - hscb->data_count = 0; - hscb->data_pointer = 0; - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_queue - * - * Description: - * Queue a SCB to the controller. - *-F*************************************************************************/ -static int aic7xxx_queue_lck(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)) -{ - struct aic7xxx_host *p; - struct aic7xxx_scb *scb; - struct aic_dev_data *aic_dev; - - p = (struct aic7xxx_host *) cmd->device->host->hostdata; - - aic_dev = cmd->device->hostdata; -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic_dev->active_cmds > aic_dev->max_q_depth) - { - printk(WARN_LEAD "Commands queued exceeds queue " - "depth, active=%d\n", - p->host_no, CTL_OF_CMD(cmd), - aic_dev->active_cmds); - } -#endif - - scb = scbq_remove_head(&p->scb_data->free_scbs); - if (scb == NULL) - { - aic7xxx_allocate_scb(p); - scb = scbq_remove_head(&p->scb_data->free_scbs); - if(scb == NULL) - { - printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no, - CTL_OF_CMD(cmd)); - return 1; - } - } - scb->cmd = cmd; - - /* - * Make sure the scsi_cmnd pointer is saved, the struct it points to - * is set up properly, and the parity error flag is reset, then send - * the SCB to the sequencer and watch the fun begin. - */ - aic7xxx_position(cmd) = scb->hscb->tag; - cmd->scsi_done = fn; - cmd->result = DID_OK; - aic7xxx_error(cmd) = DID_OK; - aic7xxx_status(cmd) = 0; - cmd->host_scribble = NULL; - - /* - * Construct the SCB beforehand, so the sequencer is - * paused a minimal amount of time. - */ - aic7xxx_buildscb(p, cmd, scb); - - scb->flags |= SCB_ACTIVE | SCB_WAITINGQ; - - scbq_insert_tail(&p->waiting_scbs, scb); - aic7xxx_run_waiting_queues(p); - return (0); -} - -static DEF_SCSI_QCMD(aic7xxx_queue) - -/*+F************************************************************************* - * Function: - * aic7xxx_bus_device_reset - * - * Description: - * Abort or reset the current SCSI command(s). If the scb has not - * previously been aborted, then we attempt to send a BUS_DEVICE_RESET - * message to the target. If the scb has previously been unsuccessfully - * aborted, then we will reset the channel and have all devices renegotiate. - * Returns an enumerated type that indicates the status of the operation. - *-F*************************************************************************/ -static int __aic7xxx_bus_device_reset(struct scsi_cmnd *cmd) -{ - struct aic7xxx_host *p; - struct aic7xxx_scb *scb; - struct aic7xxx_hwscb *hscb; - int channel; - unsigned char saved_scbptr, lastphase; - unsigned char hscb_index; - int disconnected; - struct aic_dev_data *aic_dev; - - if(cmd == NULL) - { - printk(KERN_ERR "aic7xxx_bus_device_reset: called with NULL cmd!\n"); - return FAILED; - } - p = (struct aic7xxx_host *)cmd->device->host->hostdata; - aic_dev = AIC_DEV(cmd); - if(aic7xxx_position(cmd) < p->scb_data->numscbs) - scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); - else - return FAILED; - - hscb = scb->hscb; - - aic7xxx_isr(p); - aic7xxx_done_cmds_complete(p); - /* If the command was already complete or just completed, then we didn't - * do a reset, return FAILED */ - if(!(scb->flags & SCB_ACTIVE)) - return FAILED; - - pause_sequencer(p); - lastphase = aic_inb(p, LASTPHASE); - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - { - printk(INFO_LEAD "Bus Device reset, scb flags 0x%x, ", - p->host_no, CTL_OF_SCB(scb), scb->flags); - switch (lastphase) - { - case P_DATAOUT: - printk("Data-Out phase\n"); - break; - case P_DATAIN: - printk("Data-In phase\n"); - break; - case P_COMMAND: - printk("Command phase\n"); - break; - case P_MESGOUT: - printk("Message-Out phase\n"); - break; - case P_STATUS: - printk("Status phase\n"); - break; - case P_MESGIN: - printk("Message-In phase\n"); - break; - default: - /* - * We're not in a valid phase, so assume we're idle. - */ - printk("while idle, LASTPHASE = 0x%x\n", lastphase); - break; - } - printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " - "0x%x\n", p->host_no, CTL_OF_SCB(scb), - aic_inb(p, SCSISIGI), - aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), - aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); - printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", p->host_no, - CTL_OF_SCB(scb), - (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0, - aic_inb(p, SSTAT2), - aic_inb(p, STCNT + 2) << 16 | aic_inb(p, STCNT + 1) << 8 | - aic_inb(p, STCNT)); - } - - channel = cmd->device->channel; - - /* - * Send a Device Reset Message: - * The target that is holding up the bus may not be the same as - * the one that triggered this timeout (different commands have - * different timeout lengths). Our strategy here is to queue an - * abort message to the timed out target if it is disconnected. - * Otherwise, if we have an active target we stuff the message buffer - * with an abort message and assert ATN in the hopes that the target - * will let go of the bus and go to the mesgout phase. If this - * fails, we'll get another timeout a few seconds later which will - * attempt a bus reset. - */ - saved_scbptr = aic_inb(p, SCBPTR); - disconnected = FALSE; - - if (lastphase != P_BUSFREE) - { - if (aic_inb(p, SCB_TAG) >= p->scb_data->numscbs) - { - printk(WARN_LEAD "Invalid SCB ID %d is active, " - "SCB flags = 0x%x.\n", p->host_no, - CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags); - unpause_sequencer(p, FALSE); - return FAILED; - } - if (scb->hscb->tag == aic_inb(p, SCB_TAG)) - { - if ( (lastphase == P_MESGOUT) || (lastphase == P_MESGIN) ) - { - printk(WARN_LEAD "Device reset, Message buffer " - "in use\n", p->host_no, CTL_OF_SCB(scb)); - unpause_sequencer(p, FALSE); - return FAILED; - } - - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Device reset message in " - "message buffer\n", p->host_no, CTL_OF_SCB(scb)); - scb->flags |= SCB_RESET | SCB_DEVICE_RESET; - aic7xxx_error(cmd) = DID_RESET; - aic_dev->flags |= BUS_DEVICE_RESET_PENDING; - /* Send the abort message to the active SCB. */ - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, lastphase | ATNO, SCSISIGO); - unpause_sequencer(p, FALSE); - spin_unlock_irq(p->host->host_lock); - ssleep(1); - spin_lock_irq(p->host->host_lock); - if(aic_dev->flags & BUS_DEVICE_RESET_PENDING) - return FAILED; - else - return SUCCESS; - } - } /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */ - /* - * Simply set the MK_MESSAGE flag and the SEQINT handler will do - * the rest on a reconnect/connect. - */ - scb->hscb->control |= MK_MESSAGE; - scb->flags |= SCB_RESET | SCB_DEVICE_RESET; - aic_dev->flags |= BUS_DEVICE_RESET_PENDING; - /* - * Check to see if the command is on the qinfifo. If it is, then we will - * not need to queue the command again since the card should start it soon - */ - if (aic7xxx_search_qinfifo(p, cmd->device->channel, cmd->device->id, cmd->device->lun, hscb->tag, - 0, TRUE, NULL) == 0) - { - disconnected = TRUE; - if ((hscb_index = aic7xxx_find_scb(p, scb)) != SCB_LIST_NULL) - { - unsigned char scb_control; - - aic_outb(p, hscb_index, SCBPTR); - scb_control = aic_inb(p, SCB_CONTROL); - /* - * If the DISCONNECTED bit is not set in SCB_CONTROL, then we are - * actually on the waiting list, not disconnected, and we don't - * need to requeue the command. - */ - disconnected = (scb_control & DISCONNECTED); - aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL); - } - if (disconnected) - { - /* - * Actually requeue this SCB in case we can select the - * device before it reconnects. This can result in the command - * being on the qinfifo twice, but we don't care because it will - * all get cleaned up if/when the reset takes place. - */ - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Queueing device reset command.\n", p->host_no, - CTL_OF_SCB(scb)); - p->qinfifo[p->qinfifonext++] = scb->hscb->tag; - if (p->features & AHC_QUEUE_REGS) - aic_outb(p, p->qinfifonext, HNSCB_QOFF); - else - aic_outb(p, p->qinfifonext, KERNEL_QINPOS); - scb->flags |= SCB_QUEUED_ABORT; - } - } - aic_outb(p, saved_scbptr, SCBPTR); - unpause_sequencer(p, FALSE); - spin_unlock_irq(p->host->host_lock); - msleep(1000/4); - spin_lock_irq(p->host->host_lock); - if(aic_dev->flags & BUS_DEVICE_RESET_PENDING) - return FAILED; - else - return SUCCESS; -} - -static int aic7xxx_bus_device_reset(struct scsi_cmnd *cmd) -{ - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = __aic7xxx_bus_device_reset(cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_panic_abort - * - * Description: - * Abort the current SCSI command(s). - *-F*************************************************************************/ -static void aic7xxx_panic_abort(struct aic7xxx_host *p, struct scsi_cmnd *cmd) -{ - - printk("aic7xxx driver version %s\n", AIC7XXX_C_VERSION); - printk("Controller type:\n %s\n", board_names[p->board_name_index]); - printk("p->flags=0x%lx, p->chip=0x%x, p->features=0x%x, " - "sequencer %s paused\n", - p->flags, p->chip, p->features, - (aic_inb(p, HCNTRL) & PAUSE) ? "is" : "isn't" ); - pause_sequencer(p); - disable_irq(p->irq); - aic7xxx_print_card(p); - aic7xxx_print_scratch_ram(p); - spin_unlock_irq(p->host->host_lock); - for(;;) barrier(); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_abort - * - * Description: - * Abort the current SCSI command(s). - *-F*************************************************************************/ -static int __aic7xxx_abort(struct scsi_cmnd *cmd) -{ - struct aic7xxx_scb *scb = NULL; - struct aic7xxx_host *p; - int found=0, disconnected; - unsigned char saved_hscbptr, hscbptr, scb_control; - struct aic_dev_data *aic_dev; - - if(cmd == NULL) - { - printk(KERN_ERR "aic7xxx_abort: called with NULL cmd!\n"); - return FAILED; - } - p = (struct aic7xxx_host *)cmd->device->host->hostdata; - aic_dev = AIC_DEV(cmd); - if(aic7xxx_position(cmd) < p->scb_data->numscbs) - scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); - else - return FAILED; - - aic7xxx_isr(p); - aic7xxx_done_cmds_complete(p); - /* If the command was already complete or just completed, then we didn't - * do a reset, return FAILED */ - if(!(scb->flags & SCB_ACTIVE)) - return FAILED; - - pause_sequencer(p); - - /* - * I added a new config option to the driver: "panic_on_abort" that will - * cause the driver to panic and the machine to stop on the first abort - * or reset call into the driver. At that point, it prints out a lot of - * useful information for me which I can then use to try and debug the - * problem. Simply enable the boot time prompt in order to activate this - * code. - */ - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, cmd); - - if (aic7xxx_verbose & VERBOSE_ABORT) - { - printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE " - "0x%x\n", - p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags, - aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), - aic_inb(p, LASTPHASE)); - printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n", - p->host_no, CTL_OF_SCB(scb), (p->features & AHC_ULTRA2) ? - aic_inb(p, SG_CACHEPTR) : 0, aic_inb(p, SG_COUNT), - aic_inb(p, SCSISIGI)); - printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n", - p->host_no, CTL_OF_SCB(scb), aic_inb(p, SSTAT0), - aic_inb(p, SSTAT1), aic_inb(p, SSTAT2)); - } - - if (scb->flags & SCB_WAITINGQ) - { - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "SCB found on waiting list and " - "aborted.\n", p->host_no, CTL_OF_SCB(scb)); - scbq_remove(&p->waiting_scbs, scb); - scbq_remove(&aic_dev->delayed_scbs, scb); - aic_dev->active_cmds++; - p->activescbs++; - scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE); - scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE; - goto success; - } - -/* - * We just checked the waiting_q, now for the QINFIFO - */ - if ( ((found = aic7xxx_search_qinfifo(p, cmd->device->id, cmd->device->channel, - cmd->device->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE, - FALSE, NULL)) != 0) && - (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)) - { - printk(INFO_LEAD "SCB found in QINFIFO and aborted.\n", p->host_no, - CTL_OF_SCB(scb)); - goto success; - } - -/* - * QINFIFO, waitingq, completeq done. Next, check WAITING_SCB list in card - */ - - saved_hscbptr = aic_inb(p, SCBPTR); - if ((hscbptr = aic7xxx_find_scb(p, scb)) != SCB_LIST_NULL) - { - aic_outb(p, hscbptr, SCBPTR); - scb_control = aic_inb(p, SCB_CONTROL); - disconnected = scb_control & DISCONNECTED; - /* - * If the DISCONNECTED bit is not set in SCB_CONTROL, then we are - * either currently active or on the waiting list. - */ - if(!disconnected && aic_inb(p, LASTPHASE) == P_BUSFREE) { - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "SCB found on hardware waiting" - " list and aborted.\n", p->host_no, CTL_OF_SCB(scb)); - /* If we are the only waiting command, stop the selection engine */ - if (aic_inb(p, WAITING_SCBH) == hscbptr && aic_inb(p, SCB_NEXT) == - SCB_LIST_NULL) - { - aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); - aic_outb(p, CLRSELTIMEO, CLRSINT1); - aic_outb(p, SCB_LIST_NULL, WAITING_SCBH); - } - else - { - unsigned char prev, next; - prev = SCB_LIST_NULL; - next = aic_inb(p, WAITING_SCBH); - while(next != SCB_LIST_NULL) - { - aic_outb(p, next, SCBPTR); - if (next == hscbptr) - { - next = aic_inb(p, SCB_NEXT); - if (prev != SCB_LIST_NULL) - { - aic_outb(p, prev, SCBPTR); - aic_outb(p, next, SCB_NEXT); - } - else - aic_outb(p, next, WAITING_SCBH); - aic_outb(p, hscbptr, SCBPTR); - next = SCB_LIST_NULL; - } - else - { - prev = next; - next = aic_inb(p, SCB_NEXT); - } - } - } - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic_outb(p, 0, SCB_CONTROL); - aic7xxx_add_curscb_to_free_list(p); - scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE; - goto success; - } - else if (!disconnected) - { - /* - * We are the currently active command - */ - if((aic_inb(p, LASTPHASE) == P_MESGIN) || - (aic_inb(p, LASTPHASE) == P_MESGOUT)) - { - /* - * Message buffer busy, unable to abort - */ - printk(INFO_LEAD "message buffer busy, unable to abort.\n", - p->host_no, CTL_OF_SCB(scb)); - unpause_sequencer(p, FALSE); - return FAILED; - } - /* Fallthrough to below, set ATNO after we set SCB_CONTROL */ - } - aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL); - if(!disconnected) - { - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); - } - aic_outb(p, saved_hscbptr, SCBPTR); - } - else - { - /* - * The scb isn't in the card at all and it is active and it isn't in - * any of the queues, so it must be disconnected and paged out. Fall - * through to the code below. - */ - disconnected = 1; - } - - p->flags |= AHC_ABORT_PENDING; - scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB; - scb->hscb->control |= MK_MESSAGE; - if(disconnected) - { - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "SCB disconnected. Queueing Abort" - " SCB.\n", p->host_no, CTL_OF_SCB(scb)); - p->qinfifo[p->qinfifonext++] = scb->hscb->tag; - if (p->features & AHC_QUEUE_REGS) - aic_outb(p, p->qinfifonext, HNSCB_QOFF); - else - aic_outb(p, p->qinfifonext, KERNEL_QINPOS); - } - unpause_sequencer(p, FALSE); - spin_unlock_irq(p->host->host_lock); - msleep(1000/4); - spin_lock_irq(p->host->host_lock); - if (p->flags & AHC_ABORT_PENDING) - { - if (aic7xxx_verbose & VERBOSE_ABORT_RETURN) - printk(INFO_LEAD "Abort never delivered, returning FAILED\n", p->host_no, - CTL_OF_CMD(cmd)); - p->flags &= ~AHC_ABORT_PENDING; - return FAILED; - } - if (aic7xxx_verbose & VERBOSE_ABORT_RETURN) - printk(INFO_LEAD "Abort successful.\n", p->host_no, CTL_OF_CMD(cmd)); - return SUCCESS; - -success: - if (aic7xxx_verbose & VERBOSE_ABORT_RETURN) - printk(INFO_LEAD "Abort successful.\n", p->host_no, CTL_OF_CMD(cmd)); - aic7xxx_run_done_queue(p, TRUE); - unpause_sequencer(p, FALSE); - return SUCCESS; -} - -static int aic7xxx_abort(struct scsi_cmnd *cmd) -{ - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = __aic7xxx_abort(cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_reset - * - * Description: - * Resetting the bus always succeeds - is has to, otherwise the - * kernel will panic! Try a surgical technique - sending a BUS - * DEVICE RESET message - on the offending target before pulling - * the SCSI bus reset line. - *-F*************************************************************************/ -static int aic7xxx_reset(struct scsi_cmnd *cmd) -{ - struct aic7xxx_scb *scb; - struct aic7xxx_host *p; - struct aic_dev_data *aic_dev; - - p = (struct aic7xxx_host *) cmd->device->host->hostdata; - spin_lock_irq(p->host->host_lock); - - aic_dev = AIC_DEV(cmd); - if(aic7xxx_position(cmd) < p->scb_data->numscbs) - { - scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); - if (scb->cmd != cmd) - scb = NULL; - } - else - { - scb = NULL; - } - - /* - * I added a new config option to the driver: "panic_on_abort" that will - * cause the driver to panic and the machine to stop on the first abort - * or reset call into the driver. At that point, it prints out a lot of - * useful information for me which I can then use to try and debug the - * problem. Simply enable the boot time prompt in order to activate this - * code. - */ - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, cmd); - - pause_sequencer(p); - - while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) - { - aic7xxx_isr(p); - pause_sequencer(p); - } - aic7xxx_done_cmds_complete(p); - - if(scb && (scb->cmd == NULL)) - { - /* - * We just completed the command when we ran the isr stuff, so we no - * longer have it. - */ - unpause_sequencer(p, FALSE); - spin_unlock_irq(p->host->host_lock); - return SUCCESS; - } - -/* - * By this point, we want to already know what we are going to do and - * only have the following code implement our course of action. - */ - aic7xxx_reset_channel(p, cmd->device->channel, TRUE); - if (p->features & AHC_TWIN) - { - aic7xxx_reset_channel(p, cmd->device->channel ^ 0x01, TRUE); - restart_sequencer(p); - } - aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1); - aic7xxx_clear_intstat(p); - p->flags &= ~AHC_HANDLING_REQINITS; - p->msg_type = MSG_TYPE_NONE; - p->msg_index = 0; - p->msg_len = 0; - aic7xxx_run_done_queue(p, TRUE); - unpause_sequencer(p, FALSE); - spin_unlock_irq(p->host->host_lock); - ssleep(2); - return SUCCESS; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_biosparam - * - * Description: - * Return the disk geometry for the given SCSI device. - * - * Note: - * This function is broken for today's really large drives and needs - * fixed. - *-F*************************************************************************/ -static int -aic7xxx_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]) -{ - sector_t heads, sectors, cylinders; - int ret; - struct aic7xxx_host *p; - unsigned char *buf; - - p = (struct aic7xxx_host *) sdev->host->hostdata; - buf = scsi_bios_ptable(bdev); - - if ( buf ) - { - ret = scsi_partsize(buf, capacity, &geom[2], &geom[0], &geom[1]); - kfree(buf); - if ( ret != -1 ) - return(ret); - } - - heads = 64; - sectors = 32; - cylinders = capacity >> 11; - - if ((p->flags & AHC_EXTEND_TRANS_A) && (cylinders > 1024)) - { - heads = 255; - sectors = 63; - cylinders = capacity >> 14; - if(capacity > (65535 * heads * sectors)) - cylinders = 65535; - else - cylinders = ((unsigned int)capacity) / (unsigned int)(heads * sectors); - } - - geom[0] = (int)heads; - geom[1] = (int)sectors; - geom[2] = (int)cylinders; - - return (0); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_release - * - * Description: - * Free the passed in Scsi_Host memory structures prior to unloading the - * module. - *-F*************************************************************************/ -static int -aic7xxx_release(struct Scsi_Host *host) -{ - struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata; - struct aic7xxx_host *next, *prev; - - if(p->irq) - free_irq(p->irq, p); -#ifdef MMAPIO - if(p->maddr) - { - iounmap(p->maddr); - } -#endif /* MMAPIO */ - if(!p->pdev) - release_region(p->base, MAXREG - MINREG); -#ifdef CONFIG_PCI - else { - pci_release_regions(p->pdev); - pci_dev_put(p->pdev); - } -#endif - prev = NULL; - next = first_aic7xxx; - while(next != NULL) - { - if(next == p) - { - if(prev == NULL) - first_aic7xxx = next->next; - else - prev->next = next->next; - } - else - { - prev = next; - } - next = next->next; - } - aic7xxx_free(p); - return(0); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_print_card - * - * Description: - * Print out all of the control registers on the card - * - * NOTE: This function is not yet safe for use on the VLB and EISA - * controllers, so it isn't used on those controllers at all. - *-F*************************************************************************/ -static void -aic7xxx_print_card(struct aic7xxx_host *p) -{ - int i, j, k, chip; - static struct register_ranges { - int num_ranges; - int range_val[32]; - } cards_ds[] = { - { 0, {0,} }, /* none */ - {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1f, 0x1f, 0x60, 0x60, /*7771*/ - 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9b, 0x9f} }, - { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7850*/ - 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, - { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7860*/ - 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, - {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1c, 0x1f, 0x60, 0x60, /*7870*/ - 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, - {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1a, 0x1c, 0x1f, 0x60, 0x60, /*7880*/ - 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, - {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7890*/ - 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f, - 0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc, - 0xfe, 0xff} }, - {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1b, 0x1f, 0x60, 0x60, /*7895*/ - 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, - 0x9f, 0x9f, 0xe0, 0xf1} }, - {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7896*/ - 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f, - 0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc, - 0xfe, 0xff} }, - {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7892*/ - 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f, - 0xe0, 0xf1, 0xf4, 0xfc} }, - {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7899*/ - 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f, - 0xe0, 0xf1, 0xf4, 0xfc} }, - }; - chip = p->chip & AHC_CHIPID_MASK; - printk("%s at ", - board_names[p->board_name_index]); - switch(p->chip & ~AHC_CHIPID_MASK) - { - case AHC_VL: - printk("VLB Slot %d.\n", p->pci_device_fn); - break; - case AHC_EISA: - printk("EISA Slot %d.\n", p->pci_device_fn); - break; - case AHC_PCI: - default: - printk("PCI %d/%d/%d.\n", p->pci_bus, PCI_SLOT(p->pci_device_fn), - PCI_FUNC(p->pci_device_fn)); - break; - } - - /* - * the registers on the card.... - */ - printk("Card Dump:\n"); - k = 0; - for(i=0; ifeatures & AHC_QUEUE_REGS) - { - aic_outb(p, 0, SDSCB_QOFF); - aic_outb(p, 0, SNSCB_QOFF); - aic_outb(p, 0, HNSCB_QOFF); - } - -} - -/*+F************************************************************************* - * Function: - * aic7xxx_print_scratch_ram - * - * Description: - * Print out the scratch RAM values on the card. - *-F*************************************************************************/ -static void -aic7xxx_print_scratch_ram(struct aic7xxx_host *p) -{ - int i, k; - - k = 0; - printk("Scratch RAM:\n"); - for(i = SRAM_BASE; i < SEQCTL; i++) - { - printk("%02x:%02x ", i, aic_inb(p, i)); - if(++k == 13) - { - printk("\n"); - k=0; - } - } - if (p->features & AHC_MORE_SRAM) - { - for(i = TARG_OFFSET; i < 0x80; i++) - { - printk("%02x:%02x ", i, aic_inb(p, i)); - if(++k == 13) - { - printk("\n"); - k=0; - } - } - } - printk("\n"); -} - - -#include "aic7xxx_old/aic7xxx_proc.c" - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION(AIC7XXX_H_VERSION); - - -static struct scsi_host_template driver_template = { - .show_info = aic7xxx_show_info, - .detect = aic7xxx_detect, - .release = aic7xxx_release, - .info = aic7xxx_info, - .queuecommand = aic7xxx_queue, - .slave_alloc = aic7xxx_slave_alloc, - .slave_configure = aic7xxx_slave_configure, - .slave_destroy = aic7xxx_slave_destroy, - .bios_param = aic7xxx_biosparam, - .eh_abort_handler = aic7xxx_abort, - .eh_device_reset_handler = aic7xxx_bus_device_reset, - .eh_host_reset_handler = aic7xxx_reset, - .can_queue = 255, - .this_id = -1, - .max_sectors = 2048, - .cmd_per_lun = 3, - .use_clustering = ENABLE_CLUSTERING, -}; - -#include "scsi_module.c" - -/* - * Overrides for Emacs so that we almost follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 2 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -2 - * c-argdecl-indent: 2 - * c-label-offset: -2 - * c-continued-statement-offset: 2 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ diff --git a/drivers/scsi/aic7xxx_old/aic7xxx.h b/drivers/scsi/aic7xxx_old/aic7xxx.h deleted file mode 100644 index 0116c8128a6b..000000000000 --- a/drivers/scsi/aic7xxx_old/aic7xxx.h +++ /dev/null @@ -1,28 +0,0 @@ -/*+M************************************************************************* - * Adaptec AIC7xxx device driver for Linux. - * - * Copyright (c) 1994 John Aycock - * The University of Calgary Department of Computer Science. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $ - *-M*************************************************************************/ -#ifndef _aic7xxx_h -#define _aic7xxx_h - -#define AIC7XXX_H_VERSION "5.2.0" - -#endif /* _aic7xxx_h */ diff --git a/drivers/scsi/aic7xxx_old/aic7xxx.reg b/drivers/scsi/aic7xxx_old/aic7xxx.reg deleted file mode 100644 index f67b4bced01c..000000000000 --- a/drivers/scsi/aic7xxx_old/aic7xxx.reg +++ /dev/null @@ -1,1401 +0,0 @@ -/* - * Aic7xxx register and scratch ram definitions. - * - * Copyright (c) 1994-1998 Justin Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU General Public License ("GPL") and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: aic7xxx.reg,v 1.4 1997/06/27 19:38:39 gibbs Exp $ - */ - -/* - * This file is processed by the aic7xxx_asm utility for use in assembling - * firmware for the aic7xxx family of SCSI host adapters as well as to generate - * a C header file for use in the kernel portion of the Aic7xxx driver. - * - * All page numbers refer to the Adaptec AIC-7770 Data Book available from - * Adaptec's Technical Documents Department 1-800-934-2766 - */ - -/* - * SCSI Sequence Control (p. 3-11). - * Each bit, when set starts a specific SCSI sequence on the bus - */ -register SCSISEQ { - address 0x000 - access_mode RW - bit TEMODE 0x80 - bit ENSELO 0x40 - bit ENSELI 0x20 - bit ENRSELI 0x10 - bit ENAUTOATNO 0x08 - bit ENAUTOATNI 0x04 - bit ENAUTOATNP 0x02 - bit SCSIRSTO 0x01 -} - -/* - * SCSI Transfer Control 0 Register (pp. 3-13). - * Controls the SCSI module data path. - */ -register SXFRCTL0 { - address 0x001 - access_mode RW - bit DFON 0x80 - bit DFPEXP 0x40 - bit FAST20 0x20 - bit CLRSTCNT 0x10 - bit SPIOEN 0x08 - bit SCAMEN 0x04 - bit CLRCHN 0x02 -} - -/* - * SCSI Transfer Control 1 Register (pp. 3-14,15). - * Controls the SCSI module data path. - */ -register SXFRCTL1 { - address 0x002 - access_mode RW - bit BITBUCKET 0x80 - bit SWRAPEN 0x40 - bit ENSPCHK 0x20 - mask STIMESEL 0x18 - bit ENSTIMER 0x04 - bit ACTNEGEN 0x02 - bit STPWEN 0x01 /* Powered Termination */ -} - -/* - * SCSI Control Signal Read Register (p. 3-15). - * Reads the actual state of the SCSI bus pins - */ -register SCSISIGI { - address 0x003 - access_mode RO - bit CDI 0x80 - bit IOI 0x40 - bit MSGI 0x20 - bit ATNI 0x10 - bit SELI 0x08 - bit BSYI 0x04 - bit REQI 0x02 - bit ACKI 0x01 -/* - * Possible phases in SCSISIGI - */ - mask PHASE_MASK CDI|IOI|MSGI - mask P_DATAOUT 0x00 - mask P_DATAIN IOI - mask P_COMMAND CDI - mask P_MESGOUT CDI|MSGI - mask P_STATUS CDI|IOI - mask P_MESGIN CDI|IOI|MSGI -} - -/* - * SCSI Control Signal Write Register (p. 3-16). - * Writing to this register modifies the control signals on the bus. Only - * those signals that are allowed in the current mode (Initiator/Target) are - * asserted. - */ -register SCSISIGO { - address 0x003 - access_mode WO - bit CDO 0x80 - bit IOO 0x40 - bit MSGO 0x20 - bit ATNO 0x10 - bit SELO 0x08 - bit BSYO 0x04 - bit REQO 0x02 - bit ACKO 0x01 -/* - * Possible phases to write into SCSISIG0 - */ - mask PHASE_MASK CDI|IOI|MSGI - mask P_DATAOUT 0x00 - mask P_DATAIN IOI - mask P_COMMAND CDI - mask P_MESGOUT CDI|MSGI - mask P_STATUS CDI|IOI - mask P_MESGIN CDI|IOI|MSGI -} - -/* - * SCSI Rate Control (p. 3-17). - * Contents of this register determine the Synchronous SCSI data transfer - * rate and the maximum synchronous Req/Ack offset. An offset of 0 in the - * SOFS (3:0) bits disables synchronous data transfers. Any offset value - * greater than 0 enables synchronous transfers. - */ -register SCSIRATE { - address 0x004 - access_mode RW - bit WIDEXFER 0x80 /* Wide transfer control */ - mask SXFR 0x70 /* Sync transfer rate */ - mask SXFR_ULTRA2 0x7f /* Sync transfer rate */ - mask SOFS 0x0f /* Sync offset */ -} - -/* - * SCSI ID (p. 3-18). - * Contains the ID of the board and the current target on the - * selected channel. - */ -register SCSIID { - address 0x005 - access_mode RW - mask TID 0xf0 /* Target ID mask */ - mask OID 0x0f /* Our ID mask */ - /* - * SCSI Maximum Offset (p. 4-61 aic7890/91 Data Book) - * The aic7890/91 allow an offset of up to 127 transfers in both wide - * and narrow mode. - */ - alias SCSIOFFSET - mask SOFS_ULTRA2 0x7f /* Sync offset U2 chips */ -} - -/* - * SCSI Latched Data (p. 3-19). - * Read/Write latches used to transfer data on the SCSI bus during - * Automatic or Manual PIO mode. SCSIDATH can be used for the - * upper byte of a 16bit wide asynchronouse data phase transfer. - */ -register SCSIDATL { - address 0x006 - access_mode RW -} - -register SCSIDATH { - address 0x007 - access_mode RW -} - -/* - * SCSI Transfer Count (pp. 3-19,20) - * These registers count down the number of bytes transferred - * across the SCSI bus. The counter is decremented only once - * the data has been safely transferred. SDONE in SSTAT0 is - * set when STCNT goes to 0 - */ -register STCNT { - address 0x008 - size 3 - access_mode RW -} - -/* - * Option Mode Register (Alternate Mode) (p. 5-198) - * This register is used to set certain options on Ultra3 based chips. - * The chip must be in alternate mode (bit ALT_MODE in SFUNCT must be set) - */ -register OPTIONMODE { - address 0x008 - access_mode RW - bit AUTORATEEN 0x80 - bit AUTOACKEN 0x40 - bit ATNMGMNTEN 0x20 - bit BUSFREEREV 0x10 - bit EXPPHASEDIS 0x08 - bit SCSIDATL_IMGEN 0x04 - bit AUTO_MSGOUT_DE 0x02 - bit DIS_MSGIN_DUALEDGE 0x01 -} - - -/* - * Clear SCSI Interrupt 0 (p. 3-20) - * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0. - */ -register CLRSINT0 { - address 0x00b - access_mode WO - bit CLRSELDO 0x40 - bit CLRSELDI 0x20 - bit CLRSELINGO 0x10 - bit CLRSWRAP 0x08 - bit CLRSPIORDY 0x02 -} - -/* - * SCSI Status 0 (p. 3-21) - * Contains one set of SCSI Interrupt codes - * These are most likely of interest to the sequencer - */ -register SSTAT0 { - address 0x00b - access_mode RO - bit TARGET 0x80 /* Board acting as target */ - bit SELDO 0x40 /* Selection Done */ - bit SELDI 0x20 /* Board has been selected */ - bit SELINGO 0x10 /* Selection In Progress */ - bit SWRAP 0x08 /* 24bit counter wrap */ - bit IOERR 0x08 /* LVD Tranceiver mode changed */ - bit SDONE 0x04 /* STCNT = 0x000000 */ - bit SPIORDY 0x02 /* SCSI PIO Ready */ - bit DMADONE 0x01 /* DMA transfer completed */ -} - -/* - * Clear SCSI Interrupt 1 (p. 3-23) - * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1. - */ -register CLRSINT1 { - address 0x00c - access_mode WO - bit CLRSELTIMEO 0x80 - bit CLRATNO 0x40 - bit CLRSCSIRSTI 0x20 - bit CLRBUSFREE 0x08 - bit CLRSCSIPERR 0x04 - bit CLRPHASECHG 0x02 - bit CLRREQINIT 0x01 -} - -/* - * SCSI Status 1 (p. 3-24) - */ -register SSTAT1 { - address 0x00c - access_mode RO - bit SELTO 0x80 - bit ATNTARG 0x40 - bit SCSIRSTI 0x20 - bit PHASEMIS 0x10 - bit BUSFREE 0x08 - bit SCSIPERR 0x04 - bit PHASECHG 0x02 - bit REQINIT 0x01 -} - -/* - * SCSI Status 2 (pp. 3-25,26) - */ -register SSTAT2 { - address 0x00d - access_mode RO - bit OVERRUN 0x80 - bit SHVALID 0x40 - bit WIDE_RES 0x20 - bit EXP_ACTIVE 0x10 /* SCSI Expander Active */ - bit CRCVALERR 0x08 /* CRC Value Error */ - bit CRCENDERR 0x04 /* CRC End Error */ - bit CRCREQERR 0x02 /* CRC REQ Error */ - bit DUAL_EDGE_ERROR 0x01 /* Invalid pins for Dual Edge phase */ - mask SFCNT 0x1f -} - -/* - * SCSI Status 3 (p. 3-26) - */ -register SSTAT3 { - address 0x00e - access_mode RO - mask SCSICNT 0xf0 - mask OFFCNT 0x0f -} - -/* - * SCSI ID for the aic7890/91 chips - */ -register SCSIID_ULTRA2 { - address 0x00f - access_mode RW - mask TID 0xf0 /* Target ID mask */ - mask OID 0x0f /* Our ID mask */ -} - -/* - * SCSI Interrupt Mode 1 (p. 3-28) - * Setting any bit will enable the corresponding function - * in SIMODE0 to interrupt via the IRQ pin. - */ -register SIMODE0 { - address 0x010 - access_mode RW - bit ENSELDO 0x40 - bit ENSELDI 0x20 - bit ENSELINGO 0x10 - bit ENSWRAP 0x08 - bit ENIOERR 0x08 /* LVD Tranceiver mode changes */ - bit ENSDONE 0x04 - bit ENSPIORDY 0x02 - bit ENDMADONE 0x01 -} - -/* - * SCSI Interrupt Mode 1 (pp. 3-28,29) - * Setting any bit will enable the corresponding function - * in SIMODE1 to interrupt via the IRQ pin. - */ -register SIMODE1 { - address 0x011 - access_mode RW - bit ENSELTIMO 0x80 - bit ENATNTARG 0x40 - bit ENSCSIRST 0x20 - bit ENPHASEMIS 0x10 - bit ENBUSFREE 0x08 - bit ENSCSIPERR 0x04 - bit ENPHASECHG 0x02 - bit ENREQINIT 0x01 -} - -/* - * SCSI Data Bus (High) (p. 3-29) - * This register reads data on the SCSI Data bus directly. - */ -register SCSIBUSL { - address 0x012 - access_mode RO -} - -register SCSIBUSH { - address 0x013 - access_mode RO -} - -/* - * SCSI/Host Address (p. 3-30) - * These registers hold the host address for the byte about to be - * transferred on the SCSI bus. They are counted up in the same - * manner as STCNT is counted down. SHADDR should always be used - * to determine the address of the last byte transferred since HADDR - * can be skewed by write ahead. - */ -register SHADDR { - address 0x014 - size 4 - access_mode RO -} - -/* - * Selection Timeout Timer (p. 3-30) - */ -register SELTIMER { - address 0x018 - access_mode RW - bit STAGE6 0x20 - bit STAGE5 0x10 - bit STAGE4 0x08 - bit STAGE3 0x04 - bit STAGE2 0x02 - bit STAGE1 0x01 -} - -/* - * Selection/Reselection ID (p. 3-31) - * Upper four bits are the device id. The ONEBIT is set when the re/selecting - * device did not set its own ID. - */ -register SELID { - address 0x019 - access_mode RW - mask SELID_MASK 0xf0 - bit ONEBIT 0x08 -} - -/* - * Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book) - * Indicates if external logic has been attached to the chip to - * perform the tasks of accessing a serial eeprom, testing termination - * strength, and performing cable detection. On the aic7860, most of - * these features are handled on chip, but on the aic7855 an attached - * aic3800 does the grunt work. - */ -register SPIOCAP { - address 0x01b - access_mode RW - bit SOFT1 0x80 - bit SOFT0 0x40 - bit SOFTCMDEN 0x20 - bit HAS_BRDCTL 0x10 /* External Board control */ - bit SEEPROM 0x08 /* External serial eeprom logic */ - bit EEPROM 0x04 /* Writable external BIOS ROM */ - bit ROM 0x02 /* Logic for accessing external ROM */ - bit SSPIOCPS 0x01 /* Termination and cable detection */ -} - -/* - * SCSI Block Control (p. 3-32) - * Controls Bus type and channel selection. In a twin channel configuration - * addresses 0x00-0x1e are gated to the appropriate channel based on this - * register. SELWIDE allows for the coexistence of 8bit and 16bit devices - * on a wide bus. - */ -register SBLKCTL { - address 0x01f - access_mode RW - bit DIAGLEDEN 0x80 /* Aic78X0 only */ - bit DIAGLEDON 0x40 /* Aic78X0 only */ - bit AUTOFLUSHDIS 0x20 - bit SELBUSB 0x08 - bit ENAB40 0x08 /* LVD transceiver active */ - bit ENAB20 0x04 /* SE/HVD transceiver active */ - bit SELWIDE 0x02 - bit XCVR 0x01 /* External transceiver active */ -} - -/* - * Sequencer Control (p. 3-33) - * Error detection mode and speed configuration - */ -register SEQCTL { - address 0x060 - access_mode RW - bit PERRORDIS 0x80 - bit PAUSEDIS 0x40 - bit FAILDIS 0x20 - bit FASTMODE 0x10 - bit BRKADRINTEN 0x08 - bit STEP 0x04 - bit SEQRESET 0x02 - bit LOADRAM 0x01 -} - -/* - * Sequencer RAM Data (p. 3-34) - * Single byte window into the Scratch Ram area starting at the address - * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write - * four bytes in succession. The SEQADDRs will increment after the most - * significant byte is written - */ -register SEQRAM { - address 0x061 - access_mode RW -} - -/* - * Sequencer Address Registers (p. 3-35) - * Only the first bit of SEQADDR1 holds addressing information - */ -register SEQADDR0 { - address 0x062 - access_mode RW -} - -register SEQADDR1 { - address 0x063 - access_mode RW - mask SEQADDR1_MASK 0x01 -} - -/* - * Accumulator - * We cheat by passing arguments in the Accumulator up to the kernel driver - */ -register ACCUM { - address 0x064 - access_mode RW - accumulator -} - -register SINDEX { - address 0x065 - access_mode RW - sindex -} - -register DINDEX { - address 0x066 - access_mode RW -} - -register ALLONES { - address 0x069 - access_mode RO - allones -} - -register ALLZEROS { - address 0x06a - access_mode RO - allzeros -} - -register NONE { - address 0x06a - access_mode WO - none -} - -register FLAGS { - address 0x06b - access_mode RO - bit ZERO 0x02 - bit CARRY 0x01 -} - -register SINDIR { - address 0x06c - access_mode RO -} - -register DINDIR { - address 0x06d - access_mode WO -} - -register FUNCTION1 { - address 0x06e - access_mode RW -} - -register STACK { - address 0x06f - access_mode RO -} - -/* - * Board Control (p. 3-43) - */ -register BCTL { - address 0x084 - access_mode RW - bit ACE 0x08 - bit ENABLE 0x01 -} - -register DSCOMMAND0 { - address 0x084 - access_mode RW - bit CACHETHEN 0x80 - bit DPARCKEN 0x40 - bit MPARCKEN 0x20 - bit EXTREQLCK 0x10 - bit INTSCBRAMSEL 0x08 - bit RAMPS 0x04 - bit USCBSIZE32 0x02 - bit CIOPARCKEN 0x01 -} - -/* - * On the aic78X0 chips, Board Control is replaced by the DSCommand - * register (p. 4-64) - */ -register DSCOMMAND { - address 0x084 - access_mode RW - bit CACHETHEN 0x80 /* Cache Threshold enable */ - bit DPARCKEN 0x40 /* Data Parity Check Enable */ - bit MPARCKEN 0x20 /* Memory Parity Check Enable */ - bit EXTREQLCK 0x10 /* External Request Lock */ -} - -/* - * Bus On/Off Time (p. 3-44) - */ -register BUSTIME { - address 0x085 - access_mode RW - mask BOFF 0xf0 - mask BON 0x0f -} - -/* - * Bus Speed (p. 3-45) - */ -register BUSSPD { - address 0x086 - access_mode RW - mask DFTHRSH 0xc0 - mask STBOFF 0x38 - mask STBON 0x07 - mask DFTHRSH_100 0xc0 -} - -/* - * Host Control (p. 3-47) R/W - * Overall host control of the device. - */ -register HCNTRL { - address 0x087 - access_mode RW - bit POWRDN 0x40 - bit SWINT 0x10 - bit IRQMS 0x08 - bit PAUSE 0x04 - bit INTEN 0x02 - bit CHIPRST 0x01 - bit CHIPRSTACK 0x01 -} - -/* - * Host Address (p. 3-48) - * This register contains the address of the byte about - * to be transferred across the host bus. - */ -register HADDR { - address 0x088 - size 4 - access_mode RW -} - -register HCNT { - address 0x08c - size 3 - access_mode RW -} - -/* - * SCB Pointer (p. 3-49) - * Gate one of the four SCBs into the SCBARRAY window. - */ -register SCBPTR { - address 0x090 - access_mode RW -} - -/* - * Interrupt Status (p. 3-50) - * Status for system interrupts - */ -register INTSTAT { - address 0x091 - access_mode RW - bit BRKADRINT 0x08 - bit SCSIINT 0x04 - bit CMDCMPLT 0x02 - bit SEQINT 0x01 - mask BAD_PHASE SEQINT /* unknown scsi bus phase */ - mask SEND_REJECT 0x10|SEQINT /* sending a message reject */ - mask NO_IDENT 0x20|SEQINT /* no IDENTIFY after reconnect*/ - mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */ - mask EXTENDED_MSG 0x40|SEQINT /* Extended message received */ - mask WIDE_RESIDUE 0x50|SEQINT /* need kernel to back up */ - /* the SG array for us */ - mask REJECT_MSG 0x60|SEQINT /* Reject message received */ - mask BAD_STATUS 0x70|SEQINT /* Bad status from target */ - mask RESIDUAL 0x80|SEQINT /* Residual byte count != 0 */ - mask AWAITING_MSG 0xa0|SEQINT /* - * Kernel requested to specify - * a message to this target - * (command was null), so tell - * it that it can fill the - * message buffer. - */ - mask SEQ_SG_FIXUP 0xb0|SEQINT /* need help with fixing up - * the sg array pointer after - * a phasemis with no valid - * sg elements in the shadow - * pipeline. - */ - mask TRACEPOINT2 0xc0|SEQINT - mask MSGIN_PHASEMIS 0xd0|SEQINT /* - * Target changed phase on us - * when we were expecting - * another msgin byte. - */ - mask DATA_OVERRUN 0xe0|SEQINT /* - * Target attempted to write - * beyond the bounds of its - * command. - */ - - mask SEQINT_MASK 0xf0|SEQINT /* SEQINT Status Codes */ - mask INT_PEND (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT) -} - -/* - * Hard Error (p. 3-53) - * Reporting of catastrophic errors. You usually cannot recover from - * these without a full board reset. - */ -register ERROR { - address 0x092 - access_mode RO - bit CIOPARERR 0x80 /* Ultra2 only */ - bit PCIERRSTAT 0x40 /* PCI only */ - bit MPARERR 0x20 /* PCI only */ - bit DPARERR 0x10 /* PCI only */ - bit SQPARERR 0x08 - bit ILLOPCODE 0x04 - bit ILLSADDR 0x02 - bit DSCTMOUT 0x02 /* Ultra3 only */ - bit ILLHADDR 0x01 -} - -/* - * Clear Interrupt Status (p. 3-52) - */ -register CLRINT { - address 0x092 - access_mode WO - bit CLRPARERR 0x10 /* PCI only */ - bit CLRBRKADRINT 0x08 - bit CLRSCSIINT 0x04 - bit CLRCMDINT 0x02 - bit CLRSEQINT 0x01 -} - -register DFCNTRL { - address 0x093 - access_mode RW - bit PRELOADEN 0x80 /* aic7890 only */ - bit WIDEODD 0x40 - bit SCSIEN 0x20 - bit SDMAEN 0x10 - bit SDMAENACK 0x10 - bit HDMAEN 0x08 - bit HDMAENACK 0x08 - bit DIRECTION 0x04 - bit FIFOFLUSH 0x02 - bit FIFORESET 0x01 -} - -register DFSTATUS { - address 0x094 - access_mode RO - bit PRELOAD_AVAIL 0x80 - bit DWORDEMP 0x20 - bit MREQPEND 0x10 - bit HDONE 0x08 - bit DFTHRESH 0x04 - bit FIFOFULL 0x02 - bit FIFOEMP 0x01 -} - -register DFDAT { - address 0x099 - access_mode RW -} - -/* - * SCB Auto Increment (p. 3-59) - * Byte offset into the SCB Array and an optional bit to allow auto - * incrementing of the address during download and upload operations - */ -register SCBCNT { - address 0x09a - access_mode RW - bit SCBAUTO 0x80 - mask SCBCNT_MASK 0x1f -} - -/* - * Queue In FIFO (p. 3-60) - * Input queue for queued SCBs (commands that the seqencer has yet to start) - */ -register QINFIFO { - address 0x09b - access_mode RW -} - -/* - * Queue In Count (p. 3-60) - * Number of queued SCBs - */ -register QINCNT { - address 0x09c - access_mode RO -} - -/* - * SCSIDATL IMAGE Register (p. 5-104) - * Write to this register also go to SCSIDATL but this register will preserve - * the data for later reading as long as the SCSIDATL_IMGEN bit in the - * OPTIONMODE register is set. - */ -register SCSIDATL_IMG { - address 0x09c - access_mode RW -} - -/* - * Queue Out FIFO (p. 3-61) - * Queue of SCBs that have completed and await the host - */ -register QOUTFIFO { - address 0x09d - access_mode WO -} - -/* - * CRC Control 1 Register (p. 5-105) - * Control bits for the Ultra 160/m CRC facilities - */ -register CRCCONTROL1 { - address 0x09d - access_mode RW - bit CRCONSEEN 0x80 /* CRC ON Single Edge ENable */ - bit CRCVALCHKEN 0x40 /* CRC Value Check Enable */ - bit CRCENDCHKEN 0x20 /* CRC End Check Enable */ - bit CRCREQCHKEN 0x10 - bit TARGCRCENDEN 0x08 /* Enable End CRC transfer when target */ - bit TARGCRCCNTEN 0x04 /* Enable CRC transfer when target */ -} - -/* - * Queue Out Count (p. 3-61) - * Number of queued SCBs in the Out FIFO - */ -register QOUTCNT { - address 0x09e - access_mode RO -} - -/* - * SCSI Phase Register (p. 5-106) - * Current bus phase - */ -register SCSIPHASE { - address 0x09e - access_mode RO - bit SP_STATUS 0x20 - bit SP_COMMAND 0x10 - bit SP_MSG_IN 0x08 - bit SP_MSG_OUT 0x04 - bit SP_DATA_IN 0x02 - bit SP_DATA_OUT 0x01 -} - -/* - * Special Function - */ -register SFUNCT { - address 0x09f - access_mode RW - bit ALT_MODE 0x80 -} - -/* - * SCB Definition (p. 5-4) - */ -scb { - address 0x0a0 - SCB_CONTROL { - size 1 - bit MK_MESSAGE 0x80 - bit DISCENB 0x40 - bit TAG_ENB 0x20 - bit DISCONNECTED 0x04 - mask SCB_TAG_TYPE 0x03 - } - SCB_TCL { - size 1 - bit SELBUSB 0x08 - mask TID 0xf0 - mask LID 0x07 - } - SCB_TARGET_STATUS { - size 1 - } - SCB_SGCOUNT { - size 1 - } - SCB_SGPTR { - size 4 - } - SCB_RESID_SGCNT { - size 1 - } - SCB_RESID_DCNT { - size 3 - } - SCB_DATAPTR { - size 4 - } - SCB_DATACNT { - /* - * Really only 3 bytes, but padded to make - * the kernel's job easier. - */ - size 4 - } - SCB_CMDPTR { - size 4 - } - SCB_CMDLEN { - size 1 - } - SCB_TAG { - size 1 - } - SCB_NEXT { - size 1 - } - SCB_PREV { - size 1 - } - SCB_BUSYTARGETS { - size 4 - } -} - -const SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */ - -/* --------------------- AHA-2840-only definitions -------------------- */ - -register SEECTL_2840 { - address 0x0c0 - access_mode RW - bit CS_2840 0x04 - bit CK_2840 0x02 - bit DO_2840 0x01 -} - -register STATUS_2840 { - address 0x0c1 - access_mode RW - bit EEPROM_TF 0x80 - mask BIOS_SEL 0x60 - mask ADSEL 0x1e - bit DI_2840 0x01 -} - -/* --------------------- AIC-7870-only definitions -------------------- */ - -register DSPCISTATUS { - address 0x086 - mask DFTHRSH_100 0xc0 -} - -register CCHADDR { - address 0x0E0 - size 8 -} - -register CCHCNT { - address 0x0E8 -} - -register CCSGRAM { - address 0x0E9 -} - -register CCSGADDR { - address 0x0EA -} - -register CCSGCTL { - address 0x0EB - bit CCSGDONE 0x80 - bit CCSGEN 0x08 - bit FLAG 0x02 - bit CCSGRESET 0x01 -} - -register CCSCBCNT { - address 0xEF -} - -register CCSCBCTL { - address 0x0EE - bit CCSCBDONE 0x80 - bit ARRDONE 0x40 /* SCB Array prefetch done */ - bit CCARREN 0x10 - bit CCSCBEN 0x08 - bit CCSCBDIR 0x04 - bit CCSCBRESET 0x01 -} - -register CCSCBADDR { - address 0x0ED -} - -register CCSCBRAM { - address 0xEC -} - -register CCSCBPTR { - address 0x0F1 -} - -register HNSCB_QOFF { - address 0x0F4 -} - -register HESCB_QOFF { - address 0x0F5 -} - -register SNSCB_QOFF { - address 0x0F6 -} - -register SESCB_QOFF { - address 0x0F7 -} - -register SDSCB_QOFF { - address 0x0F8 -} - -register QOFF_CTLSTA { - address 0x0FA - bit ESTABLISH_SCB_AVAIL 0x80 - bit SCB_AVAIL 0x40 - bit SNSCB_ROLLOVER 0x20 - bit SDSCB_ROLLOVER 0x10 - bit SESCB_ROLLOVER 0x08 - mask SCB_QSIZE 0x07 - mask SCB_QSIZE_256 0x06 -} - -register DFF_THRSH { - address 0x0FB - mask WR_DFTHRSH 0x70 - mask RD_DFTHRSH 0x07 - mask RD_DFTHRSH_MIN 0x00 - mask RD_DFTHRSH_25 0x01 - mask RD_DFTHRSH_50 0x02 - mask RD_DFTHRSH_63 0x03 - mask RD_DFTHRSH_75 0x04 - mask RD_DFTHRSH_85 0x05 - mask RD_DFTHRSH_90 0x06 - mask RD_DFTHRSH_MAX 0x07 - mask WR_DFTHRSH_MIN 0x00 - mask WR_DFTHRSH_25 0x10 - mask WR_DFTHRSH_50 0x20 - mask WR_DFTHRSH_63 0x30 - mask WR_DFTHRSH_75 0x40 - mask WR_DFTHRSH_85 0x50 - mask WR_DFTHRSH_90 0x60 - mask WR_DFTHRSH_MAX 0x70 -} - -register SG_CACHEPTR { - access_mode RW - address 0x0fc - mask SG_USER_DATA 0xfc - bit LAST_SEG 0x02 - bit LAST_SEG_DONE 0x01 -} - -register BRDCTL { - address 0x01d - bit BRDDAT7 0x80 - bit BRDDAT6 0x40 - bit BRDDAT5 0x20 - bit BRDSTB 0x10 - bit BRDCS 0x08 - bit BRDRW 0x04 - bit BRDCTL1 0x02 - bit BRDCTL0 0x01 - /* 7890 Definitions */ - bit BRDDAT4 0x10 - bit BRDDAT3 0x08 - bit BRDDAT2 0x04 - bit BRDRW_ULTRA2 0x02 - bit BRDSTB_ULTRA2 0x01 -} - -/* - * Serial EEPROM Control (p. 4-92 in 7870 Databook) - * Controls the reading and writing of an external serial 1-bit - * EEPROM Device. In order to access the serial EEPROM, you must - * first set the SEEMS bit that generates a request to the memory - * port for access to the serial EEPROM device. When the memory - * port is not busy servicing another request, it reconfigures - * to allow access to the serial EEPROM. When this happens, SEERDY - * gets set high to verify that the memory port access has been - * granted. - * - * After successful arbitration for the memory port, the SEECS bit of - * the SEECTL register is connected to the chip select. The SEECK, - * SEEDO, and SEEDI are connected to the clock, data out, and data in - * lines respectively. The SEERDY bit of SEECTL is useful in that it - * gives us an 800 nsec timer. After a write to the SEECTL register, - * the SEERDY goes high 800 nsec later. The one exception to this is - * when we first request access to the memory port. The SEERDY goes - * high to signify that access has been granted and, for this case, has - * no implied timing. - * - * See 93cx6.c for detailed information on the protocol necessary to - * read the serial EEPROM. - */ -register SEECTL { - address 0x01e - bit EXTARBACK 0x80 - bit EXTARBREQ 0x40 - bit SEEMS 0x20 - bit SEERDY 0x10 - bit SEECS 0x08 - bit SEECK 0x04 - bit SEEDO 0x02 - bit SEEDI 0x01 -} -/* ---------------------- Scratch RAM Offsets ------------------------- */ -/* These offsets are either to values that are initialized by the board's - * BIOS or are specified by the sequencer code. - * - * The host adapter card (at least the BIOS) uses 20-2f for SCSI - * device information, 32-33 and 5a-5f as well. As it turns out, the - * BIOS trashes 20-2f, writing the synchronous negotiation results - * on top of the BIOS values, so we re-use those for our per-target - * scratchspace (actually a value that can be copied directly into - * SCSIRATE). The kernel driver will enable synchronous negotiation - * for all targets that have a value other than 0 in the lower four - * bits of the target scratch space. This should work regardless of - * whether the bios has been installed. - */ - -scratch_ram { - address 0x020 - - /* - * 1 byte per target starting at this address for configuration values - */ - TARG_SCSIRATE { - size 16 - } - /* - * Bit vector of targets that have ULTRA enabled. - */ - ULTRA_ENB { - size 2 - } - /* - * Bit vector of targets that have disconnection disabled. - */ - DISC_DSB { - size 2 - } - /* - * Single byte buffer used to designate the type or message - * to send to a target. - */ - MSG_OUT { - size 1 - } - /* Parameters for DMA Logic */ - DMAPARAMS { - size 1 - bit PRELOADEN 0x80 - bit WIDEODD 0x40 - bit SCSIEN 0x20 - bit SDMAEN 0x10 - bit SDMAENACK 0x10 - bit HDMAEN 0x08 - bit HDMAENACK 0x08 - bit DIRECTION 0x04 - bit FIFOFLUSH 0x02 - bit FIFORESET 0x01 - } - SEQ_FLAGS { - size 1 - bit IDENTIFY_SEEN 0x80 - bit SCBPTR_VALID 0x20 - bit DPHASE 0x10 - bit AMTARGET 0x08 - bit WIDE_BUS 0x02 - bit TWIN_BUS 0x01 - } - /* - * Temporary storage for the - * target/channel/lun of a - * reconnecting target - */ - SAVED_TCL { - size 1 - } - /* Working value of the number of SG segments left */ - SG_COUNT { - size 1 - } - /* Working value of SG pointer */ - SG_NEXT { - size 4 - } - /* - * The last bus phase as seen by the sequencer. - */ - LASTPHASE { - size 1 - bit CDI 0x80 - bit IOI 0x40 - bit MSGI 0x20 - mask PHASE_MASK CDI|IOI|MSGI - mask P_DATAOUT 0x00 - mask P_DATAIN IOI - mask P_COMMAND CDI - mask P_MESGOUT CDI|MSGI - mask P_STATUS CDI|IOI - mask P_MESGIN CDI|IOI|MSGI - mask P_BUSFREE 0x01 - } - /* - * head of list of SCBs awaiting - * selection - */ - WAITING_SCBH { - size 1 - } - /* - * head of list of SCBs that are - * disconnected. Used for SCB - * paging. - */ - DISCONNECTED_SCBH { - size 1 - } - /* - * head of list of SCBs that are - * not in use. Used for SCB paging. - */ - FREE_SCBH { - size 1 - } - /* - * Address of the hardware scb array in the host. - */ - HSCB_ADDR { - size 4 - } - /* - * Address of the 256 byte array storing the SCBID of outstanding - * untagged SCBs indexed by TCL. - */ - SCBID_ADDR { - size 4 - } - /* - * Address of the array of command descriptors used to store - * information about incoming selections. - */ - TMODE_CMDADDR { - size 4 - } - KERNEL_QINPOS { - size 1 - } - QINPOS { - size 1 - } - QOUTPOS { - size 1 - } - /* - * Offset into the command descriptor array for the next - * available desciptor to use. - */ - TMODE_CMDADDR_NEXT { - size 1 - } - ARG_1 { - size 1 - mask SEND_MSG 0x80 - mask SEND_SENSE 0x40 - mask SEND_REJ 0x20 - mask MSGOUT_PHASEMIS 0x10 - alias RETURN_1 - } - ARG_2 { - size 1 - alias RETURN_2 - } - - /* - * Snapshot of MSG_OUT taken after each message is sent. - */ - LAST_MSG { - size 1 - } - - /* - * Number of times we have filled the CCSGRAM with prefetched - * SG elements. - */ - PREFETCH_CNT { - size 1 - } - - - /* - * These are reserved registers in the card's scratch ram. Some of - * the values are specified in the AHA2742 technical reference manual - * and are initialized by the BIOS at boot time. - */ - SCSICONF { - address 0x05a - size 1 - bit TERM_ENB 0x80 - bit RESET_SCSI 0x40 - mask HSCSIID 0x07 /* our SCSI ID */ - mask HWSCSIID 0x0f /* our SCSI ID if Wide Bus */ - } - HOSTCONF { - address 0x05d - size 1 - } - HA_274_BIOSCTRL { - address 0x05f - size 1 - mask BIOSMODE 0x30 - mask BIOSDISABLED 0x30 - bit CHANNEL_B_PRIMARY 0x08 - } - /* - * Per target SCSI offset values for Ultra2 controllers. - */ - TARG_OFFSET { - address 0x070 - size 16 - } -} - -const SCB_LIST_NULL 0xff - -const CCSGADDR_MAX 0x80 -const CCSGRAM_MAXSEGS 16 - -/* Offsets into the SCBID array where different data is stored */ -const UNTAGGEDSCB_OFFSET 0 -const QOUTFIFO_OFFSET 1 -const QINFIFO_OFFSET 2 - -/* WDTR Message values */ -const BUS_8_BIT 0x00 -const BUS_16_BIT 0x01 -const BUS_32_BIT 0x02 - -/* Offset maximums */ -const MAX_OFFSET_8BIT 0x0f -const MAX_OFFSET_16BIT 0x08 -const MAX_OFFSET_ULTRA2 0x7f -const HOST_MSG 0xff - -/* Target mode command processing constants */ -const CMD_GROUP_CODE_SHIFT 0x05 -const CMD_GROUP0_BYTE_DELTA -4 -const CMD_GROUP2_BYTE_DELTA -6 -const CMD_GROUP4_BYTE_DELTA 4 -const CMD_GROUP5_BYTE_DELTA 11 - -/* - * Downloaded (kernel inserted) constants - */ - -/* - * Number of command descriptors in the command descriptor array. - */ -const TMODE_NUMCMDS download diff --git a/drivers/scsi/aic7xxx_old/aic7xxx.seq b/drivers/scsi/aic7xxx_old/aic7xxx.seq deleted file mode 100644 index dc3bb81cff0c..000000000000 --- a/drivers/scsi/aic7xxx_old/aic7xxx.seq +++ /dev/null @@ -1,1539 +0,0 @@ -/* - * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. - * - * Copyright (c) 1994-1999 Justin Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU General Public License (GPL) and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: aic7xxx.seq,v 1.77 1998/06/28 02:58:57 gibbs Exp $ - */ - -#include "aic7xxx.reg" -#include "scsi_message.h" - -/* - * A few words on the waiting SCB list: - * After starting the selection hardware, we check for reconnecting targets - * as well as for our selection to complete just in case the reselection wins - * bus arbitration. The problem with this is that we must keep track of the - * SCB that we've already pulled from the QINFIFO and started the selection - * on just in case the reselection wins so that we can retry the selection at - * a later time. This problem cannot be resolved by holding a single entry - * in scratch ram since a reconnecting target can request sense and this will - * create yet another SCB waiting for selection. The solution used here is to - * use byte 27 of the SCB as a pseudo-next pointer and to thread a list - * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, - * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to - * this list every time a request sense occurs or after completing a non-tagged - * command for which a second SCB has been queued. The sequencer will - * automatically consume the entries. - */ - -reset: - clr SCSISIGO; /* De-assert BSY */ - and SXFRCTL1, ~BITBUCKET; - /* Always allow reselection */ - mvi SCSISEQ, ENRSELI|ENAUTOATNP; - - if ((p->features & AHC_CMD_CHAN) != 0) { - /* Ensure that no DMA operations are in progress */ - clr CCSGCTL; - clr CCSCBCTL; - } - - call clear_target_state; -poll_for_work: - and SXFRCTL0, ~SPIOEN; - if ((p->features & AHC_QUEUE_REGS) == 0) { - mov A, QINPOS; - } -poll_for_work_loop: - if ((p->features & AHC_QUEUE_REGS) == 0) { - and SEQCTL, ~PAUSEDIS; - } - test SSTAT0, SELDO|SELDI jnz selection; - test SCSISEQ, ENSELO jnz poll_for_work; - if ((p->features & AHC_TWIN) != 0) { - /* - * Twin channel devices cannot handle things like SELTO - * interrupts on the "background" channel. So, if we - * are selecting, keep polling the current channel util - * either a selection or reselection occurs. - */ - xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ - test SSTAT0, SELDO|SELDI jnz selection; - test SCSISEQ, ENSELO jnz poll_for_work; - xor SBLKCTL,SELBUSB; /* Toggle back */ - } - cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; -test_queue: - /* Has the driver posted any work for us? */ - if ((p->features & AHC_QUEUE_REGS) != 0) { - test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; - mov NONE, SNSCB_QOFF; - inc QINPOS; - } else { - or SEQCTL, PAUSEDIS; - cmp KERNEL_QINPOS, A je poll_for_work_loop; - inc QINPOS; - and SEQCTL, ~PAUSEDIS; - } - -/* - * We have at least one queued SCB now and we don't have any - * SCBs in the list of SCBs awaiting selection. If we have - * any SCBs available for use, pull the tag from the QINFIFO - * and get to work on it. - */ - if ((p->flags & AHC_PAGESCBS) != 0) { - mov ALLZEROS call get_free_or_disc_scb; - } - -dequeue_scb: - add A, -1, QINPOS; - mvi QINFIFO_OFFSET call fetch_byte; - - if ((p->flags & AHC_PAGESCBS) == 0) { - /* In the non-paging case, the SCBID == hardware SCB index */ - mov SCBPTR, RETURN_2; - } -dma_queued_scb: -/* - * DMA the SCB from host ram into the current SCB location. - */ - mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - mov RETURN_2 call dma_scb; - -/* - * Preset the residual fields in case we never go through a data phase. - * This isn't done by the host so we can avoid a DMA to clear these - * fields for the normal case of I/O that completes without underrun - * or overrun conditions. - */ - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov SCB_RESID_DCNT, SCB_DATACNT, 3; - } else { - mov SCB_RESID_DCNT[0],SCB_DATACNT[0]; - mov SCB_RESID_DCNT[1],SCB_DATACNT[1]; - mov SCB_RESID_DCNT[2],SCB_DATACNT[2]; - } - mov SCB_RESID_SGCNT, SCB_SGCOUNT; - -start_scb: - /* - * Place us on the waiting list in case our selection - * doesn't win during bus arbitration. - */ - mov SCB_NEXT,WAITING_SCBH; - mov WAITING_SCBH, SCBPTR; -start_waiting: - /* - * Pull the first entry off of the waiting SCB list. - */ - mov SCBPTR, WAITING_SCBH; - call start_selection; - jmp poll_for_work; - -start_selection: - if ((p->features & AHC_TWIN) != 0) { - and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ - and A,SELBUSB,SCB_TCL; /* Get new channel bit */ - or SINDEX,A; - mov SBLKCTL,SINDEX; /* select channel */ - } -initialize_scsiid: - if ((p->features & AHC_ULTRA2) != 0) { - and A, TID, SCB_TCL; /* Get target ID */ - and SCSIID_ULTRA2, OID; /* Clear old target */ - or SCSIID_ULTRA2, A; - } else { - and A, TID, SCB_TCL; /* Get target ID */ - and SCSIID, OID; /* Clear old target */ - or SCSIID, A; - } - mov SCSIDATL, ALLZEROS; /* clear out the latched */ - /* data register, this */ - /* fixes a bug on some */ - /* controllers where the */ - /* last byte written to */ - /* this register can leak */ - /* onto the data bus at */ - /* bad times, such as during */ - /* selection timeouts */ - mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret; - -/* - * Initialize Ultra mode setting and clear the SCSI channel. - * SINDEX should contain any additional bit's the client wants - * set in SXFRCTL0. - */ -initialize_channel: - or SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX; - if ((p->features & AHC_ULTRA) != 0) { -ultra: - mvi SINDEX, ULTRA_ENB+1; - test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */ - dec SINDEX; -ultra_2: - mov FUNCTION1,SAVED_TCL; - mov A,FUNCTION1; - test SINDIR, A jz ndx_dtr; - or SXFRCTL0, FAST20; - } -/* - * Initialize SCSIRATE with the appropriate value for this target. - * The SCSIRATE settings for each target are stored in an array - * based at TARG_SCSIRATE. - */ -ndx_dtr: - shr A,4,SAVED_TCL; - if ((p->features & AHC_TWIN) != 0) { - test SBLKCTL,SELBUSB jz ndx_dtr_2; - or SAVED_TCL, SELBUSB; - or A,0x08; /* Channel B entries add 8 */ -ndx_dtr_2: - } - - if ((p->features & AHC_ULTRA2) != 0) { - add SINDEX, TARG_OFFSET, A; - mov SCSIOFFSET, SINDIR; - } - - add SINDEX,TARG_SCSIRATE,A; - mov SCSIRATE,SINDIR ret; - - -selection: - test SSTAT0,SELDO jnz select_out; -/* - * Reselection has been initiated by a target. Make a note that we've been - * reselected, but haven't seen an IDENTIFY message from the target yet. - */ -initiator_reselect: - mvi CLRSINT0, CLRSELDI; - /* XXX test for and handle ONE BIT condition */ - and SAVED_TCL, SELID_MASK, SELID; - mvi CLRSINT1,CLRBUSFREE; - or SIMODE1, ENBUSFREE; /* - * We aren't expecting a - * bus free, so interrupt - * the kernel driver if it - * happens. - */ - mvi SPIOEN call initialize_channel; - mvi MSG_OUT, MSG_NOOP; /* No message to send */ - jmp ITloop; - -/* - * After the selection, remove this SCB from the "waiting SCB" - * list. This is achieved by simply moving our "next" pointer into - * WAITING_SCBH. Our next pointer will be set to null the next time this - * SCB is used, so don't bother with it now. - */ -select_out: - /* Turn off the selection hardware */ - mvi SCSISEQ, ENRSELI|ENAUTOATNP; /* - * ATN on parity errors - * for "in" phases - */ - mvi CLRSINT0, CLRSELDO; - mov SCBPTR, WAITING_SCBH; - mov WAITING_SCBH,SCB_NEXT; - mov SAVED_TCL, SCB_TCL; - mvi CLRSINT1,CLRBUSFREE; - or SIMODE1, ENBUSFREE; /* - * We aren't expecting a - * bus free, so interrupt - * the kernel driver if it - * happens. - */ - mvi SPIOEN call initialize_channel; -/* - * As soon as we get a successful selection, the target should go - * into the message out phase since we have ATN asserted. - */ - mvi MSG_OUT, MSG_IDENTIFYFLAG; - or SEQ_FLAGS, IDENTIFY_SEEN; - -/* - * Main loop for information transfer phases. Wait for the target - * to assert REQ before checking MSG, C/D and I/O for the bus phase. - */ -ITloop: - call phase_lock; - - mov A, LASTPHASE; - - test A, ~P_DATAIN jz p_data; - cmp A,P_COMMAND je p_command; - cmp A,P_MESGOUT je p_mesgout; - cmp A,P_STATUS je p_status; - cmp A,P_MESGIN je p_mesgin; - - mvi INTSTAT,BAD_PHASE; /* unknown phase - signal driver */ - jmp ITloop; /* Try reading the bus again. */ - -await_busfree: - and SIMODE1, ~ENBUSFREE; - call clear_target_state; - mov NONE, SCSIDATL; /* Ack the last byte */ - and SXFRCTL0, ~SPIOEN; - test SSTAT1,REQINIT|BUSFREE jz .; - test SSTAT1, BUSFREE jnz poll_for_work; - mvi INTSTAT, BAD_PHASE; - -clear_target_state: - /* - * We assume that the kernel driver may reset us - * at any time, even in the middle of a DMA, so - * clear DFCNTRL too. - */ - clr DFCNTRL; - - /* - * We don't know the target we will connect to, - * so default to narrow transfers to avoid - * parity problems. - */ - if ((p->features & AHC_ULTRA2) != 0) { - bmov SCSIRATE, ALLZEROS, 2; - } else { - clr SCSIRATE; - and SXFRCTL0, ~(FAST20); - } - mvi LASTPHASE, P_BUSFREE; - /* clear target specific flags */ - clr SEQ_FLAGS ret; - - -data_phase_reinit: -/* - * If we re-enter the data phase after going through another phase, the - * STCNT may have been cleared, so restore it from the residual field. - * On Ultra2, we have to put it into the HCNT field because we have to - * drop the data down into the shadow layer via the preload ability. - */ - if ((p->features & AHC_ULTRA2) != 0) { - bmov HADDR, SHADDR, 4; - bmov HCNT, SCB_RESID_DCNT, 3; - } - if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { - bmov STCNT, SCB_RESID_DCNT, 3; - } - if ((p->features & AHC_CMD_CHAN) == 0) { - mvi DINDEX, STCNT; - mvi SCB_RESID_DCNT call bcopy_3; - } - jmp data_phase_loop; -p_data: - if ((p->features & AHC_ULTRA2) != 0) { - mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; - } else { - mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; - } - test LASTPHASE, IOI jnz . + 2; - or DMAPARAMS, DIRECTION; - call assert; /* - * Ensure entering a data - * phase is okay - seen identify, etc. - */ - if ((p->features & AHC_CMD_CHAN) != 0) { - mvi CCSGADDR, CCSGADDR_MAX; - } - - test SEQ_FLAGS, DPHASE jnz data_phase_reinit; - or SEQ_FLAGS, DPHASE; /* we've seen a data phase */ - /* - * Initialize the DMA address and counter from the SCB. - * Also set SG_COUNT and SG_NEXT in memory since we cannot - * modify the values in the SCB itself until we see a - * save data pointers message. - */ - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov HADDR, SCB_DATAPTR, 7; - bmov SG_COUNT, SCB_SGCOUNT, 5; - if ((p->features & AHC_ULTRA2) == 0) { - bmov STCNT, HCNT, 3; - } - } else { - mvi DINDEX, HADDR; - mvi SCB_DATAPTR call bcopy_7; - call set_stcnt_from_hcnt; - mvi DINDEX, SG_COUNT; - mvi SCB_SGCOUNT call bcopy_5; - } -data_phase_loop: - /* Guard against overruns */ - test SG_COUNT, 0xff jnz data_phase_inbounds; -/* - * Turn on 'Bit Bucket' mode, set the transfer count to - * 16meg and let the target run until it changes phase. - * When the transfer completes, notify the host that we - * had an overrun. - */ - or SXFRCTL1,BITBUCKET; - and DMAPARAMS, ~(HDMAEN|SDMAEN); - if ((p->features & AHC_ULTRA2) != 0) { - bmov HCNT, ALLONES, 3; - } - if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { - bmov STCNT, ALLONES, 3; - } - if ((p->features & AHC_CMD_CHAN) == 0) { - mvi STCNT[0], 0xFF; - mvi STCNT[1], 0xFF; - mvi STCNT[2], 0xFF; - } - -data_phase_inbounds: -/* If we are the last SG block, tell the hardware. */ - if ((p->features & AHC_ULTRA2) != 0) { - shl A, 2, SG_COUNT; - cmp SG_COUNT,0x01 jne data_phase_wideodd; - or A, LAST_SEG; - } else { - cmp SG_COUNT,0x01 jne data_phase_wideodd; - and DMAPARAMS, ~WIDEODD; - } -data_phase_wideodd: - if ((p->features & AHC_ULTRA2) != 0) { - mov SG_CACHEPTR, A; - mov DFCNTRL, DMAPARAMS; /* start the operation */ - test SXFRCTL1, BITBUCKET jnz data_phase_overrun; -u2_preload_wait: - test SSTAT1, PHASEMIS jnz u2_phasemis; - test DFSTATUS, PRELOAD_AVAIL jz u2_preload_wait; - } else { - mov DMAPARAMS call dma; -data_phase_dma_done: -/* Go tell the host about any overruns */ - test SXFRCTL1,BITBUCKET jnz data_phase_overrun; - -/* Exit if we had an underrun. dma clears SINDEX in this case. */ - test SINDEX,0xff jz data_phase_finish; - } -/* - * Advance the scatter-gather pointers - */ -sg_advance: - if ((p->features & AHC_ULTRA2) != 0) { - cmp SG_COUNT, 0x01 je u2_data_phase_finish; - } else { - dec SG_COUNT; - test SG_COUNT, 0xff jz data_phase_finish; - } - - if ((p->features & AHC_CMD_CHAN) != 0) { - - /* - * Do we have any prefetch left??? - */ - cmp CCSGADDR, CCSGADDR_MAX jne prefetch_avail; - - /* - * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes. - */ - add A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT; - mvi A, CCSGADDR_MAX; - jc . + 2; - shl A, 3, SG_COUNT; - mov CCHCNT, A; - bmov CCHADDR, SG_NEXT, 4; - mvi CCSGCTL, CCSGEN|CCSGRESET; - test CCSGCTL, CCSGDONE jz .; - and CCSGCTL, ~CCSGEN; - test CCSGCTL, CCSGEN jnz .; - mvi CCSGCTL, CCSGRESET; -prefetch_avail: - bmov HADDR, CCSGRAM, 8; - if ((p->features & AHC_ULTRA2) == 0) { - bmov STCNT, HCNT, 3; - } else { - dec SG_COUNT; - } - } else { - mvi DINDEX, HADDR; - mvi SG_NEXT call bcopy_4; - - mvi HCNT[0],SG_SIZEOF; - clr HCNT[1]; - clr HCNT[2]; - - or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; - - call dma_finish; - -/* - * Copy data from FIFO into SCB data pointer and data count. - * This assumes that the SG segments are of the form: - * struct ahc_dma_seg { - * u_int32_t addr; four bytes, little-endian order - * u_int32_t len; four bytes, little endian order - * }; - */ - mvi DINDEX, HADDR; - call dfdat_in_7; - call set_stcnt_from_hcnt; - } -/* Advance the SG pointer */ - clr A; /* add sizeof(struct scatter) */ - add SG_NEXT[0],SG_SIZEOF; - adc SG_NEXT[1],A; - - if ((p->features & AHC_ULTRA2) != 0) { - jmp data_phase_loop; - } else { - test SSTAT1, REQINIT jz .; - test SSTAT1,PHASEMIS jz data_phase_loop; - } - - -/* - * We've loaded all of our segments into the preload layer. Now, we simply - * have to wait for it to finish or for us to get a phasemis. And, since - * we'll get a phasemis if we do finish, all we really need to do is wait - * for a phasemis then check if we did actually complete all the segments. - */ - if ((p->features & AHC_ULTRA2) != 0) { -u2_data_phase_finish: - test SSTAT1, PHASEMIS jnz u2_phasemis; - test SG_CACHEPTR, LAST_SEG_DONE jz u2_data_phase_finish; - clr SG_COUNT; - test SSTAT1, REQINIT jz .; - test SSTAT1, PHASEMIS jz data_phase_loop; -u2_phasemis: - call ultra2_dmafinish; - test SG_CACHEPTR, LAST_SEG_DONE jnz data_phase_finish; - test SSTAT2, SHVALID jnz u2_fixup_residual; - mvi INTSTAT, SEQ_SG_FIXUP; - jmp data_phase_finish; -u2_fixup_residual: - shr ARG_1, 2, SG_CACHEPTR; -u2_phasemis_loop: - and A, 0x3f, SG_COUNT; - cmp ARG_1, A je data_phase_finish; -/* - * Subtract SG_SIZEOF from the SG_NEXT pointer and add 1 to the SG_COUNT - */ - clr A; - add SG_NEXT[0], -SG_SIZEOF; - adc SG_NEXT[1], 0xff; - inc SG_COUNT; - jmp u2_phasemis_loop; - } - -data_phase_finish: -/* - * After a DMA finishes, save the SG and STCNT residuals back into the SCB - * We use STCNT instead of HCNT, since it's a reflection of how many bytes - * were transferred on the SCSI (as opposed to the host) bus. - */ - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov SCB_RESID_DCNT, STCNT, 3; - mov SCB_RESID_SGCNT, SG_COUNT; - if ((p->features & AHC_ULTRA2) != 0) { - or SXFRCTL0, CLRSTCNT|CLRCHN; - } - } else { - mov SCB_RESID_DCNT[0],STCNT[0]; - mov SCB_RESID_DCNT[1],STCNT[1]; - mov SCB_RESID_DCNT[2],STCNT[2]; - mov SCB_RESID_SGCNT, SG_COUNT; - } - - jmp ITloop; - -data_phase_overrun: -/* - * Turn off BITBUCKET mode and notify the host - */ - if ((p->features & AHC_ULTRA2) != 0) { -/* - * Wait for the target to quit transferring data on the SCSI bus - */ - test SSTAT1, PHASEMIS jz .; - call ultra2_dmafinish; - } - and SXFRCTL1, ~BITBUCKET; - mvi INTSTAT,DATA_OVERRUN; - jmp ITloop; - - - - -/* - * Actually turn off the DMA hardware, save our current position into the - * proper residual variables, wait for the next REQ signal, then jump to - * the ITloop. Jumping to the ITloop ensures that if we happen to get - * brought into the data phase again (or are still in it after our last - * segment) that we will properly signal an overrun to the kernel. - */ - if ((p->features & AHC_ULTRA2) != 0) { -ultra2_dmafinish: - test DFCNTRL, DIRECTION jnz ultra2_dmahalt; - and DFCNTRL, ~SCSIEN; - test DFCNTRL, SCSIEN jnz .; - if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) { - or DFCNTRL, FIFOFLUSH; - } -ultra2_dmafifoflush: - if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) { - /* - * hardware bug alert! This needless set of jumps - * works around a glitch in the silicon. When the - * PCI DMA fifo goes empty, but there is still SCSI - * data to be flushed into the PCI DMA fifo (and from - * there on into main memory), the FIFOEMP bit will - * come on between the time when the PCI DMA buffer - * went empty and the next bit of data is copied from - * the SCSI fifo into the PCI fifo. It should only - * come on when both FIFOs (meaning the entire FIFO - * chain) are empty. Since it can take up to 4 cycles - * for new data to be copied from the SCSI fifo into - * the PCI fifo, testing for FIFOEMP status for 4 - * extra times gives the needed time for any - * remaining SCSI fifo data to be put in the PCI fifo - * before we declare it *truly* empty. - */ - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - } - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, MREQPEND jnz .; -ultra2_dmahalt: - and DFCNTRL, ~(HDMAEN|SCSIEN); - test DFCNTRL, (HDMAEN|SCSIEN) jnz .; - ret; - } - -/* - * Command phase. Set up the DMA registers and let 'er rip. - */ -p_command: - call assert; - -/* - * Load HADDR and HCNT. - */ - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov HADDR, SCB_CMDPTR, 5; - bmov HCNT[1], ALLZEROS, 2; - if ((p->features & AHC_ULTRA2) == 0) { - bmov STCNT, HCNT, 3; - } - } else { - mvi DINDEX, HADDR; - mvi SCB_CMDPTR call bcopy_5; - clr HCNT[1]; - clr HCNT[2]; - call set_stcnt_from_hcnt; - } - - if ((p->features & AHC_ULTRA2) == 0) { - mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma; - } else { - mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); - test SSTAT0, SDONE jnz .; -p_command_dma_loop: - test SSTAT0, SDONE jnz p_command_ultra2_dma_done; - test SSTAT1,PHASEMIS jz p_command_dma_loop; /* ie. underrun */ -p_command_ultra2_dma_done: - test SCSISIGI, REQI jz p_command_ultra2_shutdown; - test SSTAT1, (PHASEMIS|REQINIT) jz p_command_ultra2_dma_done; -p_command_ultra2_shutdown: - and DFCNTRL, ~(HDMAEN|SCSIEN); - test DFCNTRL, (HDMAEN|SCSIEN) jnz .; - or SXFRCTL0, CLRSTCNT|CLRCHN; - } - jmp ITloop; - -/* - * Status phase. Wait for the data byte to appear, then read it - * and store it into the SCB. - */ -p_status: - call assert; - - mov SCB_TARGET_STATUS, SCSIDATL; - jmp ITloop; - -/* - * Message out phase. If MSG_OUT is 0x80, build I full indentify message - * sequence and send it to the target. In addition, if the MK_MESSAGE bit - * is set in the SCB_CONTROL byte, interrupt the host and allow it to send - * it's own message. - * - * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. - * This is done to allow the host to send messages outside of an identify - * sequence while protecting the seqencer from testing the MK_MESSAGE bit - * on an SCB that might not be for the current nexus. (For example, a - * BDR message in response to a bad reselection would leave us pointed to - * an SCB that doesn't have anything to do with the current target). - * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, - * bus device reset). - * - * When there are no messages to send, MSG_OUT should be set to MSG_NOOP, - * in case the target decides to put us in this phase for some strange - * reason. - */ -p_mesgout_retry: - or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ -p_mesgout: - mov SINDEX, MSG_OUT; - cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; -p_mesgout_identify: - if ((p->features & AHC_WIDE) != 0) { - and SINDEX,0xf,SCB_TCL; /* lun */ - } else { - and SINDEX,0x7,SCB_TCL; /* lun */ - } - and A,DISCENB,SCB_CONTROL; /* mask off disconnect privilege */ - or SINDEX,A; /* or in disconnect privilege */ - or SINDEX,MSG_IDENTIFYFLAG; -p_mesgout_mk_message: - test SCB_CONTROL,MK_MESSAGE jz p_mesgout_tag; - mov SCSIDATL, SINDEX; /* Send the last byte */ - jmp p_mesgout_from_host + 1;/* Skip HOST_MSG test */ -/* - * Send a tag message if TAG_ENB is set in the SCB control block. - * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. - */ -p_mesgout_tag: - test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; - mov SCSIDATL, SINDEX; /* Send the identify message */ - call phase_lock; - cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; - and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; - call phase_lock; - cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; - mov SCB_TAG jmp p_mesgout_onebyte; -/* - * Interrupt the driver, and allow it to send a message - * if it asks. - */ -p_mesgout_from_host: - cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; - mvi INTSTAT,AWAITING_MSG; - nop; - /* - * Did the host detect a phase change? - */ - cmp RETURN_1, MSGOUT_PHASEMIS je p_mesgout_done; - -p_mesgout_onebyte: - mvi CLRSINT1, CLRATNO; - mov SCSIDATL, SINDEX; - -/* - * If the next bus phase after ATN drops is a message out, it means - * that the target is requesting that the last message(s) be resent. - */ - call phase_lock; - cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; - -p_mesgout_done: - mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ - mov LAST_MSG, MSG_OUT; - cmp MSG_OUT, MSG_IDENTIFYFLAG jne . + 2; - and SCB_CONTROL, ~MK_MESSAGE; - mvi MSG_OUT, MSG_NOOP; /* No message left */ - jmp ITloop; - -/* - * Message in phase. Bytes are read using Automatic PIO mode. - */ -p_mesgin: - mvi ACCUM call inb_first; /* read the 1st message byte */ - - test A,MSG_IDENTIFYFLAG jnz mesgin_identify; - cmp A,MSG_DISCONNECT je mesgin_disconnect; - cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; - cmp ALLZEROS,A je mesgin_complete; - cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; - cmp A,MSG_EXTENDED je mesgin_extended; - cmp A,MSG_MESSAGE_REJECT je mesgin_reject; - cmp A,MSG_NOOP je mesgin_done; - cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_wide_residue; - -rej_mesgin: -/* - * We have no idea what this message in is, so we issue a message reject - * and hope for the best. In any case, rejection should be a rare - * occurrence - signal the driver when it happens. - */ - mvi INTSTAT,SEND_REJECT; /* let driver know */ - - mvi MSG_MESSAGE_REJECT call mk_mesg; - -mesgin_done: - mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ - jmp ITloop; - - -mesgin_complete: -/* - * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO, - * and trigger a completion interrupt. Before doing so, check to see if there - * is a residual or the status byte is something other than STATUS_GOOD (0). - * In either of these conditions, we upload the SCB back to the host so it can - * process this information. In the case of a non zero status byte, we - * additionally interrupt the kernel driver synchronously, allowing it to - * decide if sense should be retrieved. If the kernel driver wishes to request - * sense, it will fill the kernel SCB with a request sense command and set - * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload - * the SCB, and process it as the next command by adding it to the waiting list. - * If the kernel driver does not wish to request sense, it need only clear - * RETURN_1, and the command is allowed to complete normally. We don't bother - * to post to the QOUTFIFO in the error cases since it would require extra - * work in the kernel driver to ensure that the entry was removed before the - * command complete code tried processing it. - */ - -/* - * First check for residuals - */ - test SCB_RESID_SGCNT,0xff jnz upload_scb; - test SCB_TARGET_STATUS,0xff jz complete; /* Good Status? */ -upload_scb: - mvi DMAPARAMS, FIFORESET; - mov SCB_TAG call dma_scb; -check_status: - test SCB_TARGET_STATUS,0xff jz complete; /* Just a residual? */ - mvi INTSTAT,BAD_STATUS; /* let driver know */ - nop; - cmp RETURN_1, SEND_SENSE jne complete; - /* This SCB becomes the next to execute as it will retrieve sense */ - mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - mov SCB_TAG call dma_scb; -add_to_waiting_list: - mov SCB_NEXT,WAITING_SCBH; - mov WAITING_SCBH, SCBPTR; - /* - * Prepare our selection hardware before the busfree so we have a - * high probability of winning arbitration. - */ - call start_selection; - jmp await_busfree; - -complete: - /* If we are untagged, clear our address up in host ram */ - test SCB_CONTROL, TAG_ENB jnz complete_post; - mov A, SAVED_TCL; - mvi UNTAGGEDSCB_OFFSET call post_byte_setup; - mvi SCB_LIST_NULL call post_byte; - -complete_post: - /* Post the SCB and issue an interrupt */ - if ((p->features & AHC_QUEUE_REGS) != 0) { - mov A, SDSCB_QOFF; - } else { - mov A, QOUTPOS; - } - mvi QOUTFIFO_OFFSET call post_byte_setup; - mov SCB_TAG call post_byte; - if ((p->features & AHC_QUEUE_REGS) == 0) { - inc QOUTPOS; - } - mvi INTSTAT,CMDCMPLT; - -add_to_free_list: - call add_scb_to_free_list; - jmp await_busfree; - -/* - * Is it an extended message? Copy the message to our message buffer and - * notify the host. The host will tell us whether to reject this message, - * respond to it with the message that the host placed in our message buffer, - * or simply to do nothing. - */ -mesgin_extended: - mvi INTSTAT,EXTENDED_MSG; /* let driver know */ - jmp ITloop; - -/* - * Is it a disconnect message? Set a flag in the SCB to remind us - * and await the bus going free. - */ -mesgin_disconnect: - or SCB_CONTROL,DISCONNECTED; - call add_scb_to_disc_list; - jmp await_busfree; - -/* - * Save data pointers message: - * Copying RAM values back to SCB, for Save Data Pointers message, but - * only if we've actually been into a data phase to change them. This - * protects against bogus data in scratch ram and the residual counts - * since they are only initialized when we go into data_in or data_out. - */ -mesgin_sdptrs: - test SEQ_FLAGS, DPHASE jz mesgin_done; - /* - * The SCB SGPTR becomes the next one we'll download, - * and the SCB DATAPTR becomes the current SHADDR. - * Use the residual number since STCNT is corrupted by - * any message transfer. - */ - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov SCB_SGCOUNT, SG_COUNT, 5; - bmov SCB_DATAPTR, SHADDR, 4; - bmov SCB_DATACNT, SCB_RESID_DCNT, 3; - } else { - mvi DINDEX, SCB_SGCOUNT; - mvi SG_COUNT call bcopy_5; - mvi DINDEX, SCB_DATAPTR; - mvi SHADDR call bcopy_4; - mvi SCB_RESID_DCNT call bcopy_3; - } - jmp mesgin_done; - -/* - * Restore pointers message? Data pointers are recopied from the - * SCB anytime we enter a data phase for the first time, so all - * we need to do is clear the DPHASE flag and let the data phase - * code do the rest. - */ -mesgin_rdptrs: - and SEQ_FLAGS, ~DPHASE; /* - * We'll reload them - * the next time through - * the dataphase. - */ - jmp mesgin_done; - -/* - * Identify message? For a reconnecting target, this tells us the lun - * that the reconnection is for - find the correct SCB and switch to it, - * clearing the "disconnected" bit so we don't "find" it by accident later. - */ -mesgin_identify: - - if ((p->features & AHC_WIDE) != 0) { - and A,0x0f; /* lun in lower four bits */ - } else { - and A,0x07; /* lun in lower three bits */ - } - or SAVED_TCL,A; /* SAVED_TCL should be complete now */ - - mvi ARG_2, SCB_LIST_NULL; /* SCBID of prev SCB in disc List */ - call get_untagged_SCBID; - cmp ARG_1, SCB_LIST_NULL je snoop_tag; - if ((p->flags & AHC_PAGESCBS) != 0) { - test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB; - } - /* - * If the SCB was found in the disconnected list (as is - * always the case in non-paging scenarios), SCBPTR is already - * set to the correct SCB. So, simply setup the SCB and get - * on with things. - */ - mov SCBPTR call rem_scb_from_disc_list; - jmp setup_SCB; -/* - * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. - * If we get one, we use the tag returned to find the proper - * SCB. With SCB paging, this requires using search for both tagged - * and non-tagged transactions since the SCB may exist in any slot. - * If we're not using SCB paging, we can use the tag as the direct - * index to the SCB. - */ -snoop_tag: - mov NONE,SCSIDATL; /* ACK Identify MSG */ -snoop_tag_loop: - call phase_lock; - cmp LASTPHASE, P_MESGIN jne not_found; - cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; -get_tag: - mvi ARG_1 call inb_next; /* tag value */ - -use_retrieveSCB: - call retrieveSCB; -setup_SCB: - mov A, SAVED_TCL; - cmp SCB_TCL, A jne not_found_cleanup_scb; - test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; - and SCB_CONTROL,~DISCONNECTED; - or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ - /* See if the host wants to send a message upon reconnection */ - test SCB_CONTROL, MK_MESSAGE jz mesgin_done; - and SCB_CONTROL, ~MK_MESSAGE; - mvi HOST_MSG call mk_mesg; - jmp mesgin_done; - -not_found_cleanup_scb: - test SCB_CONTROL, DISCONNECTED jz . + 3; - call add_scb_to_disc_list; - jmp not_found; - call add_scb_to_free_list; -not_found: - mvi INTSTAT, NO_MATCH; - mvi MSG_BUS_DEV_RESET call mk_mesg; - jmp mesgin_done; - -/* - * Message reject? Let the kernel driver handle this. If we have an - * outstanding WDTR or SDTR negotiation, assume that it's a response from - * the target selecting 8bit or asynchronous transfer, otherwise just ignore - * it since we have no clue what it pertains to. - */ -mesgin_reject: - mvi INTSTAT, REJECT_MSG; - jmp mesgin_done; - -/* - * Wide Residue. We handle the simple cases, but pass of the one hard case - * to the kernel (when the residue byte happened to cause us to advance our - * sg element array, so we know have to back that advance out). - */ -mesgin_wide_residue: - mvi ARG_1 call inb_next; /* ACK the wide_residue and get */ - /* the size byte */ -/* - * In order for this to be reliable, we have to do all sorts of horrible - * magic in terms of resetting the datafifo and reloading the shadow layer - * with the correct new values (so that a subsequent save data pointers - * message will do the right thing). We let the kernel do that work. - */ - mvi INTSTAT, WIDE_RESIDUE; - jmp mesgin_done; - -/* - * [ ADD MORE MESSAGE HANDLING HERE ] - */ - -/* - * Locking the driver out, build a one-byte message passed in SINDEX - * if there is no active message already. SINDEX is returned intact. - */ -mk_mesg: - or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ - mov MSG_OUT,SINDEX ret; - -/* - * Functions to read data in Automatic PIO mode. - * - * According to Adaptec's documentation, an ACK is not sent on input from - * the target until SCSIDATL is read from. So we wait until SCSIDATL is - * latched (the usual way), then read the data byte directly off the bus - * using SCSIBUSL. When we have pulled the ATN line, or we just want to - * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI - * spec guarantees that the target will hold the data byte on the bus until - * we send our ACK. - * - * The assumption here is that these are called in a particular sequence, - * and that REQ is already set when inb_first is called. inb_{first,next} - * use the same calling convention as inb. - */ - -inb_next: - mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ -inb_next_wait: - /* - * If there is a parity error, wait for the kernel to - * see the interrupt and prepare our message response - * before continuing. - */ - test SSTAT1, REQINIT jz inb_next_wait; - test SSTAT1, SCSIPERR jnz .; - and LASTPHASE, PHASE_MASK, SCSISIGI; - cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; -inb_first: - mov DINDEX,SINDEX; - mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ -inb_last: - mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ - - -mesgin_phasemis: -/* - * We expected to receive another byte, but the target changed phase - */ - mvi INTSTAT, MSGIN_PHASEMIS; - jmp ITloop; - -/* - * DMA data transfer. HADDR and HCNT must be loaded first, and - * SINDEX should contain the value to load DFCNTRL with - 0x3d for - * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared - * during initialization. - */ -if ((p->features & AHC_ULTRA2) == 0) { -dma: - mov DFCNTRL,SINDEX; -dma_loop: - test SSTAT0,DMADONE jnz dma_dmadone; - test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ -dma_phasemis: - test SSTAT0,SDONE jnz dma_checkfifo; - mov SINDEX,ALLZEROS; /* Notify caller of phasemiss */ - -/* - * We will be "done" DMAing when the transfer count goes to zero, or - * the target changes the phase (in light of this, it makes sense that - * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are - * doing a SCSI->Host transfer, the data FIFO should be flushed auto- - * magically on STCNT=0 or a phase change, so just wait for FIFO empty - * status. - */ -dma_checkfifo: - test DFCNTRL,DIRECTION jnz dma_fifoempty; -dma_fifoflush: - test DFSTATUS,FIFOEMP jz dma_fifoflush; - -dma_fifoempty: - /* Don't clobber an inprogress host data transfer */ - test DFSTATUS, MREQPEND jnz dma_fifoempty; -/* - * Now shut the DMA enables off and make sure that the DMA enables are - * actually off first lest we get an ILLSADDR. - */ -dma_dmadone: - cmp LASTPHASE, P_COMMAND je dma_await_nreq; - test SCSIRATE, 0x0f jnz dma_shutdown; -dma_await_nreq: - test SCSISIGI, REQI jz dma_shutdown; - test SSTAT1, (PHASEMIS|REQINIT) jz dma_await_nreq; -dma_shutdown: - and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); -dma_halt: - /* - * Some revisions of the aic7880 have a problem where, if the - * data fifo is full, but the PCI input latch is not empty, - * HDMAEN cannot be cleared. The fix used here is to attempt - * to drain the data fifo until there is space for the input - * latch to drain and HDMAEN de-asserts. - */ - if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) { - mov NONE, DFDAT; - } - test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; -} -return: - ret; - -/* - * Assert that if we've been reselected, then we've seen an IDENTIFY - * message. - */ -assert: - test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ - - mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */ - -/* - * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL) - * or by the SCBID ARG_1. The search begins at the SCB index passed in - * via SINDEX which is an SCB that must be on the disconnected list. If - * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR - * is set to the proper SCB. - */ -findSCB: - mov SCBPTR,SINDEX; /* Initialize SCBPTR */ - cmp ARG_1, SCB_LIST_NULL jne findSCB_by_SCBID; - mov A, SAVED_TCL; - mvi SCB_TCL jmp findSCB_loop; /* &SCB_TCL -> SINDEX */ -findSCB_by_SCBID: - mov A, ARG_1; /* Tag passed in ARG_1 */ - mvi SCB_TAG jmp findSCB_loop; /* &SCB_TAG -> SINDEX */ -findSCB_next: - mov ARG_2, SCBPTR; - cmp SCB_NEXT, SCB_LIST_NULL je notFound; - mov SCBPTR,SCB_NEXT; - dec SINDEX; /* Last comparison moved us too far */ -findSCB_loop: - cmp SINDIR, A jne findSCB_next; - mov SINDEX, SCBPTR ret; -notFound: - mvi SINDEX, SCB_LIST_NULL ret; - -/* - * Retrieve an SCB by SCBID first searching the disconnected list falling - * back to DMA'ing the SCB down from the host. This routine assumes that - * ARG_1 is the SCBID of interest and that SINDEX is the position in the - * disconnected list to start the search from. If SINDEX is SCB_LIST_NULL, - * we go directly to the host for the SCB. - */ -retrieveSCB: - test SEQ_FLAGS, SCBPTR_VALID jz retrieve_from_host; - mov SCBPTR call findSCB; /* Continue the search */ - cmp SINDEX, SCB_LIST_NULL je retrieve_from_host; - -/* - * This routine expects SINDEX to contain the index of the SCB to be - * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the - * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL - * if it is at the head. - */ -rem_scb_from_disc_list: -/* Remove this SCB from the disconnection list */ - cmp ARG_2, SCB_LIST_NULL je rHead; - mov DINDEX, SCB_NEXT; - mov SCBPTR, ARG_2; - mov SCB_NEXT, DINDEX; - mov SCBPTR, SINDEX ret; -rHead: - mov DISCONNECTED_SCBH,SCB_NEXT ret; - -retrieve_from_host: -/* - * We didn't find it. Pull an SCB and DMA down the one we want. - * We should never get here in the non-paging case. - */ - mov ALLZEROS call get_free_or_disc_scb; - mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - /* Jump instead of call as we want to return anyway */ - mov ARG_1 jmp dma_scb; - -/* - * Determine whether a target is using tagged or non-tagged transactions - * by first looking for a matching transaction based on the TCL and if - * that fails, looking up this device in the host's untagged SCB array. - * The TCL to search for is assumed to be in SAVED_TCL. The value is - * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged). - * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information - * in an SCB instead of having to go to the host. - */ -get_untagged_SCBID: - cmp DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host; - mvi ARG_1, SCB_LIST_NULL; - mov DISCONNECTED_SCBH call findSCB; - cmp SINDEX, SCB_LIST_NULL je get_SCBID_from_host; - or SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */ - test SCB_CONTROL, TAG_ENB jnz . + 2; - mov ARG_1, SCB_TAG ret; - mvi ARG_1, SCB_LIST_NULL ret; - -/* - * Fetch a byte from host memory given an index of (A + (256 * SINDEX)) - * and a base address of SCBID_ADDR. The byte is returned in RETURN_2. - */ -fetch_byte: - mov ARG_2, SINDEX; - if ((p->features & AHC_CMD_CHAN) != 0) { - mvi DINDEX, CCHADDR; - mvi SCBID_ADDR call set_1byte_addr; - mvi CCHCNT, 1; - mvi CCSGCTL, CCSGEN|CCSGRESET; - test CCSGCTL, CCSGDONE jz .; - mvi CCSGCTL, CCSGRESET; - bmov RETURN_2, CCSGRAM, 1 ret; - } else { - mvi DINDEX, HADDR; - mvi SCBID_ADDR call set_1byte_addr; - mvi HCNT[0], 1; - clr HCNT[1]; - clr HCNT[2]; - mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET; - call dma_finish; - mov RETURN_2, DFDAT ret; - } - -/* - * Prepare the hardware to post a byte to host memory given an - * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR. - */ -post_byte_setup: - mov ARG_2, SINDEX; - if ((p->features & AHC_CMD_CHAN) != 0) { - mvi DINDEX, CCHADDR; - mvi SCBID_ADDR call set_1byte_addr; - mvi CCHCNT, 1; - mvi CCSCBCTL, CCSCBRESET ret; - } else { - mvi DINDEX, HADDR; - mvi SCBID_ADDR call set_1byte_addr; - mvi HCNT[0], 1; - clr HCNT[1]; - clr HCNT[2]; - mvi DFCNTRL, FIFORESET ret; - } - -post_byte: - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov CCSCBRAM, SINDEX, 1; - or CCSCBCTL, CCSCBEN|CCSCBRESET; - test CCSCBCTL, CCSCBDONE jz .; - clr CCSCBCTL ret; - } else { - mov DFDAT, SINDEX; - or DFCNTRL, HDMAEN|FIFOFLUSH; - jmp dma_finish; - } - -get_SCBID_from_host: - mov A, SAVED_TCL; - mvi UNTAGGEDSCB_OFFSET call fetch_byte; - mov RETURN_1, RETURN_2 ret; - -phase_lock: - test SSTAT1, REQINIT jz phase_lock; - test SSTAT1, SCSIPERR jnz phase_lock; - and SCSISIGO, PHASE_MASK, SCSISIGI; - and LASTPHASE, PHASE_MASK, SCSISIGI ret; - -if ((p->features & AHC_CMD_CHAN) == 0) { -set_stcnt_from_hcnt: - mov STCNT[0], HCNT[0]; - mov STCNT[1], HCNT[1]; - mov STCNT[2], HCNT[2] ret; - -bcopy_7: - mov DINDIR, SINDIR; - mov DINDIR, SINDIR; -bcopy_5: - mov DINDIR, SINDIR; -bcopy_4: - mov DINDIR, SINDIR; -bcopy_3: - mov DINDIR, SINDIR; - mov DINDIR, SINDIR; - mov DINDIR, SINDIR ret; -} - -/* - * Setup addr assuming that A is an index into - * an array of 32byte objects, SINDEX contains - * the base address of that array, and DINDEX - * contains the base address of the location - * to store the indexed address. - */ -set_32byte_addr: - shr ARG_2, 3, A; - shl A, 5; -/* - * Setup addr assuming that A + (ARG_1 * 256) is an - * index into an array of 1byte objects, SINDEX contains - * the base address of that array, and DINDEX contains - * the base address of the location to store the computed - * address. - */ -set_1byte_addr: - add DINDIR, A, SINDIR; - mov A, ARG_2; - adc DINDIR, A, SINDIR; - clr A; - adc DINDIR, A, SINDIR; - adc DINDIR, A, SINDIR ret; - -/* - * Either post or fetch and SCB from host memory based on the - * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. - */ -dma_scb: - mov A, SINDEX; - if ((p->features & AHC_CMD_CHAN) != 0) { - mvi DINDEX, CCHADDR; - mvi HSCB_ADDR call set_32byte_addr; - mov CCSCBPTR, SCBPTR; - mvi CCHCNT, 32; - test DMAPARAMS, DIRECTION jz dma_scb_tohost; - mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; - cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; - jmp dma_scb_finish; -dma_scb_tohost: - if ((p->features & AHC_ULTRA2) == 0) { - mvi CCSCBCTL, CCSCBRESET; - bmov CCSCBRAM, SCB_CONTROL, 32; - or CCSCBCTL, CCSCBEN|CCSCBRESET; - test CCSCBCTL, CCSCBDONE jz .; - } - if ((p->features & AHC_ULTRA2) != 0) { - if ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0) { - mvi CCSCBCTL, CCARREN|CCSCBRESET; - cmp CCSCBCTL, ARRDONE|CCARREN jne .; - mvi CCHCNT, 32; - mvi CCSCBCTL, CCSCBEN|CCSCBRESET; - cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; - } else { - mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; - cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; - } - } -dma_scb_finish: - clr CCSCBCTL; - test CCSCBCTL, CCARREN|CCSCBEN jnz .; - ret; - } - if ((p->features & AHC_CMD_CHAN) == 0) { - mvi DINDEX, HADDR; - mvi HSCB_ADDR call set_32byte_addr; - mvi HCNT[0], 32; - clr HCNT[1]; - clr HCNT[2]; - mov DFCNTRL, DMAPARAMS; - test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; - /* Fill it with the SCB data */ -copy_scb_tofifo: - mvi SINDEX, SCB_CONTROL; - add A, 32, SINDEX; -copy_scb_tofifo_loop: - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - cmp SINDEX, A jne copy_scb_tofifo_loop; - or DFCNTRL, HDMAEN|FIFOFLUSH; - jmp dma_finish; -dma_scb_fromhost: - mvi DINDEX, SCB_CONTROL; - if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) { - /* - * Set the A to -24. It it hits 0, then we let - * our code fall through to dfdat_in_8 to complete - * the last of the copy. - * - * Also, things happen 8 bytes at a time in this - * case, so we may need to drain the fifo at most - * 3 times to keep things flowing - */ - mvi A, -24; -dma_scb_hang_fifo: - /* Wait for the first bit of data to hit the fifo */ - test DFSTATUS, FIFOEMP jnz .; -dma_scb_hang_wait: - /* OK, now they've started to transfer into the fifo, - * so wait for them to stop trying to transfer any - * more data. - */ - test DFSTATUS, MREQPEND jnz .; - /* - * OK, they started, then they stopped, now see if they - * managed to complete the job before stopping. Try - * it multiple times to give the chip a few cycles to - * set the flag if it did complete. - */ - test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; - test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; - test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; - /* - * Too bad, the chip didn't complete the DMA, but there - * aren't any more memory requests pending, so that - * means it stopped part way through and hung. That's - * our bug, so now we drain what data there is in the - * fifo in order to get things going again. - */ -dma_scb_hang_empty_fifo: - call dfdat_in_8; - add A, 8; - add SINDEX, A, HCNT; - /* - * If there are another 8 bytes of data waiting in the - * fifo, then the carry bit will be set as a result - * of the above add command (unless A is non-negative, - * in which case the carry bit won't be set). - */ - jc dma_scb_hang_empty_fifo; - /* - * We've emptied the fifo now, but we wouldn't have got - * here if the memory transfer hadn't stopped part way - * through, so go back up to the beginning of the - * loop and start over. When it succeeds in getting - * all the data down, HDONE will be set and we'll - * jump to the code just below here. - */ - jmp dma_scb_hang_fifo; -dma_scb_hang_dma_done: - and DFCNTRL, ~HDMAEN; - test DFCNTRL, HDMAEN jnz .; - call dfdat_in_8; - add A, 8; - cmp A, 8 jne . - 2; - ret; - } else { - call dma_finish; - call dfdat_in_8; - call dfdat_in_8; - call dfdat_in_8; - } -dfdat_in_8: - mov DINDIR,DFDAT; -dfdat_in_7: - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT ret; - } - - -/* - * Wait for DMA from host memory to data FIFO to complete, then disable - * DMA and wait for it to acknowledge that it's off. - */ -if ((p->features & AHC_CMD_CHAN) == 0) { -dma_finish: - test DFSTATUS,HDONE jz dma_finish; - /* Turn off DMA */ - and DFCNTRL, ~HDMAEN; - test DFCNTRL, HDMAEN jnz .; - ret; -} - -add_scb_to_free_list: - if ((p->flags & AHC_PAGESCBS) != 0) { - mov SCB_NEXT, FREE_SCBH; - mov FREE_SCBH, SCBPTR; - } - mvi SCB_TAG, SCB_LIST_NULL ret; - -if ((p->flags & AHC_PAGESCBS) != 0) { -get_free_or_disc_scb: - cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; - cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; -return_error: - mvi SINDEX, SCB_LIST_NULL ret; -dequeue_disc_scb: - mov SCBPTR, DISCONNECTED_SCBH; -dma_up_scb: - mvi DMAPARAMS, FIFORESET; - mov SCB_TAG call dma_scb; -unlink_disc_scb: - mov DISCONNECTED_SCBH, SCB_NEXT ret; -dequeue_free_scb: - mov SCBPTR, FREE_SCBH; - mov FREE_SCBH, SCB_NEXT ret; -} - -add_scb_to_disc_list: -/* - * Link this SCB into the DISCONNECTED list. This list holds the - * candidates for paging out an SCB if one is needed for a new command. - * Modifying the disconnected list is a critical(pause dissabled) section. - */ - mov SCB_NEXT, DISCONNECTED_SCBH; - mov DISCONNECTED_SCBH, SCBPTR ret; diff --git a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c deleted file mode 100644 index 976f45ccf2cf..000000000000 --- a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c +++ /dev/null @@ -1,270 +0,0 @@ -/*+M************************************************************************* - * Adaptec AIC7xxx device driver proc support for Linux. - * - * Copyright (c) 1995, 1996 Dean W. Gehnert - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * ---------------------------------------------------------------- - * o Modified from the EATA-DMA /proc support. - * o Additional support for device block statistics provided by - * Matthew Jacob. - * o Correction of overflow by Heinz Mauelshagen - * o Adittional corrections by Doug Ledford - * - * Dean W. Gehnert, deang@teleport.com, 05/01/96 - * - * $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $ - *-M*************************************************************************/ - - -#define HDRB \ -" 0 - 4K 4 - 16K 16 - 64K 64 - 256K 256K - 1M 1M+" - - -/*+F************************************************************************* - * Function: - * aic7xxx_show_info - * - * Description: - * Return information to handle /proc support for the driver. - *-F*************************************************************************/ -int -aic7xxx_show_info(struct seq_file *m, struct Scsi_Host *HBAptr) -{ - struct aic7xxx_host *p; - struct aic_dev_data *aic_dev; - struct scsi_device *sdptr; - unsigned char i; - unsigned char tindex; - - for(p=first_aic7xxx; p && p->host != HBAptr; p=p->next) - ; - - if (!p) - { - seq_printf(m, "Can't find adapter for host number %d\n", HBAptr->host_no); - return 0; - } - - p = (struct aic7xxx_host *) HBAptr->hostdata; - - seq_printf(m, "Adaptec AIC7xxx driver version: "); - seq_printf(m, "%s/", AIC7XXX_C_VERSION); - seq_printf(m, "%s", AIC7XXX_H_VERSION); - seq_printf(m, "\n"); - seq_printf(m, "Adapter Configuration:\n"); - seq_printf(m, " SCSI Adapter: %s\n", - board_names[p->board_name_index]); - if (p->flags & AHC_TWIN) - seq_printf(m, " Twin Channel Controller "); - else - { - char *channel = ""; - char *ultra = ""; - char *wide = "Narrow "; - if (p->flags & AHC_MULTI_CHANNEL) - { - channel = " Channel A"; - if (p->flags & (AHC_CHNLB|AHC_CHNLC)) - channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C"; - } - if (p->features & AHC_WIDE) - wide = "Wide "; - if (p->features & AHC_ULTRA3) - { - switch(p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7892: - case AHC_AIC7899: - ultra = "Ultra-160/m LVD/SE "; - break; - default: - ultra = "Ultra-3 LVD/SE "; - break; - } - } - else if (p->features & AHC_ULTRA2) - ultra = "Ultra-2 LVD/SE "; - else if (p->features & AHC_ULTRA) - ultra = "Ultra "; - seq_printf(m, " %s%sController%s ", - ultra, wide, channel); - } - switch(p->chip & ~AHC_CHIPID_MASK) - { - case AHC_VL: - seq_printf(m, "at VLB slot %d\n", p->pci_device_fn); - break; - case AHC_EISA: - seq_printf(m, "at EISA slot %d\n", p->pci_device_fn); - break; - default: - seq_printf(m, "at PCI %d/%d/%d\n", p->pci_bus, - PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn)); - break; - } - if( !(p->maddr) ) - { - seq_printf(m, " Programmed I/O Base: %lx\n", p->base); - } - else - { - seq_printf(m, " PCI MMAPed I/O Base: 0x%lx\n", p->mbase); - } - if( (p->chip & (AHC_VL | AHC_EISA)) ) - { - seq_printf(m, " BIOS Memory Address: 0x%08x\n", p->bios_address); - } - seq_printf(m, " Adapter SEEPROM Config: %s\n", - (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." : - ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." : - "SEEPROM not found, using leftover BIOS values.") ); - seq_printf(m, " Adaptec SCSI BIOS: %s\n", - (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled"); - seq_printf(m, " IRQ: %d\n", HBAptr->irq); - seq_printf(m, " SCBs: Active %d, Max Active %d,\n", - p->activescbs, p->max_activescbs); - seq_printf(m, " Allocated %d, HW %d, " - "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs, - p->scb_data->maxscbs); - if (p->flags & AHC_EXTERNAL_SRAM) - seq_printf(m, " Using External SCB SRAM\n"); - seq_printf(m, " Interrupts: %ld", p->isr_count); - if (p->chip & AHC_EISA) - { - seq_printf(m, " %s\n", - (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)"); - } - else - { - seq_printf(m, "\n"); - } - seq_printf(m, " BIOS Control Word: 0x%04x\n", - p->bios_control); - seq_printf(m, " Adapter Control Word: 0x%04x\n", - p->adapter_control); - seq_printf(m, " Extended Translation: %sabled\n", - (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis"); - seq_printf(m, "Disconnect Enable Flags: 0x%04x\n", p->discenable); - if (p->features & (AHC_ULTRA | AHC_ULTRA2)) - { - seq_printf(m, " Ultra Enable Flags: 0x%04x\n", p->ultraenb); - } - seq_printf(m, "Default Tag Queue Depth: %d\n", aic7xxx_default_queue_depth); - seq_printf(m, " Tagged Queue By Device array for aic7xxx host " - "instance %d:\n", p->instance); - seq_printf(m, " {"); - for(i=0; i < (MAX_TARGETS - 1); i++) - seq_printf(m, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]); - seq_printf(m, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]); - - seq_printf(m, "\n"); - seq_printf(m, "Statistics:\n\n"); - list_for_each_entry(aic_dev, &p->aic_devs, list) - { - sdptr = aic_dev->SDptr; - tindex = sdptr->channel << 3 | sdptr->id; - seq_printf(m, "(scsi%d:%d:%d:%d)\n", - p->host_no, sdptr->channel, sdptr->id, sdptr->lun); - seq_printf(m, " Device using %s/%s", - (aic_dev->cur.width == MSG_EXT_WDTR_BUS_16_BIT) ? - "Wide" : "Narrow", - (aic_dev->cur.offset != 0) ? - "Sync transfers at " : "Async transfers.\n" ); - if (aic_dev->cur.offset != 0) - { - struct aic7xxx_syncrate *sync_rate; - unsigned char options = aic_dev->cur.options; - int period = aic_dev->cur.period; - int rate = (aic_dev->cur.width == - MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0; - - sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options); - if (sync_rate != NULL) - { - seq_printf(m, "%s MByte/sec, offset %d\n", - sync_rate->rate[rate], - aic_dev->cur.offset ); - } - else - { - seq_printf(m, "3.3 MByte/sec, offset %d\n", - aic_dev->cur.offset ); - } - } - seq_printf(m, " Transinfo settings: "); - seq_printf(m, "current(%d/%d/%d/%d), ", - aic_dev->cur.period, - aic_dev->cur.offset, - aic_dev->cur.width, - aic_dev->cur.options); - seq_printf(m, "goal(%d/%d/%d/%d), ", - aic_dev->goal.period, - aic_dev->goal.offset, - aic_dev->goal.width, - aic_dev->goal.options); - seq_printf(m, "user(%d/%d/%d/%d)\n", - p->user[tindex].period, - p->user[tindex].offset, - p->user[tindex].width, - p->user[tindex].options); - if(sdptr->simple_tags) - { - seq_printf(m, " Tagged Command Queueing Enabled, Ordered Tags %s, Depth %d/%d\n", sdptr->ordered_tags ? "Enabled" : "Disabled", sdptr->queue_depth, aic_dev->max_q_depth); - } - if(aic_dev->barrier_total) - seq_printf(m, " Total transfers %ld:\n (%ld/%ld/%ld/%ld reads/writes/REQ_BARRIER/Ordered Tags)\n", - aic_dev->r_total+aic_dev->w_total, aic_dev->r_total, aic_dev->w_total, - aic_dev->barrier_total, aic_dev->ordered_total); - else - seq_printf(m, " Total transfers %ld:\n (%ld/%ld reads/writes)\n", - aic_dev->r_total+aic_dev->w_total, aic_dev->r_total, aic_dev->w_total); - seq_printf(m, "%s\n", HDRB); - seq_printf(m, " Reads:"); - for (i = 0; i < ARRAY_SIZE(aic_dev->r_bins); i++) - { - seq_printf(m, " %10ld", aic_dev->r_bins[i]); - } - seq_printf(m, "\n"); - seq_printf(m, " Writes:"); - for (i = 0; i < ARRAY_SIZE(aic_dev->w_bins); i++) - { - seq_printf(m, " %10ld", aic_dev->w_bins[i]); - } - seq_printf(m, "\n"); - seq_printf(m, "\n\n"); - } - return 0; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 2 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -2 - * c-argdecl-indent: 2 - * c-label-offset: -2 - * c-continued-statement-offset: 2 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ diff --git a/drivers/scsi/aic7xxx_old/aic7xxx_reg.h b/drivers/scsi/aic7xxx_old/aic7xxx_reg.h deleted file mode 100644 index 27f2334abc71..000000000000 --- a/drivers/scsi/aic7xxx_old/aic7xxx_reg.h +++ /dev/null @@ -1,629 +0,0 @@ -/* - * DO NOT EDIT - This file is automatically generated. - */ - -#define SCSISEQ 0x00 -#define TEMODE 0x80 -#define ENSELO 0x40 -#define ENSELI 0x20 -#define ENRSELI 0x10 -#define ENAUTOATNO 0x08 -#define ENAUTOATNI 0x04 -#define ENAUTOATNP 0x02 -#define SCSIRSTO 0x01 - -#define SXFRCTL0 0x01 -#define DFON 0x80 -#define DFPEXP 0x40 -#define FAST20 0x20 -#define CLRSTCNT 0x10 -#define SPIOEN 0x08 -#define SCAMEN 0x04 -#define CLRCHN 0x02 - -#define SXFRCTL1 0x02 -#define BITBUCKET 0x80 -#define SWRAPEN 0x40 -#define ENSPCHK 0x20 -#define STIMESEL 0x18 -#define ENSTIMER 0x04 -#define ACTNEGEN 0x02 -#define STPWEN 0x01 - -#define SCSISIGO 0x03 -#define CDO 0x80 -#define IOO 0x40 -#define MSGO 0x20 -#define ATNO 0x10 -#define SELO 0x08 -#define BSYO 0x04 -#define REQO 0x02 -#define ACKO 0x01 - -#define SCSISIGI 0x03 -#define ATNI 0x10 -#define SELI 0x08 -#define BSYI 0x04 -#define REQI 0x02 -#define ACKI 0x01 - -#define SCSIRATE 0x04 -#define WIDEXFER 0x80 -#define SXFR_ULTRA2 0x7f -#define SXFR 0x70 -#define SOFS 0x0f - -#define SCSIID 0x05 -#define SCSIOFFSET 0x05 -#define SOFS_ULTRA2 0x7f - -#define SCSIDATL 0x06 - -#define SCSIDATH 0x07 - -#define STCNT 0x08 - -#define OPTIONMODE 0x08 -#define AUTORATEEN 0x80 -#define AUTOACKEN 0x40 -#define ATNMGMNTEN 0x20 -#define BUSFREEREV 0x10 -#define EXPPHASEDIS 0x08 -#define SCSIDATL_IMGEN 0x04 -#define AUTO_MSGOUT_DE 0x02 -#define DIS_MSGIN_DUALEDGE 0x01 - -#define CLRSINT0 0x0b -#define CLRSELDO 0x40 -#define CLRSELDI 0x20 -#define CLRSELINGO 0x10 -#define CLRSWRAP 0x08 -#define CLRSPIORDY 0x02 - -#define SSTAT0 0x0b -#define TARGET 0x80 -#define SELDO 0x40 -#define SELDI 0x20 -#define SELINGO 0x10 -#define IOERR 0x08 -#define SWRAP 0x08 -#define SDONE 0x04 -#define SPIORDY 0x02 -#define DMADONE 0x01 - -#define CLRSINT1 0x0c -#define CLRSELTIMEO 0x80 -#define CLRATNO 0x40 -#define CLRSCSIRSTI 0x20 -#define CLRBUSFREE 0x08 -#define CLRSCSIPERR 0x04 -#define CLRPHASECHG 0x02 -#define CLRREQINIT 0x01 - -#define SSTAT1 0x0c -#define SELTO 0x80 -#define ATNTARG 0x40 -#define SCSIRSTI 0x20 -#define PHASEMIS 0x10 -#define BUSFREE 0x08 -#define SCSIPERR 0x04 -#define PHASECHG 0x02 -#define REQINIT 0x01 - -#define SSTAT2 0x0d -#define OVERRUN 0x80 -#define SHVALID 0x40 -#define WIDE_RES 0x20 -#define SFCNT 0x1f -#define EXP_ACTIVE 0x10 -#define CRCVALERR 0x08 -#define CRCENDERR 0x04 -#define CRCREQERR 0x02 -#define DUAL_EDGE_ERROR 0x01 - -#define SSTAT3 0x0e -#define SCSICNT 0xf0 -#define OFFCNT 0x0f - -#define SCSIID_ULTRA2 0x0f -#define OID 0x0f - -#define SIMODE0 0x10 -#define ENSELDO 0x40 -#define ENSELDI 0x20 -#define ENSELINGO 0x10 -#define ENIOERR 0x08 -#define ENSWRAP 0x08 -#define ENSDONE 0x04 -#define ENSPIORDY 0x02 -#define ENDMADONE 0x01 - -#define SIMODE1 0x11 -#define ENSELTIMO 0x80 -#define ENATNTARG 0x40 -#define ENSCSIRST 0x20 -#define ENPHASEMIS 0x10 -#define ENBUSFREE 0x08 -#define ENSCSIPERR 0x04 -#define ENPHASECHG 0x02 -#define ENREQINIT 0x01 - -#define SCSIBUSL 0x12 - -#define SCSIBUSH 0x13 - -#define SHADDR 0x14 - -#define SELTIMER 0x18 -#define STAGE6 0x20 -#define STAGE5 0x10 -#define STAGE4 0x08 -#define STAGE3 0x04 -#define STAGE2 0x02 -#define STAGE1 0x01 - -#define SELID 0x19 -#define SELID_MASK 0xf0 -#define ONEBIT 0x08 - -#define SPIOCAP 0x1b -#define SOFT1 0x80 -#define SOFT0 0x40 -#define SOFTCMDEN 0x20 -#define HAS_BRDCTL 0x10 -#define SEEPROM 0x08 -#define EEPROM 0x04 -#define ROM 0x02 -#define SSPIOCPS 0x01 - -#define BRDCTL 0x1d -#define BRDDAT7 0x80 -#define BRDDAT6 0x40 -#define BRDDAT5 0x20 -#define BRDDAT4 0x10 -#define BRDSTB 0x10 -#define BRDCS 0x08 -#define BRDDAT3 0x08 -#define BRDDAT2 0x04 -#define BRDRW 0x04 -#define BRDRW_ULTRA2 0x02 -#define BRDCTL1 0x02 -#define BRDSTB_ULTRA2 0x01 -#define BRDCTL0 0x01 - -#define SEECTL 0x1e -#define EXTARBACK 0x80 -#define EXTARBREQ 0x40 -#define SEEMS 0x20 -#define SEERDY 0x10 -#define SEECS 0x08 -#define SEECK 0x04 -#define SEEDO 0x02 -#define SEEDI 0x01 - -#define SBLKCTL 0x1f -#define DIAGLEDEN 0x80 -#define DIAGLEDON 0x40 -#define AUTOFLUSHDIS 0x20 -#define ENAB40 0x08 -#define ENAB20 0x04 -#define SELWIDE 0x02 -#define XCVR 0x01 - -#define SRAM_BASE 0x20 - -#define TARG_SCSIRATE 0x20 - -#define ULTRA_ENB 0x30 - -#define DISC_DSB 0x32 - -#define MSG_OUT 0x34 - -#define DMAPARAMS 0x35 -#define PRELOADEN 0x80 -#define WIDEODD 0x40 -#define SCSIEN 0x20 -#define SDMAENACK 0x10 -#define SDMAEN 0x10 -#define HDMAEN 0x08 -#define HDMAENACK 0x08 -#define DIRECTION 0x04 -#define FIFOFLUSH 0x02 -#define FIFORESET 0x01 - -#define SEQ_FLAGS 0x36 -#define IDENTIFY_SEEN 0x80 -#define SCBPTR_VALID 0x20 -#define DPHASE 0x10 -#define AMTARGET 0x08 -#define WIDE_BUS 0x02 -#define TWIN_BUS 0x01 - -#define SAVED_TCL 0x37 - -#define SG_COUNT 0x38 - -#define SG_NEXT 0x39 - -#define LASTPHASE 0x3d -#define P_MESGIN 0xe0 -#define PHASE_MASK 0xe0 -#define P_STATUS 0xc0 -#define P_MESGOUT 0xa0 -#define P_COMMAND 0x80 -#define CDI 0x80 -#define IOI 0x40 -#define P_DATAIN 0x40 -#define MSGI 0x20 -#define P_BUSFREE 0x01 -#define P_DATAOUT 0x00 - -#define WAITING_SCBH 0x3e - -#define DISCONNECTED_SCBH 0x3f - -#define FREE_SCBH 0x40 - -#define HSCB_ADDR 0x41 - -#define SCBID_ADDR 0x45 - -#define TMODE_CMDADDR 0x49 - -#define KERNEL_QINPOS 0x4d - -#define QINPOS 0x4e - -#define QOUTPOS 0x4f - -#define TMODE_CMDADDR_NEXT 0x50 - -#define ARG_1 0x51 -#define RETURN_1 0x51 -#define SEND_MSG 0x80 -#define SEND_SENSE 0x40 -#define SEND_REJ 0x20 -#define MSGOUT_PHASEMIS 0x10 - -#define ARG_2 0x52 -#define RETURN_2 0x52 - -#define LAST_MSG 0x53 - -#define PREFETCH_CNT 0x54 - -#define SCSICONF 0x5a -#define TERM_ENB 0x80 -#define RESET_SCSI 0x40 -#define HWSCSIID 0x0f -#define HSCSIID 0x07 - -#define HOSTCONF 0x5d - -#define HA_274_BIOSCTRL 0x5f -#define BIOSMODE 0x30 -#define BIOSDISABLED 0x30 -#define CHANNEL_B_PRIMARY 0x08 - -#define SEQCTL 0x60 -#define PERRORDIS 0x80 -#define PAUSEDIS 0x40 -#define FAILDIS 0x20 -#define FASTMODE 0x10 -#define BRKADRINTEN 0x08 -#define STEP 0x04 -#define SEQRESET 0x02 -#define LOADRAM 0x01 - -#define SEQRAM 0x61 - -#define SEQADDR0 0x62 - -#define SEQADDR1 0x63 -#define SEQADDR1_MASK 0x01 - -#define ACCUM 0x64 - -#define SINDEX 0x65 - -#define DINDEX 0x66 - -#define ALLONES 0x69 - -#define ALLZEROS 0x6a - -#define NONE 0x6a - -#define FLAGS 0x6b -#define ZERO 0x02 -#define CARRY 0x01 - -#define SINDIR 0x6c - -#define DINDIR 0x6d - -#define FUNCTION1 0x6e - -#define STACK 0x6f - -#define TARG_OFFSET 0x70 - -#define BCTL 0x84 -#define ACE 0x08 -#define ENABLE 0x01 - -#define DSCOMMAND0 0x84 -#define INTSCBRAMSEL 0x08 -#define RAMPS 0x04 -#define USCBSIZE32 0x02 -#define CIOPARCKEN 0x01 - -#define DSCOMMAND 0x84 -#define CACHETHEN 0x80 -#define DPARCKEN 0x40 -#define MPARCKEN 0x20 -#define EXTREQLCK 0x10 - -#define BUSTIME 0x85 -#define BOFF 0xf0 -#define BON 0x0f - -#define BUSSPD 0x86 -#define DFTHRSH 0xc0 -#define STBOFF 0x38 -#define STBON 0x07 - -#define DSPCISTATUS 0x86 -#define DFTHRSH_100 0xc0 - -#define HCNTRL 0x87 -#define POWRDN 0x40 -#define SWINT 0x10 -#define IRQMS 0x08 -#define PAUSE 0x04 -#define INTEN 0x02 -#define CHIPRST 0x01 -#define CHIPRSTACK 0x01 - -#define HADDR 0x88 - -#define HCNT 0x8c - -#define SCBPTR 0x90 - -#define INTSTAT 0x91 -#define SEQINT_MASK 0xf1 -#define DATA_OVERRUN 0xe1 -#define MSGIN_PHASEMIS 0xd1 -#define TRACEPOINT2 0xc1 -#define SEQ_SG_FIXUP 0xb1 -#define AWAITING_MSG 0xa1 -#define RESIDUAL 0x81 -#define BAD_STATUS 0x71 -#define REJECT_MSG 0x61 -#define WIDE_RESIDUE 0x51 -#define EXTENDED_MSG 0x41 -#define NO_MATCH 0x31 -#define NO_IDENT 0x21 -#define SEND_REJECT 0x11 -#define INT_PEND 0x0f -#define BRKADRINT 0x08 -#define SCSIINT 0x04 -#define CMDCMPLT 0x02 -#define BAD_PHASE 0x01 -#define SEQINT 0x01 - -#define CLRINT 0x92 -#define CLRPARERR 0x10 -#define CLRBRKADRINT 0x08 -#define CLRSCSIINT 0x04 -#define CLRCMDINT 0x02 -#define CLRSEQINT 0x01 - -#define ERROR 0x92 -#define CIOPARERR 0x80 -#define PCIERRSTAT 0x40 -#define MPARERR 0x20 -#define DPARERR 0x10 -#define SQPARERR 0x08 -#define ILLOPCODE 0x04 -#define DSCTMOUT 0x02 -#define ILLSADDR 0x02 -#define ILLHADDR 0x01 - -#define DFCNTRL 0x93 - -#define DFSTATUS 0x94 -#define PRELOAD_AVAIL 0x80 -#define DWORDEMP 0x20 -#define MREQPEND 0x10 -#define HDONE 0x08 -#define DFTHRESH 0x04 -#define FIFOFULL 0x02 -#define FIFOEMP 0x01 - -#define DFDAT 0x99 - -#define SCBCNT 0x9a -#define SCBAUTO 0x80 -#define SCBCNT_MASK 0x1f - -#define QINFIFO 0x9b - -#define QINCNT 0x9c - -#define SCSIDATL_IMG 0x9c - -#define QOUTFIFO 0x9d - -#define CRCCONTROL1 0x9d -#define CRCONSEEN 0x80 -#define CRCVALCHKEN 0x40 -#define CRCENDCHKEN 0x20 -#define CRCREQCHKEN 0x10 -#define TARGCRCENDEN 0x08 -#define TARGCRCCNTEN 0x04 - -#define SCSIPHASE 0x9e -#define SP_STATUS 0x20 -#define SP_COMMAND 0x10 -#define SP_MSG_IN 0x08 -#define SP_MSG_OUT 0x04 -#define SP_DATA_IN 0x02 -#define SP_DATA_OUT 0x01 - -#define QOUTCNT 0x9e - -#define SFUNCT 0x9f -#define ALT_MODE 0x80 - -#define SCB_CONTROL 0xa0 -#define MK_MESSAGE 0x80 -#define DISCENB 0x40 -#define TAG_ENB 0x20 -#define DISCONNECTED 0x04 -#define SCB_TAG_TYPE 0x03 - -#define SCB_BASE 0xa0 - -#define SCB_TCL 0xa1 -#define TID 0xf0 -#define SELBUSB 0x08 -#define LID 0x07 - -#define SCB_TARGET_STATUS 0xa2 - -#define SCB_SGCOUNT 0xa3 - -#define SCB_SGPTR 0xa4 - -#define SCB_RESID_SGCNT 0xa8 - -#define SCB_RESID_DCNT 0xa9 - -#define SCB_DATAPTR 0xac - -#define SCB_DATACNT 0xb0 - -#define SCB_CMDPTR 0xb4 - -#define SCB_CMDLEN 0xb8 - -#define SCB_TAG 0xb9 - -#define SCB_NEXT 0xba - -#define SCB_PREV 0xbb - -#define SCB_BUSYTARGETS 0xbc - -#define SEECTL_2840 0xc0 -#define CS_2840 0x04 -#define CK_2840 0x02 -#define DO_2840 0x01 - -#define STATUS_2840 0xc1 -#define EEPROM_TF 0x80 -#define BIOS_SEL 0x60 -#define ADSEL 0x1e -#define DI_2840 0x01 - -#define CCHADDR 0xe0 - -#define CCHCNT 0xe8 - -#define CCSGRAM 0xe9 - -#define CCSGADDR 0xea - -#define CCSGCTL 0xeb -#define CCSGDONE 0x80 -#define CCSGEN 0x08 -#define FLAG 0x02 -#define CCSGRESET 0x01 - -#define CCSCBRAM 0xec - -#define CCSCBADDR 0xed - -#define CCSCBCTL 0xee -#define CCSCBDONE 0x80 -#define ARRDONE 0x40 -#define CCARREN 0x10 -#define CCSCBEN 0x08 -#define CCSCBDIR 0x04 -#define CCSCBRESET 0x01 - -#define CCSCBCNT 0xef - -#define CCSCBPTR 0xf1 - -#define HNSCB_QOFF 0xf4 - -#define HESCB_QOFF 0xf5 - -#define SNSCB_QOFF 0xf6 - -#define SESCB_QOFF 0xf7 - -#define SDSCB_QOFF 0xf8 - -#define QOFF_CTLSTA 0xfa -#define ESTABLISH_SCB_AVAIL 0x80 -#define SCB_AVAIL 0x40 -#define SNSCB_ROLLOVER 0x20 -#define SDSCB_ROLLOVER 0x10 -#define SESCB_ROLLOVER 0x08 -#define SCB_QSIZE 0x07 -#define SCB_QSIZE_256 0x06 - -#define DFF_THRSH 0xfb -#define WR_DFTHRSH 0x70 -#define WR_DFTHRSH_MAX 0x70 -#define WR_DFTHRSH_90 0x60 -#define WR_DFTHRSH_85 0x50 -#define WR_DFTHRSH_75 0x40 -#define WR_DFTHRSH_63 0x30 -#define WR_DFTHRSH_50 0x20 -#define WR_DFTHRSH_25 0x10 -#define RD_DFTHRSH_MAX 0x07 -#define RD_DFTHRSH 0x07 -#define RD_DFTHRSH_90 0x06 -#define RD_DFTHRSH_85 0x05 -#define RD_DFTHRSH_75 0x04 -#define RD_DFTHRSH_63 0x03 -#define RD_DFTHRSH_50 0x02 -#define RD_DFTHRSH_25 0x01 -#define WR_DFTHRSH_MIN 0x00 -#define RD_DFTHRSH_MIN 0x00 - -#define SG_CACHEPTR 0xfc -#define SG_USER_DATA 0xfc -#define LAST_SEG 0x02 -#define LAST_SEG_DONE 0x01 - - -#define CMD_GROUP2_BYTE_DELTA 0xfa -#define MAX_OFFSET_8BIT 0x0f -#define BUS_16_BIT 0x01 -#define QINFIFO_OFFSET 0x02 -#define CMD_GROUP5_BYTE_DELTA 0x0b -#define CMD_GROUP_CODE_SHIFT 0x05 -#define MAX_OFFSET_ULTRA2 0x7f -#define MAX_OFFSET_16BIT 0x08 -#define BUS_8_BIT 0x00 -#define QOUTFIFO_OFFSET 0x01 -#define UNTAGGEDSCB_OFFSET 0x00 -#define CCSGRAM_MAXSEGS 0x10 -#define SCB_LIST_NULL 0xff -#define SG_SIZEOF 0x08 -#define CMD_GROUP4_BYTE_DELTA 0x04 -#define CMD_GROUP0_BYTE_DELTA 0xfc -#define HOST_MSG 0xff -#define BUS_32_BIT 0x02 -#define CCSGADDR_MAX 0x80 - - -/* Downloaded Constant Definitions */ -#define TMODE_NUMCMDS 0x00 diff --git a/drivers/scsi/aic7xxx_old/aic7xxx_seq.c b/drivers/scsi/aic7xxx_old/aic7xxx_seq.c deleted file mode 100644 index e1bc140e9735..000000000000 --- a/drivers/scsi/aic7xxx_old/aic7xxx_seq.c +++ /dev/null @@ -1,817 +0,0 @@ -/* - * DO NOT EDIT - This file is automatically generated. - */ -static unsigned char seqprog[] = { - 0xff, 0x6a, 0x06, 0x08, - 0x7f, 0x02, 0x04, 0x08, - 0x12, 0x6a, 0x00, 0x00, - 0xff, 0x6a, 0xd6, 0x09, - 0xff, 0x6a, 0xdc, 0x09, - 0x00, 0x65, 0xca, 0x58, - 0xf7, 0x01, 0x02, 0x08, - 0xff, 0x4e, 0xc8, 0x08, - 0xbf, 0x60, 0xc0, 0x08, - 0x60, 0x0b, 0x86, 0x68, - 0x40, 0x00, 0x0c, 0x68, - 0x08, 0x1f, 0x3e, 0x10, - 0x60, 0x0b, 0x86, 0x68, - 0x40, 0x00, 0x0c, 0x68, - 0x08, 0x1f, 0x3e, 0x10, - 0xff, 0x3e, 0x48, 0x60, - 0x40, 0xfa, 0x10, 0x78, - 0xff, 0xf6, 0xd4, 0x08, - 0x01, 0x4e, 0x9c, 0x18, - 0x40, 0x60, 0xc0, 0x00, - 0x00, 0x4d, 0x10, 0x70, - 0x01, 0x4e, 0x9c, 0x18, - 0xbf, 0x60, 0xc0, 0x08, - 0x00, 0x6a, 0x86, 0x5c, - 0xff, 0x4e, 0xc8, 0x18, - 0x02, 0x6a, 0x70, 0x5b, - 0xff, 0x52, 0x20, 0x09, - 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0x52, 0xe6, 0x5b, - 0x03, 0xb0, 0x52, 0x31, - 0xff, 0xb0, 0x52, 0x09, - 0xff, 0xb1, 0x54, 0x09, - 0xff, 0xb2, 0x56, 0x09, - 0xff, 0xa3, 0x50, 0x09, - 0xff, 0x3e, 0x74, 0x09, - 0xff, 0x90, 0x7c, 0x08, - 0xff, 0x3e, 0x20, 0x09, - 0x00, 0x65, 0x4e, 0x58, - 0x00, 0x65, 0x0c, 0x40, - 0xf7, 0x1f, 0xca, 0x08, - 0x08, 0xa1, 0xc8, 0x08, - 0x00, 0x65, 0xca, 0x00, - 0xff, 0x65, 0x3e, 0x08, - 0xf0, 0xa1, 0xc8, 0x08, - 0x0f, 0x0f, 0x1e, 0x08, - 0x00, 0x0f, 0x1e, 0x00, - 0xf0, 0xa1, 0xc8, 0x08, - 0x0f, 0x05, 0x0a, 0x08, - 0x00, 0x05, 0x0a, 0x00, - 0xff, 0x6a, 0x0c, 0x08, - 0x5a, 0x6a, 0x00, 0x04, - 0x12, 0x65, 0x02, 0x00, - 0x31, 0x6a, 0xca, 0x00, - 0x80, 0x37, 0x6e, 0x68, - 0xff, 0x65, 0xca, 0x18, - 0xff, 0x37, 0xdc, 0x08, - 0xff, 0x6e, 0xc8, 0x08, - 0x00, 0x6c, 0x76, 0x78, - 0x20, 0x01, 0x02, 0x00, - 0x4c, 0x37, 0xc8, 0x28, - 0x08, 0x1f, 0x7e, 0x78, - 0x08, 0x37, 0x6e, 0x00, - 0x08, 0x64, 0xc8, 0x00, - 0x70, 0x64, 0xca, 0x18, - 0xff, 0x6c, 0x0a, 0x08, - 0x20, 0x64, 0xca, 0x18, - 0xff, 0x6c, 0x08, 0x0c, - 0x40, 0x0b, 0x96, 0x68, - 0x20, 0x6a, 0x16, 0x00, - 0xf0, 0x19, 0x6e, 0x08, - 0x08, 0x6a, 0x18, 0x00, - 0x08, 0x11, 0x22, 0x00, - 0x08, 0x6a, 0x66, 0x58, - 0x08, 0x6a, 0x68, 0x00, - 0x00, 0x65, 0xaa, 0x40, - 0x12, 0x6a, 0x00, 0x00, - 0x40, 0x6a, 0x16, 0x00, - 0xff, 0x3e, 0x20, 0x09, - 0xff, 0xba, 0x7c, 0x08, - 0xff, 0xa1, 0x6e, 0x08, - 0x08, 0x6a, 0x18, 0x00, - 0x08, 0x11, 0x22, 0x00, - 0x08, 0x6a, 0x66, 0x58, - 0x80, 0x6a, 0x68, 0x00, - 0x80, 0x36, 0x6c, 0x00, - 0x00, 0x65, 0xba, 0x5b, - 0xff, 0x3d, 0xc8, 0x08, - 0xbf, 0x64, 0xe2, 0x78, - 0x80, 0x64, 0xc8, 0x71, - 0xa0, 0x64, 0xf8, 0x71, - 0xc0, 0x64, 0xf0, 0x71, - 0xe0, 0x64, 0x38, 0x72, - 0x01, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0xf7, 0x11, 0x22, 0x08, - 0x00, 0x65, 0xca, 0x58, - 0xff, 0x06, 0xd4, 0x08, - 0xf7, 0x01, 0x02, 0x08, - 0x09, 0x0c, 0xc4, 0x78, - 0x08, 0x0c, 0x0c, 0x68, - 0x01, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0x26, 0x09, - 0x02, 0x6a, 0x08, 0x30, - 0xff, 0x6a, 0x08, 0x08, - 0xdf, 0x01, 0x02, 0x08, - 0x01, 0x6a, 0x7a, 0x00, - 0xff, 0x6a, 0x6c, 0x0c, - 0x04, 0x14, 0x10, 0x31, - 0x03, 0xa9, 0x18, 0x31, - 0x03, 0xa9, 0x10, 0x30, - 0x08, 0x6a, 0xcc, 0x00, - 0xa9, 0x6a, 0xd0, 0x5b, - 0x00, 0x65, 0x02, 0x41, - 0xa8, 0x6a, 0x6a, 0x00, - 0x79, 0x6a, 0x6a, 0x00, - 0x40, 0x3d, 0xea, 0x68, - 0x04, 0x35, 0x6a, 0x00, - 0x00, 0x65, 0x2a, 0x5b, - 0x80, 0x6a, 0xd4, 0x01, - 0x10, 0x36, 0xd6, 0x68, - 0x10, 0x36, 0x6c, 0x00, - 0x07, 0xac, 0x10, 0x31, - 0x05, 0xa3, 0x70, 0x30, - 0x03, 0x8c, 0x10, 0x30, - 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0xc8, 0x5b, - 0x00, 0x65, 0xc2, 0x5b, - 0x38, 0x6a, 0xcc, 0x00, - 0xa3, 0x6a, 0xcc, 0x5b, - 0xff, 0x38, 0x12, 0x69, - 0x80, 0x02, 0x04, 0x00, - 0xe7, 0x35, 0x6a, 0x08, - 0x03, 0x69, 0x18, 0x31, - 0x03, 0x69, 0x10, 0x30, - 0xff, 0x6a, 0x10, 0x00, - 0xff, 0x6a, 0x12, 0x00, - 0xff, 0x6a, 0x14, 0x00, - 0x22, 0x38, 0xc8, 0x28, - 0x01, 0x38, 0x1c, 0x61, - 0x02, 0x64, 0xc8, 0x00, - 0x01, 0x38, 0x1c, 0x61, - 0xbf, 0x35, 0x6a, 0x08, - 0xff, 0x64, 0xf8, 0x09, - 0xff, 0x35, 0x26, 0x09, - 0x80, 0x02, 0xa4, 0x69, - 0x10, 0x0c, 0x7a, 0x69, - 0x80, 0x94, 0x22, 0x79, - 0x00, 0x35, 0x0a, 0x5b, - 0x80, 0x02, 0xa4, 0x69, - 0xff, 0x65, 0x94, 0x79, - 0x01, 0x38, 0x70, 0x71, - 0xff, 0x38, 0x70, 0x18, - 0xff, 0x38, 0x94, 0x79, - 0x80, 0xea, 0x4a, 0x61, - 0xef, 0x38, 0xc8, 0x18, - 0x80, 0x6a, 0xc8, 0x00, - 0x00, 0x65, 0x3c, 0x49, - 0x33, 0x38, 0xc8, 0x28, - 0xff, 0x64, 0xd0, 0x09, - 0x04, 0x39, 0xc0, 0x31, - 0x09, 0x6a, 0xd6, 0x01, - 0x80, 0xeb, 0x42, 0x79, - 0xf7, 0xeb, 0xd6, 0x09, - 0x08, 0xeb, 0x46, 0x69, - 0x01, 0x6a, 0xd6, 0x01, - 0x08, 0xe9, 0x10, 0x31, - 0x03, 0x8c, 0x10, 0x30, - 0xff, 0x38, 0x70, 0x18, - 0x88, 0x6a, 0xcc, 0x00, - 0x39, 0x6a, 0xce, 0x5b, - 0x08, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x78, 0x5c, - 0x88, 0x6a, 0xcc, 0x00, - 0x00, 0x65, 0x6a, 0x5c, - 0x00, 0x65, 0xc2, 0x5b, - 0xff, 0x6a, 0xc8, 0x08, - 0x08, 0x39, 0x72, 0x18, - 0x00, 0x3a, 0x74, 0x20, - 0x00, 0x65, 0x02, 0x41, - 0x01, 0x0c, 0x6c, 0x79, - 0x10, 0x0c, 0x02, 0x79, - 0x10, 0x0c, 0x7a, 0x69, - 0x01, 0xfc, 0x70, 0x79, - 0xff, 0x6a, 0x70, 0x08, - 0x01, 0x0c, 0x76, 0x79, - 0x10, 0x0c, 0x02, 0x79, - 0x00, 0x65, 0xae, 0x59, - 0x01, 0xfc, 0x94, 0x69, - 0x40, 0x0d, 0x84, 0x69, - 0xb1, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x94, 0x41, - 0x2e, 0xfc, 0xa2, 0x28, - 0x3f, 0x38, 0xc8, 0x08, - 0x00, 0x51, 0x94, 0x71, - 0xff, 0x6a, 0xc8, 0x08, - 0xf8, 0x39, 0x72, 0x18, - 0xff, 0x3a, 0x74, 0x20, - 0x01, 0x38, 0x70, 0x18, - 0x00, 0x65, 0x86, 0x41, - 0x03, 0x08, 0x52, 0x31, - 0xff, 0x38, 0x50, 0x09, - 0x12, 0x01, 0x02, 0x00, - 0xff, 0x08, 0x52, 0x09, - 0xff, 0x09, 0x54, 0x09, - 0xff, 0x0a, 0x56, 0x09, - 0xff, 0x38, 0x50, 0x09, - 0x00, 0x65, 0xaa, 0x40, - 0x10, 0x0c, 0xa4, 0x79, - 0x00, 0x65, 0xae, 0x59, - 0x7f, 0x02, 0x04, 0x08, - 0xe1, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0x04, 0x93, 0xc2, 0x69, - 0xdf, 0x93, 0x26, 0x09, - 0x20, 0x93, 0xb2, 0x69, - 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0xb6, 0x79, - 0x01, 0x94, 0xb6, 0x79, - 0x01, 0x94, 0xb6, 0x79, - 0x01, 0x94, 0xb6, 0x79, - 0x01, 0x94, 0xb6, 0x79, - 0x10, 0x94, 0xc0, 0x69, - 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xc4, 0x69, - 0xff, 0x6a, 0xd4, 0x0c, - 0x00, 0x65, 0x2a, 0x5b, - 0x05, 0xb4, 0x10, 0x31, - 0x02, 0x6a, 0x1a, 0x31, - 0x03, 0x8c, 0x10, 0x30, - 0x88, 0x6a, 0xcc, 0x00, - 0xb4, 0x6a, 0xcc, 0x5b, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x00, 0x65, 0xc2, 0x5b, - 0x3d, 0x6a, 0x0a, 0x5b, - 0xac, 0x6a, 0x26, 0x01, - 0x04, 0x0b, 0xde, 0x69, - 0x04, 0x0b, 0xe4, 0x69, - 0x10, 0x0c, 0xe0, 0x79, - 0x02, 0x03, 0xe8, 0x79, - 0x11, 0x0c, 0xe4, 0x79, - 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xea, 0x69, - 0x12, 0x01, 0x02, 0x00, - 0x00, 0x65, 0xaa, 0x40, - 0x00, 0x65, 0x2a, 0x5b, - 0xff, 0x06, 0x44, 0x09, - 0x00, 0x65, 0xaa, 0x40, - 0x10, 0x3d, 0x06, 0x00, - 0xff, 0x34, 0xca, 0x08, - 0x80, 0x65, 0x1c, 0x62, - 0x0f, 0xa1, 0xca, 0x08, - 0x07, 0xa1, 0xca, 0x08, - 0x40, 0xa0, 0xc8, 0x08, - 0x00, 0x65, 0xca, 0x00, - 0x80, 0x65, 0xca, 0x00, - 0x80, 0xa0, 0x0c, 0x7a, - 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x1e, 0x42, - 0x20, 0xa0, 0x24, 0x7a, - 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0xba, 0x5b, - 0xa0, 0x3d, 0x2c, 0x62, - 0x23, 0xa0, 0x0c, 0x08, - 0x00, 0x65, 0xba, 0x5b, - 0xa0, 0x3d, 0x2c, 0x62, - 0x00, 0xb9, 0x24, 0x42, - 0xff, 0x65, 0x24, 0x62, - 0xa1, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0xd4, 0x08, - 0x10, 0x51, 0x2c, 0x72, - 0x40, 0x6a, 0x18, 0x00, - 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0xba, 0x5b, - 0xa0, 0x3d, 0xf6, 0x71, - 0x40, 0x6a, 0x18, 0x00, - 0xff, 0x34, 0xa6, 0x08, - 0x80, 0x34, 0x34, 0x62, - 0x7f, 0xa0, 0x40, 0x09, - 0x08, 0x6a, 0x68, 0x00, - 0x00, 0x65, 0xaa, 0x40, - 0x64, 0x6a, 0x00, 0x5b, - 0x80, 0x64, 0xaa, 0x6a, - 0x04, 0x64, 0x8c, 0x72, - 0x02, 0x64, 0x92, 0x72, - 0x00, 0x6a, 0x54, 0x72, - 0x03, 0x64, 0xa6, 0x72, - 0x01, 0x64, 0x88, 0x72, - 0x07, 0x64, 0xe8, 0x72, - 0x08, 0x64, 0x50, 0x72, - 0x23, 0x64, 0xec, 0x72, - 0x11, 0x6a, 0x22, 0x01, - 0x07, 0x6a, 0xf2, 0x5a, - 0xff, 0x06, 0xd4, 0x08, - 0x00, 0x65, 0xaa, 0x40, - 0xff, 0xa8, 0x58, 0x6a, - 0xff, 0xa2, 0x70, 0x7a, - 0x01, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xe6, 0x5b, - 0xff, 0xa2, 0x70, 0x7a, - 0x71, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0xd4, 0x08, - 0x40, 0x51, 0x70, 0x62, - 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xe6, 0x5b, - 0xff, 0x3e, 0x74, 0x09, - 0xff, 0x90, 0x7c, 0x08, - 0x00, 0x65, 0x4e, 0x58, - 0x00, 0x65, 0xbc, 0x40, - 0x20, 0xa0, 0x78, 0x6a, - 0xff, 0x37, 0xc8, 0x08, - 0x00, 0x6a, 0x90, 0x5b, - 0xff, 0x6a, 0xa6, 0x5b, - 0xff, 0xf8, 0xc8, 0x08, - 0xff, 0x4f, 0xc8, 0x08, - 0x01, 0x6a, 0x90, 0x5b, - 0x00, 0xb9, 0xa6, 0x5b, - 0x01, 0x4f, 0x9e, 0x18, - 0x02, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x80, 0x5c, - 0x00, 0x65, 0xbc, 0x40, - 0x41, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0x04, 0xa0, 0x40, 0x01, - 0x00, 0x65, 0x98, 0x5c, - 0x00, 0x65, 0xbc, 0x40, - 0x10, 0x36, 0x50, 0x7a, - 0x05, 0x38, 0x46, 0x31, - 0x04, 0x14, 0x58, 0x31, - 0x03, 0xa9, 0x60, 0x31, - 0xa3, 0x6a, 0xcc, 0x00, - 0x38, 0x6a, 0xcc, 0x5b, - 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xce, 0x5b, - 0xa9, 0x6a, 0xd0, 0x5b, - 0x00, 0x65, 0x50, 0x42, - 0xef, 0x36, 0x6c, 0x08, - 0x00, 0x65, 0x50, 0x42, - 0x0f, 0x64, 0xc8, 0x08, - 0x07, 0x64, 0xc8, 0x08, - 0x00, 0x37, 0x6e, 0x00, - 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0x60, 0x5b, - 0xff, 0x51, 0xbc, 0x72, - 0x20, 0x36, 0xc6, 0x7a, - 0x00, 0x90, 0x4e, 0x5b, - 0x00, 0x65, 0xc8, 0x42, - 0xff, 0x06, 0xd4, 0x08, - 0x00, 0x65, 0xba, 0x5b, - 0xe0, 0x3d, 0xe2, 0x62, - 0x20, 0x12, 0xe2, 0x62, - 0x51, 0x6a, 0xf6, 0x5a, - 0x00, 0x65, 0x48, 0x5b, - 0xff, 0x37, 0xc8, 0x08, - 0x00, 0xa1, 0xda, 0x62, - 0x04, 0xa0, 0xda, 0x7a, - 0xfb, 0xa0, 0x40, 0x09, - 0x80, 0x36, 0x6c, 0x00, - 0x80, 0xa0, 0x50, 0x7a, - 0x7f, 0xa0, 0x40, 0x09, - 0xff, 0x6a, 0xf2, 0x5a, - 0x00, 0x65, 0x50, 0x42, - 0x04, 0xa0, 0xe0, 0x7a, - 0x00, 0x65, 0x98, 0x5c, - 0x00, 0x65, 0xe2, 0x42, - 0x00, 0x65, 0x80, 0x5c, - 0x31, 0x6a, 0x22, 0x01, - 0x0c, 0x6a, 0xf2, 0x5a, - 0x00, 0x65, 0x50, 0x42, - 0x61, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x50, 0x42, - 0x51, 0x6a, 0xf6, 0x5a, - 0x51, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x50, 0x42, - 0x10, 0x3d, 0x06, 0x00, - 0xff, 0x65, 0x68, 0x0c, - 0xff, 0x06, 0xd4, 0x08, - 0x01, 0x0c, 0xf8, 0x7a, - 0x04, 0x0c, 0xfa, 0x6a, - 0xe0, 0x03, 0x7a, 0x08, - 0xe0, 0x3d, 0x06, 0x63, - 0xff, 0x65, 0xcc, 0x08, - 0xff, 0x12, 0xda, 0x0c, - 0xff, 0x06, 0xd4, 0x0c, - 0xd1, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0xff, 0x65, 0x26, 0x09, - 0x01, 0x0b, 0x1a, 0x6b, - 0x10, 0x0c, 0x0c, 0x7b, - 0x04, 0x0b, 0x14, 0x6b, - 0xff, 0x6a, 0xca, 0x08, - 0x04, 0x93, 0x18, 0x6b, - 0x01, 0x94, 0x16, 0x7b, - 0x10, 0x94, 0x18, 0x6b, - 0x80, 0x3d, 0x1e, 0x73, - 0x0f, 0x04, 0x22, 0x6b, - 0x02, 0x03, 0x22, 0x7b, - 0x11, 0x0c, 0x1e, 0x7b, - 0xc7, 0x93, 0x26, 0x09, - 0xff, 0x99, 0xd4, 0x08, - 0x38, 0x93, 0x24, 0x6b, - 0xff, 0x6a, 0xd4, 0x0c, - 0x80, 0x36, 0x28, 0x6b, - 0x21, 0x6a, 0x22, 0x05, - 0xff, 0x65, 0x20, 0x09, - 0xff, 0x51, 0x36, 0x63, - 0xff, 0x37, 0xc8, 0x08, - 0xa1, 0x6a, 0x42, 0x43, - 0xff, 0x51, 0xc8, 0x08, - 0xb9, 0x6a, 0x42, 0x43, - 0xff, 0x90, 0xa4, 0x08, - 0xff, 0xba, 0x46, 0x73, - 0xff, 0xba, 0x20, 0x09, - 0xff, 0x65, 0xca, 0x18, - 0x00, 0x6c, 0x3a, 0x63, - 0xff, 0x90, 0xca, 0x0c, - 0xff, 0x6a, 0xca, 0x04, - 0x20, 0x36, 0x5a, 0x7b, - 0x00, 0x90, 0x2e, 0x5b, - 0xff, 0x65, 0x5a, 0x73, - 0xff, 0x52, 0x58, 0x73, - 0xff, 0xba, 0xcc, 0x08, - 0xff, 0x52, 0x20, 0x09, - 0xff, 0x66, 0x74, 0x09, - 0xff, 0x65, 0x20, 0x0d, - 0xff, 0xba, 0x7e, 0x0c, - 0x00, 0x6a, 0x86, 0x5c, - 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0x51, 0xe6, 0x43, - 0xff, 0x3f, 0xb4, 0x73, - 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3f, 0x2e, 0x5b, - 0xff, 0x65, 0xb4, 0x73, - 0x20, 0x36, 0x6c, 0x00, - 0x20, 0xa0, 0x6e, 0x6b, - 0xff, 0xb9, 0xa2, 0x0c, - 0xff, 0x6a, 0xa2, 0x04, - 0xff, 0x65, 0xa4, 0x08, - 0xe0, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xda, 0x5b, - 0x01, 0x6a, 0xd0, 0x01, - 0x09, 0x6a, 0xd6, 0x01, - 0x80, 0xeb, 0x7a, 0x7b, - 0x01, 0x6a, 0xd6, 0x01, - 0x01, 0xe9, 0xa4, 0x34, - 0x88, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xda, 0x5b, - 0x01, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x0d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0x78, 0x5c, - 0xff, 0x99, 0xa4, 0x0c, - 0xff, 0x65, 0xa4, 0x08, - 0xe0, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xda, 0x5b, - 0x01, 0x6a, 0xd0, 0x01, - 0x01, 0x6a, 0xdc, 0x05, - 0x88, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xda, 0x5b, - 0x01, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x01, 0x6a, 0x26, 0x05, - 0x01, 0x65, 0xd8, 0x31, - 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xaa, 0x7b, - 0xff, 0x6a, 0xdc, 0x0d, - 0xff, 0x65, 0x32, 0x09, - 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x78, 0x44, - 0xff, 0x37, 0xc8, 0x08, - 0x00, 0x6a, 0x70, 0x5b, - 0xff, 0x52, 0xa2, 0x0c, - 0x01, 0x0c, 0xba, 0x7b, - 0x04, 0x0c, 0xba, 0x6b, - 0xe0, 0x03, 0x06, 0x08, - 0xe0, 0x03, 0x7a, 0x0c, - 0xff, 0x8c, 0x10, 0x08, - 0xff, 0x8d, 0x12, 0x08, - 0xff, 0x8e, 0x14, 0x0c, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x0c, - 0x3d, 0x64, 0xa4, 0x28, - 0x55, 0x64, 0xc8, 0x28, - 0x00, 0x6c, 0xda, 0x18, - 0xff, 0x52, 0xc8, 0x08, - 0x00, 0x6c, 0xda, 0x20, - 0xff, 0x6a, 0xc8, 0x08, - 0x00, 0x6c, 0xda, 0x20, - 0x00, 0x6c, 0xda, 0x24, - 0xff, 0x65, 0xc8, 0x08, - 0xe0, 0x6a, 0xcc, 0x00, - 0x41, 0x6a, 0xd6, 0x5b, - 0xff, 0x90, 0xe2, 0x09, - 0x20, 0x6a, 0xd0, 0x01, - 0x04, 0x35, 0xf8, 0x7b, - 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0xf4, 0x63, - 0x00, 0x65, 0x0e, 0x44, - 0x01, 0x6a, 0xdc, 0x01, - 0x20, 0xa0, 0xd8, 0x31, - 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xfe, 0x7b, - 0x11, 0x6a, 0xdc, 0x01, - 0x50, 0xee, 0x02, 0x64, - 0x20, 0x6a, 0xd0, 0x01, - 0x09, 0x6a, 0xdc, 0x01, - 0x88, 0xee, 0x08, 0x64, - 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0x0c, 0x64, - 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0x10, 0x6c, - 0xff, 0x6a, 0xd4, 0x0c, - 0x88, 0x6a, 0xcc, 0x00, - 0x41, 0x6a, 0xd6, 0x5b, - 0x20, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0xff, 0x35, 0x26, 0x09, - 0x04, 0x35, 0x3c, 0x6c, - 0xa0, 0x6a, 0xca, 0x00, - 0x20, 0x65, 0xc8, 0x18, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0x00, 0x65, 0x26, 0x64, - 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x78, 0x44, - 0xa0, 0x6a, 0xcc, 0x00, - 0xe8, 0x6a, 0xc8, 0x00, - 0x01, 0x94, 0x40, 0x6c, - 0x10, 0x94, 0x42, 0x6c, - 0x08, 0x94, 0x54, 0x6c, - 0x08, 0x94, 0x54, 0x6c, - 0x08, 0x94, 0x54, 0x6c, - 0x00, 0x65, 0x68, 0x5c, - 0x08, 0x64, 0xc8, 0x18, - 0x00, 0x8c, 0xca, 0x18, - 0x00, 0x65, 0x4a, 0x4c, - 0x00, 0x65, 0x40, 0x44, - 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x56, 0x6c, - 0x00, 0x65, 0x68, 0x5c, - 0x08, 0x64, 0xc8, 0x18, - 0x08, 0x64, 0x58, 0x64, - 0xff, 0x6a, 0xd4, 0x0c, - 0x00, 0x65, 0x78, 0x5c, - 0x00, 0x65, 0x68, 0x5c, - 0x00, 0x65, 0x68, 0x5c, - 0x00, 0x65, 0x68, 0x5c, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x0c, - 0x08, 0x94, 0x78, 0x7c, - 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x7c, 0x6c, - 0xff, 0x6a, 0xd4, 0x0c, - 0xff, 0x40, 0x74, 0x09, - 0xff, 0x90, 0x80, 0x08, - 0xff, 0x6a, 0x72, 0x05, - 0xff, 0x40, 0x94, 0x64, - 0xff, 0x3f, 0x8c, 0x64, - 0xff, 0x6a, 0xca, 0x04, - 0xff, 0x3f, 0x20, 0x09, - 0x01, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xe6, 0x5b, - 0xff, 0xba, 0x7e, 0x0c, - 0xff, 0x40, 0x20, 0x09, - 0xff, 0xba, 0x80, 0x0c, - 0xff, 0x3f, 0x74, 0x09, - 0xff, 0x90, 0x7e, 0x0c, -}; - -static int aic7xxx_patch15_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch15_func(struct aic7xxx_host *p) -{ - return ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0); -} - -static int aic7xxx_patch14_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch14_func(struct aic7xxx_host *p) -{ - return ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0); -} - -static int aic7xxx_patch13_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch13_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_WIDE) != 0); -} - -static int aic7xxx_patch12_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch12_func(struct aic7xxx_host *p) -{ - return ((p->bugs & AHC_BUG_AUTOFLUSH) != 0); -} - -static int aic7xxx_patch11_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch11_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_ULTRA2) == 0); -} - -static int aic7xxx_patch10_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch10_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_CMD_CHAN) == 0); -} - -static int aic7xxx_patch9_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch9_func(struct aic7xxx_host *p) -{ - return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895); -} - -static int aic7xxx_patch8_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch8_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_ULTRA) != 0); -} - -static int aic7xxx_patch7_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch7_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_ULTRA2) != 0); -} - -static int aic7xxx_patch6_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch6_func(struct aic7xxx_host *p) -{ - return ((p->flags & AHC_PAGESCBS) == 0); -} - -static int aic7xxx_patch5_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch5_func(struct aic7xxx_host *p) -{ - return ((p->flags & AHC_PAGESCBS) != 0); -} - -static int aic7xxx_patch4_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch4_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_QUEUE_REGS) != 0); -} - -static int aic7xxx_patch3_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch3_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_TWIN) != 0); -} - -static int aic7xxx_patch2_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch2_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_QUEUE_REGS) == 0); -} - -static int aic7xxx_patch1_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch1_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_CMD_CHAN) != 0); -} - -static int aic7xxx_patch0_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch0_func(struct aic7xxx_host *p) -{ - return (0); -} - -struct sequencer_patch { - int (*patch_func)(struct aic7xxx_host *); - unsigned int begin :10, - skip_instr :10, - skip_patch :12; -} sequencer_patches[] = { - { aic7xxx_patch1_func, 3, 2, 1 }, - { aic7xxx_patch2_func, 7, 1, 1 }, - { aic7xxx_patch2_func, 8, 1, 1 }, - { aic7xxx_patch3_func, 11, 4, 1 }, - { aic7xxx_patch4_func, 16, 3, 2 }, - { aic7xxx_patch0_func, 19, 4, 1 }, - { aic7xxx_patch5_func, 23, 1, 1 }, - { aic7xxx_patch6_func, 26, 1, 1 }, - { aic7xxx_patch1_func, 29, 1, 2 }, - { aic7xxx_patch0_func, 30, 3, 1 }, - { aic7xxx_patch3_func, 39, 4, 1 }, - { aic7xxx_patch7_func, 43, 3, 2 }, - { aic7xxx_patch0_func, 46, 3, 1 }, - { aic7xxx_patch8_func, 52, 7, 1 }, - { aic7xxx_patch3_func, 60, 3, 1 }, - { aic7xxx_patch7_func, 63, 2, 1 }, - { aic7xxx_patch7_func, 102, 1, 2 }, - { aic7xxx_patch0_func, 103, 2, 1 }, - { aic7xxx_patch7_func, 107, 2, 1 }, - { aic7xxx_patch9_func, 109, 1, 1 }, - { aic7xxx_patch10_func, 110, 2, 1 }, - { aic7xxx_patch7_func, 113, 1, 2 }, - { aic7xxx_patch0_func, 114, 1, 1 }, - { aic7xxx_patch1_func, 118, 1, 1 }, - { aic7xxx_patch1_func, 121, 3, 3 }, - { aic7xxx_patch11_func, 123, 1, 1 }, - { aic7xxx_patch0_func, 124, 5, 1 }, - { aic7xxx_patch7_func, 132, 1, 1 }, - { aic7xxx_patch9_func, 133, 1, 1 }, - { aic7xxx_patch10_func, 134, 3, 1 }, - { aic7xxx_patch7_func, 137, 3, 2 }, - { aic7xxx_patch0_func, 140, 2, 1 }, - { aic7xxx_patch7_func, 142, 5, 2 }, - { aic7xxx_patch0_func, 147, 3, 1 }, - { aic7xxx_patch7_func, 150, 1, 2 }, - { aic7xxx_patch0_func, 151, 2, 1 }, - { aic7xxx_patch1_func, 153, 15, 4 }, - { aic7xxx_patch11_func, 166, 1, 2 }, - { aic7xxx_patch0_func, 167, 1, 1 }, - { aic7xxx_patch0_func, 168, 10, 1 }, - { aic7xxx_patch7_func, 181, 1, 2 }, - { aic7xxx_patch0_func, 182, 2, 1 }, - { aic7xxx_patch7_func, 184, 18, 1 }, - { aic7xxx_patch1_func, 202, 3, 3 }, - { aic7xxx_patch7_func, 204, 1, 1 }, - { aic7xxx_patch0_func, 205, 4, 1 }, - { aic7xxx_patch7_func, 210, 2, 1 }, - { aic7xxx_patch7_func, 215, 13, 3 }, - { aic7xxx_patch12_func, 218, 1, 1 }, - { aic7xxx_patch12_func, 219, 4, 1 }, - { aic7xxx_patch1_func, 229, 3, 3 }, - { aic7xxx_patch11_func, 231, 1, 1 }, - { aic7xxx_patch0_func, 232, 5, 1 }, - { aic7xxx_patch11_func, 237, 1, 2 }, - { aic7xxx_patch0_func, 238, 9, 1 }, - { aic7xxx_patch13_func, 254, 1, 2 }, - { aic7xxx_patch0_func, 255, 1, 1 }, - { aic7xxx_patch4_func, 316, 1, 2 }, - { aic7xxx_patch0_func, 317, 1, 1 }, - { aic7xxx_patch2_func, 320, 1, 1 }, - { aic7xxx_patch1_func, 330, 3, 2 }, - { aic7xxx_patch0_func, 333, 5, 1 }, - { aic7xxx_patch13_func, 341, 1, 2 }, - { aic7xxx_patch0_func, 342, 1, 1 }, - { aic7xxx_patch5_func, 347, 1, 1 }, - { aic7xxx_patch11_func, 389, 15, 2 }, - { aic7xxx_patch14_func, 402, 1, 1 }, - { aic7xxx_patch1_func, 441, 7, 2 }, - { aic7xxx_patch0_func, 448, 8, 1 }, - { aic7xxx_patch1_func, 457, 4, 2 }, - { aic7xxx_patch0_func, 461, 6, 1 }, - { aic7xxx_patch1_func, 467, 4, 2 }, - { aic7xxx_patch0_func, 471, 3, 1 }, - { aic7xxx_patch10_func, 481, 10, 1 }, - { aic7xxx_patch1_func, 500, 22, 5 }, - { aic7xxx_patch11_func, 508, 4, 1 }, - { aic7xxx_patch7_func, 512, 7, 3 }, - { aic7xxx_patch15_func, 512, 5, 2 }, - { aic7xxx_patch0_func, 517, 2, 1 }, - { aic7xxx_patch10_func, 522, 50, 3 }, - { aic7xxx_patch14_func, 543, 17, 2 }, - { aic7xxx_patch0_func, 560, 4, 1 }, - { aic7xxx_patch10_func, 572, 4, 1 }, - { aic7xxx_patch5_func, 576, 2, 1 }, - { aic7xxx_patch5_func, 579, 9, 1 }, - -}; diff --git a/drivers/scsi/aic7xxx_old/scsi_message.h b/drivers/scsi/aic7xxx_old/scsi_message.h deleted file mode 100644 index a79f89c65173..000000000000 --- a/drivers/scsi/aic7xxx_old/scsi_message.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Messages (1 byte) */ /* I/T (M)andatory or (O)ptional */ -#define MSG_CMDCOMPLETE 0x00 /* M/M */ -#define MSG_EXTENDED 0x01 /* O/O */ -#define MSG_SAVEDATAPOINTER 0x02 /* O/O */ -#define MSG_RESTOREPOINTERS 0x03 /* O/O */ -#define MSG_DISCONNECT 0x04 /* O/O */ -#define MSG_INITIATOR_DET_ERR 0x05 /* M/M */ -#define MSG_ABORT 0x06 /* O/M */ -#define MSG_MESSAGE_REJECT 0x07 /* M/M */ -#define MSG_NOOP 0x08 /* M/M */ -#define MSG_PARITY_ERROR 0x09 /* M/M */ -#define MSG_LINK_CMD_COMPLETE 0x0a /* O/O */ -#define MSG_LINK_CMD_COMPLETEF 0x0b /* O/O */ -#define MSG_BUS_DEV_RESET 0x0c /* O/M */ -#define MSG_ABORT_TAG 0x0d /* O/O */ -#define MSG_CLEAR_QUEUE 0x0e /* O/O */ -#define MSG_INIT_RECOVERY 0x0f /* O/O */ -#define MSG_REL_RECOVERY 0x10 /* O/O */ -#define MSG_TERM_IO_PROC 0x11 /* O/O */ - -/* Messages (2 byte) */ -#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */ -#define MSG_HEAD_OF_Q_TAG 0x21 /* O/O */ -#define MSG_ORDERED_Q_TAG 0x22 /* O/O */ -#define MSG_IGN_WIDE_RESIDUE 0x23 /* O/O */ - -/* Identify message */ /* M/M */ -#define MSG_IDENTIFYFLAG 0x80 -#define MSG_IDENTIFY_DISCFLAG 0x40 -#define MSG_IDENTIFY(lun, disc) (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun)) -#define MSG_ISIDENTIFY(m) ((m) & MSG_IDENTIFYFLAG) - -/* Extended messages (opcode and length) */ -#define MSG_EXT_SDTR 0x01 -#define MSG_EXT_SDTR_LEN 0x03 - -#define MSG_EXT_WDTR 0x03 -#define MSG_EXT_WDTR_LEN 0x02 -#define MSG_EXT_WDTR_BUS_8_BIT 0x00 -#define MSG_EXT_WDTR_BUS_16_BIT 0x01 -#define MSG_EXT_WDTR_BUS_32_BIT 0x02 - -#define MSG_EXT_PPR 0x04 -#define MSG_EXT_PPR_LEN 0x06 -#define MSG_EXT_PPR_OPTION_ST 0x00 -#define MSG_EXT_PPR_OPTION_DT_CRC 0x02 -#define MSG_EXT_PPR_OPTION_DT_UNITS 0x03 -#define MSG_EXT_PPR_OPTION_DT_CRC_QUICK 0x04 -#define MSG_EXT_PPR_OPTION_DT_UNITS_QUICK 0x05 diff --git a/drivers/scsi/aic7xxx_old/sequencer.h b/drivers/scsi/aic7xxx_old/sequencer.h deleted file mode 100644 index ee66855222b1..000000000000 --- a/drivers/scsi/aic7xxx_old/sequencer.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Instruction formats for the sequencer program downloaded to - * Aic7xxx SCSI host adapters - * - * Copyright (c) 1997, 1998 Justin T. Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU General Public License ("GPL") and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: sequencer.h,v 1.3 1997/09/27 19:37:31 gibbs Exp $ - */ - -#ifdef __LITTLE_ENDIAN_BITFIELD -struct ins_format1 { - unsigned int - immediate : 8, - source : 9, - destination : 9, - ret : 1, - opcode : 4, - parity : 1; -}; - -struct ins_format2 { - unsigned int - shift_control : 8, - source : 9, - destination : 9, - ret : 1, - opcode : 4, - parity : 1; -}; - -struct ins_format3 { - unsigned int - immediate : 8, - source : 9, - address : 10, - opcode : 4, - parity : 1; -}; -#elif defined(__BIG_ENDIAN_BITFIELD) -struct ins_format1 { - unsigned int - parity : 1, - opcode : 4, - ret : 1, - destination : 9, - source : 9, - immediate : 8; -}; - -struct ins_format2 { - unsigned int - parity : 1, - opcode : 4, - ret : 1, - destination : 9, - source : 9, - shift_control : 8; -}; - -struct ins_format3 { - unsigned int - parity : 1, - opcode : 4, - address : 10, - source : 9, - immediate : 8; -}; -#endif - -union ins_formats { - struct ins_format1 format1; - struct ins_format2 format2; - struct ins_format3 format3; - unsigned char bytes[4]; - unsigned int integer; -}; -struct instruction { - union ins_formats format; - unsigned int srcline; - struct symbol *patch_label; - struct { - struct instruction *stqe_next; - } links; -}; - -#define AIC_OP_OR 0x0 -#define AIC_OP_AND 0x1 -#define AIC_OP_XOR 0x2 -#define AIC_OP_ADD 0x3 -#define AIC_OP_ADC 0x4 -#define AIC_OP_ROL 0x5 -#define AIC_OP_BMOV 0x6 - -#define AIC_OP_JMP 0x8 -#define AIC_OP_JC 0x9 -#define AIC_OP_JNC 0xa -#define AIC_OP_CALL 0xb -#define AIC_OP_JNE 0xc -#define AIC_OP_JNZ 0xd -#define AIC_OP_JE 0xe -#define AIC_OP_JZ 0xf - -/* Pseudo Ops */ -#define AIC_OP_SHL 0x10 -#define AIC_OP_SHR 0x20 -#define AIC_OP_ROR 0x30 -- cgit v1.2.3 From 6ad55502c65638cad53f211e301c724fe7e64a8e Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 11 Nov 2013 13:44:57 +0100 Subject: [SCSI] Update documentation The documentation has gone out-of-sync, so update it to the current status. Signed-off-by: Hannes Reinecke Signed-off-by: James Bottomley --- Documentation/scsi/scsi_eh.txt | 69 +++++++++++++++++++-------------- Documentation/scsi/scsi_mid_low_api.txt | 9 ++++- drivers/scsi/scsi.c | 6 +-- 3 files changed, 48 insertions(+), 36 deletions(-) (limited to 'Documentation') diff --git a/Documentation/scsi/scsi_eh.txt b/Documentation/scsi/scsi_eh.txt index 6ff16b620d84..a0c85110a07e 100644 --- a/Documentation/scsi/scsi_eh.txt +++ b/Documentation/scsi/scsi_eh.txt @@ -42,20 +42,14 @@ discussion. Once LLDD gets hold of a scmd, either the LLDD will complete the command by calling scsi_done callback passed from midlayer when -invoking hostt->queuecommand() or SCSI midlayer will time it out. +invoking hostt->queuecommand() or the block layer will time it out. [1-2-1] Completing a scmd w/ scsi_done For all non-EH commands, scsi_done() is the completion callback. It -does the following. - - 1. Delete timeout timer. If it fails, it means that timeout timer - has expired and is going to finish the command. Just return. - - 2. Link scmd to per-cpu scsi_done_q using scmd->en_entry - - 3. Raise SCSI_SOFTIRQ +just calls blk_complete_request() to delete the block layer timer and +raise SCSI_SOFTIRQ SCSI_SOFTIRQ handler scsi_softirq calls scsi_decide_disposition() to determine what to do with the command. scsi_decide_disposition() @@ -64,10 +58,12 @@ with the command. - SUCCESS scsi_finish_command() is invoked for the command. The - function does some maintenance choirs and notify completion by - calling scmd->done() callback, which, for fs requests, would - be HLD completion callback - sd:sd_rw_intr, sr:rw_intr, - st:st_intr. + function does some maintenance chores and then calls + scsi_io_completion() to finish the I/O. + scsi_io_completion() then notifies the block layer on + the completed request by calling blk_end_request and + friends or figures out what to do with the remainder + of the data in case of an error. - NEEDS_RETRY - ADD_TO_MLQUEUE @@ -86,33 +82,45 @@ function 1. invokes optional hostt->eh_timed_out() callback. Return value can be one of - - EH_HANDLED - This indicates that eh_timed_out() dealt with the timeout. The - scmd is passed to __scsi_done() and thus linked into per-cpu - scsi_done_q. Normal command completion described in [1-2-1] - follows. + - BLK_EH_HANDLED + This indicates that eh_timed_out() dealt with the timeout. + The command is passed back to the block layer and completed + via __blk_complete_requests(). + + *NOTE* After returning BLK_EH_HANDLED the SCSI layer is + assumed to be finished with the command, and no other + functions from the SCSI layer will be called. So this + should typically only be returned if the eh_timed_out() + handler raced with normal completion. - - EH_RESET_TIMER + - BLK_EH_RESET_TIMER This indicates that more time is required to finish the command. Timer is restarted. This action is counted as a retry and only allowed scmd->allowed + 1(!) times. Once the - limit is reached, action for EH_NOT_HANDLED is taken instead. + limit is reached, action for BLK_EH_NOT_HANDLED is taken instead. - *NOTE* This action is racy as the LLDD could finish the scmd - after the timeout has expired but before it's added back. In - such cases, scsi_done() would think that timeout has occurred - and return without doing anything. We lose completion and the - command will time out again. - - - EH_NOT_HANDLED - This is the same as when eh_timed_out() callback doesn't exist. + - BLK_EH_NOT_HANDLED + eh_timed_out() callback did not handle the command. Step #2 is taken. + 2. If the host supports asynchronous completion (as indicated by the + no_async_abort setting in the host template) scsi_abort_command() + is invoked to schedule an asynchrous abort. If that fails + Step #3 is taken. + 2. scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD) is invoked for the command. See [1-3] for more information. +[1-3] Asynchronous command aborts + + After a timeout occurs a command abort is scheduled from + scsi_abort_command(). If the abort is successful the command + will either be retried (if the number of retries is not exhausted) + or terminated with DID_TIME_OUT. + Otherwise scsi_eh_scmd_add() is invoked for the command. + See [1-4] for more information. -[1-3] How EH takes over +[1-4] How EH takes over scmds enter EH via scsi_eh_scmd_add(), which does the following. @@ -320,7 +328,8 @@ scmd->allowed. <> - This action is taken for each timed out command. + This action is taken for each timed out command when + no_async_abort is enabled in the host template. hostt->eh_abort_handler() is invoked for each scmd. The handler returns SUCCESS if it has succeeded to make LLDD and all related hardware forget about the scmd. diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt index 2b06aba4fa0f..d6a9bdeee7f2 100644 --- a/Documentation/scsi/scsi_mid_low_api.txt +++ b/Documentation/scsi/scsi_mid_low_api.txt @@ -882,8 +882,11 @@ Details: * * Calling context: kernel thread * - * Notes: Invoked from scsi_eh thread. No other commands will be - * queued on current host during eh. + * Notes: If 'no_async_abort' is defined this callback + * will be invoked from scsi_eh thread. No other commands + * will then be queued on current host during eh. + * Otherwise it will be called whenever scsi_times_out() + * is called due to a command timeout. * * Optionally defined in: LLD **/ @@ -1257,6 +1260,8 @@ of interest: address space use_clustering - 1=>SCSI commands in mid level's queue can be merged, 0=>disallow SCSI command merging + no_async_abort - 1=>Asynchronous aborts are not supported + 0=>Timed-out commands will be aborted asynchronously hostt - pointer to driver's struct scsi_host_template from which this struct Scsi_Host instance was spawned hostt->proc_name - name of LLD. This is the driver name that sysfs uses diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 2b04a57e0f4f..d8afec8317cf 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -745,15 +745,13 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) } /** - * scsi_done - Enqueue the finished SCSI command into the done queue. + * scsi_done - Invoke completion on finished SCSI command. * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives * ownership back to SCSI Core -- i.e. the LLDD has finished with it. * * Description: This function is the mid-level's (SCSI Core) interrupt routine, * which regains ownership of the SCSI command (de facto) from a LLDD, and - * enqueues the command to the done queue for further processing. - * - * This is the producer of the done queue who enqueues at the tail. + * calls blk_complete_request() for further processing. * * This function is interrupt context safe. */ -- cgit v1.2.3 From 8dcf94bcff5bf3b54380ae2a17b034fb3b9d58e5 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 19 Dec 2013 10:17:11 -0700 Subject: misc: Reserve minor for VFIO VFIO currently allocates it's own dynamic chardev range, reserving the first minor for the control part of the interface (/dev/vfio/vfio) and the remainder for VFIO groups (/dev/vfio/$GROUP). This works, but it doesn't support auto loading. For instance when libvirt checks for VFIO support it looks for /dev/vfio/vfio, which currently doesn't exist unless the vfio module is loaded. By converting the control device to a misc driver and reserving a static minor, we can enable auto loading. Reserving the minor is a prerequist to that conversion. Minor 196 is unused by anything currently in the kernel. Suggested-by: Paolo Bonzini Signed-off-by: Alex Williamson Acked-by: Greg Kroah-Hartman --- Documentation/devices.txt | 1 + include/linux/miscdevice.h | 1 + 2 files changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devices.txt b/Documentation/devices.txt index 80b72419ffd8..10378cc48374 100644 --- a/Documentation/devices.txt +++ b/Documentation/devices.txt @@ -409,6 +409,7 @@ Your cooperation is appreciated. 193 = /dev/d7s SPARC 7-segment display 194 = /dev/zkshim Zero-Knowledge network shim control 195 = /dev/elographics/e2201 Elographics touchscreen E271-2201 + 196 = /dev/vfio/vfio VFIO userspace driver interface 198 = /dev/sexec Signed executable interface 199 = /dev/scanners/cuecat :CueCat barcode scanner 200 = /dev/net/tun TAP/TUN network device diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index f7eaf2d60083..3737f7218f51 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -30,6 +30,7 @@ #define STORE_QUEUE_MINOR 155 #define I2O_MINOR 166 #define MICROCODE_MINOR 184 +#define VFIO_MINOR 196 #define TUN_MINOR 200 #define CUSE_MINOR 203 #define MWAVE_MINOR 219 /* ACP/Mwave Modem */ -- cgit v1.2.3 From c28f8a1f2b5ed24d48ca6827d0ae499c2e48e8c9 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 12 Dec 2013 22:49:58 +0100 Subject: PCI: imx6: Make reset-gpio optional Some boards do not have a PCIe reset GPIO. To avoid probe failure on these boards, make the reset GPIO optional as well. [bhelgaas: whitespace fixes] Signed-off-by: Marek Vasut Signed-off-by: Bjorn Helgaas Reviewed-by: Jingoo Han Acked-by: Shawn Guo Cc: Frank Li Cc: Harro Haan Cc: Mohit KUMAR Cc: Pratyush Anand Cc: Richard Zhu Cc: Sascha Hauer Cc: Sean Cross Cc: Siva Reddy Kallam Cc: Srikanth T Shivanand Cc: Tim Harvey Cc: Troy Kisky Cc: Yinghai Lu --- .../devicetree/bindings/pci/designware-pcie.txt | 2 ++ drivers/pci/host/pci-imx6.c | 27 +++++++++++----------- 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/pci/designware-pcie.txt b/Documentation/devicetree/bindings/pci/designware-pcie.txt index d5d26d443693..d6fae13ff062 100644 --- a/Documentation/devicetree/bindings/pci/designware-pcie.txt +++ b/Documentation/devicetree/bindings/pci/designware-pcie.txt @@ -19,6 +19,8 @@ Required properties: to define the mapping of the PCIe interface to interrupt numbers. - num-lanes: number of lanes to use + +Optional properties: - reset-gpio: gpio pin number of power good signal Optional properties for fsl,imx6q-pcie diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c index 9fc1cb66c64e..1176bddee1cc 100644 --- a/drivers/pci/host/pci-imx6.c +++ b/drivers/pci/host/pci-imx6.c @@ -214,9 +214,12 @@ static int imx6_pcie_assert_core_reset(struct pcie_port *pp) regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16); - gpio_set_value(imx6_pcie->reset_gpio, 0); - msleep(100); - gpio_set_value(imx6_pcie->reset_gpio, 1); + /* Some boards don't have PCIe reset GPIO. */ + if (gpio_is_valid(imx6_pcie->reset_gpio)) { + gpio_set_value(imx6_pcie->reset_gpio, 0); + msleep(100); + gpio_set_value(imx6_pcie->reset_gpio, 1); + } return 0; } @@ -432,17 +435,13 @@ static int __init imx6_pcie_probe(struct platform_device *pdev) /* Fetch GPIOs */ imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); - if (!gpio_is_valid(imx6_pcie->reset_gpio)) { - dev_err(&pdev->dev, "no reset-gpio defined\n"); - ret = -ENODEV; - } - ret = devm_gpio_request_one(&pdev->dev, - imx6_pcie->reset_gpio, - GPIOF_OUT_INIT_LOW, - "PCIe reset"); - if (ret) { - dev_err(&pdev->dev, "unable to get reset gpio\n"); - return ret; + if (gpio_is_valid(imx6_pcie->reset_gpio)) { + ret = devm_gpio_request_one(&pdev->dev, imx6_pcie->reset_gpio, + GPIOF_OUT_INIT_LOW, "PCIe reset"); + if (ret) { + dev_err(&pdev->dev, "unable to get reset gpio\n"); + return ret; + } } imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0); -- cgit v1.2.3 From 880ae359173c229f5d5a44e08b529cffb102bbbc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 12 Dec 2013 15:27:12 +0100 Subject: Documentation: fix spelling in design-patterns This fixes two spelling mistakes in the design pattern doc. Reported-by: Randy Dunlap Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-model/design-patterns.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/driver-model/design-patterns.txt b/Documentation/driver-model/design-patterns.txt index 9ef8c1684558..ba7b2df64904 100644 --- a/Documentation/driver-model/design-patterns.txt +++ b/Documentation/driver-model/design-patterns.txt @@ -66,7 +66,7 @@ your interrupt handler. 2. container_of() ~~~~~~~~~~~~~~~~~ -Continuing on the above example we add a offloaded work: +Continuing on the above example we add an offloaded work: struct foo { spinlock_t lock; @@ -99,7 +99,7 @@ static int foo_probe(...) (...) } -The design pattern is the same for a a hrtimer or something similar that will +The design pattern is the same for an hrtimer or something similar that will return a single argument which is a pointer to a struct member in the callback. -- cgit v1.2.3 From 1c51b50c2995f543d145d3bce78029ac9f8ca6b3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 19 Dec 2013 12:30:17 -0800 Subject: PCI/MSI: Export MSI mode using attributes, not kobjects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCI MSI sysfs code is a mess with kobjects for things that don't really need to be kobjects. This patch creates attributes dynamically for the MSI interrupts instead of using kobjects. Note, this removes a directory from sysfs. Old MSI kobjects: pci_device └── msi_irqs    └── 40    └── mode New MSI attributes: pci_device └── msi_irqs    └── 40 As there was only one file "mode" with the kobject model, the interrupt number is now a file that returns the "mode" of the interrupt (msi vs. msix). Signed-off-by: Greg Kroah-Hartman Signed-off-by: Bjorn Helgaas Acked-by: Neil Horman --- Documentation/ABI/testing/sysfs-bus-pci | 11 +-- drivers/pci/msi.c | 166 +++++++++++++++++--------------- include/linux/pci.h | 2 +- 3 files changed, 96 insertions(+), 83 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 5210a51c90fd..a3c5a6685036 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -70,18 +70,15 @@ Date: September, 2011 Contact: Neil Horman Description: The /sys/devices/.../msi_irqs directory contains a variable set - of sub-directories, with each sub-directory being named after a - corresponding msi irq vector allocated to that device. Each - numbered sub-directory N contains attributes of that irq. - Note that this directory is not created for device drivers which - do not support msi irqs + of files, with each file being named after a corresponding msi + irq vector allocated to that device. -What: /sys/bus/pci/devices/.../msi_irqs//mode +What: /sys/bus/pci/devices/.../msi_irqs/ Date: September 2011 Contact: Neil Horman Description: This attribute indicates the mode that the irq vector named by - the parent directory is in (msi vs. msix) + the file is in (msi vs. msix) What: /sys/bus/pci/devices/.../remove Date: January 2009 diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 3fcd67a16677..f88fa1277802 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -363,6 +363,9 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) static void free_msi_irqs(struct pci_dev *dev) { struct msi_desc *entry, *tmp; + struct attribute **msi_attrs; + struct device_attribute *dev_attr; + int count = 0; list_for_each_entry(entry, &dev->msi_list, list) { int i, nvec; @@ -398,6 +401,22 @@ static void free_msi_irqs(struct pci_dev *dev) list_del(&entry->list); kfree(entry); } + + if (dev->msi_irq_groups) { + sysfs_remove_groups(&dev->dev.kobj, dev->msi_irq_groups); + msi_attrs = dev->msi_irq_groups[0]->attrs; + list_for_each_entry(entry, &dev->msi_list, list) { + dev_attr = container_of(msi_attrs[count], + struct device_attribute, attr); + kfree(dev_attr->attr.name); + kfree(dev_attr); + ++count; + } + kfree(msi_attrs); + kfree(dev->msi_irq_groups[0]); + kfree(dev->msi_irq_groups); + dev->msi_irq_groups = NULL; + } } static struct msi_desc *alloc_msi_entry(struct pci_dev *dev) @@ -471,94 +490,95 @@ void pci_restore_msi_state(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_restore_msi_state); - -#define to_msi_attr(obj) container_of(obj, struct msi_attribute, attr) -#define to_msi_desc(obj) container_of(obj, struct msi_desc, kobj) - -struct msi_attribute { - struct attribute attr; - ssize_t (*show)(struct msi_desc *entry, struct msi_attribute *attr, - char *buf); - ssize_t (*store)(struct msi_desc *entry, struct msi_attribute *attr, - const char *buf, size_t count); -}; - -static ssize_t show_msi_mode(struct msi_desc *entry, struct msi_attribute *atr, +static ssize_t msi_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%s\n", entry->msi_attrib.is_msix ? "msix" : "msi"); -} - -static ssize_t msi_irq_attr_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct msi_attribute *attribute = to_msi_attr(attr); - struct msi_desc *entry = to_msi_desc(kobj); - - if (!attribute->show) - return -EIO; - - return attribute->show(entry, attribute, buf); -} - -static const struct sysfs_ops msi_irq_sysfs_ops = { - .show = msi_irq_attr_show, -}; - -static struct msi_attribute mode_attribute = - __ATTR(mode, S_IRUGO, show_msi_mode, NULL); - - -static struct attribute *msi_irq_default_attrs[] = { - &mode_attribute.attr, - NULL -}; + struct pci_dev *pdev = to_pci_dev(dev); + struct msi_desc *entry; + unsigned long irq; + int retval; -static void msi_kobj_release(struct kobject *kobj) -{ - struct msi_desc *entry = to_msi_desc(kobj); + retval = kstrtoul(attr->attr.name, 10, &irq); + if (retval) + return retval; - pci_dev_put(entry->dev); + list_for_each_entry(entry, &pdev->msi_list, list) { + if (entry->irq == irq) { + return sprintf(buf, "%s\n", + entry->msi_attrib.is_msix ? "msix" : "msi"); + } + } + return -ENODEV; } -static struct kobj_type msi_irq_ktype = { - .release = msi_kobj_release, - .sysfs_ops = &msi_irq_sysfs_ops, - .default_attrs = msi_irq_default_attrs, -}; - static int populate_msi_sysfs(struct pci_dev *pdev) { + struct attribute **msi_attrs; + struct attribute *msi_attr; + struct device_attribute *msi_dev_attr; + struct attribute_group *msi_irq_group; + const struct attribute_group **msi_irq_groups; struct msi_desc *entry; - struct kobject *kobj; - int ret; + int ret = -ENOMEM; + int num_msi = 0; int count = 0; - pdev->msi_kset = kset_create_and_add("msi_irqs", NULL, &pdev->dev.kobj); - if (!pdev->msi_kset) - return -ENOMEM; + /* Determine how many msi entries we have */ + list_for_each_entry(entry, &pdev->msi_list, list) { + ++num_msi; + } + if (!num_msi) + return 0; + /* Dynamically create the MSI attributes for the PCI device */ + msi_attrs = kzalloc(sizeof(void *) * (num_msi + 1), GFP_KERNEL); + if (!msi_attrs) + return -ENOMEM; list_for_each_entry(entry, &pdev->msi_list, list) { - kobj = &entry->kobj; - kobj->kset = pdev->msi_kset; - pci_dev_get(pdev); - ret = kobject_init_and_add(kobj, &msi_irq_ktype, NULL, - "%u", entry->irq); - if (ret) - goto out_unroll; - - count++; + char *name = kmalloc(20, GFP_KERNEL); + msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL); + if (!msi_dev_attr) + goto error_attrs; + sprintf(name, "%d", entry->irq); + sysfs_attr_init(&msi_dev_attr->attr); + msi_dev_attr->attr.name = name; + msi_dev_attr->attr.mode = S_IRUGO; + msi_dev_attr->show = msi_mode_show; + msi_attrs[count] = &msi_dev_attr->attr; + ++count; } + msi_irq_group = kzalloc(sizeof(*msi_irq_group), GFP_KERNEL); + if (!msi_irq_group) + goto error_attrs; + msi_irq_group->name = "msi_irqs"; + msi_irq_group->attrs = msi_attrs; + + msi_irq_groups = kzalloc(sizeof(void *) * 2, GFP_KERNEL); + if (!msi_irq_groups) + goto error_irq_group; + msi_irq_groups[0] = msi_irq_group; + + ret = sysfs_create_groups(&pdev->dev.kobj, msi_irq_groups); + if (ret) + goto error_irq_groups; + pdev->msi_irq_groups = msi_irq_groups; + return 0; -out_unroll: - list_for_each_entry(entry, &pdev->msi_list, list) { - if (!count) - break; - kobject_del(&entry->kobj); - kobject_put(&entry->kobj); - count--; +error_irq_groups: + kfree(msi_irq_groups); +error_irq_group: + kfree(msi_irq_group); +error_attrs: + count = 0; + msi_attr = msi_attrs[count]; + while (msi_attr) { + msi_dev_attr = container_of(msi_attr, struct device_attribute, attr); + kfree(msi_attr->name); + kfree(msi_dev_attr); + ++count; + msi_attr = msi_attrs[count]; } return ret; } @@ -925,8 +945,6 @@ void pci_disable_msi(struct pci_dev *dev) pci_msi_shutdown(dev); free_msi_irqs(dev); - kset_unregister(dev->msi_kset); - dev->msi_kset = NULL; } EXPORT_SYMBOL(pci_disable_msi); @@ -1023,8 +1041,6 @@ void pci_disable_msix(struct pci_dev *dev) pci_msix_shutdown(dev); free_msi_irqs(dev); - kset_unregister(dev->msi_kset); - dev->msi_kset = NULL; } EXPORT_SYMBOL(pci_disable_msix); diff --git a/include/linux/pci.h b/include/linux/pci.h index 1084a15175e0..36a5b1828f91 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -351,7 +351,7 @@ struct pci_dev { struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */ #ifdef CONFIG_PCI_MSI struct list_head msi_list; - struct kset *msi_kset; + const struct attribute_group **msi_irq_groups; #endif struct pci_vpd *vpd; #ifdef CONFIG_PCI_ATS -- cgit v1.2.3 From ba52f8a986089e263ea28e231b6a405769ae1235 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Wed, 27 Nov 2013 12:16:23 -0800 Subject: clk/zynq/clkc: Add 'fclk-enable' feature In some use cases Zynq's FPGA clocks are used as static clock generators for IP in the FPGA part of the SOC for which no Linux driver exists and would control those clocks. To avoid automatic gating of these clocks in such cases a new property - fclk-enable - is added to the clock controller's DT description to accomodate such use cases. It's value is a bitmask, where a set bit results in enabling the corresponding FCLK through the clkc. FPGA clocks are handled following the rules below: If an FCLK is not enabled by bootloaders, that FCLK will be disabled in Linux. Drivers can enable and control it through the CCF as usual. If an FCLK is enabled by bootloaders AND the corresponding bit in the 'fclk-enable' DT property is set, that FCLK will be enabled by the clkc, resulting in an off by one reference count for that clock. Ensuring it will always be running. Signed-off-by: Soren Brinkmann Acked-by: Michal Simek Signed-off-by: Michal Simek --- Documentation/devicetree/bindings/clock/zynq-7000.txt | 4 ++++ drivers/clk/zynq/clkc.c | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/zynq-7000.txt b/Documentation/devicetree/bindings/clock/zynq-7000.txt index d99af878f5d7..17b4a94916d6 100644 --- a/Documentation/devicetree/bindings/clock/zynq-7000.txt +++ b/Documentation/devicetree/bindings/clock/zynq-7000.txt @@ -22,6 +22,10 @@ Required properties: Optional properties: - clocks : as described in the clock bindings - clock-names : as described in the clock bindings + - fclk-enable : Bit mask to enable FCLKs statically at boot time. + Bit [0..3] correspond to FCLK0..FCLK3. The corresponding + FCLK will only be enabled if it is actually running at + boot time. Clock inputs: The following strings are optional parameters to the 'clock-names' property in diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c index 10772aa72e4e..09dd0173ea0a 100644 --- a/drivers/clk/zynq/clkc.c +++ b/drivers/clk/zynq/clkc.c @@ -102,9 +102,10 @@ static const char *swdt_ext_clk_input_names[] __initdata = {"swdt_ext_clk"}; static void __init zynq_clk_register_fclk(enum zynq_clk fclk, const char *clk_name, void __iomem *fclk_ctrl_reg, - const char **parents) + const char **parents, int enable) { struct clk *clk; + u32 enable_reg; char *mux_name; char *div0_name; char *div1_name; @@ -147,6 +148,12 @@ static void __init zynq_clk_register_fclk(enum zynq_clk fclk, clks[fclk] = clk_register_gate(NULL, clk_name, div1_name, CLK_SET_RATE_PARENT, fclk_gate_reg, 0, CLK_GATE_SET_TO_DISABLE, fclk_gate_lock); + enable_reg = readl(fclk_gate_reg) & 1; + if (enable && !enable_reg) { + if (clk_prepare_enable(clks[fclk])) + pr_warn("%s: FCLK%u enable failed\n", __func__, + fclk - fclk0); + } kfree(mux_name); kfree(div0_name); kfree(div1_name); @@ -213,6 +220,7 @@ static void __init zynq_clk_setup(struct device_node *np) int ret; struct clk *clk; char *clk_name; + unsigned int fclk_enable = 0; const char *clk_output_name[clk_max]; const char *cpu_parents[4]; const char *periph_parents[4]; @@ -238,6 +246,8 @@ static void __init zynq_clk_setup(struct device_node *np) periph_parents[2] = clk_output_name[armpll]; periph_parents[3] = clk_output_name[ddrpll]; + of_property_read_u32(np, "fclk-enable", &fclk_enable); + /* ps_clk */ ret = of_property_read_u32(np, "ps-clk-frequency", &tmp); if (ret) { @@ -340,10 +350,12 @@ static void __init zynq_clk_setup(struct device_node *np) clk_prepare_enable(clks[dci]); /* Peripheral clocks */ - for (i = fclk0; i <= fclk3; i++) + for (i = fclk0; i <= fclk3; i++) { + int enable = !!(fclk_enable & BIT(i - fclk0)); zynq_clk_register_fclk(i, clk_output_name[i], SLCR_FPGA0_CLK_CTRL + 0x10 * (i - fclk0), - periph_parents); + periph_parents, enable); + } zynq_clk_register_periph_clk(lqspi, 0, clk_output_name[lqspi], NULL, SLCR_LQSPI_CLK_CTRL, periph_parents, 0); -- cgit v1.2.3 From dec727399a4b36bec87b7b4d4c1b20025e69758a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 3 Sep 2013 08:45:46 +0200 Subject: drm/tegra: Add DSI support This commit adds support for both DSI outputs found on Tegra. Only very minimal functionality is implemented, so advanced features like ganged mode won't work. Due to the lack of other test hardware, some sections of the driver are hardcoded to work with Dalmore. Signed-off-by: Thierry Reding --- .../bindings/gpu/nvidia,tegra20-host1x.txt | 10 + drivers/gpu/drm/tegra/Kconfig | 1 + drivers/gpu/drm/tegra/Makefile | 2 + drivers/gpu/drm/tegra/dc.h | 2 + drivers/gpu/drm/tegra/drm.c | 10 +- drivers/gpu/drm/tegra/drm.h | 2 + drivers/gpu/drm/tegra/dsi.c | 963 +++++++++++++++++++++ drivers/gpu/drm/tegra/dsi.h | 134 +++ drivers/gpu/drm/tegra/mipi-phy.c | 137 +++ drivers/gpu/drm/tegra/mipi-phy.h | 65 ++ drivers/gpu/drm/tegra/output.c | 5 + 11 files changed, 1330 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/tegra/dsi.c create mode 100644 drivers/gpu/drm/tegra/dsi.h create mode 100644 drivers/gpu/drm/tegra/mipi-phy.c create mode 100644 drivers/gpu/drm/tegra/mipi-phy.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt index 53045fe32d20..9e9008f8fa32 100644 --- a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt @@ -171,11 +171,21 @@ of the following host1x client modules: - clock-names: Must include the following entries: - dsi This MUST be the first entry. + - lp - parent - resets: Must contain an entry for each entry in reset-names. See ../reset/reset.txt for details. - reset-names: Must include the following entries: - dsi + - nvidia,mipi-calibrate: Should contain a phandle and a specifier specifying + which pads are used by this DSI output and need to be calibrated. See also + ../mipi/nvidia,tegra114-mipi.txt. + + Optional properties: + - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing + - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection + - nvidia,edid: supplies a binary EDID blob + - nvidia,panel: phandle of a display panel Example: diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig index 7a3e8ae90631..5acb2504efb1 100644 --- a/drivers/gpu/drm/tegra/Kconfig +++ b/drivers/gpu/drm/tegra/Kconfig @@ -6,6 +6,7 @@ config DRM_TEGRA select TEGRA_HOST1X select DRM_KMS_HELPER select DRM_KMS_FB_HELPER + select DRM_MIPI_DSI select DRM_PANEL select FB_SYS_FILLRECT select FB_SYS_COPYAREA diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile index edc76abd58bb..8d220afbd85f 100644 --- a/drivers/gpu/drm/tegra/Makefile +++ b/drivers/gpu/drm/tegra/Makefile @@ -9,6 +9,8 @@ tegra-drm-y := \ output.o \ rgb.o \ hdmi.o \ + mipi-phy.o \ + dsi.o \ gr2d.o \ gr3d.o diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index 91bbda291470..788627a060d7 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -28,6 +28,7 @@ #define DISP_CTRL_MODE_STOP (0 << 5) #define DISP_CTRL_MODE_C_DISPLAY (1 << 5) #define DISP_CTRL_MODE_NC_DISPLAY (2 << 5) +#define DISP_CTRL_MODE_MASK (3 << 5) #define DC_CMD_SIGNAL_RAISE 0x033 #define DC_CMD_DISPLAY_POWER_CONTROL 0x036 #define PW0_ENABLE (1 << 0) @@ -116,6 +117,7 @@ #define DC_DISP_DISP_WIN_OPTIONS 0x402 #define HDMI_ENABLE (1 << 30) +#define DSI_ENABLE (1 << 29) #define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403 #define CURSOR_THRESHOLD(x) (((x) & 0x03) << 24) diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 07eba596d458..08e9e3740c13 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -653,6 +653,7 @@ static const struct of_device_id host1x_drm_subdevs[] = { { .compatible = "nvidia,tegra30-hdmi", }, { .compatible = "nvidia,tegra30-gr2d", }, { .compatible = "nvidia,tegra30-gr3d", }, + { .compatible = "nvidia,tegra114-dsi", }, { .compatible = "nvidia,tegra114-hdmi", }, { .compatible = "nvidia,tegra114-gr3d", }, { /* sentinel */ } @@ -677,10 +678,14 @@ static int __init host1x_drm_init(void) if (err < 0) goto unregister_host1x; - err = platform_driver_register(&tegra_hdmi_driver); + err = platform_driver_register(&tegra_dsi_driver); if (err < 0) goto unregister_dc; + err = platform_driver_register(&tegra_hdmi_driver); + if (err < 0) + goto unregister_dsi; + err = platform_driver_register(&tegra_gr2d_driver); if (err < 0) goto unregister_hdmi; @@ -695,6 +700,8 @@ unregister_gr2d: platform_driver_unregister(&tegra_gr2d_driver); unregister_hdmi: platform_driver_unregister(&tegra_hdmi_driver); +unregister_dsi: + platform_driver_unregister(&tegra_dsi_driver); unregister_dc: platform_driver_unregister(&tegra_dc_driver); unregister_host1x: @@ -708,6 +715,7 @@ static void __exit host1x_drm_exit(void) platform_driver_unregister(&tegra_gr3d_driver); platform_driver_unregister(&tegra_gr2d_driver); platform_driver_unregister(&tegra_hdmi_driver); + platform_driver_unregister(&tegra_dsi_driver); platform_driver_unregister(&tegra_dc_driver); host1x_driver_unregister(&host1x_drm_driver); } diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index bb8b1305606e..ddaa937836de 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -177,6 +177,7 @@ struct tegra_output_ops { enum tegra_output_type { TEGRA_OUTPUT_RGB, TEGRA_OUTPUT_HDMI, + TEGRA_OUTPUT_DSI, }; struct tegra_output { @@ -267,6 +268,7 @@ extern void tegra_drm_fb_exit(struct drm_device *drm); extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev); extern struct platform_driver tegra_dc_driver; +extern struct platform_driver tegra_dsi_driver; extern struct platform_driver tegra_hdmi_driver; extern struct platform_driver tegra_gr2d_driver; extern struct platform_driver tegra_gr3d_driver; diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c new file mode 100644 index 000000000000..84a73e32214f --- /dev/null +++ b/drivers/gpu/drm/tegra/dsi.c @@ -0,0 +1,963 @@ +/* + * Copyright (C) 2013 NVIDIA Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include