1*da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 231ef9134SClemens Ladisch /* 331ef9134SClemens Ladisch * miscellaneous helper functions 431ef9134SClemens Ladisch * 531ef9134SClemens Ladisch * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 631ef9134SClemens Ladisch */ 731ef9134SClemens Ladisch 831ef9134SClemens Ladisch #include <linux/delay.h> 931ef9134SClemens Ladisch #include <linux/device.h> 1031ef9134SClemens Ladisch #include <linux/firewire.h> 1131ef9134SClemens Ladisch #include <linux/module.h> 12585d7cbaSTakashi Sakamoto #include <linux/slab.h> 1331ef9134SClemens Ladisch #include "lib.h" 1431ef9134SClemens Ladisch 151b70485fSClemens Ladisch #define ERROR_RETRY_DELAY_MS 20 1631ef9134SClemens Ladisch 1731ef9134SClemens Ladisch /** 1831ef9134SClemens Ladisch * snd_fw_transaction - send a request and wait for its completion 1931ef9134SClemens Ladisch * @unit: the driver's unit on the target device 2031ef9134SClemens Ladisch * @tcode: the transaction code 2131ef9134SClemens Ladisch * @offset: the address in the target's address space 2231ef9134SClemens Ladisch * @buffer: input/output data 2331ef9134SClemens Ladisch * @length: length of @buffer 241b70485fSClemens Ladisch * @flags: use %FW_FIXED_GENERATION and add the generation value to attempt the 251b70485fSClemens Ladisch * request only in that generation; use %FW_QUIET to suppress error 261b70485fSClemens Ladisch * messages 2731ef9134SClemens Ladisch * 2831ef9134SClemens Ladisch * Submits an asynchronous request to the target device, and waits for the 2931ef9134SClemens Ladisch * response. The node ID and the current generation are derived from @unit. 3031ef9134SClemens Ladisch * On a bus reset or an error, the transaction is retried a few times. 3131ef9134SClemens Ladisch * Returns zero on success, or a negative error code. 3231ef9134SClemens Ladisch */ 3331ef9134SClemens Ladisch int snd_fw_transaction(struct fw_unit *unit, int tcode, 341b70485fSClemens Ladisch u64 offset, void *buffer, size_t length, 351b70485fSClemens Ladisch unsigned int flags) 3631ef9134SClemens Ladisch { 3731ef9134SClemens Ladisch struct fw_device *device = fw_parent_device(unit); 3831ef9134SClemens Ladisch int generation, rcode, tries = 0; 3931ef9134SClemens Ladisch 401b70485fSClemens Ladisch generation = flags & FW_GENERATION_MASK; 4131ef9134SClemens Ladisch for (;;) { 421b70485fSClemens Ladisch if (!(flags & FW_FIXED_GENERATION)) { 4331ef9134SClemens Ladisch generation = device->generation; 4431ef9134SClemens Ladisch smp_rmb(); /* node_id vs. generation */ 451b70485fSClemens Ladisch } 4631ef9134SClemens Ladisch rcode = fw_run_transaction(device->card, tcode, 4731ef9134SClemens Ladisch device->node_id, generation, 4831ef9134SClemens Ladisch device->max_speed, offset, 4931ef9134SClemens Ladisch buffer, length); 5031ef9134SClemens Ladisch 5131ef9134SClemens Ladisch if (rcode == RCODE_COMPLETE) 5231ef9134SClemens Ladisch return 0; 5331ef9134SClemens Ladisch 541b70485fSClemens Ladisch if (rcode == RCODE_GENERATION && (flags & FW_FIXED_GENERATION)) 551b70485fSClemens Ladisch return -EAGAIN; 561b70485fSClemens Ladisch 5731ef9134SClemens Ladisch if (rcode_is_permanent_error(rcode) || ++tries >= 3) { 581b70485fSClemens Ladisch if (!(flags & FW_QUIET)) 591b70485fSClemens Ladisch dev_err(&unit->device, 601b70485fSClemens Ladisch "transaction failed: %s\n", 617bdbff67SClemens Ladisch fw_rcode_string(rcode)); 6231ef9134SClemens Ladisch return -EIO; 6331ef9134SClemens Ladisch } 6431ef9134SClemens Ladisch 6531ef9134SClemens Ladisch msleep(ERROR_RETRY_DELAY_MS); 6631ef9134SClemens Ladisch } 6731ef9134SClemens Ladisch } 6831ef9134SClemens Ladisch EXPORT_SYMBOL(snd_fw_transaction); 6931ef9134SClemens Ladisch 70923f92ebSTakashi Sakamoto #define PROBE_DELAY_MS (2 * MSEC_PER_SEC) 71923f92ebSTakashi Sakamoto 72923f92ebSTakashi Sakamoto /** 73923f92ebSTakashi Sakamoto * snd_fw_schedule_registration - schedule work for sound card registration 74923f92ebSTakashi Sakamoto * @unit: an instance for unit on IEEE 1394 bus 75923f92ebSTakashi Sakamoto * @dwork: delayed work with callback function 76923f92ebSTakashi Sakamoto * 77923f92ebSTakashi Sakamoto * This function is not designed for general purposes. When new unit is 78923f92ebSTakashi Sakamoto * connected to IEEE 1394 bus, the bus is under bus-reset state because of 79923f92ebSTakashi Sakamoto * topological change. In this state, units tend to fail both of asynchronous 80923f92ebSTakashi Sakamoto * and isochronous communication. To avoid this problem, this function is used 81923f92ebSTakashi Sakamoto * to postpone sound card registration after the state. The callers must 82923f92ebSTakashi Sakamoto * set up instance of delayed work in advance. 83923f92ebSTakashi Sakamoto */ 84923f92ebSTakashi Sakamoto void snd_fw_schedule_registration(struct fw_unit *unit, 85923f92ebSTakashi Sakamoto struct delayed_work *dwork) 86923f92ebSTakashi Sakamoto { 87923f92ebSTakashi Sakamoto u64 now, delay; 88923f92ebSTakashi Sakamoto 89923f92ebSTakashi Sakamoto now = get_jiffies_64(); 90923f92ebSTakashi Sakamoto delay = fw_parent_device(unit)->card->reset_jiffies 91923f92ebSTakashi Sakamoto + msecs_to_jiffies(PROBE_DELAY_MS); 92923f92ebSTakashi Sakamoto 93923f92ebSTakashi Sakamoto if (time_after64(delay, now)) 94923f92ebSTakashi Sakamoto delay -= now; 95923f92ebSTakashi Sakamoto else 96923f92ebSTakashi Sakamoto delay = 0; 97923f92ebSTakashi Sakamoto 98923f92ebSTakashi Sakamoto mod_delayed_work(system_wq, dwork, delay); 99923f92ebSTakashi Sakamoto } 100923f92ebSTakashi Sakamoto EXPORT_SYMBOL(snd_fw_schedule_registration); 101923f92ebSTakashi Sakamoto 10231ef9134SClemens Ladisch MODULE_DESCRIPTION("FireWire audio helper functions"); 10331ef9134SClemens Ladisch MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); 10431ef9134SClemens Ladisch MODULE_LICENSE("GPL v2"); 105