1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 231ef9134SClemens Ladisch /* 331ef9134SClemens Ladisch * Connection Management Procedures (IEC 61883-1) helper functions 431ef9134SClemens Ladisch * 531ef9134SClemens Ladisch * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 631ef9134SClemens Ladisch */ 731ef9134SClemens Ladisch 831ef9134SClemens Ladisch #include <linux/device.h> 931ef9134SClemens Ladisch #include <linux/firewire.h> 1031ef9134SClemens Ladisch #include <linux/firewire-constants.h> 1131ef9134SClemens Ladisch #include <linux/module.h> 1231ef9134SClemens Ladisch #include <linux/sched.h> 1331ef9134SClemens Ladisch #include "lib.h" 1431ef9134SClemens Ladisch #include "iso-resources.h" 1531ef9134SClemens Ladisch #include "cmp.h" 1631ef9134SClemens Ladisch 17a7fa0d04STakashi Sakamoto /* MPR common fields */ 18a7fa0d04STakashi Sakamoto #define MPR_SPEED_MASK 0xc0000000 19a7fa0d04STakashi Sakamoto #define MPR_SPEED_SHIFT 30 20a7fa0d04STakashi Sakamoto #define MPR_XSPEED_MASK 0x00000060 21a7fa0d04STakashi Sakamoto #define MPR_XSPEED_SHIFT 5 22a7fa0d04STakashi Sakamoto #define MPR_PLUGS_MASK 0x0000001f 2331ef9134SClemens Ladisch 24a7fa0d04STakashi Sakamoto /* PCR common fields */ 25a7fa0d04STakashi Sakamoto #define PCR_ONLINE 0x80000000 26a7fa0d04STakashi Sakamoto #define PCR_BCAST_CONN 0x40000000 27a7fa0d04STakashi Sakamoto #define PCR_P2P_CONN_MASK 0x3f000000 28a7fa0d04STakashi Sakamoto #define PCR_P2P_CONN_SHIFT 24 29a7fa0d04STakashi Sakamoto #define PCR_CHANNEL_MASK 0x003f0000 30a7fa0d04STakashi Sakamoto #define PCR_CHANNEL_SHIFT 16 3131ef9134SClemens Ladisch 3244aff698STakashi Sakamoto /* oPCR specific fields */ 3344aff698STakashi Sakamoto #define OPCR_XSPEED_MASK 0x00C00000 3444aff698STakashi Sakamoto #define OPCR_XSPEED_SHIFT 22 3544aff698STakashi Sakamoto #define OPCR_SPEED_MASK 0x0000C000 3644aff698STakashi Sakamoto #define OPCR_SPEED_SHIFT 14 3744aff698STakashi Sakamoto #define OPCR_OVERHEAD_ID_MASK 0x00003C00 3844aff698STakashi Sakamoto #define OPCR_OVERHEAD_ID_SHIFT 10 3944aff698STakashi Sakamoto 4031ef9134SClemens Ladisch enum bus_reset_handling { 4131ef9134SClemens Ladisch ABORT_ON_BUS_RESET, 4231ef9134SClemens Ladisch SUCCEED_ON_BUS_RESET, 4331ef9134SClemens Ladisch }; 4431ef9134SClemens Ladisch 45b9075fa9SJoe Perches static __printf(2, 3) 4631ef9134SClemens Ladisch void cmp_error(struct cmp_connection *c, const char *fmt, ...) 4731ef9134SClemens Ladisch { 4831ef9134SClemens Ladisch va_list va; 4931ef9134SClemens Ladisch 5031ef9134SClemens Ladisch va_start(va, fmt); 5131ef9134SClemens Ladisch dev_err(&c->resources.unit->device, "%cPCR%u: %pV", 5244aff698STakashi Sakamoto (c->direction == CMP_INPUT) ? 'i' : 'o', 5344aff698STakashi Sakamoto c->pcr_index, &(struct va_format){ fmt, &va }); 5431ef9134SClemens Ladisch va_end(va); 5531ef9134SClemens Ladisch } 5631ef9134SClemens Ladisch 5744aff698STakashi Sakamoto static u64 mpr_address(struct cmp_connection *c) 5844aff698STakashi Sakamoto { 5944aff698STakashi Sakamoto if (c->direction == CMP_INPUT) 6044aff698STakashi Sakamoto return CSR_REGISTER_BASE + CSR_IMPR; 6144aff698STakashi Sakamoto else 6244aff698STakashi Sakamoto return CSR_REGISTER_BASE + CSR_OMPR; 6344aff698STakashi Sakamoto } 6444aff698STakashi Sakamoto 6544aff698STakashi Sakamoto static u64 pcr_address(struct cmp_connection *c) 6644aff698STakashi Sakamoto { 6744aff698STakashi Sakamoto if (c->direction == CMP_INPUT) 6844aff698STakashi Sakamoto return CSR_REGISTER_BASE + CSR_IPCR(c->pcr_index); 6944aff698STakashi Sakamoto else 7044aff698STakashi Sakamoto return CSR_REGISTER_BASE + CSR_OPCR(c->pcr_index); 7144aff698STakashi Sakamoto } 7244aff698STakashi Sakamoto 7331ef9134SClemens Ladisch static int pcr_modify(struct cmp_connection *c, 7431ef9134SClemens Ladisch __be32 (*modify)(struct cmp_connection *c, __be32 old), 7531ef9134SClemens Ladisch int (*check)(struct cmp_connection *c, __be32 pcr), 7631ef9134SClemens Ladisch enum bus_reset_handling bus_reset_handling) 7731ef9134SClemens Ladisch { 78f30e6d3eSStefan Richter __be32 old_arg, buffer[2]; 7931ef9134SClemens Ladisch int err; 8031ef9134SClemens Ladisch 8131ef9134SClemens Ladisch buffer[0] = c->last_pcr_value; 8231ef9134SClemens Ladisch for (;;) { 8331ef9134SClemens Ladisch old_arg = buffer[0]; 8431ef9134SClemens Ladisch buffer[1] = modify(c, buffer[0]); 8531ef9134SClemens Ladisch 861b70485fSClemens Ladisch err = snd_fw_transaction( 871b70485fSClemens Ladisch c->resources.unit, TCODE_LOCK_COMPARE_SWAP, 8844aff698STakashi Sakamoto pcr_address(c), buffer, 8, 891b70485fSClemens Ladisch FW_FIXED_GENERATION | c->resources.generation); 9031ef9134SClemens Ladisch 911b70485fSClemens Ladisch if (err < 0) { 921b70485fSClemens Ladisch if (err == -EAGAIN && 931b70485fSClemens Ladisch bus_reset_handling == SUCCEED_ON_BUS_RESET) 941b70485fSClemens Ladisch err = 0; 951b70485fSClemens Ladisch return err; 961b70485fSClemens Ladisch } 971b70485fSClemens Ladisch 9831ef9134SClemens Ladisch if (buffer[0] == old_arg) /* success? */ 9931ef9134SClemens Ladisch break; 10031ef9134SClemens Ladisch 10131ef9134SClemens Ladisch if (check) { 10231ef9134SClemens Ladisch err = check(c, buffer[0]); 10331ef9134SClemens Ladisch if (err < 0) 10431ef9134SClemens Ladisch return err; 10531ef9134SClemens Ladisch } 10631ef9134SClemens Ladisch } 10731ef9134SClemens Ladisch c->last_pcr_value = buffer[1]; 10831ef9134SClemens Ladisch 10931ef9134SClemens Ladisch return 0; 11031ef9134SClemens Ladisch } 11131ef9134SClemens Ladisch 11231ef9134SClemens Ladisch 11331ef9134SClemens Ladisch /** 11431ef9134SClemens Ladisch * cmp_connection_init - initializes a connection manager 11531ef9134SClemens Ladisch * @c: the connection manager to initialize 11631ef9134SClemens Ladisch * @unit: a unit of the target device 1175f217f90STakashi Sakamoto * @direction: input or output 118a7fa0d04STakashi Sakamoto * @pcr_index: the index of the iPCR/oPCR on the target device 11931ef9134SClemens Ladisch */ 12031ef9134SClemens Ladisch int cmp_connection_init(struct cmp_connection *c, 12131ef9134SClemens Ladisch struct fw_unit *unit, 122c68a1c65STakashi Sakamoto enum cmp_direction direction, 123a7fa0d04STakashi Sakamoto unsigned int pcr_index) 12431ef9134SClemens Ladisch { 125a7fa0d04STakashi Sakamoto __be32 mpr_be; 126a7fa0d04STakashi Sakamoto u32 mpr; 12731ef9134SClemens Ladisch int err; 12831ef9134SClemens Ladisch 12944aff698STakashi Sakamoto c->direction = direction; 13031ef9134SClemens Ladisch err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, 13144aff698STakashi Sakamoto mpr_address(c), &mpr_be, 4, 0); 13231ef9134SClemens Ladisch if (err < 0) 13331ef9134SClemens Ladisch return err; 134a7fa0d04STakashi Sakamoto mpr = be32_to_cpu(mpr_be); 13531ef9134SClemens Ladisch 136a7fa0d04STakashi Sakamoto if (pcr_index >= (mpr & MPR_PLUGS_MASK)) 13731ef9134SClemens Ladisch return -EINVAL; 13831ef9134SClemens Ladisch 1395b2599a0SClemens Ladisch err = fw_iso_resources_init(&c->resources, unit); 1405b2599a0SClemens Ladisch if (err < 0) 1415b2599a0SClemens Ladisch return err; 1425b2599a0SClemens Ladisch 14331ef9134SClemens Ladisch c->connected = false; 14431ef9134SClemens Ladisch mutex_init(&c->mutex); 14531ef9134SClemens Ladisch c->last_pcr_value = cpu_to_be32(0x80000000); 146a7fa0d04STakashi Sakamoto c->pcr_index = pcr_index; 147a7fa0d04STakashi Sakamoto c->max_speed = (mpr & MPR_SPEED_MASK) >> MPR_SPEED_SHIFT; 14831ef9134SClemens Ladisch if (c->max_speed == SCODE_BETA) 149a7fa0d04STakashi Sakamoto c->max_speed += (mpr & MPR_XSPEED_MASK) >> MPR_XSPEED_SHIFT; 15031ef9134SClemens Ladisch 15131ef9134SClemens Ladisch return 0; 15231ef9134SClemens Ladisch } 15331ef9134SClemens Ladisch EXPORT_SYMBOL(cmp_connection_init); 15431ef9134SClemens Ladisch 15531ef9134SClemens Ladisch /** 156b04479fbSTakashi Sakamoto * cmp_connection_check_used - check connection is already esablished or not 157b04479fbSTakashi Sakamoto * @c: the connection manager to be checked 1585f217f90STakashi Sakamoto * @used: the pointer to store the result of checking the connection 159b04479fbSTakashi Sakamoto */ 160b04479fbSTakashi Sakamoto int cmp_connection_check_used(struct cmp_connection *c, bool *used) 161b04479fbSTakashi Sakamoto { 162b04479fbSTakashi Sakamoto __be32 pcr; 163b04479fbSTakashi Sakamoto int err; 164b04479fbSTakashi Sakamoto 165b04479fbSTakashi Sakamoto err = snd_fw_transaction( 166b04479fbSTakashi Sakamoto c->resources.unit, TCODE_READ_QUADLET_REQUEST, 167b04479fbSTakashi Sakamoto pcr_address(c), &pcr, 4, 0); 168b04479fbSTakashi Sakamoto if (err >= 0) 16951212eeaSTakashi Sakamoto *used = !!(pcr & cpu_to_be32(PCR_BCAST_CONN | 17051212eeaSTakashi Sakamoto PCR_P2P_CONN_MASK)); 17151212eeaSTakashi Sakamoto 172b04479fbSTakashi Sakamoto return err; 173b04479fbSTakashi Sakamoto } 174b04479fbSTakashi Sakamoto EXPORT_SYMBOL(cmp_connection_check_used); 175b04479fbSTakashi Sakamoto 176b04479fbSTakashi Sakamoto /** 17731ef9134SClemens Ladisch * cmp_connection_destroy - free connection manager resources 17831ef9134SClemens Ladisch * @c: the connection manager 17931ef9134SClemens Ladisch */ 18031ef9134SClemens Ladisch void cmp_connection_destroy(struct cmp_connection *c) 18131ef9134SClemens Ladisch { 18231ef9134SClemens Ladisch WARN_ON(c->connected); 18331ef9134SClemens Ladisch mutex_destroy(&c->mutex); 18431ef9134SClemens Ladisch fw_iso_resources_destroy(&c->resources); 18531ef9134SClemens Ladisch } 18631ef9134SClemens Ladisch EXPORT_SYMBOL(cmp_connection_destroy); 18731ef9134SClemens Ladisch 188*7bc93821STakashi Sakamoto int cmp_connection_reserve(struct cmp_connection *c, 189*7bc93821STakashi Sakamoto unsigned int max_payload_bytes) 190*7bc93821STakashi Sakamoto { 191*7bc93821STakashi Sakamoto int err; 192*7bc93821STakashi Sakamoto 193*7bc93821STakashi Sakamoto mutex_lock(&c->mutex); 194*7bc93821STakashi Sakamoto 195*7bc93821STakashi Sakamoto if (WARN_ON(c->resources.allocated)) { 196*7bc93821STakashi Sakamoto err = -EBUSY; 197*7bc93821STakashi Sakamoto goto end; 198*7bc93821STakashi Sakamoto } 199*7bc93821STakashi Sakamoto 200*7bc93821STakashi Sakamoto c->speed = min(c->max_speed, 201*7bc93821STakashi Sakamoto fw_parent_device(c->resources.unit)->max_speed); 202*7bc93821STakashi Sakamoto 203*7bc93821STakashi Sakamoto err = fw_iso_resources_allocate(&c->resources, max_payload_bytes, 204*7bc93821STakashi Sakamoto c->speed); 205*7bc93821STakashi Sakamoto end: 206*7bc93821STakashi Sakamoto mutex_unlock(&c->mutex); 207*7bc93821STakashi Sakamoto 208*7bc93821STakashi Sakamoto return err; 209*7bc93821STakashi Sakamoto } 210*7bc93821STakashi Sakamoto EXPORT_SYMBOL(cmp_connection_reserve); 211*7bc93821STakashi Sakamoto 212*7bc93821STakashi Sakamoto void cmp_connection_release(struct cmp_connection *c) 213*7bc93821STakashi Sakamoto { 214*7bc93821STakashi Sakamoto mutex_lock(&c->mutex); 215*7bc93821STakashi Sakamoto fw_iso_resources_free(&c->resources); 216*7bc93821STakashi Sakamoto mutex_unlock(&c->mutex); 217*7bc93821STakashi Sakamoto } 218*7bc93821STakashi Sakamoto EXPORT_SYMBOL(cmp_connection_release); 21931ef9134SClemens Ladisch 22031ef9134SClemens Ladisch static __be32 ipcr_set_modify(struct cmp_connection *c, __be32 ipcr) 22131ef9134SClemens Ladisch { 222a7fa0d04STakashi Sakamoto ipcr &= ~cpu_to_be32(PCR_BCAST_CONN | 223a7fa0d04STakashi Sakamoto PCR_P2P_CONN_MASK | 224a7fa0d04STakashi Sakamoto PCR_CHANNEL_MASK); 225a7fa0d04STakashi Sakamoto ipcr |= cpu_to_be32(1 << PCR_P2P_CONN_SHIFT); 226a7fa0d04STakashi Sakamoto ipcr |= cpu_to_be32(c->resources.channel << PCR_CHANNEL_SHIFT); 22731ef9134SClemens Ladisch 22831ef9134SClemens Ladisch return ipcr; 22931ef9134SClemens Ladisch } 23031ef9134SClemens Ladisch 23144aff698STakashi Sakamoto static int get_overhead_id(struct cmp_connection *c) 23244aff698STakashi Sakamoto { 23344aff698STakashi Sakamoto int id; 23444aff698STakashi Sakamoto 23544aff698STakashi Sakamoto /* 23644aff698STakashi Sakamoto * apply "oPCR overhead ID encoding" 23744aff698STakashi Sakamoto * the encoding table can convert up to 512. 23844aff698STakashi Sakamoto * here the value over 512 is converted as the same way as 512. 23944aff698STakashi Sakamoto */ 24044aff698STakashi Sakamoto for (id = 1; id < 16; id++) { 24144aff698STakashi Sakamoto if (c->resources.bandwidth_overhead < (id << 5)) 24244aff698STakashi Sakamoto break; 24344aff698STakashi Sakamoto } 24444aff698STakashi Sakamoto if (id == 16) 24544aff698STakashi Sakamoto id = 0; 24644aff698STakashi Sakamoto 24744aff698STakashi Sakamoto return id; 24844aff698STakashi Sakamoto } 24944aff698STakashi Sakamoto 25044aff698STakashi Sakamoto static __be32 opcr_set_modify(struct cmp_connection *c, __be32 opcr) 25144aff698STakashi Sakamoto { 25244aff698STakashi Sakamoto unsigned int spd, xspd; 25344aff698STakashi Sakamoto 25444aff698STakashi Sakamoto /* generate speed and extended speed field value */ 25544aff698STakashi Sakamoto if (c->speed > SCODE_400) { 25644aff698STakashi Sakamoto spd = SCODE_800; 25744aff698STakashi Sakamoto xspd = c->speed - SCODE_800; 25844aff698STakashi Sakamoto } else { 25944aff698STakashi Sakamoto spd = c->speed; 26044aff698STakashi Sakamoto xspd = 0; 26144aff698STakashi Sakamoto } 26244aff698STakashi Sakamoto 26344aff698STakashi Sakamoto opcr &= ~cpu_to_be32(PCR_BCAST_CONN | 26444aff698STakashi Sakamoto PCR_P2P_CONN_MASK | 26544aff698STakashi Sakamoto OPCR_XSPEED_MASK | 26644aff698STakashi Sakamoto PCR_CHANNEL_MASK | 26744aff698STakashi Sakamoto OPCR_SPEED_MASK | 26844aff698STakashi Sakamoto OPCR_OVERHEAD_ID_MASK); 26944aff698STakashi Sakamoto opcr |= cpu_to_be32(1 << PCR_P2P_CONN_SHIFT); 27044aff698STakashi Sakamoto opcr |= cpu_to_be32(xspd << OPCR_XSPEED_SHIFT); 27144aff698STakashi Sakamoto opcr |= cpu_to_be32(c->resources.channel << PCR_CHANNEL_SHIFT); 27244aff698STakashi Sakamoto opcr |= cpu_to_be32(spd << OPCR_SPEED_SHIFT); 27344aff698STakashi Sakamoto opcr |= cpu_to_be32(get_overhead_id(c) << OPCR_OVERHEAD_ID_SHIFT); 27444aff698STakashi Sakamoto 27544aff698STakashi Sakamoto return opcr; 27644aff698STakashi Sakamoto } 27744aff698STakashi Sakamoto 278a7fa0d04STakashi Sakamoto static int pcr_set_check(struct cmp_connection *c, __be32 pcr) 27931ef9134SClemens Ladisch { 280a7fa0d04STakashi Sakamoto if (pcr & cpu_to_be32(PCR_BCAST_CONN | 281a7fa0d04STakashi Sakamoto PCR_P2P_CONN_MASK)) { 28231ef9134SClemens Ladisch cmp_error(c, "plug is already in use\n"); 28331ef9134SClemens Ladisch return -EBUSY; 28431ef9134SClemens Ladisch } 285a7fa0d04STakashi Sakamoto if (!(pcr & cpu_to_be32(PCR_ONLINE))) { 28631ef9134SClemens Ladisch cmp_error(c, "plug is not on-line\n"); 28731ef9134SClemens Ladisch return -ECONNREFUSED; 28831ef9134SClemens Ladisch } 28931ef9134SClemens Ladisch 29031ef9134SClemens Ladisch return 0; 29131ef9134SClemens Ladisch } 29231ef9134SClemens Ladisch 29331ef9134SClemens Ladisch /** 29431ef9134SClemens Ladisch * cmp_connection_establish - establish a connection to the target 29531ef9134SClemens Ladisch * @c: the connection manager 29631ef9134SClemens Ladisch * 29731ef9134SClemens Ladisch * This function establishes a point-to-point connection from the local 29831ef9134SClemens Ladisch * computer to the target by allocating isochronous resources (channel and 299a7fa0d04STakashi Sakamoto * bandwidth) and setting the target's input/output plug control register. 300a7fa0d04STakashi Sakamoto * When this function succeeds, the caller is responsible for starting 301a7fa0d04STakashi Sakamoto * transmitting packets. 30231ef9134SClemens Ladisch */ 303*7bc93821STakashi Sakamoto int cmp_connection_establish(struct cmp_connection *c) 30431ef9134SClemens Ladisch { 30531ef9134SClemens Ladisch int err; 30631ef9134SClemens Ladisch 30731ef9134SClemens Ladisch mutex_lock(&c->mutex); 30831ef9134SClemens Ladisch 309*7bc93821STakashi Sakamoto if (WARN_ON(c->connected)) { 310*7bc93821STakashi Sakamoto mutex_unlock(&c->mutex); 311*7bc93821STakashi Sakamoto return -EISCONN; 312*7bc93821STakashi Sakamoto } 31331ef9134SClemens Ladisch 314*7bc93821STakashi Sakamoto retry_after_bus_reset: 31544aff698STakashi Sakamoto if (c->direction == CMP_OUTPUT) 31644aff698STakashi Sakamoto err = pcr_modify(c, opcr_set_modify, pcr_set_check, 31744aff698STakashi Sakamoto ABORT_ON_BUS_RESET); 31844aff698STakashi Sakamoto else 319a7fa0d04STakashi Sakamoto err = pcr_modify(c, ipcr_set_modify, pcr_set_check, 32031ef9134SClemens Ladisch ABORT_ON_BUS_RESET); 32144aff698STakashi Sakamoto 32231ef9134SClemens Ladisch if (err == -EAGAIN) { 323*7bc93821STakashi Sakamoto err = fw_iso_resources_update(&c->resources); 324*7bc93821STakashi Sakamoto if (err >= 0) 32531ef9134SClemens Ladisch goto retry_after_bus_reset; 32631ef9134SClemens Ladisch } 327*7bc93821STakashi Sakamoto if (err >= 0) 32831ef9134SClemens Ladisch c->connected = true; 32931ef9134SClemens Ladisch 33031ef9134SClemens Ladisch mutex_unlock(&c->mutex); 33131ef9134SClemens Ladisch 33231ef9134SClemens Ladisch return err; 33331ef9134SClemens Ladisch } 33431ef9134SClemens Ladisch EXPORT_SYMBOL(cmp_connection_establish); 33531ef9134SClemens Ladisch 33631ef9134SClemens Ladisch /** 33731ef9134SClemens Ladisch * cmp_connection_update - update the connection after a bus reset 33831ef9134SClemens Ladisch * @c: the connection manager 33931ef9134SClemens Ladisch * 340a7fa0d04STakashi Sakamoto * This function must be called from the driver's .update handler to 341a7fa0d04STakashi Sakamoto * reestablish any connection that might have been active. 34231ef9134SClemens Ladisch * 34331ef9134SClemens Ladisch * Returns zero on success, or a negative error code. On an error, the 34431ef9134SClemens Ladisch * connection is broken and the caller must stop transmitting iso packets. 34531ef9134SClemens Ladisch */ 34631ef9134SClemens Ladisch int cmp_connection_update(struct cmp_connection *c) 34731ef9134SClemens Ladisch { 34831ef9134SClemens Ladisch int err; 34931ef9134SClemens Ladisch 35031ef9134SClemens Ladisch mutex_lock(&c->mutex); 35131ef9134SClemens Ladisch 35231ef9134SClemens Ladisch if (!c->connected) { 35331ef9134SClemens Ladisch mutex_unlock(&c->mutex); 35431ef9134SClemens Ladisch return 0; 35531ef9134SClemens Ladisch } 35631ef9134SClemens Ladisch 35731ef9134SClemens Ladisch err = fw_iso_resources_update(&c->resources); 35831ef9134SClemens Ladisch if (err < 0) 35931ef9134SClemens Ladisch goto err_unconnect; 36031ef9134SClemens Ladisch 36144aff698STakashi Sakamoto if (c->direction == CMP_OUTPUT) 36244aff698STakashi Sakamoto err = pcr_modify(c, opcr_set_modify, pcr_set_check, 36344aff698STakashi Sakamoto SUCCEED_ON_BUS_RESET); 36444aff698STakashi Sakamoto else 365a7fa0d04STakashi Sakamoto err = pcr_modify(c, ipcr_set_modify, pcr_set_check, 36631ef9134SClemens Ladisch SUCCEED_ON_BUS_RESET); 36744aff698STakashi Sakamoto 36831ef9134SClemens Ladisch if (err < 0) 369*7bc93821STakashi Sakamoto goto err_unconnect; 37031ef9134SClemens Ladisch 37131ef9134SClemens Ladisch mutex_unlock(&c->mutex); 37231ef9134SClemens Ladisch 37331ef9134SClemens Ladisch return 0; 37431ef9134SClemens Ladisch 37531ef9134SClemens Ladisch err_unconnect: 37631ef9134SClemens Ladisch c->connected = false; 37731ef9134SClemens Ladisch mutex_unlock(&c->mutex); 37831ef9134SClemens Ladisch 37931ef9134SClemens Ladisch return err; 38031ef9134SClemens Ladisch } 38131ef9134SClemens Ladisch EXPORT_SYMBOL(cmp_connection_update); 38231ef9134SClemens Ladisch 383a7fa0d04STakashi Sakamoto static __be32 pcr_break_modify(struct cmp_connection *c, __be32 pcr) 38431ef9134SClemens Ladisch { 385a7fa0d04STakashi Sakamoto return pcr & ~cpu_to_be32(PCR_BCAST_CONN | PCR_P2P_CONN_MASK); 38631ef9134SClemens Ladisch } 38731ef9134SClemens Ladisch 38831ef9134SClemens Ladisch /** 38931ef9134SClemens Ladisch * cmp_connection_break - break the connection to the target 39031ef9134SClemens Ladisch * @c: the connection manager 39131ef9134SClemens Ladisch * 392a7fa0d04STakashi Sakamoto * This function deactives the connection in the target's input/output plug 393a7fa0d04STakashi Sakamoto * control register, and frees the isochronous resources of the connection. 394a7fa0d04STakashi Sakamoto * Before calling this function, the caller should cease transmitting packets. 39531ef9134SClemens Ladisch */ 39631ef9134SClemens Ladisch void cmp_connection_break(struct cmp_connection *c) 39731ef9134SClemens Ladisch { 39831ef9134SClemens Ladisch int err; 39931ef9134SClemens Ladisch 40031ef9134SClemens Ladisch mutex_lock(&c->mutex); 40131ef9134SClemens Ladisch 40231ef9134SClemens Ladisch if (!c->connected) { 40331ef9134SClemens Ladisch mutex_unlock(&c->mutex); 40431ef9134SClemens Ladisch return; 40531ef9134SClemens Ladisch } 40631ef9134SClemens Ladisch 407a7fa0d04STakashi Sakamoto err = pcr_modify(c, pcr_break_modify, NULL, SUCCEED_ON_BUS_RESET); 40831ef9134SClemens Ladisch if (err < 0) 40931ef9134SClemens Ladisch cmp_error(c, "plug is still connected\n"); 41031ef9134SClemens Ladisch 41131ef9134SClemens Ladisch c->connected = false; 41231ef9134SClemens Ladisch 41331ef9134SClemens Ladisch mutex_unlock(&c->mutex); 41431ef9134SClemens Ladisch } 41531ef9134SClemens Ladisch EXPORT_SYMBOL(cmp_connection_break); 416