1c781c06d119d04601727f2fbc30151e6760d536dKristian Høgsberg/* 2b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * Isochronous I/O functionality: 3b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * - Isochronous DMA context management 4b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * - Isochronous bus resource management (channels, bandwidth), client side 53038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * 63038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * Copyright (C) 2006 Kristian Hoegsberg <krh@bitplanet.net> 73038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * 83038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * This program is free software; you can redistribute it and/or modify 93038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * it under the terms of the GNU General Public License as published by 103038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * the Free Software Foundation; either version 2 of the License, or 113038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * (at your option) any later version. 123038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * 133038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * This program is distributed in the hope that it will be useful, 143038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * but WITHOUT ANY WARRANTY; without even the implied warranty of 153038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 163038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * GNU General Public License for more details. 173038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * 183038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * You should have received a copy of the GNU General Public License 193038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * along with this program; if not, write to the Free Software Foundation, 203038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 213038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg */ 223038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg 233038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg#include <linux/dma-mapping.h> 24b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter#include <linux/errno.h> 2577c9a5daa9c4d9b37812c9c69c7bcbb3f9399c3cStefan Richter#include <linux/firewire.h> 26b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter#include <linux/firewire-constants.h> 27b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter#include <linux/kernel.h> 283038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg#include <linux/mm.h> 295a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 30b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter#include <linux/spinlock.h> 31b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter#include <linux/vmalloc.h> 32823467e5fc0c8566a93cfca0e40df6d5de6a4bc3Paul Gortmaker#include <linux/export.h> 333038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg 34e8ca97021c8eb127bb04aec4e2420e1d66be371dStefan Richter#include <asm/byteorder.h> 35e8ca97021c8eb127bb04aec4e2420e1d66be371dStefan Richter 3677c9a5daa9c4d9b37812c9c69c7bcbb3f9399c3cStefan Richter#include "core.h" 37b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 38b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter/* 39b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * Isochronous DMA context management 40b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter */ 413038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg 4253dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterint fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card, 4353dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter int page_count, enum dma_data_direction direction) 443038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg{ 452dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter int i, j; 469aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg dma_addr_t address; 479aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg 489aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg buffer->page_count = page_count; 499aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg buffer->direction = direction; 509aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg 519aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg buffer->pages = kmalloc(page_count * sizeof(buffer->pages[0]), 529aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg GFP_KERNEL); 539aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg if (buffer->pages == NULL) 549aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg goto out; 559aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg 569aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg for (i = 0; i < buffer->page_count; i++) { 5768be3fa15a420d96b1aaed4c519607bf2bfcb2e1Kristian Høgsberg buffer->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO); 589aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg if (buffer->pages[i] == NULL) 599aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg goto out_pages; 60373b2edd864b8753419521b715bd1ddafd2f2af3Stefan Richter 619aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg address = dma_map_page(card->device, buffer->pages[i], 629aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg 0, PAGE_SIZE, direction); 638d8bb39b9eba32dd70e87fd5ad5c5dd4ba118e06FUJITA Tomonori if (dma_mapping_error(card->device, address)) { 649aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg __free_page(buffer->pages[i]); 659aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg goto out_pages; 669aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg } 679aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg set_page_private(buffer->pages[i], address); 683038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg } 693038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg 703038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg return 0; 7182eff9db7dc5d8f78898d5051975d14f48be2028Kristian Høgsberg 729aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg out_pages: 739aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg for (j = 0; j < i; j++) { 749aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg address = page_private(buffer->pages[j]); 759aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg dma_unmap_page(card->device, address, 7629ad14cddd6246d17ff22f496363dfd6b3de8964Stefan Richter PAGE_SIZE, direction); 779aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg __free_page(buffer->pages[j]); 789aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg } 799aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg kfree(buffer->pages); 809aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg out: 819aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg buffer->pages = NULL; 82e1eff7a393d4a4e3ad1cf65fcba899146840bfd2Stefan Richter 832dbd7d7e2327b0c2cc4e2de903e1cfa19980a504Stefan Richter return -ENOMEM; 849aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg} 85c76acec6d55107b652a37c90b36c00bc8b04dabbJay FenlasonEXPORT_SYMBOL(fw_iso_buffer_init); 869aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg 879aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsbergint fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma) 889aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg{ 899aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg unsigned long uaddr; 90e1eff7a393d4a4e3ad1cf65fcba899146840bfd2Stefan Richter int i, err; 919aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg 929aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg uaddr = vma->vm_start; 939aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg for (i = 0; i < buffer->page_count; i++) { 94e1eff7a393d4a4e3ad1cf65fcba899146840bfd2Stefan Richter err = vm_insert_page(vma, uaddr, buffer->pages[i]); 95e1eff7a393d4a4e3ad1cf65fcba899146840bfd2Stefan Richter if (err) 96e1eff7a393d4a4e3ad1cf65fcba899146840bfd2Stefan Richter return err; 97e1eff7a393d4a4e3ad1cf65fcba899146840bfd2Stefan Richter 989aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg uaddr += PAGE_SIZE; 999aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg } 1009aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg 1019aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg return 0; 1023038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg} 1033038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg 1049aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsbergvoid fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, 1059aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg struct fw_card *card) 1063038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg{ 1073038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg int i; 1089aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg dma_addr_t address; 1093038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg 1109aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg for (i = 0; i < buffer->page_count; i++) { 1119aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg address = page_private(buffer->pages[i]); 1129aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg dma_unmap_page(card->device, address, 11329ad14cddd6246d17ff22f496363dfd6b3de8964Stefan Richter PAGE_SIZE, buffer->direction); 1149aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg __free_page(buffer->pages[i]); 1159aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg } 1163038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg 1179aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg kfree(buffer->pages); 1189aad8125389a7a2990dee72d7892e22330a945ebKristian Høgsberg buffer->pages = NULL; 1193038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg} 120c76acec6d55107b652a37c90b36c00bc8b04dabbJay FenlasonEXPORT_SYMBOL(fw_iso_buffer_destroy); 1213038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg 122872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter/* Convert DMA address to offset into virtually contiguous buffer. */ 123872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richtersize_t fw_iso_buffer_lookup(struct fw_iso_buffer *buffer, dma_addr_t completed) 124872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter{ 125872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter int i; 126872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter dma_addr_t address; 127872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter ssize_t offset; 128872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter 129872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter for (i = 0; i < buffer->page_count; i++) { 130872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter address = page_private(buffer->pages[i]); 131872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter offset = (ssize_t)completed - (ssize_t)address; 132872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter if (offset > 0 && offset <= PAGE_SIZE) 133872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter return (i << PAGE_SHIFT) + offset; 134872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter } 135872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter 136872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter return 0; 137872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter} 138872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter 13953dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterstruct fw_iso_context *fw_iso_context_create(struct fw_card *card, 14053dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter int type, int channel, int speed, size_t header_size, 14153dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter fw_iso_callback_t callback, void *callback_data) 1423038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg{ 1433038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg struct fw_iso_context *ctx; 1443038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg 1454817ed240232e89583b0506c2d8e426739af5da3Stefan Richter ctx = card->driver->allocate_iso_context(card, 1464817ed240232e89583b0506c2d8e426739af5da3Stefan Richter type, channel, header_size); 1473038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg if (IS_ERR(ctx)) 1483038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg return ctx; 1493038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg 1503038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg ctx->card = card; 1513038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg ctx->type = type; 15221efb3cfc6ed49991638000f58bb23b838c76e25Kristian Høgsberg ctx->channel = channel; 15321efb3cfc6ed49991638000f58bb23b838c76e25Kristian Høgsberg ctx->speed = speed; 154295e3feb92e5073ec32a3c626302d4b92c4c8a95Kristian Høgsberg ctx->header_size = header_size; 155872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter ctx->callback.sc = callback; 1563038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg ctx->callback_data = callback_data; 1573038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg 1583038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg return ctx; 1593038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg} 160c76acec6d55107b652a37c90b36c00bc8b04dabbJay FenlasonEXPORT_SYMBOL(fw_iso_context_create); 1613038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg 1623038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsbergvoid fw_iso_context_destroy(struct fw_iso_context *ctx) 1633038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg{ 164872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter ctx->card->driver->free_iso_context(ctx); 1653038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg} 166c76acec6d55107b652a37c90b36c00bc8b04dabbJay FenlasonEXPORT_SYMBOL(fw_iso_context_destroy); 1673038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg 16853dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterint fw_iso_context_start(struct fw_iso_context *ctx, 16953dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter int cycle, int sync, int tags) 1703038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg{ 171eb0306eac0aad0b7da18d8fbfb777f155b2c010dKristian Høgsberg return ctx->card->driver->start_iso(ctx, cycle, sync, tags); 1723038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg} 173c76acec6d55107b652a37c90b36c00bc8b04dabbJay FenlasonEXPORT_SYMBOL(fw_iso_context_start); 1743038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg 175872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richterint fw_iso_context_set_channels(struct fw_iso_context *ctx, u64 *channels) 176872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter{ 177872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter return ctx->card->driver->set_iso_channels(ctx, channels); 178872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter} 179872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter 18053dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterint fw_iso_context_queue(struct fw_iso_context *ctx, 18153dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter struct fw_iso_packet *packet, 18253dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter struct fw_iso_buffer *buffer, 18353dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richter unsigned long payload) 1843038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg{ 185872e330e38806d835bd6c311c93ab998e2fb9058Stefan Richter return ctx->card->driver->queue_iso(ctx, packet, buffer, payload); 1863038e353cfaf548eb94f02b172b9dbe412abd24cKristian Høgsberg} 187c76acec6d55107b652a37c90b36c00bc8b04dabbJay FenlasonEXPORT_SYMBOL(fw_iso_context_queue); 188b82956685aab4a9d333714300eb8a86fed6c9ab3Kristian Høgsberg 18913882a82ee1646336c3996c93b4a560a55d2a419Clemens Ladischvoid fw_iso_context_queue_flush(struct fw_iso_context *ctx) 19013882a82ee1646336c3996c93b4a560a55d2a419Clemens Ladisch{ 19113882a82ee1646336c3996c93b4a560a55d2a419Clemens Ladisch ctx->card->driver->flush_queue_iso(ctx); 19213882a82ee1646336c3996c93b4a560a55d2a419Clemens Ladisch} 19313882a82ee1646336c3996c93b4a560a55d2a419Clemens LadischEXPORT_SYMBOL(fw_iso_context_queue_flush); 19413882a82ee1646336c3996c93b4a560a55d2a419Clemens Ladisch 19553dca51175cc2f66d21aeb1e70146cca65c53dadStefan Richterint fw_iso_context_stop(struct fw_iso_context *ctx) 196b82956685aab4a9d333714300eb8a86fed6c9ab3Kristian Høgsberg{ 197b82956685aab4a9d333714300eb8a86fed6c9ab3Kristian Høgsberg return ctx->card->driver->stop_iso(ctx); 198b82956685aab4a9d333714300eb8a86fed6c9ab3Kristian Høgsberg} 199c76acec6d55107b652a37c90b36c00bc8b04dabbJay FenlasonEXPORT_SYMBOL(fw_iso_context_stop); 200b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 201b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter/* 202b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * Isochronous bus resource management (channels, bandwidth), client side 203b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter */ 204b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 205b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richterstatic int manage_bandwidth(struct fw_card *card, int irm_id, int generation, 206f30e6d3e419bfb5540fa82ba7eca01d578556e6bStefan Richter int bandwidth, bool allocate) 207b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter{ 208b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter int try, new, old = allocate ? BANDWIDTH_AVAILABLE_INITIAL : 0; 209f30e6d3e419bfb5540fa82ba7eca01d578556e6bStefan Richter __be32 data[2]; 210b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 211b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter /* 212b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * On a 1394a IRM with low contention, try < 1 is enough. 213b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * On a 1394-1995 IRM, we need at least try < 2. 214b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * Let's just do try < 5. 215b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter */ 216b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter for (try = 0; try < 5; try++) { 217b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter new = allocate ? old - bandwidth : old + bandwidth; 218b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (new < 0 || new > BANDWIDTH_AVAILABLE_INITIAL) 219d6372b6e7c6142e6cc2108b3b850584cd7ade106Clemens Ladisch return -EBUSY; 220b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 221b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter data[0] = cpu_to_be32(old); 222b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter data[1] = cpu_to_be32(new); 223b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, 224b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter irm_id, generation, SCODE_100, 225b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter CSR_REGISTER_BASE + CSR_BANDWIDTH_AVAILABLE, 2261821bc19d54009b6f5e6462dd79074d728080839Stefan Richter data, 8)) { 227b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter case RCODE_GENERATION: 228b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter /* A generation change frees all bandwidth. */ 229b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter return allocate ? -EAGAIN : bandwidth; 230b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 231b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter case RCODE_COMPLETE: 232b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (be32_to_cpup(data) == old) 233b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter return bandwidth; 234b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 235b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter old = be32_to_cpup(data); 236b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter /* Fall through. */ 237b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter } 238b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter } 239b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 240b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter return -EIO; 241b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter} 242b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 243b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richterstatic int manage_channel(struct fw_card *card, int irm_id, int generation, 244f30e6d3e419bfb5540fa82ba7eca01d578556e6bStefan Richter u32 channels_mask, u64 offset, bool allocate) 245b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter{ 2465aaffc65a27dd9db65455c2c9ab3ede57238d2f5Clemens Ladisch __be32 bit, all, old; 247f30e6d3e419bfb5540fa82ba7eca01d578556e6bStefan Richter __be32 data[2]; 2485aaffc65a27dd9db65455c2c9ab3ede57238d2f5Clemens Ladisch int channel, ret = -EIO, retry = 5; 249b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 2505d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter old = all = allocate ? cpu_to_be32(~0) : 0; 2515d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter 2525aaffc65a27dd9db65455c2c9ab3ede57238d2f5Clemens Ladisch for (channel = 0; channel < 32; channel++) { 2535aaffc65a27dd9db65455c2c9ab3ede57238d2f5Clemens Ladisch if (!(channels_mask & 1 << channel)) 254b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter continue; 255b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 256d6372b6e7c6142e6cc2108b3b850584cd7ade106Clemens Ladisch ret = -EBUSY; 257d6372b6e7c6142e6cc2108b3b850584cd7ade106Clemens Ladisch 2585aaffc65a27dd9db65455c2c9ab3ede57238d2f5Clemens Ladisch bit = cpu_to_be32(1 << (31 - channel)); 2595aaffc65a27dd9db65455c2c9ab3ede57238d2f5Clemens Ladisch if ((old & bit) != (all & bit)) 260b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter continue; 261b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 262b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter data[0] = old; 2635aaffc65a27dd9db65455c2c9ab3ede57238d2f5Clemens Ladisch data[1] = old ^ bit; 264b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, 265b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter irm_id, generation, SCODE_100, 2661821bc19d54009b6f5e6462dd79074d728080839Stefan Richter offset, data, 8)) { 267b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter case RCODE_GENERATION: 268b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter /* A generation change frees all channels. */ 2695aaffc65a27dd9db65455c2c9ab3ede57238d2f5Clemens Ladisch return allocate ? -EAGAIN : channel; 270b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 271b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter case RCODE_COMPLETE: 272b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (data[0] == old) 2735aaffc65a27dd9db65455c2c9ab3ede57238d2f5Clemens Ladisch return channel; 274b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 275b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter old = data[0]; 276b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 277b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter /* Is the IRM 1394a-2000 compliant? */ 2785aaffc65a27dd9db65455c2c9ab3ede57238d2f5Clemens Ladisch if ((data[0] & bit) == (data[1] & bit)) 279b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter continue; 280b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 281b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter /* 1394-1995 IRM, fall through to retry. */ 282b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter default: 2833a1f0a0e3d871e3d3e08a1429009992151becda8Clemens Ladisch if (retry) { 2843a1f0a0e3d871e3d3e08a1429009992151becda8Clemens Ladisch retry--; 2855aaffc65a27dd9db65455c2c9ab3ede57238d2f5Clemens Ladisch channel--; 286d6372b6e7c6142e6cc2108b3b850584cd7ade106Clemens Ladisch } else { 287d6372b6e7c6142e6cc2108b3b850584cd7ade106Clemens Ladisch ret = -EIO; 2883a1f0a0e3d871e3d3e08a1429009992151becda8Clemens Ladisch } 289b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter } 290b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter } 291b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 292d6372b6e7c6142e6cc2108b3b850584cd7ade106Clemens Ladisch return ret; 293b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter} 294b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 295b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richterstatic void deallocate_channel(struct fw_card *card, int irm_id, 296f30e6d3e419bfb5540fa82ba7eca01d578556e6bStefan Richter int generation, int channel) 297b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter{ 2985d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter u32 mask; 299b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter u64 offset; 300b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 3015d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter mask = channel < 32 ? 1 << channel : 1 << (channel - 32); 302b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter offset = channel < 32 ? CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI : 303b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO; 304b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 305f30e6d3e419bfb5540fa82ba7eca01d578556e6bStefan Richter manage_channel(card, irm_id, generation, mask, offset, false); 306b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter} 307b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 308b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter/** 309656b7afd40a9f2b0d6cf8ef1972681961b428558Stefan Richter * fw_iso_resource_manage() - Allocate or deallocate a channel and/or bandwidth 310b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * 311b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * In parameters: card, generation, channels_mask, bandwidth, allocate 312b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * Out parameters: channel, bandwidth 313b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * This function blocks (sleeps) during communication with the IRM. 3145d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter * 315b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * Allocates or deallocates at most one channel out of channels_mask. 3165d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter * channels_mask is a bitfield with MSB for channel 63 and LSB for channel 0. 3175d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter * (Note, the IRM's CHANNELS_AVAILABLE is a big-endian bitfield with MSB for 3185d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter * channel 0 and LSB for channel 63.) 3195d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter * Allocates or deallocates as many bandwidth allocation units as specified. 320b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * 321b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * Returns channel < 0 if no channel was allocated or deallocated. 322b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * Returns bandwidth = 0 if no bandwidth was allocated or deallocated. 323b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * 324b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * If generation is stale, deallocations succeed but allocations fail with 325b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * channel = -EAGAIN. 326b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * 3275d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter * If channel allocation fails, no bandwidth will be allocated either. 328b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter * If bandwidth allocation fails, no channel will be allocated either. 3295d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter * But deallocations of channel and bandwidth are tried independently 3305d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter * of each other's success. 331b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter */ 332b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richtervoid fw_iso_resource_manage(struct fw_card *card, int generation, 333b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter u64 channels_mask, int *channel, int *bandwidth, 334f30e6d3e419bfb5540fa82ba7eca01d578556e6bStefan Richter bool allocate) 335b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter{ 3365d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter u32 channels_hi = channels_mask; /* channels 31...0 */ 3375d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter u32 channels_lo = channels_mask >> 32; /* channels 63...32 */ 338b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter int irm_id, ret, c = -EINVAL; 339b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 340b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter spin_lock_irq(&card->lock); 341b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter irm_id = card->irm_node->node_id; 342b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter spin_unlock_irq(&card->lock); 343b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 344b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (channels_hi) 345b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter c = manage_channel(card, irm_id, generation, channels_hi, 3466fdc03709433ccc2005f0f593ae9d9dd04f7b485Stefan Richter CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI, 347f30e6d3e419bfb5540fa82ba7eca01d578556e6bStefan Richter allocate); 348b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (channels_lo && c < 0) { 349b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter c = manage_channel(card, irm_id, generation, channels_lo, 3506fdc03709433ccc2005f0f593ae9d9dd04f7b485Stefan Richter CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO, 351f30e6d3e419bfb5540fa82ba7eca01d578556e6bStefan Richter allocate); 352b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (c >= 0) 353b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter c += 32; 354b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter } 355b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter *channel = c; 356b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 3575d9cb7d276a9c465fef5a771792eac2cf1929f2bStefan Richter if (allocate && channels_mask != 0 && c < 0) 358b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter *bandwidth = 0; 359b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 360b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (*bandwidth == 0) 361b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter return; 362b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 363f30e6d3e419bfb5540fa82ba7eca01d578556e6bStefan Richter ret = manage_bandwidth(card, irm_id, generation, *bandwidth, allocate); 364b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter if (ret < 0) 365b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter *bandwidth = 0; 366b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter 367cf36df6bfb49fd265a39f676bfc9718029fef160Clemens Ladisch if (allocate && ret < 0) { 368cf36df6bfb49fd265a39f676bfc9718029fef160Clemens Ladisch if (c >= 0) 369f30e6d3e419bfb5540fa82ba7eca01d578556e6bStefan Richter deallocate_channel(card, irm_id, generation, c); 370b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter *channel = ret; 371b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter } 372b1bda4cdc2037447bd66753bf5ccab66d91b0b59Jay Fenlason, Stefan Richter} 37331ef9134eb52636d383a7d0626cbbd345cb94f2fClemens LadischEXPORT_SYMBOL(fw_iso_resource_manage); 374