12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737 |
- /*
- * ohci1394.c - driver for OHCI 1394 boards
- * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
- * Gord Peters <GordPeters@smarttech.com>
- * 2001 Ben Collins <bcollins@debian.org>
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- /*
- * Things known to be working:
- * . Async Request Transmit
- * . Async Response Receive
- * . Async Request Receive
- * . Async Response Transmit
- * . Iso Receive
- * . DMA mmap for iso receive
- * . Config ROM generation
- *
- * Things implemented, but still in test phase:
- * . Iso Transmit
- * . Async Stream Packets Transmit (Receive done via Iso interface)
- *
- * Things not implemented:
- * . DMA error recovery
- *
- * Known bugs:
- * . devctl BUS_RESET arg confusion (reset type or root holdoff?)
- * added LONG_RESET_ROOT and SHORT_RESET_ROOT for root holdoff --kk
- */
- /*
- * Acknowledgments:
- *
- * Adam J Richter <adam@yggdrasil.com>
- * . Use of pci_class to find device
- *
- * Emilie Chung <emilie.chung@axis.com>
- * . Tip on Async Request Filter
- *
- * Pascal Drolet <pascal.drolet@informission.ca>
- * . Various tips for optimization and functionnalities
- *
- * Robert Ficklin <rficklin@westengineering.com>
- * . Loop in irq_handler
- *
- * James Goodwin <jamesg@Filanet.com>
- * . Various tips on initialization, self-id reception, etc.
- *
- * Albrecht Dress <ad@mpifr-bonn.mpg.de>
- * . Apple PowerBook detection
- *
- * Daniel Kobras <daniel.kobras@student.uni-tuebingen.de>
- * . Reset the board properly before leaving + misc cleanups
- *
- * Leon van Stuivenberg <leonvs@iae.nl>
- * . Bug fixes
- *
- * Ben Collins <bcollins@debian.org>
- * . Working big-endian support
- * . Updated to 2.4.x module scheme (PCI aswell)
- * . Config ROM generation
- *
- * Manfred Weihs <weihs@ict.tuwien.ac.at>
- * . Reworked code for initiating bus resets
- * (long, short, with or without hold-off)
- *
- * Nandu Santhi <contactnandu@users.sourceforge.net>
- * . Added support for nVidia nForce2 onboard Firewire chipset
- *
- */
- #include <linux/config.h>
- #include <linux/kernel.h>
- #include <linux/list.h>
- #include <linux/slab.h>
- #include <linux/interrupt.h>
- #include <linux/wait.h>
- #include <linux/errno.h>
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/pci.h>
- #include <linux/fs.h>
- #include <linux/poll.h>
- #include <asm/byteorder.h>
- #include <asm/atomic.h>
- #include <asm/uaccess.h>
- #include <linux/delay.h>
- #include <linux/spinlock.h>
- #include <asm/pgtable.h>
- #include <asm/page.h>
- #include <asm/irq.h>
- #include <linux/sched.h>
- #include <linux/types.h>
- #include <linux/vmalloc.h>
- #include <linux/init.h>
- #ifdef CONFIG_PPC_PMAC
- #include <asm/machdep.h>
- #include <asm/pmac_feature.h>
- #include <asm/prom.h>
- #include <asm/pci-bridge.h>
- #endif
- #include "csr1212.h"
- #include "ieee1394.h"
- #include "ieee1394_types.h"
- #include "hosts.h"
- #include "dma.h"
- #include "iso.h"
- #include "ieee1394_core.h"
- #include "highlevel.h"
- #include "ohci1394.h"
- #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
- #define OHCI1394_DEBUG
- #endif
- #ifdef DBGMSG
- #undef DBGMSG
- #endif
- #ifdef OHCI1394_DEBUG
- #define DBGMSG(fmt, args...) \
- printk(KERN_INFO "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args)
- #else
- #define DBGMSG(fmt, args...)
- #endif
- #ifdef CONFIG_IEEE1394_OHCI_DMA_DEBUG
- #define OHCI_DMA_ALLOC(fmt, args...) \
- HPSB_ERR("%s(%s)alloc(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \
- ++global_outstanding_dmas, ## args)
- #define OHCI_DMA_FREE(fmt, args...) \
- HPSB_ERR("%s(%s)free(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \
- --global_outstanding_dmas, ## args)
- static int global_outstanding_dmas = 0;
- #else
- #define OHCI_DMA_ALLOC(fmt, args...)
- #define OHCI_DMA_FREE(fmt, args...)
- #endif
- /* print general (card independent) information */
- #define PRINT_G(level, fmt, args...) \
- printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)
- /* print card specific information */
- #define PRINT(level, fmt, args...) \
- printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args)
- static char version[] __devinitdata =
- "$Rev: 1299 $ Ben Collins <bcollins@debian.org>";
- /* Module Parameters */
- static int phys_dma = 1;
- module_param(phys_dma, int, 0644);
- MODULE_PARM_DESC(phys_dma, "Enable physical dma (default = 1).");
- static void dma_trm_tasklet(unsigned long data);
- static void dma_trm_reset(struct dma_trm_ctx *d);
- static int alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
- enum context_type type, int ctx, int num_desc,
- int buf_size, int split_buf_size, int context_base);
- static void stop_dma_rcv_ctx(struct dma_rcv_ctx *d);
- static void free_dma_rcv_ctx(struct dma_rcv_ctx *d);
- static int alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
- enum context_type type, int ctx, int num_desc,
- int context_base);
- static void ohci1394_pci_remove(struct pci_dev *pdev);
- #ifndef __LITTLE_ENDIAN
- static unsigned hdr_sizes[] =
- {
- 3, /* TCODE_WRITEQ */
- 4, /* TCODE_WRITEB */
- 3, /* TCODE_WRITE_RESPONSE */
- 0, /* ??? */
- 3, /* TCODE_READQ */
- 4, /* TCODE_READB */
- 3, /* TCODE_READQ_RESPONSE */
- 4, /* TCODE_READB_RESPONSE */
- 1, /* TCODE_CYCLE_START (???) */
- 4, /* TCODE_LOCK_REQUEST */
- 2, /* TCODE_ISO_DATA */
- 4, /* TCODE_LOCK_RESPONSE */
- };
- /* Swap headers */
- static inline void packet_swab(quadlet_t *data, int tcode)
- {
- size_t size = hdr_sizes[tcode];
- if (tcode > TCODE_LOCK_RESPONSE || hdr_sizes[tcode] == 0)
- return;
- while (size--)
- data[size] = swab32(data[size]);
- }
- #else
- /* Don't waste cycles on same sex byte swaps */
- #define packet_swab(w,x)
- #endif /* !LITTLE_ENDIAN */
- /***********************************
- * IEEE-1394 functionality section *
- ***********************************/
- static u8 get_phy_reg(struct ti_ohci *ohci, u8 addr)
- {
- int i;
- unsigned long flags;
- quadlet_t r;
- spin_lock_irqsave (&ohci->phy_reg_lock, flags);
- reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000);
- for (i = 0; i < OHCI_LOOP_COUNT; i++) {
- if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000)
- break;
- mdelay(1);
- }
- r = reg_read(ohci, OHCI1394_PhyControl);
- if (i >= OHCI_LOOP_COUNT)
- PRINT (KERN_ERR, "Get PHY Reg timeout [0x%08x/0x%08x/%d]",
- r, r & 0x80000000, i);
- spin_unlock_irqrestore (&ohci->phy_reg_lock, flags);
- return (r & 0x00ff0000) >> 16;
- }
- static void set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data)
- {
- int i;
- unsigned long flags;
- u32 r = 0;
- spin_lock_irqsave (&ohci->phy_reg_lock, flags);
- reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000);
- for (i = 0; i < OHCI_LOOP_COUNT; i++) {
- r = reg_read(ohci, OHCI1394_PhyControl);
- if (!(r & 0x00004000))
- break;
- mdelay(1);
- }
- if (i == OHCI_LOOP_COUNT)
- PRINT (KERN_ERR, "Set PHY Reg timeout [0x%08x/0x%08x/%d]",
- r, r & 0x00004000, i);
- spin_unlock_irqrestore (&ohci->phy_reg_lock, flags);
- return;
- }
- /* Or's our value into the current value */
- static void set_phy_reg_mask(struct ti_ohci *ohci, u8 addr, u8 data)
- {
- u8 old;
- old = get_phy_reg (ohci, addr);
- old |= data;
- set_phy_reg (ohci, addr, old);
- return;
- }
- static void handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
- int phyid, int isroot)
- {
- quadlet_t *q = ohci->selfid_buf_cpu;
- quadlet_t self_id_count=reg_read(ohci, OHCI1394_SelfIDCount);
- size_t size;
- quadlet_t q0, q1;
- /* Check status of self-id reception */
- if (ohci->selfid_swap)
- q0 = le32_to_cpu(q[0]);
- else
- q0 = q[0];
- if ((self_id_count & 0x80000000) ||
- ((self_id_count & 0x00FF0000) != (q0 & 0x00FF0000))) {
- PRINT(KERN_ERR,
- "Error in reception of SelfID packets [0x%08x/0x%08x] (count: %d)",
- self_id_count, q0, ohci->self_id_errors);
- /* Tip by James Goodwin <jamesg@Filanet.com>:
- * We had an error, generate another bus reset in response. */
- if (ohci->self_id_errors<OHCI1394_MAX_SELF_ID_ERRORS) {
- set_phy_reg_mask (ohci, 1, 0x40);
- ohci->self_id_errors++;
- } else {
- PRINT(KERN_ERR,
- "Too many errors on SelfID error reception, giving up!");
- }
- return;
- }
- /* SelfID Ok, reset error counter. */
- ohci->self_id_errors = 0;
- size = ((self_id_count & 0x00001FFC) >> 2) - 1;
- q++;
- while (size > 0) {
- if (ohci->selfid_swap) {
- q0 = le32_to_cpu(q[0]);
- q1 = le32_to_cpu(q[1]);
- } else {
- q0 = q[0];
- q1 = q[1];
- }
- if (q0 == ~q1) {
- DBGMSG ("SelfID packet 0x%x received", q0);
- hpsb_selfid_received(host, cpu_to_be32(q0));
- if (((q0 & 0x3f000000) >> 24) == phyid)
- DBGMSG ("SelfID for this node is 0x%08x", q0);
- } else {
- PRINT(KERN_ERR,
- "SelfID is inconsistent [0x%08x/0x%08x]", q0, q1);
- }
- q += 2;
- size -= 2;
- }
- DBGMSG("SelfID complete");
- return;
- }
- static void ohci_soft_reset(struct ti_ohci *ohci) {
- int i;
- reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
- for (i = 0; i < OHCI_LOOP_COUNT; i++) {
- if (!(reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_softReset))
- break;
- mdelay(1);
- }
- DBGMSG ("Soft reset finished");
- }
- /* Generate the dma receive prgs and start the context */
- static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d, int generate_irq)
- {
- struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
- int i;
- ohci1394_stop_context(ohci, d->ctrlClear, NULL);
- for (i=0; i<d->num_desc; i++) {
- u32 c;
- c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH;
- if (generate_irq)
- c |= DMA_CTL_IRQ;
- d->prg_cpu[i]->control = cpu_to_le32(c | d->buf_size);
- /* End of descriptor list? */
- if (i + 1 < d->num_desc) {
- d->prg_cpu[i]->branchAddress =
- cpu_to_le32((d->prg_bus[i+1] & 0xfffffff0) | 0x1);
- } else {
- d->prg_cpu[i]->branchAddress =
- cpu_to_le32((d->prg_bus[0] & 0xfffffff0));
- }
- d->prg_cpu[i]->address = cpu_to_le32(d->buf_bus[i]);
- d->prg_cpu[i]->status = cpu_to_le32(d->buf_size);
- }
- d->buf_ind = 0;
- d->buf_offset = 0;
- if (d->type == DMA_CTX_ISO) {
- /* Clear contextControl */
- reg_write(ohci, d->ctrlClear, 0xffffffff);
- /* Set bufferFill, isochHeader, multichannel for IR context */
- reg_write(ohci, d->ctrlSet, 0xd0000000);
- /* Set the context match register to match on all tags */
- reg_write(ohci, d->ctxtMatch, 0xf0000000);
- /* Clear the multi channel mask high and low registers */
- reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff);
- /* Set up isoRecvIntMask to generate interrupts */
- reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << d->ctx);
- }
- /* Tell the controller where the first AR program is */
- reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1);
- /* Run context */
- reg_write(ohci, d->ctrlSet, 0x00008000);
- DBGMSG("Receive DMA ctx=%d initialized", d->ctx);
- }
- /* Initialize the dma transmit context */
- static void initialize_dma_trm_ctx(struct dma_trm_ctx *d)
- {
- struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
- /* Stop the context */
- ohci1394_stop_context(ohci, d->ctrlClear, NULL);
- d->prg_ind = 0;
- d->sent_ind = 0;
- d->free_prgs = d->num_desc;
- d->branchAddrPtr = NULL;
- INIT_LIST_HEAD(&d->fifo_list);
- INIT_LIST_HEAD(&d->pending_list);
- if (d->type == DMA_CTX_ISO) {
- /* enable interrupts */
- reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << d->ctx);
- }
- DBGMSG("Transmit DMA ctx=%d initialized", d->ctx);
- }
- /* Count the number of available iso contexts */
- static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg)
- {
- int i,ctx=0;
- u32 tmp;
- reg_write(ohci, reg, 0xffffffff);
- tmp = reg_read(ohci, reg);
- DBGMSG("Iso contexts reg: %08x implemented: %08x", reg, tmp);
- /* Count the number of contexts */
- for (i=0; i<32; i++) {
- if (tmp & 1) ctx++;
- tmp >>= 1;
- }
- return ctx;
- }
- /* Global initialization */
- static void ohci_initialize(struct ti_ohci *ohci)
- {
- char irq_buf[16];
- quadlet_t buf;
- int num_ports, i;
- spin_lock_init(&ohci->phy_reg_lock);
- /* Put some defaults to these undefined bus options */
- buf = reg_read(ohci, OHCI1394_BusOptions);
- buf |= 0x60000000; /* Enable CMC and ISC */
- if (hpsb_disable_irm)
- buf &= ~0x80000000;
- else
- buf |= 0x80000000; /* Enable IRMC */
- buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
- buf &= ~0x18000000; /* Disable PMC and BMC */
- reg_write(ohci, OHCI1394_BusOptions, buf);
- /* Set the bus number */
- reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
- /* Enable posted writes */
- reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_postedWriteEnable);
- /* Clear link control register */
- reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
- /* Enable cycle timer and cycle master and set the IRM
- * contender bit in our self ID packets if appropriate. */
- reg_write(ohci, OHCI1394_LinkControlSet,
- OHCI1394_LinkControl_CycleTimerEnable |
- OHCI1394_LinkControl_CycleMaster);
- i = get_phy_reg(ohci, 4) | PHY_04_LCTRL;
- if (hpsb_disable_irm)
- i &= ~PHY_04_CONTENDER;
- else
- i |= PHY_04_CONTENDER;
- set_phy_reg(ohci, 4, i);
- /* Set up self-id dma buffer */
- reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);
- /* enable self-id and phys */
- reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID |
- OHCI1394_LinkControl_RcvPhyPkt);
- /* Set the Config ROM mapping register */
- reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);
- /* Now get our max packet size */
- ohci->max_packet_size =
- 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
-
- /* Don't accept phy packets into AR request context */
- reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
- /* Clear the interrupt mask */
- reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
- /* Clear the interrupt mask */
- reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
- /* Initialize AR dma */
- initialize_dma_rcv_ctx(&ohci->ar_req_context, 0);
- initialize_dma_rcv_ctx(&ohci->ar_resp_context, 0);
- /* Initialize AT dma */
- initialize_dma_trm_ctx(&ohci->at_req_context);
- initialize_dma_trm_ctx(&ohci->at_resp_context);
-
- /* Initialize IR Legacy DMA channel mask */
- ohci->ir_legacy_channels = 0;
- /*
- * Accept AT requests from all nodes. This probably
- * will have to be controlled from the subsystem
- * on a per node basis.
- */
- reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000);
- /* Specify AT retries */
- reg_write(ohci, OHCI1394_ATRetries,
- OHCI1394_MAX_AT_REQ_RETRIES |
- (OHCI1394_MAX_AT_RESP_RETRIES<<4) |
- (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
- /* We don't want hardware swapping */
- reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap);
- /* Enable interrupts */
- reg_write(ohci, OHCI1394_IntMaskSet,
- OHCI1394_unrecoverableError |
- OHCI1394_masterIntEnable |
- OHCI1394_busReset |
- OHCI1394_selfIDComplete |
- OHCI1394_RSPkt |
- OHCI1394_RQPkt |
- OHCI1394_respTxComplete |
- OHCI1394_reqTxComplete |
- OHCI1394_isochRx |
- OHCI1394_isochTx |
- OHCI1394_cycleInconsistent);
- /* Enable link */
- reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
- buf = reg_read(ohci, OHCI1394_Version);
- #ifndef __sparc__
- sprintf (irq_buf, "%d", ohci->dev->irq);
- #else
- sprintf (irq_buf, "%s", __irq_itoa(ohci->dev->irq));
- #endif
- PRINT(KERN_INFO, "OHCI-1394 %d.%d (PCI): IRQ=[%s] "
- "MMIO=[%lx-%lx] Max Packet=[%d]",
- ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
- ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), irq_buf,
- pci_resource_start(ohci->dev, 0),
- pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1,
- ohci->max_packet_size);
- /* Check all of our ports to make sure that if anything is
- * connected, we enable that port. */
- num_ports = get_phy_reg(ohci, 2) & 0xf;
- for (i = 0; i < num_ports; i++) {
- unsigned int status;
- set_phy_reg(ohci, 7, i);
- status = get_phy_reg(ohci, 8);
- if (status & 0x20)
- set_phy_reg(ohci, 8, status & ~1);
- }
- /* Serial EEPROM Sanity check. */
- if ((ohci->max_packet_size < 512) ||
- (ohci->max_packet_size > 4096)) {
- /* Serial EEPROM contents are suspect, set a sane max packet
- * size and print the raw contents for bug reports if verbose
- * debug is enabled. */
- #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
- int i;
- #endif
- PRINT(KERN_DEBUG, "Serial EEPROM has suspicious values, "
- "attempting to setting max_packet_size to 512 bytes");
- reg_write(ohci, OHCI1394_BusOptions,
- (reg_read(ohci, OHCI1394_BusOptions) & 0xf007) | 0x8002);
- ohci->max_packet_size = 512;
- #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
- PRINT(KERN_DEBUG, " EEPROM Present: %d",
- (reg_read(ohci, OHCI1394_Version) >> 24) & 0x1);
- reg_write(ohci, OHCI1394_GUID_ROM, 0x80000000);
- for (i = 0;
- ((i < 1000) &&
- (reg_read(ohci, OHCI1394_GUID_ROM) & 0x80000000)); i++)
- udelay(10);
- for (i = 0; i < 0x20; i++) {
- reg_write(ohci, OHCI1394_GUID_ROM, 0x02000000);
- PRINT(KERN_DEBUG, " EEPROM %02x: %02x", i,
- (reg_read(ohci, OHCI1394_GUID_ROM) >> 16) & 0xff);
- }
- #endif
- }
- }
- /*
- * Insert a packet in the DMA fifo and generate the DMA prg
- * FIXME: rewrite the program in order to accept packets crossing
- * page boundaries.
- * check also that a single dma descriptor doesn't cross a
- * page boundary.
- */
- static void insert_packet(struct ti_ohci *ohci,
- struct dma_trm_ctx *d, struct hpsb_packet *packet)
- {
- u32 cycleTimer;
- int idx = d->prg_ind;
- DBGMSG("Inserting packet for node " NODE_BUS_FMT
- ", tlabel=%d, tcode=0x%x, speed=%d",
- NODE_BUS_ARGS(ohci->host, packet->node_id), packet->tlabel,
- packet->tcode, packet->speed_code);
- d->prg_cpu[idx]->begin.address = 0;
- d->prg_cpu[idx]->begin.branchAddress = 0;
- if (d->type == DMA_CTX_ASYNC_RESP) {
- /*
- * For response packets, we need to put a timeout value in
- * the 16 lower bits of the status... let's try 1 sec timeout
- */
- cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
- d->prg_cpu[idx]->begin.status = cpu_to_le32(
- (((((cycleTimer>>25)&0x7)+1)&0x7)<<13) |
- ((cycleTimer&0x01fff000)>>12));
- DBGMSG("cycleTimer: %08x timeStamp: %08x",
- cycleTimer, d->prg_cpu[idx]->begin.status);
- } else
- d->prg_cpu[idx]->begin.status = 0;
- if ( (packet->type == hpsb_async) || (packet->type == hpsb_raw) ) {
- if (packet->type == hpsb_raw) {
- d->prg_cpu[idx]->data[0] = cpu_to_le32(OHCI1394_TCODE_PHY<<4);
- d->prg_cpu[idx]->data[1] = cpu_to_le32(packet->header[0]);
- d->prg_cpu[idx]->data[2] = cpu_to_le32(packet->header[1]);
- } else {
- d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
- (packet->header[0] & 0xFFFF);
- if (packet->tcode == TCODE_ISO_DATA) {
- /* Sending an async stream packet */
- d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
- } else {
- /* Sending a normal async request or response */
- d->prg_cpu[idx]->data[1] =
- (packet->header[1] & 0xFFFF) |
- (packet->header[0] & 0xFFFF0000);
- d->prg_cpu[idx]->data[2] = packet->header[2];
- d->prg_cpu[idx]->data[3] = packet->header[3];
- }
- packet_swab(d->prg_cpu[idx]->data, packet->tcode);
- }
- if (packet->data_size) { /* block transmit */
- if (packet->tcode == TCODE_STREAM_DATA){
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_MORE |
- DMA_CTL_IMMEDIATE | 0x8);
- } else {
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_MORE |
- DMA_CTL_IMMEDIATE | 0x10);
- }
- d->prg_cpu[idx]->end.control =
- cpu_to_le32(DMA_CTL_OUTPUT_LAST |
- DMA_CTL_IRQ |
- DMA_CTL_BRANCH |
- packet->data_size);
- /*
- * Check that the packet data buffer
- * does not cross a page boundary.
- *
- * XXX Fix this some day. eth1394 seems to trigger
- * it, but ignoring it doesn't seem to cause a
- * problem.
- */
- #if 0
- if (cross_bound((unsigned long)packet->data,
- packet->data_size)>0) {
- /* FIXME: do something about it */
- PRINT(KERN_ERR,
- "%s: packet data addr: %p size %Zd bytes "
- "cross page boundary", __FUNCTION__,
- packet->data, packet->data_size);
- }
- #endif
- d->prg_cpu[idx]->end.address = cpu_to_le32(
- pci_map_single(ohci->dev, packet->data,
- packet->data_size,
- PCI_DMA_TODEVICE));
- OHCI_DMA_ALLOC("single, block transmit packet");
- d->prg_cpu[idx]->end.branchAddress = 0;
- d->prg_cpu[idx]->end.status = 0;
- if (d->branchAddrPtr)
- *(d->branchAddrPtr) =
- cpu_to_le32(d->prg_bus[idx] | 0x3);
- d->branchAddrPtr =
- &(d->prg_cpu[idx]->end.branchAddress);
- } else { /* quadlet transmit */
- if (packet->type == hpsb_raw)
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_LAST |
- DMA_CTL_IMMEDIATE |
- DMA_CTL_IRQ |
- DMA_CTL_BRANCH |
- (packet->header_size + 4));
- else
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_LAST |
- DMA_CTL_IMMEDIATE |
- DMA_CTL_IRQ |
- DMA_CTL_BRANCH |
- packet->header_size);
- if (d->branchAddrPtr)
- *(d->branchAddrPtr) =
- cpu_to_le32(d->prg_bus[idx] | 0x2);
- d->branchAddrPtr =
- &(d->prg_cpu[idx]->begin.branchAddress);
- }
- } else { /* iso packet */
- d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
- (packet->header[0] & 0xFFFF);
- d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
- packet_swab(d->prg_cpu[idx]->data, packet->tcode);
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_MORE |
- DMA_CTL_IMMEDIATE | 0x8);
- d->prg_cpu[idx]->end.control =
- cpu_to_le32(DMA_CTL_OUTPUT_LAST |
- DMA_CTL_UPDATE |
- DMA_CTL_IRQ |
- DMA_CTL_BRANCH |
- packet->data_size);
- d->prg_cpu[idx]->end.address = cpu_to_le32(
- pci_map_single(ohci->dev, packet->data,
- packet->data_size, PCI_DMA_TODEVICE));
- OHCI_DMA_ALLOC("single, iso transmit packet");
- d->prg_cpu[idx]->end.branchAddress = 0;
- d->prg_cpu[idx]->end.status = 0;
- DBGMSG("Iso xmit context info: header[%08x %08x]\n"
- " begin=%08x %08x %08x %08x\n"
- " %08x %08x %08x %08x\n"
- " end =%08x %08x %08x %08x",
- d->prg_cpu[idx]->data[0], d->prg_cpu[idx]->data[1],
- d->prg_cpu[idx]->begin.control,
- d->prg_cpu[idx]->begin.address,
- d->prg_cpu[idx]->begin.branchAddress,
- d->prg_cpu[idx]->begin.status,
- d->prg_cpu[idx]->data[0],
- d->prg_cpu[idx]->data[1],
- d->prg_cpu[idx]->data[2],
- d->prg_cpu[idx]->data[3],
- d->prg_cpu[idx]->end.control,
- d->prg_cpu[idx]->end.address,
- d->prg_cpu[idx]->end.branchAddress,
- d->prg_cpu[idx]->end.status);
- if (d->branchAddrPtr)
- *(d->branchAddrPtr) = cpu_to_le32(d->prg_bus[idx] | 0x3);
- d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress);
- }
- d->free_prgs--;
- /* queue the packet in the appropriate context queue */
- list_add_tail(&packet->driver_list, &d->fifo_list);
- d->prg_ind = (d->prg_ind + 1) % d->num_desc;
- }
- /*
- * This function fills the FIFO with the (eventual) pending packets
- * and runs or wakes up the DMA prg if necessary.
- *
- * The function MUST be called with the d->lock held.
- */
- static void dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d)
- {
- struct hpsb_packet *packet, *ptmp;
- int idx = d->prg_ind;
- int z = 0;
- /* insert the packets into the dma fifo */
- list_for_each_entry_safe(packet, ptmp, &d->pending_list, driver_list) {
- if (!d->free_prgs)
- break;
- /* For the first packet only */
- if (!z)
- z = (packet->data_size) ? 3 : 2;
- /* Insert the packet */
- list_del_init(&packet->driver_list);
- insert_packet(ohci, d, packet);
- }
- /* Nothing must have been done, either no free_prgs or no packets */
- if (z == 0)
- return;
- /* Is the context running ? (should be unless it is
- the first packet to be sent in this context) */
- if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) {
- u32 nodeId = reg_read(ohci, OHCI1394_NodeID);
- DBGMSG("Starting transmit DMA ctx=%d",d->ctx);
- reg_write(ohci, d->cmdPtr, d->prg_bus[idx] | z);
- /* Check that the node id is valid, and not 63 */
- if (!(nodeId & 0x80000000) || (nodeId & 0x3f) == 63)
- PRINT(KERN_ERR, "Running dma failed because Node ID is not valid");
- else
- reg_write(ohci, d->ctrlSet, 0x8000);
- } else {
- /* Wake up the dma context if necessary */
- if (!(reg_read(ohci, d->ctrlSet) & 0x400))
- DBGMSG("Waking transmit DMA ctx=%d",d->ctx);
- /* do this always, to avoid race condition */
- reg_write(ohci, d->ctrlSet, 0x1000);
- }
- return;
- }
- /* Transmission of an async or iso packet */
- static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet)
- {
- struct ti_ohci *ohci = host->hostdata;
- struct dma_trm_ctx *d;
- unsigned long flags;
- if (packet->data_size > ohci->max_packet_size) {
- PRINT(KERN_ERR,
- "Transmit packet size %Zd is too big",
- packet->data_size);
- return -EOVERFLOW;
- }
- /* Decide whether we have an iso, a request, or a response packet */
- if (packet->type == hpsb_raw)
- d = &ohci->at_req_context;
- else if ((packet->tcode == TCODE_ISO_DATA) && (packet->type == hpsb_iso)) {
- /* The legacy IT DMA context is initialized on first
- * use. However, the alloc cannot be run from
- * interrupt context, so we bail out if that is the
- * case. I don't see anyone sending ISO packets from
- * interrupt context anyway... */
- if (ohci->it_legacy_context.ohci == NULL) {
- if (in_interrupt()) {
- PRINT(KERN_ERR,
- "legacy IT context cannot be initialized during interrupt");
- return -EINVAL;
- }
- if (alloc_dma_trm_ctx(ohci, &ohci->it_legacy_context,
- DMA_CTX_ISO, 0, IT_NUM_DESC,
- OHCI1394_IsoXmitContextBase) < 0) {
- PRINT(KERN_ERR,
- "error initializing legacy IT context");
- return -ENOMEM;
- }
- initialize_dma_trm_ctx(&ohci->it_legacy_context);
- }
- d = &ohci->it_legacy_context;
- } else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA))
- d = &ohci->at_resp_context;
- else
- d = &ohci->at_req_context;
- spin_lock_irqsave(&d->lock,flags);
- list_add_tail(&packet->driver_list, &d->pending_list);
- dma_trm_flush(ohci, d);
- spin_unlock_irqrestore(&d->lock,flags);
- return 0;
- }
- static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
- {
- struct ti_ohci *ohci = host->hostdata;
- int retval = 0;
- unsigned long flags;
- int phy_reg;
- switch (cmd) {
- case RESET_BUS:
- switch (arg) {
- case SHORT_RESET:
- phy_reg = get_phy_reg(ohci, 5);
- phy_reg |= 0x40;
- set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
- break;
- case LONG_RESET:
- phy_reg = get_phy_reg(ohci, 1);
- phy_reg |= 0x40;
- set_phy_reg(ohci, 1, phy_reg); /* set IBR */
- break;
- case SHORT_RESET_NO_FORCE_ROOT:
- phy_reg = get_phy_reg(ohci, 1);
- if (phy_reg & 0x80) {
- phy_reg &= ~0x80;
- set_phy_reg(ohci, 1, phy_reg); /* clear RHB */
- }
- phy_reg = get_phy_reg(ohci, 5);
- phy_reg |= 0x40;
- set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
- break;
- case LONG_RESET_NO_FORCE_ROOT:
- phy_reg = get_phy_reg(ohci, 1);
- phy_reg &= ~0x80;
- phy_reg |= 0x40;
- set_phy_reg(ohci, 1, phy_reg); /* clear RHB, set IBR */
- break;
- case SHORT_RESET_FORCE_ROOT:
- phy_reg = get_phy_reg(ohci, 1);
- if (!(phy_reg & 0x80)) {
- phy_reg |= 0x80;
- set_phy_reg(ohci, 1, phy_reg); /* set RHB */
- }
- phy_reg = get_phy_reg(ohci, 5);
- phy_reg |= 0x40;
- set_phy_reg(ohci, 5, phy_reg); /* set ISBR */
- break;
- case LONG_RESET_FORCE_ROOT:
- phy_reg = get_phy_reg(ohci, 1);
- phy_reg |= 0xc0;
- set_phy_reg(ohci, 1, phy_reg); /* set RHB and IBR */
- break;
- default:
- retval = -1;
- }
- break;
- case GET_CYCLE_COUNTER:
- retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
- break;
- case SET_CYCLE_COUNTER:
- reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg);
- break;
- case SET_BUS_ID:
- PRINT(KERN_ERR, "devctl command SET_BUS_ID err");
- break;
- case ACT_CYCLE_MASTER:
- if (arg) {
- /* check if we are root and other nodes are present */
- u32 nodeId = reg_read(ohci, OHCI1394_NodeID);
- if ((nodeId & (1<<30)) && (nodeId & 0x3f)) {
- /*
- * enable cycleTimer, cycleMaster
- */
- DBGMSG("Cycle master enabled");
- reg_write(ohci, OHCI1394_LinkControlSet,
- OHCI1394_LinkControl_CycleTimerEnable |
- OHCI1394_LinkControl_CycleMaster);
- }
- } else {
- /* disable cycleTimer, cycleMaster, cycleSource */
- reg_write(ohci, OHCI1394_LinkControlClear,
- OHCI1394_LinkControl_CycleTimerEnable |
- OHCI1394_LinkControl_CycleMaster |
- OHCI1394_LinkControl_CycleSource);
- }
- break;
- case CANCEL_REQUESTS:
- DBGMSG("Cancel request received");
- dma_trm_reset(&ohci->at_req_context);
- dma_trm_reset(&ohci->at_resp_context);
- break;
- case ISO_LISTEN_CHANNEL:
- {
- u64 mask;
- struct dma_rcv_ctx *d = &ohci->ir_legacy_context;
- int ir_legacy_active;
- if (arg<0 || arg>63) {
- PRINT(KERN_ERR,
- "%s: IS0 listen channel %d is out of range",
- __FUNCTION__, arg);
- return -EFAULT;
- }
- mask = (u64)0x1<<arg;
- spin_lock_irqsave(&ohci->IR_channel_lock, flags);
- if (ohci->ISO_channel_usage & mask) {
- PRINT(KERN_ERR,
- "%s: IS0 listen channel %d is already used",
- __FUNCTION__, arg);
- spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
- return -EFAULT;
- }
- ir_legacy_active = ohci->ir_legacy_channels;
- ohci->ISO_channel_usage |= mask;
- ohci->ir_legacy_channels |= mask;
- spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
- if (!ir_legacy_active) {
- if (ohci1394_register_iso_tasklet(ohci,
- &ohci->ir_legacy_tasklet) < 0) {
- PRINT(KERN_ERR, "No IR DMA context available");
- return -EBUSY;
- }
- /* the IR context can be assigned to any DMA context
- * by ohci1394_register_iso_tasklet */
- d->ctx = ohci->ir_legacy_tasklet.context;
- d->ctrlSet = OHCI1394_IsoRcvContextControlSet +
- 32*d->ctx;
- d->ctrlClear = OHCI1394_IsoRcvContextControlClear +
- 32*d->ctx;
- d->cmdPtr = OHCI1394_IsoRcvCommandPtr + 32*d->ctx;
- d->ctxtMatch = OHCI1394_IsoRcvContextMatch + 32*d->ctx;
- initialize_dma_rcv_ctx(&ohci->ir_legacy_context, 1);
- if (printk_ratelimit())
- PRINT(KERN_ERR, "IR legacy activated");
- }
- spin_lock_irqsave(&ohci->IR_channel_lock, flags);
- if (arg>31)
- reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet,
- 1<<(arg-32));
- else
- reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet,
- 1<<arg);
- spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
- DBGMSG("Listening enabled on channel %d", arg);
- break;
- }
- case ISO_UNLISTEN_CHANNEL:
- {
- u64 mask;
- if (arg<0 || arg>63) {
- PRINT(KERN_ERR,
- "%s: IS0 unlisten channel %d is out of range",
- __FUNCTION__, arg);
- return -EFAULT;
- }
- mask = (u64)0x1<<arg;
- spin_lock_irqsave(&ohci->IR_channel_lock, flags);
- if (!(ohci->ISO_channel_usage & mask)) {
- PRINT(KERN_ERR,
- "%s: IS0 unlisten channel %d is not used",
- __FUNCTION__, arg);
- spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
- return -EFAULT;
- }
- ohci->ISO_channel_usage &= ~mask;
- ohci->ir_legacy_channels &= ~mask;
- if (arg>31)
- reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear,
- 1<<(arg-32));
- else
- reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear,
- 1<<arg);
- spin_unlock_irqrestore(&ohci->IR_channel_lock, flags);
- DBGMSG("Listening disabled on channel %d", arg);
- if (ohci->ir_legacy_channels == 0) {
- stop_dma_rcv_ctx(&ohci->ir_legacy_context);
- DBGMSG("ISO legacy receive context stopped");
- }
- break;
- }
- default:
- PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet",
- cmd);
- break;
- }
- return retval;
- }
- /***********************************
- * rawiso ISO reception *
- ***********************************/
- /*
- We use either buffer-fill or packet-per-buffer DMA mode. The DMA
- buffer is split into "blocks" (regions described by one DMA
- descriptor). Each block must be one page or less in size, and
- must not cross a page boundary.
- There is one little wrinkle with buffer-fill mode: a packet that
- starts in the final block may wrap around into the first block. But
- the user API expects all packets to be contiguous. Our solution is
- to keep the very last page of the DMA buffer in reserve - if a
- packet spans the gap, we copy its tail into this page.
- */
- struct ohci_iso_recv {
- struct ti_ohci *ohci;
- struct ohci1394_iso_tasklet task;
- int task_active;
- enum { BUFFER_FILL_MODE = 0,
- PACKET_PER_BUFFER_MODE = 1 } dma_mode;
- /* memory and PCI mapping for the DMA descriptors */
- struct dma_prog_region prog;
- struct dma_cmd *block; /* = (struct dma_cmd*) prog.virt */
- /* how many DMA blocks fit in the buffer */
- unsigned int nblocks;
- /* stride of DMA blocks */
- unsigned int buf_stride;
- /* number of blocks to batch between interrupts */
- int block_irq_interval;
- /* block that DMA will finish next */
- int block_dma;
- /* (buffer-fill only) block that the reader will release next */
- int block_reader;
- /* (buffer-fill only) bytes of buffer the reader has released,
- less than one block */
- int released_bytes;
- /* (buffer-fill only) buffer offset at which the next packet will appear */
- int dma_offset;
- /* OHCI DMA context control registers */
- u32 ContextControlSet;
- u32 ContextControlClear;
- u32 CommandPtr;
- u32 ContextMatch;
- };
- static void ohci_iso_recv_task(unsigned long data);
- static void ohci_iso_recv_stop(struct hpsb_iso *iso);
- static void ohci_iso_recv_shutdown(struct hpsb_iso *iso);
- static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync);
- static void ohci_iso_recv_program(struct hpsb_iso *iso);
- static int ohci_iso_recv_init(struct hpsb_iso *iso)
- {
- struct ti_ohci *ohci = iso->host->hostdata;
- struct ohci_iso_recv *recv;
- int ctx;
- int ret = -ENOMEM;
- recv = kmalloc(sizeof(*recv), SLAB_KERNEL);
- if (!recv)
- return -ENOMEM;
- iso->hostdata = recv;
- recv->ohci = ohci;
- recv->task_active = 0;
- dma_prog_region_init(&recv->prog);
- recv->block = NULL;
- /* use buffer-fill mode, unless irq_interval is 1
- (note: multichannel requires buffer-fill) */
- if (((iso->irq_interval == 1 && iso->dma_mode == HPSB_ISO_DMA_OLD_ABI) ||
- iso->dma_mode == HPSB_ISO_DMA_PACKET_PER_BUFFER) && iso->channel != -1) {
- recv->dma_mode = PACKET_PER_BUFFER_MODE;
- } else {
- recv->dma_mode = BUFFER_FILL_MODE;
- }
- /* set nblocks, buf_stride, block_irq_interval */
- if (recv->dma_mode == BUFFER_FILL_MODE) {
- recv->buf_stride = PAGE_SIZE;
- /* one block per page of data in the DMA buffer, minus the final guard page */
- recv->nblocks = iso->buf_size/PAGE_SIZE - 1;
- if (recv->nblocks < 3) {
- DBGMSG("ohci_iso_recv_init: DMA buffer too small");
- goto err;
- }
- /* iso->irq_interval is in packets - translate that to blocks */
- if (iso->irq_interval == 1)
- recv->block_irq_interval = 1;
- else
- recv->block_irq_interval = iso->irq_interval *
- ((recv->nblocks+1)/iso->buf_packets);
- if (recv->block_irq_interval*4 > recv->nblocks)
- recv->block_irq_interval = recv->nblocks/4;
- if (recv->block_irq_interval < 1)
- recv->block_irq_interval = 1;
- } else {
- int max_packet_size;
- recv->nblocks = iso->buf_packets;
- recv->block_irq_interval = iso->irq_interval;
- if (recv->block_irq_interval * 4 > iso->buf_packets)
- recv->block_irq_interval = iso->buf_packets / 4;
- if (recv->block_irq_interval < 1)
- recv->block_irq_interval = 1;
- /* choose a buffer stride */
- /* must be a power of 2, and <= PAGE_SIZE */
- max_packet_size = iso->buf_size / iso->buf_packets;
- for (recv->buf_stride = 8; recv->buf_stride < max_packet_size;
- recv->buf_stride *= 2);
- if (recv->buf_stride*iso->buf_packets > iso->buf_size ||
- recv->buf_stride > PAGE_SIZE) {
- /* this shouldn't happen, but anyway... */
- DBGMSG("ohci_iso_recv_init: problem choosing a buffer stride");
- goto err;
- }
- }
- recv->block_reader = 0;
- recv->released_bytes = 0;
- recv->block_dma = 0;
- recv->dma_offset = 0;
- /* size of DMA program = one descriptor per block */
- if (dma_prog_region_alloc(&recv->prog,
- sizeof(struct dma_cmd) * recv->nblocks,
- recv->ohci->dev))
- goto err;
- recv->block = (struct dma_cmd*) recv->prog.kvirt;
- ohci1394_init_iso_tasklet(&recv->task,
- iso->channel == -1 ? OHCI_ISO_MULTICHANNEL_RECEIVE :
- OHCI_ISO_RECEIVE,
- ohci_iso_recv_task, (unsigned long) iso);
- if (ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) {
- ret = -EBUSY;
- goto err;
- }
- recv->task_active = 1;
- /* recv context registers are spaced 32 bytes apart */
- ctx = recv->task.context;
- recv->ContextControlSet = OHCI1394_IsoRcvContextControlSet + 32 * ctx;
- recv->ContextControlClear = OHCI1394_IsoRcvContextControlClear + 32 * ctx;
- recv->CommandPtr = OHCI1394_IsoRcvCommandPtr + 32 * ctx;
- recv->ContextMatch = OHCI1394_IsoRcvContextMatch + 32 * ctx;
- if (iso->channel == -1) {
- /* clear multi-channel selection mask */
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, 0xFFFFFFFF);
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, 0xFFFFFFFF);
- }
- /* write the DMA program */
- ohci_iso_recv_program(iso);
- DBGMSG("ohci_iso_recv_init: %s mode, DMA buffer is %lu pages"
- " (%u bytes), using %u blocks, buf_stride %u, block_irq_interval %d",
- recv->dma_mode == BUFFER_FILL_MODE ?
- "buffer-fill" : "packet-per-buffer",
- iso->buf_size/PAGE_SIZE, iso->buf_size,
- recv->nblocks, recv->buf_stride, recv->block_irq_interval);
- return 0;
- err:
- ohci_iso_recv_shutdown(iso);
- return ret;
- }
- static void ohci_iso_recv_stop(struct hpsb_iso *iso)
- {
- struct ohci_iso_recv *recv = iso->hostdata;
- /* disable interrupts */
- reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << recv->task.context);
- /* halt DMA */
- ohci1394_stop_context(recv->ohci, recv->ContextControlClear, NULL);
- }
- static void ohci_iso_recv_shutdown(struct hpsb_iso *iso)
- {
- struct ohci_iso_recv *recv = iso->hostdata;
- if (recv->task_active) {
- ohci_iso_recv_stop(iso);
- ohci1394_unregister_iso_tasklet(recv->ohci, &recv->task);
- recv->task_active = 0;
- }
- dma_prog_region_free(&recv->prog);
- kfree(recv);
- iso->hostdata = NULL;
- }
- /* set up a "gapped" ring buffer DMA program */
- static void ohci_iso_recv_program(struct hpsb_iso *iso)
- {
- struct ohci_iso_recv *recv = iso->hostdata;
- int blk;
- /* address of 'branch' field in previous DMA descriptor */
- u32 *prev_branch = NULL;
- for (blk = 0; blk < recv->nblocks; blk++) {
- u32 control;
- /* the DMA descriptor */
- struct dma_cmd *cmd = &recv->block[blk];
- /* offset of the DMA descriptor relative to the DMA prog buffer */
- unsigned long prog_offset = blk * sizeof(struct dma_cmd);
- /* offset of this packet's data within the DMA buffer */
- unsigned long buf_offset = blk * recv->buf_stride;
- if (recv->dma_mode == BUFFER_FILL_MODE) {
- control = 2 << 28; /* INPUT_MORE */
- } else {
- control = 3 << 28; /* INPUT_LAST */
- }
- control |= 8 << 24; /* s = 1, update xferStatus and resCount */
- /* interrupt on last block, and at intervals */
- if (blk == recv->nblocks-1 || (blk % recv->block_irq_interval) == 0) {
- control |= 3 << 20; /* want interrupt */
- }
- control |= 3 << 18; /* enable branch to address */
- control |= recv->buf_stride;
- cmd->control = cpu_to_le32(control);
- cmd->address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, buf_offset));
- cmd->branchAddress = 0; /* filled in on next loop */
- cmd->status = cpu_to_le32(recv->buf_stride);
- /* link the previous descriptor to this one */
- if (prev_branch) {
- *prev_branch = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, prog_offset) | 1);
- }
- prev_branch = &cmd->branchAddress;
- }
- /* the final descriptor's branch address and Z should be left at 0 */
- }
- /* listen or unlisten to a specific channel (multi-channel mode only) */
- static void ohci_iso_recv_change_channel(struct hpsb_iso *iso, unsigned char channel, int listen)
- {
- struct ohci_iso_recv *recv = iso->hostdata;
- int reg, i;
- if (channel < 32) {
- reg = listen ? OHCI1394_IRMultiChanMaskLoSet : OHCI1394_IRMultiChanMaskLoClear;
- i = channel;
- } else {
- reg = listen ? OHCI1394_IRMultiChanMaskHiSet : OHCI1394_IRMultiChanMaskHiClear;
- i = channel - 32;
- }
- reg_write(recv->ohci, reg, (1 << i));
- /* issue a dummy read to force all PCI writes to be posted immediately */
- mb();
- reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
- }
- static void ohci_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
- {
- struct ohci_iso_recv *recv = iso->hostdata;
- int i;
- for (i = 0; i < 64; i++) {
- if (mask & (1ULL << i)) {
- if (i < 32)
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoSet, (1 << i));
- else
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiSet, (1 << (i-32)));
- } else {
- if (i < 32)
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, (1 << i));
- else
- reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, (1 << (i-32)));
- }
- }
- /* issue a dummy read to force all PCI writes to be posted immediately */
- mb();
- reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
- }
- static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
- {
- struct ohci_iso_recv *recv = iso->hostdata;
- struct ti_ohci *ohci = recv->ohci;
- u32 command, contextMatch;
- reg_write(recv->ohci, recv->ContextControlClear, 0xFFFFFFFF);
- wmb();
- /* always keep ISO headers */
- command = (1 << 30);
- if (recv->dma_mode == BUFFER_FILL_MODE)
- command |= (1 << 31);
- reg_write(recv->ohci, recv->ContextControlSet, command);
- /* match on specified tags */
- contextMatch = tag_mask << 28;
- if (iso->channel == -1) {
- /* enable multichannel reception */
- reg_write(recv->ohci, recv->ContextControlSet, (1 << 28));
- } else {
- /* listen on channel */
- contextMatch |= iso->channel;
- }
- if (cycle != -1) {
- u32 seconds;
- /* enable cycleMatch */
- reg_write(recv->ohci, recv->ContextControlSet, (1 << 29));
- /* set starting cycle */
- cycle &= 0x1FFF;
- /* 'cycle' is only mod 8000, but we also need two 'seconds' bits -
- just snarf them from the current time */
- seconds = reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer) >> 25;
- /* advance one second to give some extra time for DMA to start */
- seconds += 1;
- cycle |= (seconds & 3) << 13;
- contextMatch |= cycle << 12;
- }
- if (sync != -1) {
- /* set sync flag on first DMA descriptor */
- struct dma_cmd *cmd = &recv->block[recv->block_dma];
- cmd->control |= cpu_to_le32(DMA_CTL_WAIT);
- /* match sync field */
- contextMatch |= (sync&0xf)<<8;
- }
- reg_write(recv->ohci, recv->ContextMatch, contextMatch);
- /* address of first descriptor block */
- command = dma_prog_region_offset_to_bus(&recv->prog,
- recv->block_dma * sizeof(struct dma_cmd));
- command |= 1; /* Z=1 */
- reg_write(recv->ohci, recv->CommandPtr, command);
- /* enable interrupts */
- reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskSet, 1 << recv->task.context);
- wmb();
- /* run */
- reg_write(recv->ohci, recv->ContextControlSet, 0x8000);
- /* issue a dummy read of the cycle timer register to force
- all PCI writes to be posted immediately */
- mb();
- reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer);
- /* check RUN */
- if (!(reg_read(recv->ohci, recv->ContextControlSet) & 0x8000)) {
- PRINT(KERN_ERR,
- "Error starting IR DMA (ContextControl 0x%08x)\n",
- reg_read(recv->ohci, recv->ContextControlSet));
- return -1;
- }
- return 0;
- }
- static void ohci_iso_recv_release_block(struct ohci_iso_recv *recv, int block)
- {
- /* re-use the DMA descriptor for the block */
- /* by linking the previous descriptor to it */
- int next_i = block;
- int prev_i = (next_i == 0) ? (recv->nblocks - 1) : (next_i - 1);
- struct dma_cmd *next = &recv->block[next_i];
- struct dma_cmd *prev = &recv->block[prev_i];
-
- /* ignore out-of-range requests */
- if ((block < 0) || (block > recv->nblocks))
- return;
- /* 'next' becomes the new end of the DMA chain,
- so disable branch and enable interrupt */
- next->branchAddress = 0;
- next->control |= cpu_to_le32(3 << 20);
- next->status = cpu_to_le32(recv->buf_stride);
- /* link prev to next */
- prev->branchAddress = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog,
- sizeof(struct dma_cmd) * next_i)
- | 1); /* Z=1 */
- /* disable interrupt on previous DMA descriptor, except at intervals */
- if ((prev_i % recv->block_irq_interval) == 0) {
- prev->control |= cpu_to_le32(3 << 20); /* enable interrupt */
- } else {
- prev->control &= cpu_to_le32(~(3<<20)); /* disable interrupt */
- }
- wmb();
- /* wake up DMA in case it fell asleep */
- reg_write(recv->ohci, recv->ContextControlSet, (1 << 12));
- }
- static void ohci_iso_recv_bufferfill_release(struct ohci_iso_recv *recv,
- struct hpsb_iso_packet_info *info)
- {
- /* release the memory where the packet was */
- recv->released_bytes += info->total_len;
- /* have we released enough memory for one block? */
- while (recv->released_bytes > recv->buf_stride) {
- ohci_iso_recv_release_block(recv, recv->block_reader);
- recv->block_reader = (recv->block_reader + 1) % recv->nblocks;
- recv->released_bytes -= recv->buf_stride;
- }
- }
- static inline void ohci_iso_recv_release(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info)
- {
- struct ohci_iso_recv *recv = iso->hostdata;
- if (recv->dma_mode == BUFFER_FILL_MODE) {
- ohci_iso_recv_bufferfill_release(recv, info);
- } else {
- ohci_iso_recv_release_block(recv, info - iso->infos);
- }
- }
- /* parse all packets from blocks that have been fully received */
- static void ohci_iso_recv_bufferfill_parse(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
- {
- int wake = 0;
- int runaway = 0;
- struct ti_ohci *ohci = recv->ohci;
- while (1) {
- /* we expect the next parsable packet to begin at recv->dma_offset */
- /* note: packet layout is as shown in section 10.6.1.1 of the OHCI spec */
- unsigned int offset;
- unsigned short len, cycle, total_len;
- unsigned char channel, tag, sy;
- unsigned char *p = iso->data_buf.kvirt;
- unsigned int this_block = recv->dma_offset/recv->buf_stride;
- /* don't loop indefinitely */
- if (runaway++ > 100000) {
- atomic_inc(&iso->overflows);
- PRINT(KERN_ERR,
- "IR DMA error - Runaway during buffer parsing!\n");
- break;
- }
- /* stop parsing once we arrive at block_dma (i.e. don't get ahead of DMA) */
- if (this_block == recv->block_dma)
- break;
- wake = 1;
- /* parse data length, tag, channel, and sy */
- /* note: we keep our own local copies of 'len' and 'offset'
- so the user can't mess with them by poking in the mmap area */
- len = p[recv->dma_offset+2] | (p[recv->dma_offset+3] << 8);
- if (len > 4096) {
- PRINT(KERN_ERR,
- "IR DMA error - bogus 'len' value %u\n", len);
- }
- channel = p[recv->dma_offset+1] & 0x3F;
- tag = p[recv->dma_offset+1] >> 6;
- sy = p[recv->dma_offset+0] & 0xF;
- /* advance to data payload */
- recv->dma_offset += 4;
- /* check for wrap-around */
- if (recv->dma_offset >= recv->buf_stride*recv->nblocks) {
- recv->dma_offset -= recv->buf_stride*recv->nblocks;
- }
- /* dma_offset now points to the first byte of the data payload */
- offset = recv->dma_offset;
- /* advance to xferStatus/timeStamp */
- recv->dma_offset += len;
- total_len = len + 8; /* 8 bytes header+trailer in OHCI packet */
- /* payload is padded to 4 bytes */
- if (len % 4) {
- recv->dma_offset += 4 - (len%4);
- total_len += 4 - (len%4);
- }
- /* check for wrap-around */
- if (recv->dma_offset >= recv->buf_stride*recv->nblocks) {
- /* uh oh, the packet data wraps from the last
- to the first DMA block - make the packet
- contiguous by copying its "tail" into the
- guard page */
- int guard_off = recv->buf_stride*recv->nblocks;
- int tail_len = len - (guard_off - offset);
- if (tail_len > 0 && tail_len < recv->buf_stride) {
- memcpy(iso->data_buf.kvirt + guard_off,
- iso->data_buf.kvirt,
- tail_len);
- }
- recv->dma_offset -= recv->buf_stride*recv->nblocks;
- }
- /* parse timestamp */
- cycle = p[recv->dma_offset+0] | (p[recv->dma_offset+1]<<8);
- cycle &= 0x1FFF;
- /* advance to next packet */
- recv->dma_offset += 4;
- /* check for wrap-around */
- if (recv->dma_offset >= recv->buf_stride*recv->nblocks) {
- recv->dma_offset -= recv->buf_stride*recv->nblocks;
- }
- hpsb_iso_packet_received(iso, offset, len, total_len, cycle, channel, tag, sy);
- }
- if (wake)
- hpsb_iso_wake(iso);
- }
- static void ohci_iso_recv_bufferfill_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
- {
- int loop;
- struct ti_ohci *ohci = recv->ohci;
- /* loop over all blocks */
- for (loop = 0; loop < recv->nblocks; loop++) {
- /* check block_dma to see if it's done */
- struct dma_cmd *im = &recv->block[recv->block_dma];
- /* check the DMA descriptor for new writes to xferStatus */
- u16 xferstatus = le32_to_cpu(im->status) >> 16;
- /* rescount is the number of bytes *remaining to be written* in the block */
- u16 rescount = le32_to_cpu(im->status) & 0xFFFF;
- unsigned char event = xferstatus & 0x1F;
- if (!event) {
- /* nothing has happened to this block yet */
- break;
- }
- if (event != 0x11) {
- atomic_inc(&iso->overflows);
- PRINT(KERN_ERR,
- "IR DMA error - OHCI error code 0x%02x\n", event);
- }
- if (rescount != 0) {
- /* the card is still writing to this block;
- we can't touch it until it's done */
- break;
- }
- /* OK, the block is finished... */
- /* sync our view of the block */
- dma_region_sync_for_cpu(&iso->data_buf, recv->block_dma*recv->buf_stride, recv->buf_stride);
- /* reset the DMA descriptor */
- im->status = recv->buf_stride;
- /* advance block_dma */
- recv->block_dma = (recv->block_dma + 1) % recv->nblocks;
- if ((recv->block_dma+1) % recv->nblocks == recv->block_reader) {
- atomic_inc(&iso->overflows);
- DBGMSG("ISO reception overflow - "
- "ran out of DMA blocks");
- }
- }
- /* parse any packets that have arrived */
- ohci_iso_recv_bufferfill_parse(iso, recv);
- }
- static void ohci_iso_recv_packetperbuf_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv)
- {
- int count;
- int wake = 0;
- struct ti_ohci *ohci = recv->ohci;
- /* loop over the entire buffer */
- for (count = 0; count < recv->nblocks; count++) {
- u32 packet_len = 0;
- /* pointer to the DMA descriptor */
- struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + iso->pkt_dma;
- /* check the DMA descriptor for new writes to xferStatus */
- u16 xferstatus = le32_to_cpu(il->status) >> 16;
- u16 rescount = le32_to_cpu(il->status) & 0xFFFF;
- unsigned char event = xferstatus & 0x1F;
- if (!event) {
- /* this packet hasn't come in yet; we are done for now */
- goto out;
- }
- if (event == 0x11) {
- /* packet received successfully! */
- /* rescount is the number of bytes *remaining* in the packet buffer,
- after the packet was written */
- packet_len = recv->buf_stride - rescount;
- } else if (event == 0x02) {
- PRINT(KERN_ERR, "IR DMA error - packet too long for buffer\n");
- } else if (event) {
- PRINT(KERN_ERR, "IR DMA error - OHCI error code 0x%02x\n", event);
- }
- /* sync our view of the buffer */
- dma_region_sync_for_cpu(&iso->data_buf, iso->pkt_dma * recv->buf_stride, recv->buf_stride);
- /* record the per-packet info */
- {
- /* iso header is 8 bytes ahead of the data payload */
- unsigned char *hdr;
- unsigned int offset;
- unsigned short cycle;
- unsigned char channel, tag, sy;
- offset = iso->pkt_dma * recv->buf_stride;
- hdr = iso->data_buf.kvirt + offset;
- /* skip iso header */
- offset += 8;
- packet_len -= 8;
- cycle = (hdr[0] | (hdr[1] << 8)) & 0x1FFF;
- channel = hdr[5] & 0x3F;
- tag = hdr[5] >> 6;
- sy = hdr[4] & 0xF;
- hpsb_iso_packet_received(iso, offset, packet_len,
- recv->buf_stride, cycle, channel, tag, sy);
- }
- /* reset the DMA descriptor */
- il->status = recv->buf_stride;
- wake = 1;
- recv->block_dma = iso->pkt_dma;
- }
- out:
- if (wake)
- hpsb_iso_wake(iso);
- }
- static void ohci_iso_recv_task(unsigned long data)
- {
- struct hpsb_iso *iso = (struct hpsb_iso*) data;
- struct ohci_iso_recv *recv = iso->hostdata;
- if (recv->dma_mode == BUFFER_FILL_MODE)
- ohci_iso_recv_bufferfill_task(iso, recv);
- else
- ohci_iso_recv_packetperbuf_task(iso, recv);
- }
- /***********************************
- * rawiso ISO transmission *
- ***********************************/
- struct ohci_iso_xmit {
- struct ti_ohci *ohci;
- struct dma_prog_region prog;
- struct ohci1394_iso_tasklet task;
- int task_active;
- u32 ContextControlSet;
- u32 ContextControlClear;
- u32 CommandPtr;
- };
- /* transmission DMA program:
- one OUTPUT_MORE_IMMEDIATE for the IT header
- one OUTPUT_LAST for the buffer data */
- struct iso_xmit_cmd {
- struct dma_cmd output_more_immediate;
- u8 iso_hdr[8];
- u32 unused[2];
- struct dma_cmd output_last;
- };
- static int ohci_iso_xmit_init(struct hpsb_iso *iso);
- static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle);
- static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso);
- static void ohci_iso_xmit_task(unsigned long data);
- static int ohci_iso_xmit_init(struct hpsb_iso *iso)
- {
- struct ohci_iso_xmit *xmit;
- unsigned int prog_size;
- int ctx;
- int ret = -ENOMEM;
- xmit = kmalloc(sizeof(*xmit), SLAB_KERNEL);
- if (!xmit)
- return -ENOMEM;
- iso->hostdata = xmit;
- xmit->ohci = iso->host->hostdata;
- xmit->task_active = 0;
- dma_prog_region_init(&xmit->prog);
- prog_size = sizeof(struct iso_xmit_cmd) * iso->buf_packets;
- if (dma_prog_region_alloc(&xmit->prog, prog_size, xmit->ohci->dev))
- goto err;
- ohci1394_init_iso_tasklet(&xmit->task, OHCI_ISO_TRANSMIT,
- ohci_iso_xmit_task, (unsigned long) iso);
- if (ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0) {
- ret = -EBUSY;
- goto err;
- }
- xmit->task_active = 1;
- /* xmit context registers are spaced 16 bytes apart */
- ctx = xmit->task.context;
- xmit->ContextControlSet = OHCI1394_IsoXmitContextControlSet + 16 * ctx;
- xmit->ContextControlClear = OHCI1394_IsoXmitContextControlClear + 16 * ctx;
- xmit->CommandPtr = OHCI1394_IsoXmitCommandPtr + 16 * ctx;
- return 0;
- err:
- ohci_iso_xmit_shutdown(iso);
- return ret;
- }
- static void ohci_iso_xmit_stop(struct hpsb_iso *iso)
- {
- struct ohci_iso_xmit *xmit = iso->hostdata;
- struct ti_ohci *ohci = xmit->ohci;
- /* disable interrupts */
- reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << xmit->task.context);
- /* halt DMA */
- if (ohci1394_stop_context(xmit->ohci, xmit->ContextControlClear, NULL)) {
- /* XXX the DMA context will lock up if you try to send too much data! */
- PRINT(KERN_ERR,
- "you probably exceeded the OHCI card's bandwidth limit - "
- "reload the module and reduce xmit bandwidth");
- }
- }
- static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso)
- {
- struct ohci_iso_xmit *xmit = iso->hostdata;
- if (xmit->task_active) {
- ohci_iso_xmit_stop(iso);
- ohci1394_unregister_iso_tasklet(xmit->ohci, &xmit->task);
- xmit->task_active = 0;
- }
- dma_prog_region_free(&xmit->prog);
- kfree(xmit);
- iso->hostdata = NULL;
- }
- static void ohci_iso_xmit_task(unsigned long data)
- {
- struct hpsb_iso *iso = (struct hpsb_iso*) data;
- struct ohci_iso_xmit *xmit = iso->hostdata;
- struct ti_ohci *ohci = xmit->ohci;
- int wake = 0;
- int count;
- /* check the whole buffer if necessary, starting at pkt_dma */
- for (count = 0; count < iso->buf_packets; count++) {
- int cycle;
- /* DMA descriptor */
- struct iso_xmit_cmd *cmd = dma_region_i(&xmit->prog, struct iso_xmit_cmd, iso->pkt_dma);
- /* check for new writes to xferStatus */
- u16 xferstatus = le32_to_cpu(cmd->output_last.status) >> 16;
- u8 event = xferstatus & 0x1F;
- if (!event) {
- /* packet hasn't been sent yet; we are done for now */
- break;
- }
- if (event != 0x11)
- PRINT(KERN_ERR,
- "IT DMA error - OHCI error code 0x%02x\n", event);
- /* at least one packet went out, so wake up the writer */
- wake = 1;
- /* parse cycle */
- cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF;
- /* tell the subsystem the packet has gone out */
- hpsb_iso_packet_sent(iso, cycle, event != 0x11);
- /* reset the DMA descriptor for next time */
- cmd->output_last.status = 0;
- }
- if (wake)
- hpsb_iso_wake(iso);
- }
- static int ohci_iso_xmit_queue(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info)
- {
- struct ohci_iso_xmit *xmit = iso->hostdata;
- struct ti_ohci *ohci = xmit->ohci;
- int next_i, prev_i;
- struct iso_xmit_cmd *next, *prev;
- unsigned int offset;
- unsigned short len;
- unsigned char tag, sy;
- /* check that the packet doesn't cross a page boundary
- (we could allow this if we added OUTPUT_MORE descriptor support) */
- if (cross_bound(info->offset, info->len)) {
- PRINT(KERN_ERR,
- "rawiso xmit: packet %u crosses a page boundary",
- iso->first_packet);
- return -EINVAL;
- }
- offset = info->offset;
- len = info->len;
- tag = info->tag;
- sy = info->sy;
- /* sync up the card's view of the buffer */
- dma_region_sync_for_device(&iso->data_buf, offset, len);
- /* append first_packet to the DMA chain */
- /* by linking the previous descriptor to it */
- /* (next will become the new end of the DMA chain) */
- next_i = iso->first_packet;
- prev_i = (next_i == 0) ? (iso->buf_packets - 1) : (next_i - 1);
- next = dma_region_i(&xmit->prog, struct iso_xmit_cmd, next_i);
- prev = dma_region_i(&xmit->prog, struct iso_xmit_cmd, prev_i);
- /* set up the OUTPUT_MORE_IMMEDIATE descriptor */
- memset(next, 0, sizeof(struct iso_xmit_cmd));
- next->output_more_immediate.control = cpu_to_le32(0x02000008);
- /* ISO packet header is embedded in the OUTPUT_MORE_IMMEDIATE */
- /* tcode = 0xA, and sy */
- next->iso_hdr[0] = 0xA0 | (sy & 0xF);
- /* tag and channel number */
- next->iso_hdr[1] = (tag << 6) | (iso->channel & 0x3F);
- /* transmission speed */
- next->iso_hdr[2] = iso->speed & 0x7;
- /* payload size */
- next->iso_hdr[6] = len & 0xFF;
- next->iso_hdr[7] = len >> 8;
- /* set up the OUTPUT_LAST */
- next->output_last.control = cpu_to_le32(1 << 28);
- next->output_last.control |= cpu_to_le32(1 << 27); /* update timeStamp */
- next->output_last.control |= cpu_to_le32(3 << 20); /* want interrupt */
- next->output_last.control |= cpu_to_le32(3 << 18); /* enable branch */
- next->output_last.control |= cpu_to_le32(len);
- /* payload bus address */
- next->output_last.address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, offset));
- /* leave branchAddress at zero for now */
- /* re-write the previous DMA descriptor to chain to this one */
- /* set prev branch address to point to next (Z=3) */
- prev->output_last.branchAddress = cpu_to_le32(
- dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3);
- /* disable interrupt, unless required by the IRQ interval */
- if (prev_i % iso->irq_interval) {
- prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */
- } else {
- prev->output_last.control |= cpu_to_le32(3 << 20); /* enable interrupt */
- }
- wmb();
- /* wake DMA in case it is sleeping */
- reg_write(xmit->ohci, xmit->ContextControlSet, 1 << 12);
- /* issue a dummy read of the cycle timer to force all PCI
- writes to be posted immediately */
- mb();
- reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer);
- return 0;
- }
- static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle)
- {
- struct ohci_iso_xmit *xmit = iso->hostdata;
- struct ti_ohci *ohci = xmit->ohci;
- /* clear out the control register */
- reg_write(xmit->ohci, xmit->ContextControlClear, 0xFFFFFFFF);
- wmb();
- /* address and length of first descriptor block (Z=3) */
- reg_write(xmit->ohci, xmit->CommandPtr,
- dma_prog_region_offset_to_bus(&xmit->prog, iso->pkt_dma * sizeof(struct iso_xmit_cmd)) | 3);
- /* cycle match */
- if (cycle != -1) {
- u32 start = cycle & 0x1FFF;
- /* 'cycle' is only mod 8000, but we also need two 'seconds' bits -
- just snarf them from the current time */
- u32 seconds = reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer) >> 25;
- /* advance one second to give some extra time for DMA to start */
- seconds += 1;
- start |= (seconds & 3) << 13;
- reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (start << 16));
- }
- /* enable interrupts */
- reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskSet, 1 << xmit->task.context);
- /* run */
- reg_write(xmit->ohci, xmit->ContextControlSet, 0x8000);
- mb();
- /* wait 100 usec to give the card time to go active */
- udelay(100);
- /* check the RUN bit */
- if (!(reg_read(xmit->ohci, xmit->ContextControlSet) & 0x8000)) {
- PRINT(KERN_ERR, "Error starting IT DMA (ContextControl 0x%08x)\n",
- reg_read(xmit->ohci, xmit->ContextControlSet));
- return -1;
- }
- return 0;
- }
- static int ohci_isoctl(struct hpsb_iso *iso, enum isoctl_cmd cmd, unsigned long arg)
- {
- switch(cmd) {
- case XMIT_INIT:
- return ohci_iso_xmit_init(iso);
- case XMIT_START:
- return ohci_iso_xmit_start(iso, arg);
- case XMIT_STOP:
- ohci_iso_xmit_stop(iso);
- return 0;
- case XMIT_QUEUE:
- return ohci_iso_xmit_queue(iso, (struct hpsb_iso_packet_info*) arg);
- case XMIT_SHUTDOWN:
- ohci_iso_xmit_shutdown(iso);
- return 0;
- case RECV_INIT:
- return ohci_iso_recv_init(iso);
- case RECV_START: {
- int *args = (int*) arg;
- return ohci_iso_recv_start(iso, args[0], args[1], args[2]);
- }
- case RECV_STOP:
- ohci_iso_recv_stop(iso);
- return 0;
- case RECV_RELEASE:
- ohci_iso_recv_release(iso, (struct hpsb_iso_packet_info*) arg);
- return 0;
- case RECV_FLUSH:
- ohci_iso_recv_task((unsigned long) iso);
- return 0;
- case RECV_SHUTDOWN:
- ohci_iso_recv_shutdown(iso);
- return 0;
- case RECV_LISTEN_CHANNEL:
- ohci_iso_recv_change_channel(iso, arg, 1);
- return 0;
- case RECV_UNLISTEN_CHANNEL:
- ohci_iso_recv_change_channel(iso, arg, 0);
- return 0;
- case RECV_SET_CHANNEL_MASK:
- ohci_iso_recv_set_channel_mask(iso, *((u64*) arg));
- return 0;
- default:
- PRINT_G(KERN_ERR, "ohci_isoctl cmd %d not implemented yet",
- cmd);
- break;
- }
- return -EINVAL;
- }
- /***************************************
- * IEEE-1394 functionality section END *
- ***************************************/
- /********************************************************
- * Global stuff (interrupt handler, init/shutdown code) *
- ********************************************************/
- static void dma_trm_reset(struct dma_trm_ctx *d)
- {
- unsigned long flags;
- LIST_HEAD(packet_list);
- struct ti_ohci *ohci = d->ohci;
- struct hpsb_packet *packet, *ptmp;
- ohci1394_stop_context(ohci, d->ctrlClear, NULL);
- /* Lock the context, reset it and release it. Move the packets
- * that were pending in the context to packet_list and free
- * them after releasing the lock. */
- spin_lock_irqsave(&d->lock, flags);
- list_splice(&d->fifo_list, &packet_list);
- list_splice(&d->pending_list, &packet_list);
- INIT_LIST_HEAD(&d->fifo_list);
- INIT_LIST_HEAD(&d->pending_list);
- d->branchAddrPtr = NULL;
- d->sent_ind = d->prg_ind;
- d->free_prgs = d->num_desc;
- spin_unlock_irqrestore(&d->lock, flags);
- if (list_empty(&packet_list))
- return;
- PRINT(KERN_INFO, "AT dma reset ctx=%d, aborting transmission", d->ctx);
- /* Now process subsystem callbacks for the packets from this
- * context. */
- list_for_each_entry_safe(packet, ptmp, &packet_list, driver_list) {
- list_del_init(&packet->driver_list);
- hpsb_packet_sent(ohci->host, packet, ACKX_ABORTED);
- }
- }
- static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci,
- quadlet_t rx_event,
- quadlet_t tx_event)
- {
- struct ohci1394_iso_tasklet *t;
- unsigned long mask;
- spin_lock(&ohci->iso_tasklet_list_lock);
- list_for_each_entry(t, &ohci->iso_tasklet_list, link) {
- mask = 1 << t->context;
- if (t->type == OHCI_ISO_TRANSMIT && tx_event & mask)
- tasklet_schedule(&t->tasklet);
- else if (rx_event & mask)
- tasklet_schedule(&t->tasklet);
- }
- spin_unlock(&ohci->iso_tasklet_list_lock);
- }
- static irqreturn_t ohci_irq_handler(int irq, void *dev_id,
- struct pt_regs *regs_are_unused)
- {
- quadlet_t event, node_id;
- struct ti_ohci *ohci = (struct ti_ohci *)dev_id;
- struct hpsb_host *host = ohci->host;
- int phyid = -1, isroot = 0;
- unsigned long flags;
- /* Read and clear the interrupt event register. Don't clear
- * the busReset event, though. This is done when we get the
- * selfIDComplete interrupt. */
- spin_lock_irqsave(&ohci->event_lock, flags);
- event = reg_read(ohci, OHCI1394_IntEventClear);
- reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset);
- spin_unlock_irqrestore(&ohci->event_lock, flags);
- if (!event)
- return IRQ_NONE;
- /* If event is ~(u32)0 cardbus card was ejected. In this case
- * we just return, and clean up in the ohci1394_pci_remove
- * function. */
- if (event == ~(u32) 0) {
- DBGMSG("Device removed.");
- return IRQ_NONE;
- }
- DBGMSG("IntEvent: %08x", event);
- if (event & OHCI1394_unrecoverableError) {
- int ctx;
- PRINT(KERN_ERR, "Unrecoverable error!");
- if (reg_read(ohci, OHCI1394_AsReqTrContextControlSet) & 0x800)
- PRINT(KERN_ERR, "Async Req Tx Context died: "
- "ctrl[%08x] cmdptr[%08x]",
- reg_read(ohci, OHCI1394_AsReqTrContextControlSet),
- reg_read(ohci, OHCI1394_AsReqTrCommandPtr));
- if (reg_read(ohci, OHCI1394_AsRspTrContextControlSet) & 0x800)
- PRINT(KERN_ERR, "Async Rsp Tx Context died: "
- "ctrl[%08x] cmdptr[%08x]",
- reg_read(ohci, OHCI1394_AsRspTrContextControlSet),
- reg_read(ohci, OHCI1394_AsRspTrCommandPtr));
- if (reg_read(ohci, OHCI1394_AsReqRcvContextControlSet) & 0x800)
- PRINT(KERN_ERR, "Async Req Rcv Context died: "
- "ctrl[%08x] cmdptr[%08x]",
- reg_read(ohci, OHCI1394_AsReqRcvContextControlSet),
- reg_read(ohci, OHCI1394_AsReqRcvCommandPtr));
- if (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x800)
- PRINT(KERN_ERR, "Async Rsp Rcv Context died: "
- "ctrl[%08x] cmdptr[%08x]",
- reg_read(ohci, OHCI1394_AsRspRcvContextControlSet),
- reg_read(ohci, OHCI1394_AsRspRcvCommandPtr));
- for (ctx = 0; ctx < ohci->nb_iso_xmit_ctx; ctx++) {
- if (reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)) & 0x800)
- PRINT(KERN_ERR, "Iso Xmit %d Context died: "
- "ctrl[%08x] cmdptr[%08x]", ctx,
- reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)),
- reg_read(ohci, OHCI1394_IsoXmitCommandPtr + (16 * ctx)));
- }
- for (ctx = 0; ctx < ohci->nb_iso_rcv_ctx; ctx++) {
- if (reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)) & 0x800)
- PRINT(KERN_ERR, "Iso Recv %d Context died: "
- "ctrl[%08x] cmdptr[%08x] match[%08x]", ctx,
- reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)),
- reg_read(ohci, OHCI1394_IsoRcvCommandPtr + (32 * ctx)),
- reg_read(ohci, OHCI1394_IsoRcvContextMatch + (32 * ctx)));
- }
- event &= ~OHCI1394_unrecoverableError;
- }
- if (event & OHCI1394_cycleInconsistent) {
- /* We subscribe to the cycleInconsistent event only to
- * clear the corresponding event bit... otherwise,
- * isochronous cycleMatch DMA won't work. */
- DBGMSG("OHCI1394_cycleInconsistent");
- event &= ~OHCI1394_cycleInconsistent;
- }
- if (event & OHCI1394_busReset) {
- /* The busReset event bit can't be cleared during the
- * selfID phase, so we disable busReset interrupts, to
- * avoid burying the cpu in interrupt requests. */
- spin_lock_irqsave(&ohci->event_lock, flags);
- reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset);
- if (ohci->check_busreset) {
- int loop_count = 0;
- udelay(10);
- while (reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
- reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
- spin_unlock_irqrestore(&ohci->event_lock, flags);
- udelay(10);
- spin_lock_irqsave(&ohci->event_lock, flags);
- /* The loop counter check is to prevent the driver
- * from remaining in this state forever. For the
- * initial bus reset, the loop continues for ever
- * and the system hangs, until some device is plugged-in
- * or out manually into a port! The forced reset seems
- * to solve this problem. This mainly effects nForce2. */
- if (loop_count > 10000) {
- ohci_devctl(host, RESET_BUS, LONG_RESET);
- DBGMSG("Detected bus-reset loop. Forced a bus reset!");
- loop_count = 0;
- }
- loop_count++;
- }
- }
- spin_unlock_irqrestore(&ohci->event_lock, flags);
- if (!host->in_bus_reset) {
- DBGMSG("irq_handler: Bus reset requested");
- /* Subsystem call */
- hpsb_bus_reset(ohci->host);
- }
- event &= ~OHCI1394_busReset;
- }
- if (event & OHCI1394_reqTxComplete) {
- struct dma_trm_ctx *d = &ohci->at_req_context;
- DBGMSG("Got reqTxComplete interrupt "
- "status=0x%08X", reg_read(ohci, d->ctrlSet));
- if (reg_read(ohci, d->ctrlSet) & 0x800)
- ohci1394_stop_context(ohci, d->ctrlClear,
- "reqTxComplete");
- else
- dma_trm_tasklet((unsigned long)d);
- //tasklet_schedule(&d->task);
- event &= ~OHCI1394_reqTxComplete;
- }
- if (event & OHCI1394_respTxComplete) {
- struct dma_trm_ctx *d = &ohci->at_resp_context;
- DBGMSG("Got respTxComplete interrupt "
- "status=0x%08X", reg_read(ohci, d->ctrlSet));
- if (reg_read(ohci, d->ctrlSet) & 0x800)
- ohci1394_stop_context(ohci, d->ctrlClear,
- "respTxComplete");
- else
- tasklet_schedule(&d->task);
- event &= ~OHCI1394_respTxComplete;
- }
- if (event & OHCI1394_RQPkt) {
- struct dma_rcv_ctx *d = &ohci->ar_req_context;
- DBGMSG("Got RQPkt interrupt status=0x%08X",
- reg_read(ohci, d->ctrlSet));
- if (reg_read(ohci, d->ctrlSet) & 0x800)
- ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt");
- else
- tasklet_schedule(&d->task);
- event &= ~OHCI1394_RQPkt;
- }
- if (event & OHCI1394_RSPkt) {
- struct dma_rcv_ctx *d = &ohci->ar_resp_context;
- DBGMSG("Got RSPkt interrupt status=0x%08X",
- reg_read(ohci, d->ctrlSet));
- if (reg_read(ohci, d->ctrlSet) & 0x800)
- ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt");
- else
- tasklet_schedule(&d->task);
- event &= ~OHCI1394_RSPkt;
- }
- if (event & OHCI1394_isochRx) {
- quadlet_t rx_event;
- rx_event = reg_read(ohci, OHCI1394_IsoRecvIntEventSet);
- reg_write(ohci, OHCI1394_IsoRecvIntEventClear, rx_event);
- ohci_schedule_iso_tasklets(ohci, rx_event, 0);
- event &= ~OHCI1394_isochRx;
- }
- if (event & OHCI1394_isochTx) {
- quadlet_t tx_event;
- tx_event = reg_read(ohci, OHCI1394_IsoXmitIntEventSet);
- reg_write(ohci, OHCI1394_IsoXmitIntEventClear, tx_event);
- ohci_schedule_iso_tasklets(ohci, 0, tx_event);
- event &= ~OHCI1394_isochTx;
- }
- if (event & OHCI1394_selfIDComplete) {
- if (host->in_bus_reset) {
- node_id = reg_read(ohci, OHCI1394_NodeID);
- if (!(node_id & 0x80000000)) {
- PRINT(KERN_ERR,
- "SelfID received, but NodeID invalid "
- "(probably new bus reset occurred): %08X",
- node_id);
- goto selfid_not_valid;
- }
- phyid = node_id & 0x0000003f;
- isroot = (node_id & 0x40000000) != 0;
- DBGMSG("SelfID interrupt received "
- "(phyid %d, %s)", phyid,
- (isroot ? "root" : "not root"));
- handle_selfid(ohci, host, phyid, isroot);
- /* Clear the bus reset event and re-enable the
- * busReset interrupt. */
- spin_lock_irqsave(&ohci->event_lock, flags);
- reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
- reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
- spin_unlock_irqrestore(&ohci->event_lock, flags);
- /* Accept Physical requests from all nodes. */
- reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0xffffffff);
- reg_write(ohci,OHCI1394_AsReqFilterLoSet, 0xffffffff);
- /* Turn on phys dma reception.
- *
- * TODO: Enable some sort of filtering management.
- */
- if (phys_dma) {
- reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0xffffffff);
- reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0xffffffff);
- reg_write(ohci,OHCI1394_PhyUpperBound, 0xffff0000);
- } else {
- reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0x00000000);
- reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0x00000000);
- }
- DBGMSG("PhyReqFilter=%08x%08x",
- reg_read(ohci,OHCI1394_PhyReqFilterHiSet),
- reg_read(ohci,OHCI1394_PhyReqFilterLoSet));
- hpsb_selfid_complete(host, phyid, isroot);
- } else
- PRINT(KERN_ERR,
- "SelfID received outside of bus reset sequence");
- selfid_not_valid:
- event &= ~OHCI1394_selfIDComplete;
- }
- /* Make sure we handle everything, just in case we accidentally
- * enabled an interrupt that we didn't write a handler for. */
- if (event)
- PRINT(KERN_ERR, "Unhandled interrupt(s) 0x%08x",
- event);
- return IRQ_HANDLED;
- }
- /* Put the buffer back into the dma context */
- static void insert_dma_buffer(struct dma_rcv_ctx *d, int idx)
- {
- struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
- DBGMSG("Inserting dma buf ctx=%d idx=%d", d->ctx, idx);
- d->prg_cpu[idx]->status = cpu_to_le32(d->buf_size);
- d->prg_cpu[idx]->branchAddress &= le32_to_cpu(0xfffffff0);
- idx = (idx + d->num_desc - 1 ) % d->num_desc;
- d->prg_cpu[idx]->branchAddress |= le32_to_cpu(0x00000001);
- /* To avoid a race, ensure 1394 interface hardware sees the inserted
- * context program descriptors before it sees the wakeup bit set. */
- wmb();
-
- /* wake up the dma context if necessary */
- if (!(reg_read(ohci, d->ctrlSet) & 0x400)) {
- PRINT(KERN_INFO,
- "Waking dma ctx=%d ... processing is probably too slow",
- d->ctx);
- }
- /* do this always, to avoid race condition */
- reg_write(ohci, d->ctrlSet, 0x1000);
- }
- #define cond_le32_to_cpu(data, noswap) \
- (noswap ? data : le32_to_cpu(data))
- static const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0,
- -1, 0, -1, 0, -1, -1, 16, -1};
- /*
- * Determine the length of a packet in the buffer
- * Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca>
- */
- static __inline__ int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *buf_ptr,
- int offset, unsigned char tcode, int noswap)
- {
- int length = -1;
- if (d->type == DMA_CTX_ASYNC_REQ || d->type == DMA_CTX_ASYNC_RESP) {
- length = TCODE_SIZE[tcode];
- if (length == 0) {
- if (offset + 12 >= d->buf_size) {
- length = (cond_le32_to_cpu(d->buf_cpu[(idx + 1) % d->num_desc]
- [3 - ((d->buf_size - offset) >> 2)], noswap) >> 16);
- } else {
- length = (cond_le32_to_cpu(buf_ptr[3], noswap) >> 16);
- }
- length += 20;
- }
- } else if (d->type == DMA_CTX_ISO) {
- /* Assumption: buffer fill mode with header/trailer */
- length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8;
- }
- if (length > 0 && length % 4)
- length += 4 - (length % 4);
- return length;
- }
- /* Tasklet that processes dma receive buffers */
- static void dma_rcv_tasklet (unsigned long data)
- {
- struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data;
- struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
- unsigned int split_left, idx, offset, rescount;
- unsigned char tcode;
- int length, bytes_left, ack;
- unsigned long flags;
- quadlet_t *buf_ptr;
- char *split_ptr;
- char msg[256];
- spin_lock_irqsave(&d->lock, flags);
- idx = d->buf_ind;
- offset = d->buf_offset;
- buf_ptr = d->buf_cpu[idx] + offset/4;
- rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
- bytes_left = d->buf_size - rescount - offset;
- while (bytes_left > 0) {
- tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf;
- /* packet_length() will return < 4 for an error */
- length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->no_swap_incoming);
- if (length < 4) { /* something is wrong */
- sprintf(msg,"Unexpected tcode 0x%x(0x%08x) in AR ctx=%d, length=%d",
- tcode, cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming),
- d->ctx, length);
- ohci1394_stop_context(ohci, d->ctrlClear, msg);
- spin_unlock_irqrestore(&d->lock, flags);
- return;
- }
- /* The first case is where we have a packet that crosses
- * over more than one descriptor. The next case is where
- * it's all in the first descriptor. */
- if ((offset + length) > d->buf_size) {
- DBGMSG("Split packet rcv'd");
- if (length > d->split_buf_size) {
- ohci1394_stop_context(ohci, d->ctrlClear,
- "Split packet size exceeded");
- d->buf_ind = idx;
- d->buf_offset = offset;
- spin_unlock_irqrestore(&d->lock, flags);
- return;
- }
- if (le32_to_cpu(d->prg_cpu[(idx+1)%d->num_desc]->status)
- == d->buf_size) {
- /* Other part of packet not written yet.
- * this should never happen I think
- * anyway we'll get it on the next call. */
- PRINT(KERN_INFO,
- "Got only half a packet!");
- d->buf_ind = idx;
- d->buf_offset = offset;
- spin_unlock_irqrestore(&d->lock, flags);
- return;
- }
- split_left = length;
- split_ptr = (char *)d->spb;
- memcpy(split_ptr,buf_ptr,d->buf_size-offset);
- split_left -= d->buf_size-offset;
- split_ptr += d->buf_size-offset;
- insert_dma_buffer(d, idx);
- idx = (idx+1) % d->num_desc;
- buf_ptr = d->buf_cpu[idx];
- offset=0;
- while (split_left >= d->buf_size) {
- memcpy(split_ptr,buf_ptr,d->buf_size);
- split_ptr += d->buf_size;
- split_left -= d->buf_size;
- insert_dma_buffer(d, idx);
- idx = (idx+1) % d->num_desc;
- buf_ptr = d->buf_cpu[idx];
- }
- if (split_left > 0) {
- memcpy(split_ptr, buf_ptr, split_left);
- offset = split_left;
- buf_ptr += offset/4;
- }
- } else {
- DBGMSG("Single packet rcv'd");
- memcpy(d->spb, buf_ptr, length);
- offset += length;
- buf_ptr += length/4;
- if (offset==d->buf_size) {
- insert_dma_buffer(d, idx);
- idx = (idx+1) % d->num_desc;
- buf_ptr = d->buf_cpu[idx];
- offset=0;
- }
- }
- /* We get one phy packet to the async descriptor for each
- * bus reset. We always ignore it. */
- if (tcode != OHCI1394_TCODE_PHY) {
- if (!ohci->no_swap_incoming)
- packet_swab(d->spb, tcode);
- DBGMSG("Packet received from node"
- " %d ack=0x%02X spd=%d tcode=0x%X"
- " length=%d ctx=%d tlabel=%d",
- (d->spb[1]>>16)&0x3f,
- (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f,
- (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3,
- tcode, length, d->ctx,
- (cond_le32_to_cpu(d->spb[0], ohci->no_swap_incoming)>>10)&0x3f);
- ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f)
- == 0x11) ? 1 : 0;
- hpsb_packet_received(ohci->host, d->spb,
- length-4, ack);
- }
- #ifdef OHCI1394_DEBUG
- else
- PRINT (KERN_DEBUG, "Got phy packet ctx=%d ... discarded",
- d->ctx);
- #endif
- rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff;
- bytes_left = d->buf_size - rescount - offset;
- }
- d->buf_ind = idx;
- d->buf_offset = offset;
- spin_unlock_irqrestore(&d->lock, flags);
- }
- /* Bottom half that processes sent packets */
- static void dma_trm_tasklet (unsigned long data)
- {
- struct dma_trm_ctx *d = (struct dma_trm_ctx*)data;
- struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci);
- struct hpsb_packet *packet, *ptmp;
- unsigned long flags;
- u32 status, ack;
- size_t datasize;
- spin_lock_irqsave(&d->lock, flags);
- list_for_each_entry_safe(packet, ptmp, &d->fifo_list, driver_list) {
- datasize = packet->data_size;
- if (datasize && packet->type != hpsb_raw)
- status = le32_to_cpu(
- d->prg_cpu[d->sent_ind]->end.status) >> 16;
- else
- status = le32_to_cpu(
- d->prg_cpu[d->sent_ind]->begin.status) >> 16;
- if (status == 0)
- /* this packet hasn't been sent yet*/
- break;
- #ifdef OHCI1394_DEBUG
- if (datasize)
- if (((le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf) == 0xa)
- DBGMSG("Stream packet sent to channel %d tcode=0x%X "
- "ack=0x%X spd=%d dataLength=%d ctx=%d",
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>8)&0x3f,
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf,
- status&0x1f, (status>>5)&0x3,
- le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16,
- d->ctx);
- else
- DBGMSG("Packet sent to node %d tcode=0x%X tLabel="
- "%d ack=0x%X spd=%d dataLength=%d ctx=%d",
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16)&0x3f,
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf,
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>10)&0x3f,
- status&0x1f, (status>>5)&0x3,
- le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3])>>16,
- d->ctx);
- else
- DBGMSG("Packet sent to node %d tcode=0x%X tLabel="
- "%d ack=0x%X spd=%d data=0x%08X ctx=%d",
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])
- >>16)&0x3f,
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
- >>4)&0xf,
- (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])
- >>10)&0x3f,
- status&0x1f, (status>>5)&0x3,
- le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]),
- d->ctx);
- #endif
- if (status & 0x10) {
- ack = status & 0xf;
- } else {
- switch (status & 0x1f) {
- case EVT_NO_STATUS: /* that should never happen */
- case EVT_RESERVED_A: /* that should never happen */
- case EVT_LONG_PACKET: /* that should never happen */
- PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_MISSING_ACK:
- ack = ACKX_TIMEOUT;
- break;
- case EVT_UNDERRUN:
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_OVERRUN: /* that should never happen */
- PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_DESCRIPTOR_READ:
- case EVT_DATA_READ:
- case EVT_DATA_WRITE:
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_BUS_RESET: /* that should never happen */
- PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_TIMEOUT:
- ack = ACKX_TIMEOUT;
- break;
- case EVT_TCODE_ERR:
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_RESERVED_B: /* that should never happen */
- case EVT_RESERVED_C: /* that should never happen */
- PRINT(KERN_WARNING, "Received OHCI evt_* error 0x%x", status & 0x1f);
- ack = ACKX_SEND_ERROR;
- break;
- case EVT_UNKNOWN:
- case EVT_FLUSHED:
- ack = ACKX_SEND_ERROR;
- break;
- default:
- PRINT(KERN_ERR, "Unhandled OHCI evt_* error 0x%x", status & 0x1f);
- ack = ACKX_SEND_ERROR;
- BUG();
- }
- }
- list_del_init(&packet->driver_list);
- hpsb_packet_sent(ohci->host, packet, ack);
- if (datasize) {
- pci_unmap_single(ohci->dev,
- cpu_to_le32(d->prg_cpu[d->sent_ind]->end.address),
- datasize, PCI_DMA_TODEVICE);
- OHCI_DMA_FREE("single Xmit data packet");
- }
- d->sent_ind = (d->sent_ind+1)%d->num_desc;
- d->free_prgs++;
- }
- dma_trm_flush(ohci, d);
- spin_unlock_irqrestore(&d->lock, flags);
- }
- static void stop_dma_rcv_ctx(struct dma_rcv_ctx *d)
- {
- if (d->ctrlClear) {
- ohci1394_stop_context(d->ohci, d->ctrlClear, NULL);
- if (d->type == DMA_CTX_ISO) {
- /* disable interrupts */
- reg_write(d->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << d->ctx);
- ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->ir_legacy_tasklet);
- } else {
- tasklet_kill(&d->task);
- }
- }
- }
- static void free_dma_rcv_ctx(struct dma_rcv_ctx *d)
- {
- int i;
- struct ti_ohci *ohci = d->ohci;
- if (ohci == NULL)
- return;
- DBGMSG("Freeing dma_rcv_ctx %d", d->ctx);
- if (d->buf_cpu) {
- for (i=0; i<d->num_desc; i++)
- if (d->buf_cpu[i] && d->buf_bus[i]) {
- pci_free_consistent(
- ohci->dev, d->buf_size,
- d->buf_cpu[i], d->buf_bus[i]);
- OHCI_DMA_FREE("consistent dma_rcv buf[%d]", i);
- }
- kfree(d->buf_cpu);
- kfree(d->buf_bus);
- }
- if (d->prg_cpu) {
- for (i=0; i<d->num_desc; i++)
- if (d->prg_cpu[i] && d->prg_bus[i]) {
- pci_pool_free(d->prg_pool, d->prg_cpu[i], d->prg_bus[i]);
- OHCI_DMA_FREE("consistent dma_rcv prg[%d]", i);
- }
- pci_pool_destroy(d->prg_pool);
- OHCI_DMA_FREE("dma_rcv prg pool");
- kfree(d->prg_cpu);
- kfree(d->prg_bus);
- }
- kfree(d->spb);
- /* Mark this context as freed. */
- d->ohci = NULL;
- }
- static int
- alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d,
- enum context_type type, int ctx, int num_desc,
- int buf_size, int split_buf_size, int context_base)
- {
- int i, len;
- static int num_allocs;
- static char pool_name[20];
- d->ohci = ohci;
- d->type = type;
- d->ctx = ctx;
- d->num_desc = num_desc;
- d->buf_size = buf_size;
- d->split_buf_size = split_buf_size;
- d->ctrlSet = 0;
- d->ctrlClear = 0;
- d->cmdPtr = 0;
- d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_ATOMIC);
- d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_ATOMIC);
- if (d->buf_cpu == NULL || d->buf_bus == NULL) {
- PRINT(KERN_ERR, "Failed to allocate dma buffer");
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
- memset(d->buf_cpu, 0, d->num_desc * sizeof(quadlet_t*));
- memset(d->buf_bus, 0, d->num_desc * sizeof(dma_addr_t));
- d->prg_cpu = kmalloc(d->num_desc * sizeof(struct dma_cmd*),
- GFP_ATOMIC);
- d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_ATOMIC);
- if (d->prg_cpu == NULL || d->prg_bus == NULL) {
- PRINT(KERN_ERR, "Failed to allocate dma prg");
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
- memset(d->prg_cpu, 0, d->num_desc * sizeof(struct dma_cmd*));
- memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t));
- d->spb = kmalloc(d->split_buf_size, GFP_ATOMIC);
- if (d->spb == NULL) {
- PRINT(KERN_ERR, "Failed to allocate split buffer");
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
-
- len = sprintf(pool_name, "ohci1394_rcv_prg");
- sprintf(pool_name+len, "%d", num_allocs);
- d->prg_pool = pci_pool_create(pool_name, ohci->dev,
- sizeof(struct dma_cmd), 4, 0);
- if(d->prg_pool == NULL)
- {
- PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name);
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
- num_allocs++;
- OHCI_DMA_ALLOC("dma_rcv prg pool");
- for (i=0; i<d->num_desc; i++) {
- d->buf_cpu[i] = pci_alloc_consistent(ohci->dev,
- d->buf_size,
- d->buf_bus+i);
- OHCI_DMA_ALLOC("consistent dma_rcv buf[%d]", i);
- if (d->buf_cpu[i] != NULL) {
- memset(d->buf_cpu[i], 0, d->buf_size);
- } else {
- PRINT(KERN_ERR,
- "Failed to allocate dma buffer");
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
- d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, SLAB_KERNEL, d->prg_bus+i);
- OHCI_DMA_ALLOC("pool dma_rcv prg[%d]", i);
- if (d->prg_cpu[i] != NULL) {
- memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd));
- } else {
- PRINT(KERN_ERR,
- "Failed to allocate dma prg");
- free_dma_rcv_ctx(d);
- return -ENOMEM;
- }
- }
- spin_lock_init(&d->lock);
- if (type == DMA_CTX_ISO) {
- ohci1394_init_iso_tasklet(&ohci->ir_legacy_tasklet,
- OHCI_ISO_MULTICHANNEL_RECEIVE,
- dma_rcv_tasklet, (unsigned long) d);
- } else {
- d->ctrlSet = context_base + OHCI1394_ContextControlSet;
- d->ctrlClear = context_base + OHCI1394_ContextControlClear;
- d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
- tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long) d);
- }
- return 0;
- }
- static void free_dma_trm_ctx(struct dma_trm_ctx *d)
- {
- int i;
- struct ti_ohci *ohci = d->ohci;
- if (ohci == NULL)
- return;
- DBGMSG("Freeing dma_trm_ctx %d", d->ctx);
- if (d->prg_cpu) {
- for (i=0; i<d->num_desc; i++)
- if (d->prg_cpu[i] && d->prg_bus[i]) {
- pci_pool_free(d->prg_pool, d->prg_cpu[i], d->prg_bus[i]);
- OHCI_DMA_FREE("pool dma_trm prg[%d]", i);
- }
- pci_pool_destroy(d->prg_pool);
- OHCI_DMA_FREE("dma_trm prg pool");
- kfree(d->prg_cpu);
- kfree(d->prg_bus);
- }
- /* Mark this context as freed. */
- d->ohci = NULL;
- }
- static int
- alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
- enum context_type type, int ctx, int num_desc,
- int context_base)
- {
- int i, len;
- static char pool_name[20];
- static int num_allocs=0;
- d->ohci = ohci;
- d->type = type;
- d->ctx = ctx;
- d->num_desc = num_desc;
- d->ctrlSet = 0;
- d->ctrlClear = 0;
- d->cmdPtr = 0;
- d->prg_cpu = kmalloc(d->num_desc * sizeof(struct at_dma_prg*),
- GFP_KERNEL);
- d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL);
- if (d->prg_cpu == NULL || d->prg_bus == NULL) {
- PRINT(KERN_ERR, "Failed to allocate at dma prg");
- free_dma_trm_ctx(d);
- return -ENOMEM;
- }
- memset(d->prg_cpu, 0, d->num_desc * sizeof(struct at_dma_prg*));
- memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t));
- len = sprintf(pool_name, "ohci1394_trm_prg");
- sprintf(pool_name+len, "%d", num_allocs);
- d->prg_pool = pci_pool_create(pool_name, ohci->dev,
- sizeof(struct at_dma_prg), 4, 0);
- if (d->prg_pool == NULL) {
- PRINT(KERN_ERR, "pci_pool_create failed for %s", pool_name);
- free_dma_trm_ctx(d);
- return -ENOMEM;
- }
- num_allocs++;
- OHCI_DMA_ALLOC("dma_rcv prg pool");
- for (i = 0; i < d->num_desc; i++) {
- d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, SLAB_KERNEL, d->prg_bus+i);
- OHCI_DMA_ALLOC("pool dma_trm prg[%d]", i);
- if (d->prg_cpu[i] != NULL) {
- memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg));
- } else {
- PRINT(KERN_ERR,
- "Failed to allocate at dma prg");
- free_dma_trm_ctx(d);
- return -ENOMEM;
- }
- }
- spin_lock_init(&d->lock);
- /* initialize tasklet */
- if (type == DMA_CTX_ISO) {
- ohci1394_init_iso_tasklet(&ohci->it_legacy_tasklet, OHCI_ISO_TRANSMIT,
- dma_trm_tasklet, (unsigned long) d);
- if (ohci1394_register_iso_tasklet(ohci,
- &ohci->it_legacy_tasklet) < 0) {
- PRINT(KERN_ERR, "No IT DMA context available");
- free_dma_trm_ctx(d);
- return -EBUSY;
- }
- /* IT can be assigned to any context by register_iso_tasklet */
- d->ctx = ohci->it_legacy_tasklet.context;
- d->ctrlSet = OHCI1394_IsoXmitContextControlSet + 16 * d->ctx;
- d->ctrlClear = OHCI1394_IsoXmitContextControlClear + 16 * d->ctx;
- d->cmdPtr = OHCI1394_IsoXmitCommandPtr + 16 * d->ctx;
- } else {
- d->ctrlSet = context_base + OHCI1394_ContextControlSet;
- d->ctrlClear = context_base + OHCI1394_ContextControlClear;
- d->cmdPtr = context_base + OHCI1394_ContextCommandPtr;
- tasklet_init (&d->task, dma_trm_tasklet, (unsigned long)d);
- }
- return 0;
- }
- static void ohci_set_hw_config_rom(struct hpsb_host *host, quadlet_t *config_rom)
- {
- struct ti_ohci *ohci = host->hostdata;
- reg_write(ohci, OHCI1394_ConfigROMhdr, be32_to_cpu(config_rom[0]));
- reg_write(ohci, OHCI1394_BusOptions, be32_to_cpu(config_rom[2]));
- memcpy(ohci->csr_config_rom_cpu, config_rom, OHCI_CONFIG_ROM_LEN);
- }
- static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg,
- quadlet_t data, quadlet_t compare)
- {
- struct ti_ohci *ohci = host->hostdata;
- int i;
- reg_write(ohci, OHCI1394_CSRData, data);
- reg_write(ohci, OHCI1394_CSRCompareData, compare);
- reg_write(ohci, OHCI1394_CSRControl, reg & 0x3);
- for (i = 0; i < OHCI_LOOP_COUNT; i++) {
- if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
- break;
- mdelay(1);
- }
- return reg_read(ohci, OHCI1394_CSRData);
- }
- static struct hpsb_host_driver ohci1394_driver = {
- .owner = THIS_MODULE,
- .name = OHCI1394_DRIVER_NAME,
- .set_hw_config_rom = ohci_set_hw_config_rom,
- .transmit_packet = ohci_transmit,
- .devctl = ohci_devctl,
- .isoctl = ohci_isoctl,
- .hw_csr_reg = ohci_hw_csr_reg,
- };
- /***********************************
- * PCI Driver Interface functions *
- ***********************************/
- #define FAIL(err, fmt, args...) \
- do { \
- PRINT_G(KERN_ERR, fmt , ## args); \
- ohci1394_pci_remove(dev); \
- return err; \
- } while (0)
- static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
- {
- static int version_printed = 0;
- struct hpsb_host *host;
- struct ti_ohci *ohci; /* shortcut to currently handled device */
- unsigned long ohci_base;
- if (version_printed++ == 0)
- PRINT_G(KERN_INFO, "%s", version);
- if (pci_enable_device(dev))
- FAIL(-ENXIO, "Failed to enable OHCI hardware");
- pci_set_master(dev);
- host = hpsb_alloc_host(&ohci1394_driver, sizeof(struct ti_ohci), &dev->dev);
- if (!host) FAIL(-ENOMEM, "Failed to allocate host structure");
- ohci = host->hostdata;
- ohci->dev = dev;
- ohci->host = host;
- ohci->init_state = OHCI_INIT_ALLOC_HOST;
- host->pdev = dev;
- pci_set_drvdata(dev, ohci);
- /* We don't want hardware swapping */
- pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
- /* Some oddball Apple controllers do not order the selfid
- * properly, so we make up for it here. */
- #ifndef __LITTLE_ENDIAN
- /* XXX: Need a better way to check this. I'm wondering if we can
- * read the values of the OHCI1394_PCI_HCI_Control and the
- * noByteSwapData registers to see if they were not cleared to
- * zero. Should this work? Obviously it's not defined what these
- * registers will read when they aren't supported. Bleh! */
- if (dev->vendor == PCI_VENDOR_ID_APPLE &&
- dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) {
- ohci->no_swap_incoming = 1;
- ohci->selfid_swap = 0;
- } else
- ohci->selfid_swap = 1;
- #endif
- #ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2_FW
- #define PCI_DEVICE_ID_NVIDIA_NFORCE2_FW 0x006e
- #endif
- /* These chipsets require a bit of extra care when checking after
- * a busreset. */
- if ((dev->vendor == PCI_VENDOR_ID_APPLE &&
- dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) ||
- (dev->vendor == PCI_VENDOR_ID_NVIDIA &&
- dev->device == PCI_DEVICE_ID_NVIDIA_NFORCE2_FW))
- ohci->check_busreset = 1;
- /* We hardwire the MMIO length, since some CardBus adaptors
- * fail to report the right length. Anyway, the ohci spec
- * clearly says it's 2kb, so this shouldn't be a problem. */
- ohci_base = pci_resource_start(dev, 0);
- if (pci_resource_len(dev, 0) != OHCI1394_REGISTER_SIZE)
- PRINT(KERN_WARNING, "Unexpected PCI resource length of %lx!",
- pci_resource_len(dev, 0));
- /* Seems PCMCIA handles this internally. Not sure why. Seems
- * pretty bogus to force a driver to special case this. */
- #ifndef PCMCIA
- if (!request_mem_region (ohci_base, OHCI1394_REGISTER_SIZE, OHCI1394_DRIVER_NAME))
- FAIL(-ENOMEM, "MMIO resource (0x%lx - 0x%lx) unavailable",
- ohci_base, ohci_base + OHCI1394_REGISTER_SIZE);
- #endif
- ohci->init_state = OHCI_INIT_HAVE_MEM_REGION;
- ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE);
- if (ohci->registers == NULL)
- FAIL(-ENXIO, "Failed to remap registers - card not accessible");
- ohci->init_state = OHCI_INIT_HAVE_IOMAPPING;
- DBGMSG("Remapped memory spaces reg 0x%p", ohci->registers);
- /* csr_config rom allocation */
- ohci->csr_config_rom_cpu =
- pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,
- &ohci->csr_config_rom_bus);
- OHCI_DMA_ALLOC("consistent csr_config_rom");
- if (ohci->csr_config_rom_cpu == NULL)
- FAIL(-ENOMEM, "Failed to allocate buffer config rom");
- ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER;
- /* self-id dma buffer allocation */
- ohci->selfid_buf_cpu =
- pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE,
- &ohci->selfid_buf_bus);
- OHCI_DMA_ALLOC("consistent selfid_buf");
- if (ohci->selfid_buf_cpu == NULL)
- FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets");
- ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER;
- if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff)
- PRINT(KERN_INFO, "SelfID buffer %p is not aligned on "
- "8Kb boundary... may cause problems on some CXD3222 chip",
- ohci->selfid_buf_cpu);
- /* No self-id errors at startup */
- ohci->self_id_errors = 0;
- ohci->init_state = OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE;
- /* AR DMA request context allocation */
- if (alloc_dma_rcv_ctx(ohci, &ohci->ar_req_context,
- DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC,
- AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE,
- OHCI1394_AsReqRcvContextBase) < 0)
- FAIL(-ENOMEM, "Failed to allocate AR Req context");
- /* AR DMA response context allocation */
- if (alloc_dma_rcv_ctx(ohci, &ohci->ar_resp_context,
- DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC,
- AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE,
- OHCI1394_AsRspRcvContextBase) < 0)
- FAIL(-ENOMEM, "Failed to allocate AR Resp context");
- /* AT DMA request context */
- if (alloc_dma_trm_ctx(ohci, &ohci->at_req_context,
- DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC,
- OHCI1394_AsReqTrContextBase) < 0)
- FAIL(-ENOMEM, "Failed to allocate AT Req context");
- /* AT DMA response context */
- if (alloc_dma_trm_ctx(ohci, &ohci->at_resp_context,
- DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC,
- OHCI1394_AsRspTrContextBase) < 0)
- FAIL(-ENOMEM, "Failed to allocate AT Resp context");
- /* Start off with a soft reset, to clear everything to a sane
- * state. */
- ohci_soft_reset(ohci);
- /* Now enable LPS, which we need in order to start accessing
- * most of the registers. In fact, on some cards (ALI M5251),
- * accessing registers in the SClk domain without LPS enabled
- * will lock up the machine. Wait 50msec to make sure we have
- * full link enabled. */
- reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
- /* Disable and clear interrupts */
- reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
- mdelay(50);
- /* Determine the number of available IR and IT contexts. */
- ohci->nb_iso_rcv_ctx =
- get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet);
- DBGMSG("%d iso receive contexts available",
- ohci->nb_iso_rcv_ctx);
- ohci->nb_iso_xmit_ctx =
- get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet);
- DBGMSG("%d iso transmit contexts available",
- ohci->nb_iso_xmit_ctx);
- /* Set the usage bits for non-existent contexts so they can't
- * be allocated */
- ohci->ir_ctx_usage = ~0 << ohci->nb_iso_rcv_ctx;
- ohci->it_ctx_usage = ~0 << ohci->nb_iso_xmit_ctx;
- INIT_LIST_HEAD(&ohci->iso_tasklet_list);
- spin_lock_init(&ohci->iso_tasklet_list_lock);
- ohci->ISO_channel_usage = 0;
- spin_lock_init(&ohci->IR_channel_lock);
- /* Allocate the IR DMA context right here so we don't have
- * to do it in interrupt path - note that this doesn't
- * waste much memory and avoids the jugglery required to
- * allocate it in IRQ path. */
- if (alloc_dma_rcv_ctx(ohci, &ohci->ir_legacy_context,
- DMA_CTX_ISO, 0, IR_NUM_DESC,
- IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
- OHCI1394_IsoRcvContextBase) < 0) {
- FAIL(-ENOMEM, "Cannot allocate IR Legacy DMA context");
- }
- /* We hopefully don't have to pre-allocate IT DMA like we did
- * for IR DMA above. Allocate it on-demand and mark inactive. */
- ohci->it_legacy_context.ohci = NULL;
- spin_lock_init(&ohci->event_lock);
- /*
- * interrupts are disabled, all right, but... due to SA_SHIRQ we
- * might get called anyway. We'll see no event, of course, but
- * we need to get to that "no event", so enough should be initialized
- * by that point.
- */
- if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,
- OHCI1394_DRIVER_NAME, ohci))
- FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq);
- ohci->init_state = OHCI_INIT_HAVE_IRQ;
- ohci_initialize(ohci);
- /* Set certain csr values */
- host->csr.guid_hi = reg_read(ohci, OHCI1394_GUIDHi);
- host->csr.guid_lo = reg_read(ohci, OHCI1394_GUIDLo);
- host->csr.cyc_clk_acc = 100; /* how do we determine clk accuracy? */
- host->csr.max_rec = (reg_read(ohci, OHCI1394_BusOptions) >> 12) & 0xf;
- host->csr.lnk_spd = reg_read(ohci, OHCI1394_BusOptions) & 0x7;
- /* Tell the highlevel this host is ready */
- if (hpsb_add_host(host))
- FAIL(-ENOMEM, "Failed to register host with highlevel");
- ohci->init_state = OHCI_INIT_DONE;
- return 0;
- #undef FAIL
- }
- static void ohci1394_pci_remove(struct pci_dev *pdev)
- {
- struct ti_ohci *ohci;
- struct device *dev;
- ohci = pci_get_drvdata(pdev);
- if (!ohci)
- return;
- dev = get_device(&ohci->host->device);
- switch (ohci->init_state) {
- case OHCI_INIT_DONE:
- hpsb_remove_host(ohci->host);
- /* Clear out BUS Options */
- reg_write(ohci, OHCI1394_ConfigROMhdr, 0);
- reg_write(ohci, OHCI1394_BusOptions,
- (reg_read(ohci, OHCI1394_BusOptions) & 0x0000f007) |
- 0x00ff0000);
- memset(ohci->csr_config_rom_cpu, 0, OHCI_CONFIG_ROM_LEN);
- case OHCI_INIT_HAVE_IRQ:
- /* Clear interrupt registers */
- reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
- reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
- /* Disable IRM Contender */
- set_phy_reg(ohci, 4, ~0xc0 & get_phy_reg(ohci, 4));
- /* Clear link control register */
- reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
- /* Let all other nodes know to ignore us */
- ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT);
- /* Soft reset before we start - this disables
- * interrupts and clears linkEnable and LPS. */
- ohci_soft_reset(ohci);
- free_irq(ohci->dev->irq, ohci);
- case OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE:
- /* The ohci_soft_reset() stops all DMA contexts, so we
- * dont need to do this. */
- /* Free AR dma */
- free_dma_rcv_ctx(&ohci->ar_req_context);
- free_dma_rcv_ctx(&ohci->ar_resp_context);
- /* Free AT dma */
- free_dma_trm_ctx(&ohci->at_req_context);
- free_dma_trm_ctx(&ohci->at_resp_context);
- /* Free IR dma */
- free_dma_rcv_ctx(&ohci->ir_legacy_context);
- /* Free IT dma */
- free_dma_trm_ctx(&ohci->it_legacy_context);
- /* Free IR legacy dma */
- free_dma_rcv_ctx(&ohci->ir_legacy_context);
- case OHCI_INIT_HAVE_SELFID_BUFFER:
- pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE,
- ohci->selfid_buf_cpu,
- ohci->selfid_buf_bus);
- OHCI_DMA_FREE("consistent selfid_buf");
- case OHCI_INIT_HAVE_CONFIG_ROM_BUFFER:
- pci_free_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN,
- ohci->csr_config_rom_cpu,
- ohci->csr_config_rom_bus);
- OHCI_DMA_FREE("consistent csr_config_rom");
- case OHCI_INIT_HAVE_IOMAPPING:
- iounmap(ohci->registers);
- case OHCI_INIT_HAVE_MEM_REGION:
- #ifndef PCMCIA
- release_mem_region(pci_resource_start(ohci->dev, 0),
- OHCI1394_REGISTER_SIZE);
- #endif
- #ifdef CONFIG_PPC_PMAC
- /* On UniNorth, power down the cable and turn off the chip
- * clock when the module is removed to save power on
- * laptops. Turning it back ON is done by the arch code when
- * pci_enable_device() is called */
- {
- struct device_node* of_node;
- of_node = pci_device_to_OF_node(ohci->dev);
- if (of_node) {
- pmac_call_feature(PMAC_FTR_1394_ENABLE, of_node, 0, 0);
- pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, of_node, 0, 0);
- }
- }
- #endif /* CONFIG_PPC_PMAC */
- case OHCI_INIT_ALLOC_HOST:
- pci_set_drvdata(ohci->dev, NULL);
- }
- if (dev)
- put_device(dev);
- }
- static int ohci1394_pci_resume (struct pci_dev *pdev)
- {
- #ifdef CONFIG_PPC_PMAC
- if (_machine == _MACH_Pmac) {
- struct device_node *of_node;
- /* Re-enable 1394 */
- of_node = pci_device_to_OF_node (pdev);
- if (of_node)
- pmac_call_feature (PMAC_FTR_1394_ENABLE, of_node, 0, 1);
- }
- #endif /* CONFIG_PPC_PMAC */
- pci_enable_device(pdev);
- return 0;
- }
- static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state)
- {
- #ifdef CONFIG_PPC_PMAC
- if (_machine == _MACH_Pmac) {
- struct device_node *of_node;
- /* Disable 1394 */
- of_node = pci_device_to_OF_node (pdev);
- if (of_node)
- pmac_call_feature(PMAC_FTR_1394_ENABLE, of_node, 0, 0);
- }
- #endif
- return 0;
- }
- #define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
- static struct pci_device_id ohci1394_pci_tbl[] = {
- {
- .class = PCI_CLASS_FIREWIRE_OHCI,
- .class_mask = PCI_ANY_ID,
- .vendor = PCI_ANY_ID,
- .device = PCI_ANY_ID,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { 0, },
- };
- MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl);
- static struct pci_driver ohci1394_pci_driver = {
- .name = OHCI1394_DRIVER_NAME,
- .id_table = ohci1394_pci_tbl,
- .probe = ohci1394_pci_probe,
- .remove = ohci1394_pci_remove,
- .resume = ohci1394_pci_resume,
- .suspend = ohci1394_pci_suspend,
- };
- /***********************************
- * OHCI1394 Video Interface *
- ***********************************/
- /* essentially the only purpose of this code is to allow another
- module to hook into ohci's interrupt handler */
- int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
- {
- int i=0;
- /* stop the channel program if it's still running */
- reg_write(ohci, reg, 0x8000);
- /* Wait until it effectively stops */
- while (reg_read(ohci, reg) & 0x400) {
- i++;
- if (i>5000) {
- PRINT(KERN_ERR,
- "Runaway loop while stopping context: %s...", msg ? msg : "");
- return 1;
- }
- mb();
- udelay(10);
- }
- if (msg) PRINT(KERN_ERR, "%s: dma prg stopped", msg);
- return 0;
- }
- void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, int type,
- void (*func)(unsigned long), unsigned long data)
- {
- tasklet_init(&tasklet->tasklet, func, data);
- tasklet->type = type;
- /* We init the tasklet->link field, so we can list_del() it
- * without worrying whether it was added to the list or not. */
- INIT_LIST_HEAD(&tasklet->link);
- }
- int ohci1394_register_iso_tasklet(struct ti_ohci *ohci,
- struct ohci1394_iso_tasklet *tasklet)
- {
- unsigned long flags, *usage;
- int n, i, r = -EBUSY;
- if (tasklet->type == OHCI_ISO_TRANSMIT) {
- n = ohci->nb_iso_xmit_ctx;
- usage = &ohci->it_ctx_usage;
- }
- else {
- n = ohci->nb_iso_rcv_ctx;
- usage = &ohci->ir_ctx_usage;
- /* only one receive context can be multichannel (OHCI sec 10.4.1) */
- if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) {
- if (test_and_set_bit(0, &ohci->ir_multichannel_used)) {
- return r;
- }
- }
- }
- spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
- for (i = 0; i < n; i++)
- if (!test_and_set_bit(i, usage)) {
- tasklet->context = i;
- list_add_tail(&tasklet->link, &ohci->iso_tasklet_list);
- r = 0;
- break;
- }
- spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
- return r;
- }
- void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
- struct ohci1394_iso_tasklet *tasklet)
- {
- unsigned long flags;
- tasklet_kill(&tasklet->tasklet);
- spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags);
- if (tasklet->type == OHCI_ISO_TRANSMIT)
- clear_bit(tasklet->context, &ohci->it_ctx_usage);
- else {
- clear_bit(tasklet->context, &ohci->ir_ctx_usage);
- if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) {
- clear_bit(0, &ohci->ir_multichannel_used);
- }
- }
- list_del(&tasklet->link);
- spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
- }
- EXPORT_SYMBOL(ohci1394_stop_context);
- EXPORT_SYMBOL(ohci1394_init_iso_tasklet);
- EXPORT_SYMBOL(ohci1394_register_iso_tasklet);
- EXPORT_SYMBOL(ohci1394_unregister_iso_tasklet);
- /***********************************
- * General module initialization *
- ***********************************/
- MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
- MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers");
- MODULE_LICENSE("GPL");
- static void __exit ohci1394_cleanup (void)
- {
- pci_unregister_driver(&ohci1394_pci_driver);
- }
- static int __init ohci1394_init(void)
- {
- return pci_register_driver(&ohci1394_pci_driver);
- }
- module_init(ohci1394_init);
- module_exit(ohci1394_cleanup);
|